blob: 16442bc813e4dc0d028977a75f12519903e574a5 [file] [log] [blame]
fpizlo@apple.comfc70ba62014-09-26 03:59:33 +00001/*
mark.lam@apple.comc7657a02018-04-09 17:42:01 +00002 * Copyright (C) 2014-2018 Apple Inc. All rights reserved.
fpizlo@apple.comfc70ba62014-09-26 03:59:33 +00003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "FTLOperations.h"
28
29#if ENABLE(FTL_JIT)
30
utatane.tea@gmail.com7b95a222018-06-16 16:33:58 +000031#include "BytecodeStructs.h"
fpizlo@apple.comda834ae2015-03-26 04:28:43 +000032#include "ClonedArguments.h"
utatane.tea@gmail.com7b95a222018-06-16 16:33:58 +000033#include "CommonSlowPaths.h"
fpizlo@apple.comda834ae2015-03-26 04:28:43 +000034#include "DirectArguments.h"
fpizlo@apple.com6e697962015-10-12 17:56:26 +000035#include "FTLJITCode.h"
36#include "FTLLazySlowPath.h"
ggaren@apple.com21cd7022015-08-18 18:28:54 +000037#include "InlineCallFrame.h"
utatane.tea@gmail.comb7113162017-12-18 11:49:33 +000038#include "Interpreter.h"
caitp@igalia.com8bc562d2016-11-14 21:14:15 +000039#include "JSAsyncFunction.h"
gskachkov@gmail.comab749fd2017-08-23 17:05:33 +000040#include "JSAsyncGeneratorFunction.h"
fpizlo@apple.comfc70ba62014-09-26 03:59:33 +000041#include "JSCInlines.h"
sbarati@apple.come20444a2016-11-30 06:24:44 +000042#include "JSFixedArray.h"
utatane.tea@gmail.com9d9fd322015-12-17 10:33:08 +000043#include "JSGeneratorFunction.h"
keith_miller@apple.comc02f5d32018-05-22 18:04:31 +000044#include "JSImmutableButterfly.h"
basile_clement@apple.com2ca1f7b2015-05-05 16:34:21 +000045#include "JSLexicalEnvironment.h"
utatane.tea@gmail.com19a21f02018-01-18 04:17:32 +000046#include "RegExpObject.h"
fpizlo@apple.comfc70ba62014-09-26 03:59:33 +000047
48namespace JSC { namespace FTL {
49
basile_clement@apple.comd7930292015-07-13 23:27:30 +000050extern "C" void JIT_OPERATION operationPopulateObjectInOSR(
51 ExecState* exec, ExitTimeObjectMaterialization* materialization,
52 EncodedJSValue* encodedValue, EncodedJSValue* values)
fpizlo@apple.comfc70ba62014-09-26 03:59:33 +000053{
keith_miller@apple.com504d5852017-09-13 01:31:07 +000054 using namespace DFG;
fpizlo@apple.comfc70ba62014-09-26 03:59:33 +000055 VM& vm = exec->vm();
56 CodeBlock* codeBlock = exec->codeBlock();
57
58 // We cannot GC. We've got pointers in evil places.
basile_clement@apple.comd7930292015-07-13 23:27:30 +000059 // FIXME: We are not doing anything that can GC here, and this is
60 // probably unnecessary.
fpizlo@apple.comfc70ba62014-09-26 03:59:33 +000061 DeferGCForAWhile deferGC(vm.heap);
basile_clement@apple.comd7930292015-07-13 23:27:30 +000062
fpizlo@apple.comda834ae2015-03-26 04:28:43 +000063 switch (materialization->type()) {
64 case PhantomNewObject: {
basile_clement@apple.comd7930292015-07-13 23:27:30 +000065 JSFinalObject* object = jsCast<JSFinalObject*>(JSValue::decode(*encodedValue));
utatane.tea@gmail.comb860d692018-05-31 06:19:33 +000066 Structure* structure = object->structure(vm);
basile_clement@apple.comd7930292015-07-13 23:27:30 +000067
68 // Figure out what the heck to populate the object with. Use
69 // getPropertiesConcurrently() because that happens to be
70 // lower-level and more convenient. It doesn't change the
71 // materialization of the property table. We want to have
72 // minimal visible effects on the system. Also, don't mind
73 // that this is O(n^2). It doesn't matter. We only get here
74 // from OSR exit.
fpizlo@apple.comda834ae2015-03-26 04:28:43 +000075 for (PropertyMapEntry entry : structure->getPropertiesConcurrently()) {
76 for (unsigned i = materialization->properties().size(); i--;) {
77 const ExitPropertyValue& property = materialization->properties()[i];
78 if (property.location().kind() != NamedPropertyPLoc)
79 continue;
80 if (codeBlock->identifier(property.location().info()).impl() != entry.key)
81 continue;
basile_clement@apple.comd7930292015-07-13 23:27:30 +000082
83 object->putDirect(vm, entry.offset, JSValue::decode(values[i]));
fpizlo@apple.comda834ae2015-03-26 04:28:43 +000084 }
85 }
basile_clement@apple.comd7930292015-07-13 23:27:30 +000086 break;
87 }
88
89 case PhantomNewFunction:
utatane.tea@gmail.com9d9fd322015-12-17 10:33:08 +000090 case PhantomNewGeneratorFunction:
caitp@igalia.com8bc562d2016-11-14 21:14:15 +000091 case PhantomNewAsyncFunction:
gskachkov@gmail.comab749fd2017-08-23 17:05:33 +000092 case PhantomNewAsyncGeneratorFunction:
basile_clement@apple.comd7930292015-07-13 23:27:30 +000093 case PhantomDirectArguments:
94 case PhantomClonedArguments:
sbarati@apple.com7a74ce72016-11-01 20:03:03 +000095 case PhantomCreateRest:
sbarati@apple.come20444a2016-11-30 06:24:44 +000096 case PhantomSpread:
97 case PhantomNewArrayWithSpread:
utatane.tea@gmail.comb7113162017-12-18 11:49:33 +000098 case PhantomNewArrayBuffer:
basile_clement@apple.comd7930292015-07-13 23:27:30 +000099 // Those are completely handled by operationMaterializeObjectInOSR
100 break;
101
102 case PhantomCreateActivation: {
103 JSLexicalEnvironment* activation = jsCast<JSLexicalEnvironment*>(JSValue::decode(*encodedValue));
104
105 // Figure out what to populate the activation with
106 for (unsigned i = materialization->properties().size(); i--;) {
107 const ExitPropertyValue& property = materialization->properties()[i];
108 if (property.location().kind() != ClosureVarPLoc)
109 continue;
110
mark.lam@apple.com23e96242017-09-09 16:21:45 +0000111 activation->variableAt(ScopeOffset(property.location().info())).set(vm, activation, JSValue::decode(values[i]));
basile_clement@apple.comd7930292015-07-13 23:27:30 +0000112 }
113
114 break;
115 }
116
utatane.tea@gmail.com19a21f02018-01-18 04:17:32 +0000117 case PhantomNewRegexp: {
118 RegExpObject* regExpObject = jsCast<RegExpObject*>(JSValue::decode(*encodedValue));
119
120 for (unsigned i = materialization->properties().size(); i--;) {
121 const ExitPropertyValue& property = materialization->properties()[i];
122 if (property.location().kind() != RegExpObjectLastIndexPLoc)
123 continue;
124
125 regExpObject->setLastIndex(exec, JSValue::decode(values[i]), false /* shouldThrow */);
126 break;
127 }
128 break;
129 }
basile_clement@apple.comd7930292015-07-13 23:27:30 +0000130
131 default:
132 RELEASE_ASSERT_NOT_REACHED();
133 break;
134
135 }
136}
137
138extern "C" JSCell* JIT_OPERATION operationMaterializeObjectInOSR(
139 ExecState* exec, ExitTimeObjectMaterialization* materialization, EncodedJSValue* values)
140{
keith_miller@apple.com504d5852017-09-13 01:31:07 +0000141 using namespace DFG;
basile_clement@apple.comd7930292015-07-13 23:27:30 +0000142 VM& vm = exec->vm();
143
144 // We cannot GC. We've got pointers in evil places.
145 DeferGCForAWhile deferGC(vm.heap);
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000146
basile_clement@apple.comd7930292015-07-13 23:27:30 +0000147 switch (materialization->type()) {
148 case PhantomNewObject: {
149 // Figure out what the structure is
150 Structure* structure = nullptr;
151 for (unsigned i = materialization->properties().size(); i--;) {
152 const ExitPropertyValue& property = materialization->properties()[i];
153 if (property.location() != PromotedLocationDescriptor(StructurePLoc))
154 continue;
155
utatane.tea@gmail.comdd7199d2018-03-08 16:06:48 +0000156 RELEASE_ASSERT(JSValue::decode(values[i]).asCell()->inherits<Structure>(vm));
basile_clement@apple.comd7930292015-07-13 23:27:30 +0000157 structure = jsCast<Structure*>(JSValue::decode(values[i]));
158 break;
159 }
160 RELEASE_ASSERT(structure);
161
162 JSFinalObject* result = JSFinalObject::create(vm, structure);
163
164 // The real values will be put subsequently by
165 // operationPopulateNewObjectInOSR. We can't fill them in
166 // now, because they may not be available yet (typically
167 // because we have a cyclic dependency graph).
168
169 // We put a dummy value here in order to avoid super-subtle
170 // GC-and-OSR-exit crashes in case we have a bug and some
171 // field is, for any reason, not filled later.
172 // We use a random-ish number instead of a sensible value like
173 // undefined to make possible bugs easier to track.
174 for (PropertyMapEntry entry : structure->getPropertiesConcurrently())
175 result->putDirect(vm, entry.offset, jsNumber(19723));
176
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000177 return result;
178 }
commit-queue@webkit.org88ab4e72015-04-24 02:23:36 +0000179
utatane.tea@gmail.com9d9fd322015-12-17 10:33:08 +0000180 case PhantomNewFunction:
caitp@igalia.com8bc562d2016-11-14 21:14:15 +0000181 case PhantomNewGeneratorFunction:
gskachkov@gmail.comab749fd2017-08-23 17:05:33 +0000182 case PhantomNewAsyncGeneratorFunction:
caitp@igalia.com8bc562d2016-11-14 21:14:15 +0000183 case PhantomNewAsyncFunction: {
commit-queue@webkit.org88ab4e72015-04-24 02:23:36 +0000184 // Figure out what the executable and activation are
185 FunctionExecutable* executable = nullptr;
186 JSScope* activation = nullptr;
187 for (unsigned i = materialization->properties().size(); i--;) {
188 const ExitPropertyValue& property = materialization->properties()[i];
sbarati@apple.com78e87c72017-02-11 04:05:06 +0000189 if (property.location() == PromotedLocationDescriptor(FunctionExecutablePLoc)) {
utatane.tea@gmail.comdd7199d2018-03-08 16:06:48 +0000190 RELEASE_ASSERT(JSValue::decode(values[i]).asCell()->inherits<FunctionExecutable>(vm));
commit-queue@webkit.org88ab4e72015-04-24 02:23:36 +0000191 executable = jsCast<FunctionExecutable*>(JSValue::decode(values[i]));
sbarati@apple.com78e87c72017-02-11 04:05:06 +0000192 }
193 if (property.location() == PromotedLocationDescriptor(FunctionActivationPLoc)) {
utatane.tea@gmail.comdd7199d2018-03-08 16:06:48 +0000194 RELEASE_ASSERT(JSValue::decode(values[i]).asCell()->inherits<JSScope>(vm));
commit-queue@webkit.org88ab4e72015-04-24 02:23:36 +0000195 activation = jsCast<JSScope*>(JSValue::decode(values[i]));
sbarati@apple.com78e87c72017-02-11 04:05:06 +0000196 }
commit-queue@webkit.org88ab4e72015-04-24 02:23:36 +0000197 }
198 RELEASE_ASSERT(executable && activation);
199
utatane.tea@gmail.com9d9fd322015-12-17 10:33:08 +0000200 if (materialization->type() == PhantomNewFunction)
201 return JSFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation);
caitp@igalia.com8bc562d2016-11-14 21:14:15 +0000202 else if (materialization->type() == PhantomNewGeneratorFunction)
203 return JSGeneratorFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation);
gskachkov@gmail.comab749fd2017-08-23 17:05:33 +0000204 else if (materialization->type() == PhantomNewAsyncGeneratorFunction)
205 return JSAsyncGeneratorFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation);
caitp@igalia.com8bc562d2016-11-14 21:14:15 +0000206 ASSERT(materialization->type() == PhantomNewAsyncFunction);
207 return JSAsyncFunction::createWithInvalidatedReallocationWatchpoint(vm, executable, activation);
commit-queue@webkit.org88ab4e72015-04-24 02:23:36 +0000208 }
209
basile_clement@apple.com2ca1f7b2015-05-05 16:34:21 +0000210 case PhantomCreateActivation: {
basile_clement@apple.comd7930292015-07-13 23:27:30 +0000211 // Figure out what the scope and symbol table are
basile_clement@apple.com2ca1f7b2015-05-05 16:34:21 +0000212 JSScope* scope = nullptr;
saambarati1@gmail.com402b5852015-05-22 02:39:25 +0000213 SymbolTable* table = nullptr;
basile_clement@apple.com2ca1f7b2015-05-05 16:34:21 +0000214 for (unsigned i = materialization->properties().size(); i--;) {
215 const ExitPropertyValue& property = materialization->properties()[i];
sbarati@apple.com78e87c72017-02-11 04:05:06 +0000216 if (property.location() == PromotedLocationDescriptor(ActivationScopePLoc)) {
utatane.tea@gmail.comdd7199d2018-03-08 16:06:48 +0000217 RELEASE_ASSERT(JSValue::decode(values[i]).asCell()->inherits<JSScope>(vm));
saambarati1@gmail.com402b5852015-05-22 02:39:25 +0000218 scope = jsCast<JSScope*>(JSValue::decode(values[i]));
sbarati@apple.com78e87c72017-02-11 04:05:06 +0000219 } else if (property.location() == PromotedLocationDescriptor(ActivationSymbolTablePLoc)) {
utatane.tea@gmail.comdd7199d2018-03-08 16:06:48 +0000220 RELEASE_ASSERT(JSValue::decode(values[i]).asCell()->inherits<SymbolTable>(vm));
saambarati1@gmail.com402b5852015-05-22 02:39:25 +0000221 table = jsCast<SymbolTable*>(JSValue::decode(values[i]));
sbarati@apple.com78e87c72017-02-11 04:05:06 +0000222 }
basile_clement@apple.com2ca1f7b2015-05-05 16:34:21 +0000223 }
224 RELEASE_ASSERT(scope);
saambarati1@gmail.com402b5852015-05-22 02:39:25 +0000225 RELEASE_ASSERT(table);
basile_clement@apple.com2ca1f7b2015-05-05 16:34:21 +0000226
227 CodeBlock* codeBlock = baselineCodeBlockForOriginAndBaselineCodeBlock(
sbarati@apple.com0d9999e02018-09-26 03:14:09 +0000228 materialization->origin(), exec->codeBlock()->baselineAlternative());
basile_clement@apple.com2ca1f7b2015-05-05 16:34:21 +0000229 Structure* structure = codeBlock->globalObject()->activationStructure();
230
saambarati1@gmail.com144f17c2015-07-15 21:41:08 +0000231 // It doesn't matter what values we initialize as bottom values inside the activation constructor because
232 // activation sinking will set bottom values for each slot.
233 // FIXME: Slight optimization would be to create a constructor that doesn't initialize all slots.
234 JSLexicalEnvironment* result = JSLexicalEnvironment::create(vm, structure, scope, table, jsUndefined());
basile_clement@apple.com2ca1f7b2015-05-05 16:34:21 +0000235
saambarati1@gmail.com402b5852015-05-22 02:39:25 +0000236 RELEASE_ASSERT(materialization->properties().size() - 2 == table->scopeSize());
basile_clement@apple.comd7930292015-07-13 23:27:30 +0000237
238 // The real values will be put subsequently by
239 // operationPopulateNewObjectInOSR. See the PhantomNewObject
240 // case for details.
basile_clement@apple.com2ca1f7b2015-05-05 16:34:21 +0000241 for (unsigned i = materialization->properties().size(); i--;) {
242 const ExitPropertyValue& property = materialization->properties()[i];
243 if (property.location().kind() != ClosureVarPLoc)
244 continue;
245
basile_clement@apple.comd7930292015-07-13 23:27:30 +0000246 result->variableAt(ScopeOffset(property.location().info())).set(
mark.lam@apple.com23e96242017-09-09 16:21:45 +0000247 vm, result, jsNumber(29834));
basile_clement@apple.com2ca1f7b2015-05-05 16:34:21 +0000248 }
249
saambarati1@gmail.com402b5852015-05-22 02:39:25 +0000250 if (validationEnabled()) {
251 // Validate to make sure every slot in the scope has one value.
fpizlo@apple.com171d06f2016-11-15 23:21:50 +0000252 ConcurrentJSLocker locker(table->m_lock);
saambarati1@gmail.com402b5852015-05-22 02:39:25 +0000253 for (auto iter = table->begin(locker), end = table->end(locker); iter != end; ++iter) {
254 bool found = false;
255 for (unsigned i = materialization->properties().size(); i--;) {
256 const ExitPropertyValue& property = materialization->properties()[i];
257 if (property.location().kind() != ClosureVarPLoc)
258 continue;
259 if (ScopeOffset(property.location().info()) == iter->value.scopeOffset()) {
260 found = true;
261 break;
262 }
263 }
utatane.tea@gmail.com8268d392015-05-23 18:41:53 +0000264 ASSERT_UNUSED(found, found);
saambarati1@gmail.com402b5852015-05-22 02:39:25 +0000265 }
266 unsigned numberOfClosureVarPloc = 0;
267 for (unsigned i = materialization->properties().size(); i--;) {
268 const ExitPropertyValue& property = materialization->properties()[i];
269 if (property.location().kind() == ClosureVarPLoc)
270 numberOfClosureVarPloc++;
271 }
272 ASSERT(numberOfClosureVarPloc == table->scopeSize());
273 }
274
basile_clement@apple.com2ca1f7b2015-05-05 16:34:21 +0000275 return result;
276 }
277
sbarati@apple.com7a74ce72016-11-01 20:03:03 +0000278 case PhantomCreateRest:
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000279 case PhantomDirectArguments:
280 case PhantomClonedArguments: {
281 if (!materialization->origin().inlineCallFrame) {
282 switch (materialization->type()) {
283 case PhantomDirectArguments:
284 return DirectArguments::createByCopying(exec);
285 case PhantomClonedArguments:
286 return ClonedArguments::createWithMachineFrame(exec, exec, ArgumentsMode::Cloned);
sbarati@apple.com7a74ce72016-11-01 20:03:03 +0000287 case PhantomCreateRest: {
288 CodeBlock* codeBlock = baselineCodeBlockForOriginAndBaselineCodeBlock(
sbarati@apple.com0d9999e02018-09-26 03:14:09 +0000289 materialization->origin(), exec->codeBlock()->baselineAlternative());
sbarati@apple.com7a74ce72016-11-01 20:03:03 +0000290
utatane.tea@gmail.com463aee12017-03-16 13:24:46 +0000291 unsigned numberOfArgumentsToSkip = codeBlock->numberOfArgumentsToSkip();
sbarati@apple.com7a74ce72016-11-01 20:03:03 +0000292 JSGlobalObject* globalObject = codeBlock->globalObject();
293 Structure* structure = globalObject->restParameterStructure();
294 JSValue* argumentsToCopyRegion = exec->addressOfArgumentsStart() + numberOfArgumentsToSkip;
295 unsigned arraySize = exec->argumentCount() > numberOfArgumentsToSkip ? exec->argumentCount() - numberOfArgumentsToSkip : 0;
296 return constructArray(exec, structure, argumentsToCopyRegion, arraySize);
297 }
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000298 default:
299 RELEASE_ASSERT_NOT_REACHED();
300 return nullptr;
301 }
302 }
303
304 // First figure out the argument count. If there isn't one then we represent the machine frame.
305 unsigned argumentCount = 0;
306 if (materialization->origin().inlineCallFrame->isVarargs()) {
307 for (unsigned i = materialization->properties().size(); i--;) {
308 const ExitPropertyValue& property = materialization->properties()[i];
309 if (property.location() != PromotedLocationDescriptor(ArgumentCountPLoc))
310 continue;
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000311 argumentCount = JSValue::decode(values[i]).asUInt32();
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000312 break;
313 }
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000314 } else
utatane.tea@gmail.com0c7cd0b2017-09-02 08:35:46 +0000315 argumentCount = materialization->origin().inlineCallFrame->argumentCountIncludingThis;
sbarati@apple.com7a74ce72016-11-01 20:03:03 +0000316 RELEASE_ASSERT(argumentCount);
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000317
318 JSFunction* callee = nullptr;
319 if (materialization->origin().inlineCallFrame->isClosureCall) {
320 for (unsigned i = materialization->properties().size(); i--;) {
321 const ExitPropertyValue& property = materialization->properties()[i];
322 if (property.location() != PromotedLocationDescriptor(ArgumentsCalleePLoc))
323 continue;
324
325 callee = jsCast<JSFunction*>(JSValue::decode(values[i]));
326 break;
327 }
328 } else
329 callee = materialization->origin().inlineCallFrame->calleeConstant();
330 RELEASE_ASSERT(callee);
331
332 CodeBlock* codeBlock = baselineCodeBlockForOriginAndBaselineCodeBlock(
sbarati@apple.com0d9999e02018-09-26 03:14:09 +0000333 materialization->origin(), exec->codeBlock()->baselineAlternative());
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000334
335 // We have an inline frame and we have all of the data we need to recreate it.
336 switch (materialization->type()) {
337 case PhantomDirectArguments: {
338 unsigned length = argumentCount - 1;
339 unsigned capacity = std::max(length, static_cast<unsigned>(codeBlock->numParameters() - 1));
340 DirectArguments* result = DirectArguments::create(
341 vm, codeBlock->globalObject()->directArgumentsStructure(), length, capacity);
fpizlo@apple.com92acb5a2018-03-22 02:15:44 +0000342 result->setCallee(vm, callee);
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000343 for (unsigned i = materialization->properties().size(); i--;) {
344 const ExitPropertyValue& property = materialization->properties()[i];
345 if (property.location().kind() != ArgumentPLoc)
346 continue;
347
348 unsigned index = property.location().info();
349 if (index >= capacity)
350 continue;
fpizlo@apple.com49b1d722015-05-18 03:39:28 +0000351
352 // We don't want to use setIndexQuickly(), since that's only for the passed-in
353 // arguments but sometimes the number of named arguments is greater. For
354 // example:
355 //
356 // function foo(a, b, c) { ... }
357 // foo();
358 //
359 // setIndexQuickly() would fail for indices 0, 1, 2 - but we need to recover
360 // those here.
361 result->argument(DirectArgumentsOffset(index)).set(
362 vm, result, JSValue::decode(values[i]));
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000363 }
364 return result;
365 }
366 case PhantomClonedArguments: {
367 unsigned length = argumentCount - 1;
368 ClonedArguments* result = ClonedArguments::createEmpty(
keith_miller@apple.com26367392016-03-14 20:55:15 +0000369 vm, codeBlock->globalObject()->clonedArgumentsStructure(), callee, length);
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000370
371 for (unsigned i = materialization->properties().size(); i--;) {
372 const ExitPropertyValue& property = materialization->properties()[i];
373 if (property.location().kind() != ArgumentPLoc)
374 continue;
375
376 unsigned index = property.location().info();
377 if (index >= length)
378 continue;
mark.lam@apple.com21476402017-04-27 19:24:07 +0000379 result->putDirectIndex(exec, index, JSValue::decode(values[i]));
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000380 }
381
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000382 return result;
383 }
sbarati@apple.com7a74ce72016-11-01 20:03:03 +0000384 case PhantomCreateRest: {
utatane.tea@gmail.com463aee12017-03-16 13:24:46 +0000385 unsigned numberOfArgumentsToSkip = codeBlock->numberOfArgumentsToSkip();
sbarati@apple.com7a74ce72016-11-01 20:03:03 +0000386 JSGlobalObject* globalObject = codeBlock->globalObject();
387 Structure* structure = globalObject->restParameterStructure();
388 ASSERT(argumentCount > 0);
389 unsigned arraySize = (argumentCount - 1) > numberOfArgumentsToSkip ? argumentCount - 1 - numberOfArgumentsToSkip : 0;
mark.lam@apple.comc2e98e82017-03-23 20:31:18 +0000390
mark.lam@apple.com21476402017-04-27 19:24:07 +0000391 // FIXME: we should throw an out of memory error here if tryCreate() fails.
mark.lam@apple.comc2e98e82017-03-23 20:31:18 +0000392 // https://bugs.webkit.org/show_bug.cgi?id=169784
mark.lam@apple.com21476402017-04-27 19:24:07 +0000393 JSArray* array = JSArray::tryCreate(vm, structure, arraySize);
sbarati@apple.com7a74ce72016-11-01 20:03:03 +0000394 RELEASE_ASSERT(array);
395
396 for (unsigned i = materialization->properties().size(); i--;) {
397 const ExitPropertyValue& property = materialization->properties()[i];
398 if (property.location().kind() != ArgumentPLoc)
399 continue;
400
401 unsigned argIndex = property.location().info();
402 if (numberOfArgumentsToSkip > argIndex)
403 continue;
404 unsigned arrayIndex = argIndex - numberOfArgumentsToSkip;
405 if (arrayIndex >= arraySize)
406 continue;
mark.lam@apple.com21476402017-04-27 19:24:07 +0000407 array->putDirectIndex(exec, arrayIndex, JSValue::decode(values[i]));
sbarati@apple.com7a74ce72016-11-01 20:03:03 +0000408 }
409
410#if !ASSERT_DISABLED
411 // We avoid this O(n^2) loop when asserts are disabled, but the condition checked here
412 // must hold to ensure the correctness of the above loop because of how we allocate the array.
413 for (unsigned targetIndex = 0; targetIndex < arraySize; ++targetIndex) {
414 bool found = false;
415 for (unsigned i = materialization->properties().size(); i--;) {
416 const ExitPropertyValue& property = materialization->properties()[i];
417 if (property.location().kind() != ArgumentPLoc)
418 continue;
419
420 unsigned argIndex = property.location().info();
421 if (numberOfArgumentsToSkip > argIndex)
422 continue;
423 unsigned arrayIndex = argIndex - numberOfArgumentsToSkip;
424 if (arrayIndex >= arraySize)
425 continue;
426 if (arrayIndex == targetIndex) {
427 found = true;
428 break;
429 }
430 }
431 ASSERT(found);
432 }
433#endif
sbarati@apple.com7a74ce72016-11-01 20:03:03 +0000434 return array;
435 }
sbarati@apple.come20444a2016-11-30 06:24:44 +0000436
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000437 default:
438 RELEASE_ASSERT_NOT_REACHED();
439 return nullptr;
fpizlo@apple.comfc70ba62014-09-26 03:59:33 +0000440 }
441 }
sbarati@apple.come20444a2016-11-30 06:24:44 +0000442
443 case PhantomSpread: {
444 JSArray* array = nullptr;
445 for (unsigned i = materialization->properties().size(); i--;) {
446 const ExitPropertyValue& property = materialization->properties()[i];
447 if (property.location().kind() == SpreadPLoc) {
448 array = jsCast<JSArray*>(JSValue::decode(values[i]));
449 break;
450 }
451 }
452 RELEASE_ASSERT(array);
453
454 // Note: it is sound for JSFixedArray::createFromArray to call getDirectIndex here
455 // because we're guaranteed we won't be calling any getters. The reason for this is
456 // that we only support PhantomSpread over CreateRest, which is an array we create.
457 // Any attempts to put a getter on any indices on the rest array will escape the array.
458 JSFixedArray* fixedArray = JSFixedArray::createFromArray(exec, vm, array);
mark.lam@apple.comb269fb92017-04-28 04:15:00 +0000459 RELEASE_ASSERT(fixedArray);
sbarati@apple.come20444a2016-11-30 06:24:44 +0000460 return fixedArray;
461 }
462
utatane.tea@gmail.comb7113162017-12-18 11:49:33 +0000463 case PhantomNewArrayBuffer: {
utatane.tea@gmail.com7b95a222018-06-16 16:33:58 +0000464 JSImmutableButterfly* immutableButterfly = nullptr;
utatane.tea@gmail.comb7113162017-12-18 11:49:33 +0000465 for (unsigned i = materialization->properties().size(); i--;) {
466 const ExitPropertyValue& property = materialization->properties()[i];
467 if (property.location().kind() == NewArrayBufferPLoc) {
utatane.tea@gmail.com7b95a222018-06-16 16:33:58 +0000468 immutableButterfly = jsCast<JSImmutableButterfly*>(JSValue::decode(values[i]));
utatane.tea@gmail.comb7113162017-12-18 11:49:33 +0000469 break;
470 }
471 }
utatane.tea@gmail.com7b95a222018-06-16 16:33:58 +0000472 RELEASE_ASSERT(immutableButterfly);
utatane.tea@gmail.comb7113162017-12-18 11:49:33 +0000473
474 // For now, we use array allocation profile in the actual CodeBlock. It is OK since current NewArrayBuffer
475 // and PhantomNewArrayBuffer are always bound to a specific op_new_array_buffer.
sbarati@apple.com0d9999e02018-09-26 03:14:09 +0000476 CodeBlock* codeBlock = baselineCodeBlockForOriginAndBaselineCodeBlock(materialization->origin(), exec->codeBlock()->baselineAlternative());
utatane.tea@gmail.comb7113162017-12-18 11:49:33 +0000477 Instruction* currentInstruction = &codeBlock->instructions()[materialization->origin().bytecodeIndex];
478 RELEASE_ASSERT(Interpreter::getOpcodeID(currentInstruction[0].u.opcode) == op_new_array_buffer);
utatane.tea@gmail.com7b95a222018-06-16 16:33:58 +0000479 auto* newArrayBuffer = bitwise_cast<OpNewArrayBuffer*>(currentInstruction);
480 ArrayAllocationProfile* profile = currentInstruction[3].u.arrayAllocationProfile;
481
482 // FIXME: Share the code with CommonSlowPaths. Currently, codeBlock etc. are slightly different.
483 IndexingType indexingMode = profile->selectIndexingType();
484 Structure* structure = exec->lexicalGlobalObject()->arrayStructureForIndexingTypeDuringAllocation(indexingMode);
485 ASSERT(isCopyOnWrite(indexingMode));
keith_miller@apple.comc02f5d32018-05-22 18:04:31 +0000486 ASSERT(!structure->outOfLineCapacity());
utatane.tea@gmail.com7b95a222018-06-16 16:33:58 +0000487
488 if (UNLIKELY(immutableButterfly->indexingMode() != indexingMode)) {
489 auto* newButterfly = JSImmutableButterfly::create(vm, indexingMode, immutableButterfly->length());
490 for (unsigned i = 0; i < immutableButterfly->length(); ++i)
491 newButterfly->setIndex(vm, i, immutableButterfly->get(i));
492 immutableButterfly = newButterfly;
493
494 // FIXME: This is kinda gross and only works because we can't inline new_array_bufffer in the baseline.
495 // We also cannot allocate a new butterfly from compilation threads since it's invalid to allocate cells from
496 // a compilation thread.
497 WTF::storeStoreFence();
498 codeBlock->constantRegister(newArrayBuffer->immutableButterfly()).set(vm, codeBlock, immutableButterfly);
499 WTF::storeStoreFence();
500 }
501
502 JSArray* result = CommonSlowPaths::allocateNewArrayBuffer(vm, structure, immutableButterfly);
503 ArrayAllocationProfile::updateLastAllocationFor(profile, result);
504 return result;
utatane.tea@gmail.comb7113162017-12-18 11:49:33 +0000505 }
506
sbarati@apple.come20444a2016-11-30 06:24:44 +0000507 case PhantomNewArrayWithSpread: {
508 CodeBlock* codeBlock = baselineCodeBlockForOriginAndBaselineCodeBlock(
sbarati@apple.com0d9999e02018-09-26 03:14:09 +0000509 materialization->origin(), exec->codeBlock()->baselineAlternative());
sbarati@apple.come20444a2016-11-30 06:24:44 +0000510 JSGlobalObject* globalObject = codeBlock->globalObject();
511 Structure* structure = globalObject->arrayStructureForIndexingTypeDuringAllocation(ArrayWithContiguous);
512
mark.lam@apple.com61dbb712017-03-16 21:53:33 +0000513 Checked<unsigned, RecordOverflow> checkedArraySize = 0;
sbarati@apple.come20444a2016-11-30 06:24:44 +0000514 unsigned numProperties = 0;
515 for (unsigned i = materialization->properties().size(); i--;) {
516 const ExitPropertyValue& property = materialization->properties()[i];
517 if (property.location().kind() == NewArrayWithSpreadArgumentPLoc) {
518 ++numProperties;
519 JSValue value = JSValue::decode(values[i]);
keith_miller@apple.com45da7602017-01-27 01:47:52 +0000520 if (JSFixedArray* fixedArray = jsDynamicCast<JSFixedArray*>(vm, value))
mark.lam@apple.com61dbb712017-03-16 21:53:33 +0000521 checkedArraySize += fixedArray->size();
sbarati@apple.come20444a2016-11-30 06:24:44 +0000522 else
mark.lam@apple.com61dbb712017-03-16 21:53:33 +0000523 checkedArraySize += 1;
sbarati@apple.come20444a2016-11-30 06:24:44 +0000524 }
525 }
526
mark.lam@apple.com21476402017-04-27 19:24:07 +0000527 // FIXME: we should throw an out of memory error here if checkedArraySize has hasOverflowed() or tryCreate() fails.
mark.lam@apple.comc2e98e82017-03-23 20:31:18 +0000528 // https://bugs.webkit.org/show_bug.cgi?id=169784
mark.lam@apple.com61dbb712017-03-16 21:53:33 +0000529 unsigned arraySize = checkedArraySize.unsafeGet(); // Crashes if overflowed.
mark.lam@apple.com21476402017-04-27 19:24:07 +0000530 JSArray* result = JSArray::tryCreate(vm, structure, arraySize);
sbarati@apple.come20444a2016-11-30 06:24:44 +0000531 RELEASE_ASSERT(result);
532
533#if !ASSERT_DISABLED
534 // Ensure we see indices for everything in the range: [0, numProperties)
535 for (unsigned i = 0; i < numProperties; ++i) {
536 bool found = false;
537 for (unsigned j = 0; j < materialization->properties().size(); ++j) {
538 const ExitPropertyValue& property = materialization->properties()[j];
539 if (property.location().kind() == NewArrayWithSpreadArgumentPLoc && property.location().info() == i) {
540 found = true;
541 break;
542 }
543 }
544 ASSERT(found);
545 }
546#endif
547
548 Vector<JSValue, 8> arguments;
549 arguments.grow(numProperties);
550
551 for (unsigned i = materialization->properties().size(); i--;) {
552 const ExitPropertyValue& property = materialization->properties()[i];
553 if (property.location().kind() == NewArrayWithSpreadArgumentPLoc) {
554 JSValue value = JSValue::decode(values[i]);
555 RELEASE_ASSERT(property.location().info() < numProperties);
556 arguments[property.location().info()] = value;
557 }
558 }
559
560 unsigned arrayIndex = 0;
561 for (JSValue value : arguments) {
keith_miller@apple.com45da7602017-01-27 01:47:52 +0000562 if (JSFixedArray* fixedArray = jsDynamicCast<JSFixedArray*>(vm, value)) {
sbarati@apple.come20444a2016-11-30 06:24:44 +0000563 for (unsigned i = 0; i < fixedArray->size(); i++) {
564 ASSERT(fixedArray->get(i));
mark.lam@apple.com21476402017-04-27 19:24:07 +0000565 result->putDirectIndex(exec, arrayIndex, fixedArray->get(i));
sbarati@apple.come20444a2016-11-30 06:24:44 +0000566 ++arrayIndex;
567 }
568 } else {
569 // We are not spreading.
mark.lam@apple.com21476402017-04-27 19:24:07 +0000570 result->putDirectIndex(exec, arrayIndex, value);
sbarati@apple.come20444a2016-11-30 06:24:44 +0000571 ++arrayIndex;
572 }
573 }
574
575 return result;
576 }
577
utatane.tea@gmail.com19a21f02018-01-18 04:17:32 +0000578 case PhantomNewRegexp: {
579 RegExp* regExp = nullptr;
580 for (unsigned i = materialization->properties().size(); i--;) {
581 const ExitPropertyValue& property = materialization->properties()[i];
582 if (property.location() == PromotedLocationDescriptor(RegExpObjectRegExpPLoc)) {
utatane.tea@gmail.comdd7199d2018-03-08 16:06:48 +0000583 RELEASE_ASSERT(JSValue::decode(values[i]).asCell()->inherits<RegExp>(vm));
utatane.tea@gmail.com19a21f02018-01-18 04:17:32 +0000584 regExp = jsCast<RegExp*>(JSValue::decode(values[i]));
585 }
586 }
587 RELEASE_ASSERT(regExp);
sbarati@apple.com0d9999e02018-09-26 03:14:09 +0000588 CodeBlock* codeBlock = baselineCodeBlockForOriginAndBaselineCodeBlock(materialization->origin(), exec->codeBlock()->baselineAlternative());
utatane.tea@gmail.com19a21f02018-01-18 04:17:32 +0000589 Structure* structure = codeBlock->globalObject()->regExpStructure();
590 return RegExpObject::create(vm, structure, regExp);
591 }
592
fpizlo@apple.comda834ae2015-03-26 04:28:43 +0000593 default:
594 RELEASE_ASSERT_NOT_REACHED();
595 return nullptr;
596 }
fpizlo@apple.comfc70ba62014-09-26 03:59:33 +0000597}
598
fpizlo@apple.com6e697962015-10-12 17:56:26 +0000599extern "C" void* JIT_OPERATION compileFTLLazySlowPath(ExecState* exec, unsigned index)
600{
601 VM& vm = exec->vm();
602
603 // We cannot GC. We've got pointers in evil places.
604 DeferGCForAWhile deferGC(vm.heap);
605
606 CodeBlock* codeBlock = exec->codeBlock();
607 JITCode* jitCode = codeBlock->jitCode()->ftl();
608
609 LazySlowPath& lazySlowPath = *jitCode->lazySlowPaths[index];
610 lazySlowPath.generate(codeBlock);
611
mark.lam@apple.comde0dba72018-04-18 03:31:09 +0000612 return lazySlowPath.stub().code().executableAddress();
fpizlo@apple.com6e697962015-10-12 17:56:26 +0000613}
614
fpizlo@apple.comfc70ba62014-09-26 03:59:33 +0000615} } // namespace JSC::FTL
616
617#endif // ENABLE(FTL_JIT)
618