]> git.saurik.com Git - apple/javascriptcore.git/blame - jit/JITOperations.cpp
JavaScriptCore-7601.1.46.3.tar.gz
[apple/javascriptcore.git] / jit / JITOperations.cpp
CommitLineData
81345200 1/*
ed1e77d3 2 * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
81345200
A
3 *
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 "JITOperations.h"
28
29#if ENABLE(JIT)
30
81345200
A
31#include "ArrayConstructor.h"
32#include "DFGCompilationMode.h"
33#include "DFGDriver.h"
34#include "DFGOSREntry.h"
35#include "DFGThunks.h"
36#include "DFGWorklist.h"
37#include "Debugger.h"
ed1e77d3 38#include "DirectArguments.h"
81345200
A
39#include "Error.h"
40#include "ErrorHandlingScope.h"
ed1e77d3 41#include "ExceptionFuzz.h"
81345200
A
42#include "GetterSetter.h"
43#include "HostCallReturnValue.h"
44#include "JIT.h"
45#include "JITToDFGDeferredCompilationCallback.h"
ed1e77d3
A
46#include "JSCInlines.h"
47#include "JSCatchScope.h"
48#include "JSFunctionNameScope.h"
81345200 49#include "JSGlobalObjectFunctions.h"
ed1e77d3 50#include "JSLexicalEnvironment.h"
81345200 51#include "JSNameScope.h"
ed1e77d3 52#include "JSPropertyNameEnumerator.h"
81345200
A
53#include "JSStackInlines.h"
54#include "JSWithScope.h"
ed1e77d3 55#include "LegacyProfiler.h"
81345200 56#include "ObjectConstructor.h"
ed1e77d3 57#include "PropertyName.h"
81345200
A
58#include "Repatch.h"
59#include "RepatchBuffer.h"
ed1e77d3 60#include "ScopedArguments.h"
81345200 61#include "TestRunnerUtils.h"
ed1e77d3 62#include "TypeProfilerLog.h"
81345200
A
63#include <wtf/InlineASM.h>
64
65namespace JSC {
66
ed1e77d3
A
67template<typename ScopeType>
68void pushNameScope(ExecState* exec, int32_t dst, SymbolTable* symbolTable, EncodedJSValue encodedValue)
69{
70 VM& vm = exec->vm();
71 NativeCallFrameTracer tracer(&vm, exec);
72
73 ASSERT(!JITCode::isOptimizingJIT(exec->codeBlock()->jitType()));
74
75 // FIXME: This won't work if this operation is called from the DFG or FTL.
76 // This should be changed to pass in the new scope.
77 JSScope* currentScope = exec->uncheckedR(dst).Register::scope();
78 JSNameScope* scope = ScopeType::create(vm, exec->lexicalGlobalObject(), currentScope, symbolTable, JSValue::decode(encodedValue));
79
80 // FIXME: This won't work if this operation is called from the DFG or FTL.
81 // This should be changed to return the new scope.
82 exec->uncheckedR(dst) = scope;
83}
81345200
A
84
85extern "C" {
86
87#if COMPILER(MSVC)
88void * _ReturnAddress(void);
89#pragma intrinsic(_ReturnAddress)
90
91#define OUR_RETURN_ADDRESS _ReturnAddress()
92#else
93#define OUR_RETURN_ADDRESS __builtin_return_address(0)
94#endif
95
96#if ENABLE(OPCODE_SAMPLING)
97#define CTI_SAMPLER vm->interpreter->sampler()
98#else
99#define CTI_SAMPLER 0
100#endif
101
102
103void JIT_OPERATION operationThrowStackOverflowError(ExecState* exec, CodeBlock* codeBlock)
104{
105 // We pass in our own code block, because the callframe hasn't been populated.
106 VM* vm = codeBlock->vm();
ed1e77d3
A
107
108 VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame;
109 CallFrame* callerFrame = exec->callerFrame(vmEntryFrame);
81345200
A
110 if (!callerFrame)
111 callerFrame = exec;
112
ed1e77d3 113 NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame);
81345200
A
114 ErrorHandlingScope errorScope(*vm);
115 vm->throwException(callerFrame, createStackOverflowError(callerFrame));
116}
117
118int32_t JIT_OPERATION operationCallArityCheck(ExecState* exec)
119{
120 VM* vm = &exec->vm();
ed1e77d3
A
121 VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame;
122 CallFrame* callerFrame = exec->callerFrame(vmEntryFrame);
81345200
A
123
124 JSStack& stack = vm->interpreter->stack();
125
126 int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForCall);
ed1e77d3
A
127 if (missingArgCount < 0) {
128 NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame);
81345200 129 throwStackOverflowError(callerFrame);
ed1e77d3 130 }
81345200
A
131
132 return missingArgCount;
133}
134
135int32_t JIT_OPERATION operationConstructArityCheck(ExecState* exec)
136{
137 VM* vm = &exec->vm();
ed1e77d3
A
138 VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame;
139 CallFrame* callerFrame = exec->callerFrame(vmEntryFrame);
81345200
A
140
141 JSStack& stack = vm->interpreter->stack();
142
143 int32_t missingArgCount = CommonSlowPaths::arityCheckFor(exec, &stack, CodeForConstruct);
ed1e77d3
A
144 if (missingArgCount < 0) {
145 NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame);
81345200 146 throwStackOverflowError(callerFrame);
ed1e77d3 147 }
81345200
A
148
149 return missingArgCount;
150}
151
ed1e77d3
A
152EncodedJSValue JIT_OPERATION operationGetById(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
153{
154 VM* vm = &exec->vm();
155 NativeCallFrameTracer tracer(vm, exec);
156
157 stubInfo->tookSlowPath = true;
158
159 JSValue baseValue = JSValue::decode(base);
160 PropertySlot slot(baseValue);
161 Identifier ident = Identifier::fromUid(vm, uid);
162 return JSValue::encode(baseValue.get(exec, ident, slot));
163}
164
165EncodedJSValue JIT_OPERATION operationGetByIdGeneric(ExecState* exec, EncodedJSValue base, UniquedStringImpl* uid)
81345200
A
166{
167 VM* vm = &exec->vm();
168 NativeCallFrameTracer tracer(vm, exec);
169
170 JSValue baseValue = JSValue::decode(base);
171 PropertySlot slot(baseValue);
ed1e77d3 172 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
173 return JSValue::encode(baseValue.get(exec, ident, slot));
174}
175
ed1e77d3 176EncodedJSValue JIT_OPERATION operationGetByIdBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
81345200
A
177{
178 VM* vm = &exec->vm();
179 NativeCallFrameTracer tracer(vm, exec);
180
ed1e77d3 181 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
182 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
183
184 JSValue baseValue = JSValue::decode(base);
185 PropertySlot slot(baseValue);
ed1e77d3
A
186 bool hasResult = baseValue.getPropertySlot(exec, ident, slot);
187
81345200
A
188 if (accessType == static_cast<AccessType>(stubInfo->accessType))
189 buildGetByIDList(exec, baseValue, ident, slot, *stubInfo);
190
ed1e77d3 191 return JSValue::encode(hasResult? slot.getValue(exec, ident) : jsUndefined());
81345200
A
192}
193
ed1e77d3 194EncodedJSValue JIT_OPERATION operationGetByIdOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue base, UniquedStringImpl* uid)
81345200
A
195{
196 VM* vm = &exec->vm();
197 NativeCallFrameTracer tracer(vm, exec);
ed1e77d3 198 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
199
200 JSValue baseValue = JSValue::decode(base);
201 PropertySlot slot(baseValue);
81345200 202
ed1e77d3
A
203 bool hasResult = baseValue.getPropertySlot(exec, ident, slot);
204 if (stubInfo->seen)
205 repatchGetByID(exec, baseValue, ident, slot, *stubInfo);
206 else
207 stubInfo->seen = true;
208
209 return JSValue::encode(hasResult? slot.getValue(exec, ident) : jsUndefined());
81345200 210
81345200
A
211}
212
ed1e77d3 213EncodedJSValue JIT_OPERATION operationInOptimize(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, UniquedStringImpl* key)
81345200
A
214{
215 VM* vm = &exec->vm();
216 NativeCallFrameTracer tracer(vm, exec);
217
218 if (!base->isObject()) {
ed1e77d3 219 vm->throwException(exec, createInvalidInParameterError(exec, base));
81345200
A
220 return JSValue::encode(jsUndefined());
221 }
222
223 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
224
ed1e77d3 225 Identifier ident = Identifier::fromUid(vm, key);
81345200
A
226 PropertySlot slot(base);
227 bool result = asObject(base)->getPropertySlot(exec, ident, slot);
228
229 RELEASE_ASSERT(accessType == stubInfo->accessType);
230
231 if (stubInfo->seen)
232 repatchIn(exec, base, ident, result, slot, *stubInfo);
233 else
234 stubInfo->seen = true;
235
236 return JSValue::encode(jsBoolean(result));
237}
238
ed1e77d3 239EncodedJSValue JIT_OPERATION operationIn(ExecState* exec, StructureStubInfo* stubInfo, JSCell* base, UniquedStringImpl* key)
81345200
A
240{
241 VM* vm = &exec->vm();
242 NativeCallFrameTracer tracer(vm, exec);
ed1e77d3
A
243
244 stubInfo->tookSlowPath = true;
81345200
A
245
246 if (!base->isObject()) {
ed1e77d3 247 vm->throwException(exec, createInvalidInParameterError(exec, base));
81345200
A
248 return JSValue::encode(jsUndefined());
249 }
250
ed1e77d3 251 Identifier ident = Identifier::fromUid(vm, key);
81345200
A
252 return JSValue::encode(jsBoolean(asObject(base)->hasProperty(exec, ident)));
253}
254
255EncodedJSValue JIT_OPERATION operationGenericIn(ExecState* exec, JSCell* base, EncodedJSValue key)
256{
257 VM* vm = &exec->vm();
258 NativeCallFrameTracer tracer(vm, exec);
259
260 return JSValue::encode(jsBoolean(CommonSlowPaths::opIn(exec, JSValue::decode(key), base)));
261}
262
ed1e77d3 263void JIT_OPERATION operationPutByIdStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
81345200
A
264{
265 VM* vm = &exec->vm();
266 NativeCallFrameTracer tracer(vm, exec);
267
ed1e77d3
A
268 stubInfo->tookSlowPath = true;
269
270 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
271 PutPropertySlot slot(JSValue::decode(encodedBase), true, exec->codeBlock()->putByIdContext());
272 JSValue::decode(encodedBase).put(exec, ident, JSValue::decode(encodedValue), slot);
273}
274
ed1e77d3 275void JIT_OPERATION operationPutByIdNonStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
81345200
A
276{
277 VM* vm = &exec->vm();
278 NativeCallFrameTracer tracer(vm, exec);
279
ed1e77d3
A
280 stubInfo->tookSlowPath = true;
281
282 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
283 PutPropertySlot slot(JSValue::decode(encodedBase), false, exec->codeBlock()->putByIdContext());
284 JSValue::decode(encodedBase).put(exec, ident, JSValue::decode(encodedValue), slot);
285}
286
ed1e77d3 287void JIT_OPERATION operationPutByIdDirectStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
81345200
A
288{
289 VM* vm = &exec->vm();
290 NativeCallFrameTracer tracer(vm, exec);
291
ed1e77d3
A
292 stubInfo->tookSlowPath = true;
293
294 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
295 PutPropertySlot slot(JSValue::decode(encodedBase), true, exec->codeBlock()->putByIdContext());
296 asObject(JSValue::decode(encodedBase))->putDirect(exec->vm(), ident, JSValue::decode(encodedValue), slot);
297}
298
ed1e77d3 299void JIT_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
81345200
A
300{
301 VM* vm = &exec->vm();
302 NativeCallFrameTracer tracer(vm, exec);
303
ed1e77d3
A
304 stubInfo->tookSlowPath = true;
305
306 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
307 PutPropertySlot slot(JSValue::decode(encodedBase), false, exec->codeBlock()->putByIdContext());
308 asObject(JSValue::decode(encodedBase))->putDirect(exec->vm(), ident, JSValue::decode(encodedValue), slot);
309}
310
ed1e77d3 311void JIT_OPERATION operationPutByIdStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
81345200
A
312{
313 VM* vm = &exec->vm();
314 NativeCallFrameTracer tracer(vm, exec);
315
ed1e77d3 316 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
317 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
318
319 JSValue value = JSValue::decode(encodedValue);
320 JSValue baseValue = JSValue::decode(encodedBase);
321 PutPropertySlot slot(baseValue, true, exec->codeBlock()->putByIdContext());
ed1e77d3
A
322
323 Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr;
81345200
A
324 baseValue.put(exec, ident, value, slot);
325
326 if (accessType != static_cast<AccessType>(stubInfo->accessType))
327 return;
328
329 if (stubInfo->seen)
ed1e77d3 330 repatchPutByID(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect);
81345200
A
331 else
332 stubInfo->seen = true;
333}
334
ed1e77d3 335void JIT_OPERATION operationPutByIdNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
81345200
A
336{
337 VM* vm = &exec->vm();
338 NativeCallFrameTracer tracer(vm, exec);
339
ed1e77d3 340 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
341 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
342
343 JSValue value = JSValue::decode(encodedValue);
344 JSValue baseValue = JSValue::decode(encodedBase);
345 PutPropertySlot slot(baseValue, false, exec->codeBlock()->putByIdContext());
ed1e77d3
A
346
347 Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr;
81345200
A
348 baseValue.put(exec, ident, value, slot);
349
350 if (accessType != static_cast<AccessType>(stubInfo->accessType))
351 return;
352
353 if (stubInfo->seen)
ed1e77d3 354 repatchPutByID(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect);
81345200
A
355 else
356 stubInfo->seen = true;
357}
358
ed1e77d3 359void JIT_OPERATION operationPutByIdDirectStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
81345200
A
360{
361 VM* vm = &exec->vm();
362 NativeCallFrameTracer tracer(vm, exec);
363
ed1e77d3 364 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
365 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
366
367 JSValue value = JSValue::decode(encodedValue);
368 JSObject* baseObject = asObject(JSValue::decode(encodedBase));
369 PutPropertySlot slot(baseObject, true, exec->codeBlock()->putByIdContext());
370
ed1e77d3 371 Structure* structure = baseObject->structure(*vm);
81345200
A
372 baseObject->putDirect(exec->vm(), ident, value, slot);
373
374 if (accessType != static_cast<AccessType>(stubInfo->accessType))
375 return;
376
377 if (stubInfo->seen)
ed1e77d3 378 repatchPutByID(exec, baseObject, structure, ident, slot, *stubInfo, Direct);
81345200
A
379 else
380 stubInfo->seen = true;
381}
382
ed1e77d3 383void JIT_OPERATION operationPutByIdDirectNonStrictOptimize(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
81345200
A
384{
385 VM* vm = &exec->vm();
386 NativeCallFrameTracer tracer(vm, exec);
387
ed1e77d3 388 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
389 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
390
391 JSValue value = JSValue::decode(encodedValue);
392 JSObject* baseObject = asObject(JSValue::decode(encodedBase));
393 PutPropertySlot slot(baseObject, false, exec->codeBlock()->putByIdContext());
394
ed1e77d3 395 Structure* structure = baseObject->structure(*vm);
81345200
A
396 baseObject->putDirect(exec->vm(), ident, value, slot);
397
398 if (accessType != static_cast<AccessType>(stubInfo->accessType))
399 return;
400
401 if (stubInfo->seen)
ed1e77d3 402 repatchPutByID(exec, baseObject, structure, ident, slot, *stubInfo, Direct);
81345200
A
403 else
404 stubInfo->seen = true;
405}
406
ed1e77d3 407void JIT_OPERATION operationPutByIdStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
81345200
A
408{
409 VM* vm = &exec->vm();
410 NativeCallFrameTracer tracer(vm, exec);
411
ed1e77d3 412 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
413 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
414
415 JSValue value = JSValue::decode(encodedValue);
416 JSValue baseValue = JSValue::decode(encodedBase);
417 PutPropertySlot slot(baseValue, true, exec->codeBlock()->putByIdContext());
418
ed1e77d3 419 Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr;
81345200 420 baseValue.put(exec, ident, value, slot);
ed1e77d3 421
81345200
A
422 if (accessType != static_cast<AccessType>(stubInfo->accessType))
423 return;
ed1e77d3
A
424
425 buildPutByIdList(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect);
81345200
A
426}
427
ed1e77d3 428void JIT_OPERATION operationPutByIdNonStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
81345200
A
429{
430 VM* vm = &exec->vm();
431 NativeCallFrameTracer tracer(vm, exec);
432
ed1e77d3 433 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
434 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
435
436 JSValue value = JSValue::decode(encodedValue);
437 JSValue baseValue = JSValue::decode(encodedBase);
438 PutPropertySlot slot(baseValue, false, exec->codeBlock()->putByIdContext());
ed1e77d3
A
439
440 Structure* structure = baseValue.isCell() ? baseValue.asCell()->structure(*vm) : nullptr;
81345200
A
441 baseValue.put(exec, ident, value, slot);
442
443 if (accessType != static_cast<AccessType>(stubInfo->accessType))
444 return;
445
ed1e77d3 446 buildPutByIdList(exec, baseValue, structure, ident, slot, *stubInfo, NotDirect);
81345200
A
447}
448
ed1e77d3 449void JIT_OPERATION operationPutByIdDirectStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
81345200
A
450{
451 VM* vm = &exec->vm();
452 NativeCallFrameTracer tracer(vm, exec);
453
ed1e77d3 454 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
455 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
456
457 JSValue value = JSValue::decode(encodedValue);
458 JSObject* baseObject = asObject(JSValue::decode(encodedBase));
459 PutPropertySlot slot(baseObject, true, exec->codeBlock()->putByIdContext());
ed1e77d3
A
460
461 Structure* structure = baseObject->structure(*vm);
462 baseObject->putDirect(*vm, ident, value, slot);
81345200
A
463
464 if (accessType != static_cast<AccessType>(stubInfo->accessType))
465 return;
466
ed1e77d3 467 buildPutByIdList(exec, baseObject, structure, ident, slot, *stubInfo, Direct);
81345200
A
468}
469
ed1e77d3 470void JIT_OPERATION operationPutByIdDirectNonStrictBuildList(ExecState* exec, StructureStubInfo* stubInfo, EncodedJSValue encodedValue, EncodedJSValue encodedBase, UniquedStringImpl* uid)
81345200
A
471{
472 VM* vm = &exec->vm();
473 NativeCallFrameTracer tracer(vm, exec);
474
ed1e77d3 475 Identifier ident = Identifier::fromUid(vm, uid);
81345200
A
476 AccessType accessType = static_cast<AccessType>(stubInfo->accessType);
477
478 JSValue value = JSValue::decode(encodedValue);
479 JSObject* baseObject = asObject(JSValue::decode(encodedBase));
480 PutPropertySlot slot(baseObject, false, exec->codeBlock()->putByIdContext());
ed1e77d3
A
481
482 Structure* structure = baseObject->structure(*vm);
483 baseObject->putDirect(*vm, ident, value, slot);
484
81345200
A
485 if (accessType != static_cast<AccessType>(stubInfo->accessType))
486 return;
487
ed1e77d3 488 buildPutByIdList(exec, baseObject, structure, ident, slot, *stubInfo, Direct);
81345200
A
489}
490
491void JIT_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObject* base, Structure* structure, PropertyOffset offset, EncodedJSValue value)
492{
493 VM& vm = exec->vm();
494 NativeCallFrameTracer tracer(&vm, exec);
495
496 ASSERT(structure->outOfLineCapacity() > base->structure(vm)->outOfLineCapacity());
497 ASSERT(!vm.heap.storageAllocator().fastPathShouldSucceed(structure->outOfLineCapacity() * sizeof(JSValue)));
498 base->setStructureAndReallocateStorageIfNecessary(vm, structure);
499 base->putDirect(vm, offset, JSValue::decode(value));
500}
501
ed1e77d3 502static void putByVal(CallFrame* callFrame, JSValue baseValue, JSValue subscript, JSValue value, ArrayProfile* arrayProfile)
81345200
A
503{
504 VM& vm = callFrame->vm();
505 if (LIKELY(subscript.isUInt32())) {
506 uint32_t i = subscript.asUInt32();
507 if (baseValue.isObject()) {
508 JSObject* object = asObject(baseValue);
509 if (object->canSetIndexQuickly(i))
510 object->setIndexQuickly(callFrame->vm(), i, value);
ed1e77d3
A
511 else {
512 arrayProfile->setOutOfBounds();
81345200 513 object->methodTable(vm)->putByIndex(object, callFrame, i, value, callFrame->codeBlock()->isStrictMode());
ed1e77d3 514 }
81345200
A
515 } else
516 baseValue.putByIndex(callFrame, i, value, callFrame->codeBlock()->isStrictMode());
81345200 517 } else {
ed1e77d3 518 auto property = subscript.toPropertyKey(callFrame);
81345200
A
519 if (!callFrame->vm().exception()) { // Don't put to an object if toString threw an exception.
520 PutPropertySlot slot(baseValue, callFrame->codeBlock()->isStrictMode());
521 baseValue.put(callFrame, property, value, slot);
522 }
523 }
524}
525
ed1e77d3 526static void directPutByVal(CallFrame* callFrame, JSObject* baseObject, JSValue subscript, JSValue value, ArrayProfile* arrayProfile)
81345200 527{
ed1e77d3 528 bool isStrictMode = callFrame->codeBlock()->isStrictMode();
81345200 529 if (LIKELY(subscript.isUInt32())) {
ed1e77d3
A
530 // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
531 uint32_t index = subscript.asUInt32();
532 ASSERT(isIndex(index));
533 if (baseObject->canSetIndexQuicklyForPutDirect(index)) {
534 baseObject->setIndexQuickly(callFrame->vm(), index, value);
535 return;
536 }
537
538 arrayProfile->setOutOfBounds();
539 baseObject->putDirectIndex(callFrame, index, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
540 return;
541 }
542
543 if (subscript.isDouble()) {
544 double subscriptAsDouble = subscript.asDouble();
545 uint32_t subscriptAsUInt32 = static_cast<uint32_t>(subscriptAsDouble);
546 if (subscriptAsDouble == subscriptAsUInt32 && isIndex(subscriptAsUInt32)) {
547 baseObject->putDirectIndex(callFrame, subscriptAsUInt32, value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
548 return;
81345200
A
549 }
550 }
ed1e77d3
A
551
552 // Don't put to an object if toString threw an exception.
553 auto property = subscript.toPropertyKey(callFrame);
554 if (callFrame->vm().exception())
555 return;
556
557 if (Optional<uint32_t> index = parseIndex(property))
558 baseObject->putDirectIndex(callFrame, index.value(), value, 0, isStrictMode ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
559 else {
560 PutPropertySlot slot(baseObject, isStrictMode);
561 baseObject->putDirect(callFrame->vm(), property, value, slot);
562 }
81345200 563}
ed1e77d3 564void JIT_OPERATION operationPutByVal(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
81345200
A
565{
566 VM& vm = exec->vm();
567 NativeCallFrameTracer tracer(&vm, exec);
568
569 JSValue baseValue = JSValue::decode(encodedBaseValue);
570 JSValue subscript = JSValue::decode(encodedSubscript);
571 JSValue value = JSValue::decode(encodedValue);
572
573 if (baseValue.isObject() && subscript.isInt32()) {
574 // See if it's worth optimizing at all.
575 JSObject* object = asObject(baseValue);
576 bool didOptimize = false;
577
578 unsigned bytecodeOffset = exec->locationAsBytecodeOffset();
579 ASSERT(bytecodeOffset);
580 ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1);
581 ASSERT(!byValInfo.stubRoutine);
582
ed1e77d3
A
583 Structure* structure = object->structure(vm);
584 if (hasOptimizableIndexing(structure)) {
81345200 585 // Attempt to optimize.
ed1e77d3
A
586 JITArrayMode arrayMode = jitArrayModeForStructure(structure);
587 if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo.arrayMode) {
588 CodeBlock* codeBlock = exec->codeBlock();
589 ConcurrentJITLocker locker(codeBlock->m_lock);
590 arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
591
81345200
A
592 JIT::compilePutByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
593 didOptimize = true;
594 }
595 }
596
597 if (!didOptimize) {
598 // If we take slow path more than 10 times without patching then make sure we
599 // never make that mistake again. Or, if we failed to patch and we have some object
600 // that intercepts indexed get, then don't even wait until 10 times. For cases
601 // where we see non-index-intercepting objects, this gives 10 iterations worth of
602 // opportunity for us to observe that the get_by_val may be polymorphic.
603 if (++byValInfo.slowPathCount >= 10
604 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
605 // Don't ever try to optimize.
ed1e77d3 606 ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationPutByValGeneric));
81345200
A
607 }
608 }
609 }
610
ed1e77d3 611 putByVal(exec, baseValue, subscript, value, arrayProfile);
81345200
A
612}
613
ed1e77d3 614void JIT_OPERATION operationDirectPutByVal(ExecState* callFrame, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
81345200
A
615{
616 VM& vm = callFrame->vm();
617 NativeCallFrameTracer tracer(&vm, callFrame);
618
619 JSValue baseValue = JSValue::decode(encodedBaseValue);
620 JSValue subscript = JSValue::decode(encodedSubscript);
621 JSValue value = JSValue::decode(encodedValue);
622 RELEASE_ASSERT(baseValue.isObject());
623 JSObject* object = asObject(baseValue);
624 if (subscript.isInt32()) {
625 // See if it's worth optimizing at all.
626 bool didOptimize = false;
627
628 unsigned bytecodeOffset = callFrame->locationAsBytecodeOffset();
629 ASSERT(bytecodeOffset);
630 ByValInfo& byValInfo = callFrame->codeBlock()->getByValInfo(bytecodeOffset - 1);
631 ASSERT(!byValInfo.stubRoutine);
ed1e77d3
A
632
633 Structure* structure = object->structure(vm);
634 if (hasOptimizableIndexing(structure)) {
81345200 635 // Attempt to optimize.
ed1e77d3
A
636 JITArrayMode arrayMode = jitArrayModeForStructure(structure);
637 if (jitArrayModePermitsPut(arrayMode) && arrayMode != byValInfo.arrayMode) {
638 CodeBlock* codeBlock = callFrame->codeBlock();
639 ConcurrentJITLocker locker(codeBlock->m_lock);
640 arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
641
81345200
A
642 JIT::compileDirectPutByVal(&vm, callFrame->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
643 didOptimize = true;
644 }
645 }
646
647 if (!didOptimize) {
648 // If we take slow path more than 10 times without patching then make sure we
649 // never make that mistake again. Or, if we failed to patch and we have some object
650 // that intercepts indexed get, then don't even wait until 10 times. For cases
651 // where we see non-index-intercepting objects, this gives 10 iterations worth of
652 // opportunity for us to observe that the get_by_val may be polymorphic.
653 if (++byValInfo.slowPathCount >= 10
654 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
655 // Don't ever try to optimize.
ed1e77d3 656 ctiPatchCallByReturnAddress(callFrame->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationDirectPutByValGeneric));
81345200
A
657 }
658 }
659 }
ed1e77d3 660 directPutByVal(callFrame, object, subscript, value, arrayProfile);
81345200
A
661}
662
ed1e77d3 663void JIT_OPERATION operationPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
81345200
A
664{
665 VM& vm = exec->vm();
666 NativeCallFrameTracer tracer(&vm, exec);
667
668 JSValue baseValue = JSValue::decode(encodedBaseValue);
669 JSValue subscript = JSValue::decode(encodedSubscript);
670 JSValue value = JSValue::decode(encodedValue);
671
ed1e77d3 672 putByVal(exec, baseValue, subscript, value, arrayProfile);
81345200
A
673}
674
675
ed1e77d3 676void JIT_OPERATION operationDirectPutByValGeneric(ExecState* exec, EncodedJSValue encodedBaseValue, EncodedJSValue encodedSubscript, EncodedJSValue encodedValue, ArrayProfile* arrayProfile)
81345200
A
677{
678 VM& vm = exec->vm();
679 NativeCallFrameTracer tracer(&vm, exec);
680
681 JSValue baseValue = JSValue::decode(encodedBaseValue);
682 JSValue subscript = JSValue::decode(encodedSubscript);
683 JSValue value = JSValue::decode(encodedValue);
684 RELEASE_ASSERT(baseValue.isObject());
ed1e77d3 685 directPutByVal(exec, asObject(baseValue), subscript, value, arrayProfile);
81345200
A
686}
687
688EncodedJSValue JIT_OPERATION operationCallEval(ExecState* exec, ExecState* execCallee)
689{
ed1e77d3
A
690
691 ASSERT_UNUSED(exec, exec->codeBlock()->codeType() != FunctionCode
81345200
A
692 || !exec->codeBlock()->needsActivation()
693 || exec->hasActivation());
694
81345200
A
695 execCallee->setCodeBlock(0);
696
697 if (!isHostFunction(execCallee->calleeAsValue(), globalFuncEval))
698 return JSValue::encode(JSValue());
699
700 VM* vm = &execCallee->vm();
701 JSValue result = eval(execCallee);
702 if (vm->exception())
703 return EncodedJSValue();
704
705 return JSValue::encode(result);
706}
707
708static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializationKind kind)
709{
710 ExecState* exec = execCallee->callerFrame();
711 VM* vm = &exec->vm();
712
81345200
A
713 execCallee->setCodeBlock(0);
714
715 if (kind == CodeForCall) {
716 CallData callData;
717 CallType callType = getCallData(callee, callData);
718
719 ASSERT(callType != CallTypeJS);
720
721 if (callType == CallTypeHost) {
722 NativeCallFrameTracer tracer(vm, execCallee);
723 execCallee->setCallee(asObject(callee));
724 vm->hostCallReturnValue = JSValue::decode(callData.native.function(execCallee));
725 if (vm->exception())
726 return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress();
727
728 return reinterpret_cast<void*>(getHostCallReturnValue);
729 }
730
731 ASSERT(callType == CallTypeNone);
732 exec->vm().throwException(exec, createNotAFunctionError(exec, callee));
733 return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress();
734 }
735
736 ASSERT(kind == CodeForConstruct);
737
738 ConstructData constructData;
739 ConstructType constructType = getConstructData(callee, constructData);
740
741 ASSERT(constructType != ConstructTypeJS);
742
743 if (constructType == ConstructTypeHost) {
744 NativeCallFrameTracer tracer(vm, execCallee);
745 execCallee->setCallee(asObject(callee));
746 vm->hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee));
747 if (vm->exception())
748 return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress();
749
750 return reinterpret_cast<void*>(getHostCallReturnValue);
751 }
752
753 ASSERT(constructType == ConstructTypeNone);
754 exec->vm().throwException(exec, createNotAConstructorError(exec, callee));
755 return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress();
756}
757
758inline char* linkFor(
759 ExecState* execCallee, CallLinkInfo* callLinkInfo, CodeSpecializationKind kind,
760 RegisterPreservationMode registers)
761{
762 ExecState* exec = execCallee->callerFrame();
763 VM* vm = &exec->vm();
764 NativeCallFrameTracer tracer(vm, exec);
765
766 JSValue calleeAsValue = execCallee->calleeAsValue();
767 JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue);
ed1e77d3
A
768 if (!calleeAsFunctionCell) {
769 // FIXME: We should cache these kinds of calls. They can be common and currently they are
770 // expensive.
771 // https://bugs.webkit.org/show_bug.cgi?id=144458
81345200 772 return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind));
ed1e77d3 773 }
81345200
A
774
775 JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell);
776 JSScope* scope = callee->scopeUnchecked();
81345200
A
777 ExecutableBase* executable = callee->executable();
778
779 MacroAssemblerCodePtr codePtr;
780 CodeBlock* codeBlock = 0;
781 if (executable->isHostFunction())
782 codePtr = executable->entrypointFor(*vm, kind, MustCheckArity, registers);
783 else {
784 FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
ed1e77d3
A
785
786 if (!isCall(kind) && functionExecutable->isBuiltinFunction()) {
787 exec->vm().throwException(exec, createNotAConstructorError(exec, callee));
788 return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
789 }
790
791 JSObject* error = functionExecutable->prepareForExecution(execCallee, callee, scope, kind);
81345200 792 if (error) {
ed1e77d3 793 exec->vm().throwException(exec, error);
81345200
A
794 return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
795 }
796 codeBlock = functionExecutable->codeBlockFor(kind);
797 ArityCheckMode arity;
ed1e77d3 798 if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters()) || callLinkInfo->callType() == CallLinkInfo::CallVarargs || callLinkInfo->callType() == CallLinkInfo::ConstructVarargs)
81345200
A
799 arity = MustCheckArity;
800 else
801 arity = ArityCheckNotRequired;
802 codePtr = functionExecutable->entrypointFor(*vm, kind, arity, registers);
803 }
804 if (!callLinkInfo->seenOnce())
805 callLinkInfo->setSeen();
806 else
807 linkFor(execCallee, *callLinkInfo, codeBlock, callee, codePtr, kind, registers);
ed1e77d3 808
81345200
A
809 return reinterpret_cast<char*>(codePtr.executableAddress());
810}
811
812char* JIT_OPERATION operationLinkCall(ExecState* execCallee, CallLinkInfo* callLinkInfo)
813{
814 return linkFor(execCallee, callLinkInfo, CodeForCall, RegisterPreservationNotRequired);
815}
816
817char* JIT_OPERATION operationLinkConstruct(ExecState* execCallee, CallLinkInfo* callLinkInfo)
818{
819 return linkFor(execCallee, callLinkInfo, CodeForConstruct, RegisterPreservationNotRequired);
820}
821
822char* JIT_OPERATION operationLinkCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo)
823{
824 return linkFor(execCallee, callLinkInfo, CodeForCall, MustPreserveRegisters);
825}
826
827char* JIT_OPERATION operationLinkConstructThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo)
828{
829 return linkFor(execCallee, callLinkInfo, CodeForConstruct, MustPreserveRegisters);
830}
831
832inline char* virtualForWithFunction(
833 ExecState* execCallee, CodeSpecializationKind kind, RegisterPreservationMode registers,
834 JSCell*& calleeAsFunctionCell)
835{
836 ExecState* exec = execCallee->callerFrame();
837 VM* vm = &exec->vm();
838 NativeCallFrameTracer tracer(vm, exec);
839
840 JSValue calleeAsValue = execCallee->calleeAsValue();
841 calleeAsFunctionCell = getJSFunction(calleeAsValue);
842 if (UNLIKELY(!calleeAsFunctionCell))
843 return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind));
844
845 JSFunction* function = jsCast<JSFunction*>(calleeAsFunctionCell);
846 JSScope* scope = function->scopeUnchecked();
81345200
A
847 ExecutableBase* executable = function->executable();
848 if (UNLIKELY(!executable->hasJITCodeFor(kind))) {
849 FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable);
ed1e77d3
A
850
851 if (!isCall(kind) && functionExecutable->isBuiltinFunction()) {
852 exec->vm().throwException(exec, createNotAConstructorError(exec, function));
853 return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
854 }
855
856 JSObject* error = functionExecutable->prepareForExecution(execCallee, function, scope, kind);
81345200
A
857 if (error) {
858 exec->vm().throwException(exec, error);
859 return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress());
860 }
861 }
862 return reinterpret_cast<char*>(executable->entrypointFor(
863 *vm, kind, MustCheckArity, registers).executableAddress());
864}
865
866inline char* virtualFor(
867 ExecState* execCallee, CodeSpecializationKind kind, RegisterPreservationMode registers)
868{
869 JSCell* calleeAsFunctionCellIgnored;
870 return virtualForWithFunction(execCallee, kind, registers, calleeAsFunctionCellIgnored);
871}
872
ed1e77d3 873char* JIT_OPERATION operationLinkPolymorphicCall(ExecState* execCallee, CallLinkInfo* callLinkInfo)
81345200
A
874{
875 JSCell* calleeAsFunctionCell;
876 char* result = virtualForWithFunction(execCallee, CodeForCall, RegisterPreservationNotRequired, calleeAsFunctionCell);
877
ed1e77d3 878 linkPolymorphicCall(execCallee, *callLinkInfo, CallVariant(calleeAsFunctionCell), RegisterPreservationNotRequired);
81345200
A
879
880 return result;
881}
882
883char* JIT_OPERATION operationVirtualCall(ExecState* execCallee, CallLinkInfo*)
884{
885 return virtualFor(execCallee, CodeForCall, RegisterPreservationNotRequired);
886}
887
888char* JIT_OPERATION operationVirtualConstruct(ExecState* execCallee, CallLinkInfo*)
889{
890 return virtualFor(execCallee, CodeForConstruct, RegisterPreservationNotRequired);
891}
892
ed1e77d3 893char* JIT_OPERATION operationLinkPolymorphicCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo* callLinkInfo)
81345200
A
894{
895 JSCell* calleeAsFunctionCell;
896 char* result = virtualForWithFunction(execCallee, CodeForCall, MustPreserveRegisters, calleeAsFunctionCell);
897
ed1e77d3 898 linkPolymorphicCall(execCallee, *callLinkInfo, CallVariant(calleeAsFunctionCell), MustPreserveRegisters);
81345200
A
899
900 return result;
901}
902
903char* JIT_OPERATION operationVirtualCallThatPreservesRegs(ExecState* execCallee, CallLinkInfo*)
904{
905 return virtualFor(execCallee, CodeForCall, MustPreserveRegisters);
906}
907
908char* JIT_OPERATION operationVirtualConstructThatPreservesRegs(ExecState* execCallee, CallLinkInfo*)
909{
910 return virtualFor(execCallee, CodeForConstruct, MustPreserveRegisters);
911}
912
913size_t JIT_OPERATION operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
914{
915 VM* vm = &exec->vm();
916 NativeCallFrameTracer tracer(vm, exec);
917
918 return jsLess<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
919}
920
921size_t JIT_OPERATION operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
922{
923 VM* vm = &exec->vm();
924 NativeCallFrameTracer tracer(vm, exec);
925
926 return jsLessEq<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
927}
928
929size_t JIT_OPERATION operationCompareGreater(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
930{
931 VM* vm = &exec->vm();
932 NativeCallFrameTracer tracer(vm, exec);
933
934 return jsLess<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1));
935}
936
937size_t JIT_OPERATION operationCompareGreaterEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
938{
939 VM* vm = &exec->vm();
940 NativeCallFrameTracer tracer(vm, exec);
941
942 return jsLessEq<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1));
943}
944
945size_t JIT_OPERATION operationConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp)
946{
947 VM* vm = &exec->vm();
948 NativeCallFrameTracer tracer(vm, exec);
949
950 return JSValue::decode(encodedOp).toBoolean(exec);
951}
952
953size_t JIT_OPERATION operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
954{
955 VM* vm = &exec->vm();
956 NativeCallFrameTracer tracer(vm, exec);
957
958 return JSValue::equalSlowCaseInline(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
959}
960
961#if USE(JSVALUE64)
962EncodedJSValue JIT_OPERATION operationCompareStringEq(ExecState* exec, JSCell* left, JSCell* right)
963#else
964size_t JIT_OPERATION operationCompareStringEq(ExecState* exec, JSCell* left, JSCell* right)
965#endif
966{
967 VM* vm = &exec->vm();
968 NativeCallFrameTracer tracer(vm, exec);
969
970 bool result = WTF::equal(*asString(left)->value(exec).impl(), *asString(right)->value(exec).impl());
971#if USE(JSVALUE64)
972 return JSValue::encode(jsBoolean(result));
973#else
974 return result;
975#endif
976}
977
978size_t JIT_OPERATION operationHasProperty(ExecState* exec, JSObject* base, JSString* property)
979{
ed1e77d3 980 int result = base->hasProperty(exec, property->toIdentifier(exec));
81345200
A
981 return result;
982}
983
984
985EncodedJSValue JIT_OPERATION operationNewArrayWithProfile(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, int size)
986{
987 VM* vm = &exec->vm();
988 NativeCallFrameTracer tracer(vm, exec);
989 return JSValue::encode(constructArrayNegativeIndexed(exec, profile, values, size));
990}
991
992EncodedJSValue JIT_OPERATION operationNewArrayBufferWithProfile(ExecState* exec, ArrayAllocationProfile* profile, const JSValue* values, int size)
993{
994 VM* vm = &exec->vm();
995 NativeCallFrameTracer tracer(vm, exec);
996 return JSValue::encode(constructArray(exec, profile, values, size));
997}
998
999EncodedJSValue JIT_OPERATION operationNewArrayWithSizeAndProfile(ExecState* exec, ArrayAllocationProfile* profile, EncodedJSValue size)
1000{
1001 VM* vm = &exec->vm();
1002 NativeCallFrameTracer tracer(vm, exec);
1003 JSValue sizeValue = JSValue::decode(size);
1004 return JSValue::encode(constructArrayWithSizeQuirk(exec, profile, exec->lexicalGlobalObject(), sizeValue));
1005}
1006
ed1e77d3 1007EncodedJSValue JIT_OPERATION operationNewFunction(ExecState* exec, JSScope* scope, JSCell* functionExecutable)
81345200
A
1008{
1009 ASSERT(functionExecutable->inherits(FunctionExecutable::info()));
1010 VM& vm = exec->vm();
1011 NativeCallFrameTracer tracer(&vm, exec);
ed1e77d3
A
1012 return JSValue::encode(JSFunction::create(vm, static_cast<FunctionExecutable*>(functionExecutable), scope));
1013}
1014
1015EncodedJSValue JIT_OPERATION operationNewFunctionWithInvalidatedReallocationWatchpoint(ExecState* exec, JSScope* scope, JSCell* functionExecutable)
1016{
1017 ASSERT(functionExecutable->inherits(FunctionExecutable::info()));
1018 VM& vm = exec->vm();
1019 NativeCallFrameTracer tracer(&vm, exec);
1020 return JSValue::encode(JSFunction::createWithInvalidatedReallocationWatchpoint(vm, static_cast<FunctionExecutable*>(functionExecutable), scope));
81345200
A
1021}
1022
1023JSCell* JIT_OPERATION operationNewObject(ExecState* exec, Structure* structure)
1024{
1025 VM* vm = &exec->vm();
1026 NativeCallFrameTracer tracer(vm, exec);
1027
1028 return constructEmptyObject(exec, structure);
1029}
1030
1031EncodedJSValue JIT_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr)
1032{
1033 VM& vm = exec->vm();
1034 NativeCallFrameTracer tracer(&vm, exec);
1035 RegExp* regexp = static_cast<RegExp*>(regexpPtr);
1036 if (!regexp->isValid()) {
ed1e77d3 1037 vm.throwException(exec, createSyntaxError(exec, ASCIILiteral("Invalid flags supplied to RegExp constructor.")));
81345200
A
1038 return JSValue::encode(jsUndefined());
1039 }
1040
1041 return JSValue::encode(RegExpObject::create(vm, exec->lexicalGlobalObject()->regExpStructure(), regexp));
1042}
1043
1044void JIT_OPERATION operationHandleWatchdogTimer(ExecState* exec)
1045{
1046 VM& vm = exec->vm();
1047 NativeCallFrameTracer tracer(&vm, exec);
1048
1049 if (UNLIKELY(vm.watchdog && vm.watchdog->didFire(exec)))
1050 vm.throwException(exec, createTerminatedExecutionException(&vm));
1051}
1052
1053void JIT_OPERATION operationThrowStaticError(ExecState* exec, EncodedJSValue encodedValue, int32_t referenceErrorFlag)
1054{
1055 VM& vm = exec->vm();
1056 NativeCallFrameTracer tracer(&vm, exec);
ed1e77d3
A
1057 JSValue errorMessageValue = JSValue::decode(encodedValue);
1058 RELEASE_ASSERT(errorMessageValue.isString());
1059 String errorMessage = asString(errorMessageValue)->value(exec);
81345200 1060 if (referenceErrorFlag)
ed1e77d3 1061 vm.throwException(exec, createReferenceError(exec, errorMessage));
81345200 1062 else
ed1e77d3 1063 vm.throwException(exec, createTypeError(exec, errorMessage));
81345200
A
1064}
1065
1066void JIT_OPERATION operationDebug(ExecState* exec, int32_t debugHookID)
1067{
1068 VM& vm = exec->vm();
1069 NativeCallFrameTracer tracer(&vm, exec);
1070
1071 vm.interpreter->debug(exec, static_cast<DebugHookID>(debugHookID));
1072}
1073
1074#if ENABLE(DFG_JIT)
1075static void updateAllPredictionsAndOptimizeAfterWarmUp(CodeBlock* codeBlock)
1076{
1077 codeBlock->updateAllPredictions();
1078 codeBlock->optimizeAfterWarmUp();
1079}
1080
1081SlowPathReturnType JIT_OPERATION operationOptimize(ExecState* exec, int32_t bytecodeIndex)
1082{
1083 VM& vm = exec->vm();
1084 NativeCallFrameTracer tracer(&vm, exec);
1085
1086 // Defer GC for a while so that it doesn't run between when we enter into this
1087 // slow path and when we figure out the state of our code block. This prevents
1088 // a number of awkward reentrancy scenarios, including:
1089 //
1090 // - The optimized version of our code block being jettisoned by GC right after
1091 // we concluded that we wanted to use it, but have not planted it into the JS
1092 // stack yet.
1093 //
1094 // - An optimized version of our code block being installed just as we decided
1095 // that it wasn't ready yet.
1096 //
1097 // Note that jettisoning won't happen if we already initiated OSR, because in
1098 // that case we would have already planted the optimized code block into the JS
1099 // stack.
1100 DeferGCForAWhile deferGC(vm.heap);
1101
1102 CodeBlock* codeBlock = exec->codeBlock();
ed1e77d3
A
1103 if (codeBlock->jitType() != JITCode::BaselineJIT) {
1104 dataLog("Unexpected code block in Baseline->DFG tier-up: ", *codeBlock, "\n");
1105 RELEASE_ASSERT_NOT_REACHED();
1106 }
81345200
A
1107
1108 if (bytecodeIndex) {
1109 // If we're attempting to OSR from a loop, assume that this should be
1110 // separately optimized.
1111 codeBlock->m_shouldAlwaysBeInlined = false;
1112 }
1113
1114 if (Options::verboseOSR()) {
1115 dataLog(
1116 *codeBlock, ": Entered optimize with bytecodeIndex = ", bytecodeIndex,
1117 ", executeCounter = ", codeBlock->jitExecuteCounter(),
1118 ", optimizationDelayCounter = ", codeBlock->reoptimizationRetryCounter(),
1119 ", exitCounter = ");
1120 if (codeBlock->hasOptimizedReplacement())
1121 dataLog(codeBlock->replacement()->osrExitCounter());
1122 else
1123 dataLog("N/A");
1124 dataLog("\n");
1125 }
1126
1127 if (!codeBlock->checkIfOptimizationThresholdReached()) {
1128 codeBlock->updateAllPredictions();
1129 if (Options::verboseOSR())
1130 dataLog("Choosing not to optimize ", *codeBlock, " yet, because the threshold hasn't been reached.\n");
1131 return encodeResult(0, 0);
1132 }
1133
1134 if (vm.enabledProfiler()) {
1135 updateAllPredictionsAndOptimizeAfterWarmUp(codeBlock);
1136 return encodeResult(0, 0);
1137 }
1138
1139 Debugger* debugger = codeBlock->globalObject()->debugger();
1140 if (debugger && (debugger->isStepping() || codeBlock->baselineAlternative()->hasDebuggerRequests())) {
1141 updateAllPredictionsAndOptimizeAfterWarmUp(codeBlock);
1142 return encodeResult(0, 0);
1143 }
1144
1145 if (codeBlock->m_shouldAlwaysBeInlined) {
1146 updateAllPredictionsAndOptimizeAfterWarmUp(codeBlock);
1147 if (Options::verboseOSR())
1148 dataLog("Choosing not to optimize ", *codeBlock, " yet, because m_shouldAlwaysBeInlined == true.\n");
1149 return encodeResult(0, 0);
1150 }
1151
1152 // We cannot be in the process of asynchronous compilation and also have an optimized
1153 // replacement.
1154 DFG::Worklist* worklist = DFG::existingGlobalDFGWorklistOrNull();
1155 ASSERT(
1156 !worklist
1157 || !(worklist->compilationState(DFG::CompilationKey(codeBlock, DFG::DFGMode)) != DFG::Worklist::NotKnown
1158 && codeBlock->hasOptimizedReplacement()));
1159
1160 DFG::Worklist::State worklistState;
1161 if (worklist) {
1162 // The call to DFG::Worklist::completeAllReadyPlansForVM() will complete all ready
1163 // (i.e. compiled) code blocks. But if it completes ours, we also need to know
1164 // what the result was so that we don't plow ahead and attempt OSR or immediate
1165 // reoptimization. This will have already also set the appropriate JIT execution
1166 // count threshold depending on what happened, so if the compilation was anything
1167 // but successful we just want to return early. See the case for worklistState ==
1168 // DFG::Worklist::Compiled, below.
1169
1170 // Note that we could have alternatively just called Worklist::compilationState()
1171 // here, and if it returned Compiled, we could have then called
1172 // completeAndScheduleOSR() below. But that would have meant that it could take
1173 // longer for code blocks to be completed: they would only complete when *their*
1174 // execution count trigger fired; but that could take a while since the firing is
1175 // racy. It could also mean that code blocks that never run again after being
1176 // compiled would sit on the worklist until next GC. That's fine, but it's
1177 // probably a waste of memory. Our goal here is to complete code blocks as soon as
1178 // possible in order to minimize the chances of us executing baseline code after
1179 // optimized code is already available.
1180 worklistState = worklist->completeAllReadyPlansForVM(
1181 vm, DFG::CompilationKey(codeBlock, DFG::DFGMode));
1182 } else
1183 worklistState = DFG::Worklist::NotKnown;
1184
1185 if (worklistState == DFG::Worklist::Compiling) {
1186 // We cannot be in the process of asynchronous compilation and also have an optimized
1187 // replacement.
1188 RELEASE_ASSERT(!codeBlock->hasOptimizedReplacement());
1189 codeBlock->setOptimizationThresholdBasedOnCompilationResult(CompilationDeferred);
1190 return encodeResult(0, 0);
1191 }
1192
1193 if (worklistState == DFG::Worklist::Compiled) {
1194 // If we don't have an optimized replacement but we did just get compiled, then
1195 // the compilation failed or was invalidated, in which case the execution count
1196 // thresholds have already been set appropriately by
1197 // CodeBlock::setOptimizationThresholdBasedOnCompilationResult() and we have
1198 // nothing left to do.
1199 if (!codeBlock->hasOptimizedReplacement()) {
1200 codeBlock->updateAllPredictions();
1201 if (Options::verboseOSR())
1202 dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
1203 return encodeResult(0, 0);
1204 }
1205 } else if (codeBlock->hasOptimizedReplacement()) {
1206 if (Options::verboseOSR())
1207 dataLog("Considering OSR ", *codeBlock, " -> ", *codeBlock->replacement(), ".\n");
1208 // If we have an optimized replacement, then it must be the case that we entered
1209 // cti_optimize from a loop. That's because if there's an optimized replacement,
1210 // then all calls to this function will be relinked to the replacement and so
1211 // the prologue OSR will never fire.
1212
1213 // This is an interesting threshold check. Consider that a function OSR exits
1214 // in the middle of a loop, while having a relatively low exit count. The exit
1215 // will reset the execution counter to some target threshold, meaning that this
1216 // code won't be reached until that loop heats up for >=1000 executions. But then
1217 // we do a second check here, to see if we should either reoptimize, or just
1218 // attempt OSR entry. Hence it might even be correct for
1219 // shouldReoptimizeFromLoopNow() to always return true. But we make it do some
1220 // additional checking anyway, to reduce the amount of recompilation thrashing.
1221 if (codeBlock->replacement()->shouldReoptimizeFromLoopNow()) {
1222 if (Options::verboseOSR()) {
1223 dataLog(
1224 "Triggering reoptimization of ", *codeBlock,
1225 "(", *codeBlock->replacement(), ") (in loop).\n");
1226 }
1227 codeBlock->replacement()->jettison(Profiler::JettisonDueToBaselineLoopReoptimizationTrigger, CountReoptimization);
1228 return encodeResult(0, 0);
1229 }
1230 } else {
1231 if (!codeBlock->shouldOptimizeNow()) {
1232 if (Options::verboseOSR()) {
1233 dataLog(
1234 "Delaying optimization for ", *codeBlock,
1235 " because of insufficient profiling.\n");
1236 }
1237 return encodeResult(0, 0);
1238 }
1239
1240 if (Options::verboseOSR())
1241 dataLog("Triggering optimized compilation of ", *codeBlock, "\n");
1242
1243 unsigned numVarsWithValues;
1244 if (bytecodeIndex)
1245 numVarsWithValues = codeBlock->m_numVars;
1246 else
1247 numVarsWithValues = 0;
1248 Operands<JSValue> mustHandleValues(codeBlock->numParameters(), numVarsWithValues);
1249 for (size_t i = 0; i < mustHandleValues.size(); ++i) {
1250 int operand = mustHandleValues.operandForIndex(i);
ed1e77d3 1251 mustHandleValues[i] = exec->uncheckedR(operand).jsValue();
81345200
A
1252 }
1253
1254 RefPtr<CodeBlock> replacementCodeBlock = codeBlock->newReplacement();
1255 CompilationResult result = DFG::compile(
1256 vm, replacementCodeBlock.get(), 0, DFG::DFGMode, bytecodeIndex,
1257 mustHandleValues, JITToDFGDeferredCompilationCallback::create());
1258
1259 if (result != CompilationSuccessful) {
1260 ASSERT(result == CompilationDeferred || replacementCodeBlock->hasOneRef());
1261 return encodeResult(0, 0);
1262 }
1263 }
1264
1265 CodeBlock* optimizedCodeBlock = codeBlock->replacement();
1266 ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType()));
1267
1268 if (void* dataBuffer = DFG::prepareOSREntry(exec, optimizedCodeBlock, bytecodeIndex)) {
1269 if (Options::verboseOSR()) {
1270 dataLog(
1271 "Performing OSR ", *codeBlock, " -> ", *optimizedCodeBlock, ".\n");
1272 }
1273
1274 codeBlock->optimizeSoon();
1275 return encodeResult(vm.getCTIStub(DFG::osrEntryThunkGenerator).code().executableAddress(), dataBuffer);
1276 }
1277
1278 if (Options::verboseOSR()) {
1279 dataLog(
1280 "Optimizing ", *codeBlock, " -> ", *codeBlock->replacement(),
1281 " succeeded, OSR failed, after a delay of ",
1282 codeBlock->optimizationDelayCounter(), ".\n");
1283 }
1284
1285 // Count the OSR failure as a speculation failure. If this happens a lot, then
1286 // reoptimize.
1287 optimizedCodeBlock->countOSRExit();
1288
1289 // We are a lot more conservative about triggering reoptimization after OSR failure than
1290 // before it. If we enter the optimize_from_loop trigger with a bucket full of fail
1291 // already, then we really would like to reoptimize immediately. But this case covers
1292 // something else: there weren't many (or any) speculation failures before, but we just
1293 // failed to enter the speculative code because some variable had the wrong value or
1294 // because the OSR code decided for any spurious reason that it did not want to OSR
1295 // right now. So, we only trigger reoptimization only upon the more conservative (non-loop)
1296 // reoptimization trigger.
1297 if (optimizedCodeBlock->shouldReoptimizeNow()) {
1298 if (Options::verboseOSR()) {
1299 dataLog(
1300 "Triggering reoptimization of ", *codeBlock, " -> ",
1301 *codeBlock->replacement(), " (after OSR fail).\n");
1302 }
1303 optimizedCodeBlock->jettison(Profiler::JettisonDueToBaselineLoopReoptimizationTriggerOnOSREntryFail, CountReoptimization);
1304 return encodeResult(0, 0);
1305 }
1306
1307 // OSR failed this time, but it might succeed next time! Let the code run a bit
1308 // longer and then try again.
1309 codeBlock->optimizeAfterWarmUp();
1310
1311 return encodeResult(0, 0);
1312}
1313#endif
1314
1315void JIT_OPERATION operationPutByIndex(ExecState* exec, EncodedJSValue encodedArrayValue, int32_t index, EncodedJSValue encodedValue)
1316{
1317 VM& vm = exec->vm();
1318 NativeCallFrameTracer tracer(&vm, exec);
1319
1320 JSValue arrayValue = JSValue::decode(encodedArrayValue);
1321 ASSERT(isJSArray(arrayValue));
1322 asArray(arrayValue)->putDirectIndex(exec, index, JSValue::decode(encodedValue));
1323}
1324
1325#if USE(JSVALUE64)
ed1e77d3
A
1326void JIT_OPERATION operationPutGetterById(ExecState* exec, EncodedJSValue encodedObjectValue, Identifier* identifier, EncodedJSValue encodedGetterValue)
1327{
1328 VM& vm = exec->vm();
1329 NativeCallFrameTracer tracer(&vm, exec);
1330
1331 ASSERT(JSValue::decode(encodedObjectValue).isObject());
1332 JSObject* baseObj = asObject(JSValue::decode(encodedObjectValue));
1333
1334 JSValue getter = JSValue::decode(encodedGetterValue);
1335 ASSERT(getter.isObject());
1336 baseObj->putGetter(exec, *identifier, asObject(getter));
1337}
1338
1339void JIT_OPERATION operationPutSetterById(ExecState* exec, EncodedJSValue encodedObjectValue, Identifier* identifier, EncodedJSValue encodedSetterValue)
1340{
1341 VM& vm = exec->vm();
1342 NativeCallFrameTracer tracer(&vm, exec);
1343
1344 ASSERT(JSValue::decode(encodedObjectValue).isObject());
1345 JSObject* baseObj = asObject(JSValue::decode(encodedObjectValue));
1346
1347 JSValue setter = JSValue::decode(encodedSetterValue);
1348 ASSERT(setter.isObject());
1349 baseObj->putSetter(exec, *identifier, asObject(setter));
1350}
1351
81345200
A
1352void JIT_OPERATION operationPutGetterSetter(ExecState* exec, EncodedJSValue encodedObjectValue, Identifier* identifier, EncodedJSValue encodedGetterValue, EncodedJSValue encodedSetterValue)
1353{
1354 VM& vm = exec->vm();
1355 NativeCallFrameTracer tracer(&vm, exec);
1356
1357 ASSERT(JSValue::decode(encodedObjectValue).isObject());
1358 JSObject* baseObj = asObject(JSValue::decode(encodedObjectValue));
1359
ed1e77d3 1360 GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject());
81345200
A
1361
1362 JSValue getter = JSValue::decode(encodedGetterValue);
1363 JSValue setter = JSValue::decode(encodedSetterValue);
1364 ASSERT(getter.isObject() || getter.isUndefined());
1365 ASSERT(setter.isObject() || setter.isUndefined());
1366 ASSERT(getter.isObject() || setter.isObject());
1367
1368 if (!getter.isUndefined())
ed1e77d3 1369 accessor->setGetter(vm, exec->lexicalGlobalObject(), asObject(getter));
81345200 1370 if (!setter.isUndefined())
ed1e77d3 1371 accessor->setSetter(vm, exec->lexicalGlobalObject(), asObject(setter));
81345200
A
1372 baseObj->putDirectAccessor(exec, *identifier, accessor, Accessor);
1373}
1374#else
ed1e77d3
A
1375void JIT_OPERATION operationPutGetterById(ExecState* exec, JSCell* object, Identifier* identifier, JSCell* getter)
1376{
1377 VM& vm = exec->vm();
1378 NativeCallFrameTracer tracer(&vm, exec);
1379
1380 ASSERT(object && object->isObject());
1381 JSObject* baseObj = object->getObject();
1382
1383 ASSERT(getter->isObject());
1384 baseObj->putGetter(exec, *identifier, getter);
1385}
1386
1387void JIT_OPERATION operationPutSetterById(ExecState* exec, JSCell* object, Identifier* identifier, JSCell* setter)
1388{
1389 VM& vm = exec->vm();
1390 NativeCallFrameTracer tracer(&vm, exec);
1391
1392 ASSERT(object && object->isObject());
1393 JSObject* baseObj = object->getObject();
1394
1395 ASSERT(setter->isObject());
1396 baseObj->putSetter(exec, *identifier, setter);
1397}
1398
81345200
A
1399void JIT_OPERATION operationPutGetterSetter(ExecState* exec, JSCell* object, Identifier* identifier, JSCell* getter, JSCell* setter)
1400{
1401 VM& vm = exec->vm();
1402 NativeCallFrameTracer tracer(&vm, exec);
1403
1404 ASSERT(object && object->isObject());
1405 JSObject* baseObj = object->getObject();
1406
ed1e77d3 1407 GetterSetter* accessor = GetterSetter::create(vm, exec->lexicalGlobalObject());
81345200
A
1408
1409 ASSERT(!getter || getter->isObject());
1410 ASSERT(!setter || setter->isObject());
1411 ASSERT(getter || setter);
1412
1413 if (getter)
ed1e77d3 1414 accessor->setGetter(vm, exec->lexicalGlobalObject(), getter->getObject());
81345200 1415 if (setter)
ed1e77d3 1416 accessor->setSetter(vm, exec->lexicalGlobalObject(), setter->getObject());
81345200
A
1417 baseObj->putDirectAccessor(exec, *identifier, accessor, Accessor);
1418}
1419#endif
1420
ed1e77d3 1421void JIT_OPERATION operationPushCatchScope(ExecState* exec, int32_t dst, SymbolTable* symbolTable, EncodedJSValue encodedValue)
81345200 1422{
ed1e77d3
A
1423 pushNameScope<JSCatchScope>(exec, dst, symbolTable, encodedValue);
1424}
81345200 1425
ed1e77d3
A
1426void JIT_OPERATION operationPushFunctionNameScope(ExecState* exec, int32_t dst, SymbolTable* symbolTable, EncodedJSValue encodedValue)
1427{
1428 pushNameScope<JSFunctionNameScope>(exec, dst, symbolTable, encodedValue);
81345200
A
1429}
1430
ed1e77d3 1431void JIT_OPERATION operationPushWithScope(ExecState* exec, int32_t dst, EncodedJSValue encodedValue)
81345200
A
1432{
1433 VM& vm = exec->vm();
1434 NativeCallFrameTracer tracer(&vm, exec);
1435
1436 JSObject* o = JSValue::decode(encodedValue).toObject(exec);
1437 if (vm.exception())
1438 return;
1439
ed1e77d3
A
1440 // FIXME: This won't work if this operation is called from the DFG or FTL.
1441 // This should be changed to pass in the old scope and return the new scope.
1442 JSScope* currentScope = exec->uncheckedR(dst).Register::scope();
1443 exec->uncheckedR(dst) = JSWithScope::create(exec, o, currentScope);
81345200
A
1444}
1445
ed1e77d3 1446void JIT_OPERATION operationPopScope(ExecState* exec, int32_t scopeReg)
81345200
A
1447{
1448 VM& vm = exec->vm();
1449 NativeCallFrameTracer tracer(&vm, exec);
1450
ed1e77d3
A
1451 JSScope* scope = exec->uncheckedR(scopeReg).Register::scope();
1452 exec->uncheckedR(scopeReg) = scope->next();
81345200
A
1453}
1454
1455void JIT_OPERATION operationProfileDidCall(ExecState* exec, EncodedJSValue encodedValue)
1456{
1457 VM& vm = exec->vm();
1458 NativeCallFrameTracer tracer(&vm, exec);
1459
1460 if (LegacyProfiler* profiler = vm.enabledProfiler())
1461 profiler->didExecute(exec, JSValue::decode(encodedValue));
1462}
1463
1464void JIT_OPERATION operationProfileWillCall(ExecState* exec, EncodedJSValue encodedValue)
1465{
1466 VM& vm = exec->vm();
1467 NativeCallFrameTracer tracer(&vm, exec);
1468
1469 if (LegacyProfiler* profiler = vm.enabledProfiler())
1470 profiler->willExecute(exec, JSValue::decode(encodedValue));
1471}
1472
1473EncodedJSValue JIT_OPERATION operationCheckHasInstance(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBaseVal)
1474{
1475 VM& vm = exec->vm();
1476 NativeCallFrameTracer tracer(&vm, exec);
1477
1478 JSValue value = JSValue::decode(encodedValue);
1479 JSValue baseVal = JSValue::decode(encodedBaseVal);
1480
1481 if (baseVal.isObject()) {
1482 JSObject* baseObject = asObject(baseVal);
1483 ASSERT(!baseObject->structure(vm)->typeInfo().implementsDefaultHasInstance());
1484 if (baseObject->structure(vm)->typeInfo().implementsHasInstance()) {
1485 bool result = baseObject->methodTable(vm)->customHasInstance(baseObject, exec, value);
1486 return JSValue::encode(jsBoolean(result));
1487 }
1488 }
1489
ed1e77d3 1490 vm.throwException(exec, createInvalidInstanceofParameterError(exec, baseVal));
81345200
A
1491 return JSValue::encode(JSValue());
1492}
1493
ed1e77d3 1494JSCell* JIT_OPERATION operationCreateActivation(ExecState* exec, JSScope* currentScope)
81345200
A
1495{
1496 VM& vm = exec->vm();
1497 NativeCallFrameTracer tracer(&vm, exec);
ed1e77d3
A
1498 JSLexicalEnvironment* lexicalEnvironment = JSLexicalEnvironment::create(vm, exec, currentScope, exec->codeBlock());
1499 return lexicalEnvironment;
81345200
A
1500}
1501
81345200
A
1502}
1503
ed1e77d3 1504static bool canAccessArgumentIndexQuickly(JSObject& object, uint32_t index)
81345200 1505{
ed1e77d3
A
1506 switch (object.structure()->typeInfo().type()) {
1507 case DirectArgumentsType: {
1508 DirectArguments* directArguments = jsCast<DirectArguments*>(&object);
1509 if (directArguments->canAccessArgumentIndexQuicklyInDFG(index))
1510 return true;
1511 break;
1512 }
1513 case ScopedArgumentsType: {
1514 ScopedArguments* scopedArguments = jsCast<ScopedArguments*>(&object);
1515 if (scopedArguments->canAccessArgumentIndexQuicklyInDFG(index))
1516 return true;
1517 break;
1518 }
1519 default:
1520 break;
1521 }
1522 return false;
81345200
A
1523}
1524
ed1e77d3 1525static JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript, ArrayProfile* arrayProfile, ReturnAddressPtr returnAddress)
81345200
A
1526{
1527 if (LIKELY(baseValue.isCell() && subscript.isString())) {
1528 VM& vm = exec->vm();
1529 Structure& structure = *baseValue.asCell()->structure(vm);
1530 if (JSCell::canUseFastGetOwnProperty(structure)) {
ed1e77d3
A
1531 if (RefPtr<AtomicStringImpl> existingAtomicString = asString(subscript)->toExistingAtomicString(exec)) {
1532 if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, existingAtomicString.get()))
1533 return result;
1534 }
81345200
A
1535 }
1536 }
1537
1538 if (subscript.isUInt32()) {
1539 uint32_t i = subscript.asUInt32();
ed1e77d3
A
1540 if (isJSString(baseValue)) {
1541 if (asString(baseValue)->canGetIndex(i)) {
1542 ctiPatchCallByReturnAddress(exec->codeBlock(), returnAddress, FunctionPtr(operationGetByValString));
1543 return asString(baseValue)->getIndex(exec, i);
1544 }
1545 arrayProfile->setOutOfBounds();
1546 } else if (baseValue.isObject()) {
1547 JSObject* object = asObject(baseValue);
1548 if (object->canGetIndexQuickly(i))
1549 return object->getIndexQuickly(i);
1550
1551 if (!canAccessArgumentIndexQuickly(*object, i))
1552 arrayProfile->setOutOfBounds();
81345200 1553 }
ed1e77d3 1554
81345200
A
1555 return baseValue.get(exec, i);
1556 }
1557
ed1e77d3
A
1558 baseValue.requireObjectCoercible(exec);
1559 if (exec->hadException())
1560 return jsUndefined();
1561 auto property = subscript.toPropertyKey(exec);
1562 if (exec->hadException())
1563 return jsUndefined();
81345200
A
1564 return baseValue.get(exec, property);
1565}
1566
1567extern "C" {
1568
ed1e77d3 1569EncodedJSValue JIT_OPERATION operationGetByValGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
81345200
A
1570{
1571 VM& vm = exec->vm();
1572 NativeCallFrameTracer tracer(&vm, exec);
1573 JSValue baseValue = JSValue::decode(encodedBase);
1574 JSValue subscript = JSValue::decode(encodedSubscript);
1575
ed1e77d3 1576 JSValue result = getByVal(exec, baseValue, subscript, arrayProfile, ReturnAddressPtr(OUR_RETURN_ADDRESS));
81345200
A
1577 return JSValue::encode(result);
1578}
1579
ed1e77d3 1580EncodedJSValue JIT_OPERATION operationGetByValDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
81345200
A
1581{
1582 VM& vm = exec->vm();
1583 NativeCallFrameTracer tracer(&vm, exec);
1584 JSValue baseValue = JSValue::decode(encodedBase);
1585 JSValue subscript = JSValue::decode(encodedSubscript);
1586
1587 if (baseValue.isObject() && subscript.isInt32()) {
1588 // See if it's worth optimizing this at all.
1589 JSObject* object = asObject(baseValue);
1590 bool didOptimize = false;
1591
1592 unsigned bytecodeOffset = exec->locationAsBytecodeOffset();
1593 ASSERT(bytecodeOffset);
1594 ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1);
1595 ASSERT(!byValInfo.stubRoutine);
1596
1597 if (hasOptimizableIndexing(object->structure(vm))) {
1598 // Attempt to optimize.
ed1e77d3
A
1599 Structure* structure = object->structure(vm);
1600 JITArrayMode arrayMode = jitArrayModeForStructure(structure);
81345200 1601 if (arrayMode != byValInfo.arrayMode) {
ed1e77d3
A
1602 // If we reached this case, we got an interesting array mode we did not expect when we compiled.
1603 // Let's update the profile to do better next time.
1604 CodeBlock* codeBlock = exec->codeBlock();
1605 ConcurrentJITLocker locker(codeBlock->m_lock);
1606 arrayProfile->computeUpdatedPrediction(locker, codeBlock, structure);
1607
81345200
A
1608 JIT::compileGetByVal(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
1609 didOptimize = true;
1610 }
1611 }
1612
1613 if (!didOptimize) {
1614 // If we take slow path more than 10 times without patching then make sure we
1615 // never make that mistake again. Or, if we failed to patch and we have some object
1616 // that intercepts indexed get, then don't even wait until 10 times. For cases
1617 // where we see non-index-intercepting objects, this gives 10 iterations worth of
1618 // opportunity for us to observe that the get_by_val may be polymorphic.
1619 if (++byValInfo.slowPathCount >= 10
1620 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
1621 // Don't ever try to optimize.
ed1e77d3 1622 ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationGetByValGeneric));
81345200
A
1623 }
1624 }
1625 }
1626
ed1e77d3 1627 JSValue result = getByVal(exec, baseValue, subscript, arrayProfile, ReturnAddressPtr(OUR_RETURN_ADDRESS));
81345200
A
1628 return JSValue::encode(result);
1629}
1630
ed1e77d3
A
1631EncodedJSValue JIT_OPERATION operationHasIndexedPropertyDefault(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
1632{
1633 VM& vm = exec->vm();
1634 NativeCallFrameTracer tracer(&vm, exec);
1635 JSValue baseValue = JSValue::decode(encodedBase);
1636 JSValue subscript = JSValue::decode(encodedSubscript);
1637
1638 ASSERT(baseValue.isObject());
1639 ASSERT(subscript.isUInt32());
1640
1641 JSObject* object = asObject(baseValue);
1642 bool didOptimize = false;
1643
1644 unsigned bytecodeOffset = exec->locationAsBytecodeOffset();
1645 ASSERT(bytecodeOffset);
1646 ByValInfo& byValInfo = exec->codeBlock()->getByValInfo(bytecodeOffset - 1);
1647 ASSERT(!byValInfo.stubRoutine);
1648
1649 if (hasOptimizableIndexing(object->structure(vm))) {
1650 // Attempt to optimize.
1651 JITArrayMode arrayMode = jitArrayModeForStructure(object->structure(vm));
1652 if (arrayMode != byValInfo.arrayMode) {
1653 JIT::compileHasIndexedProperty(&vm, exec->codeBlock(), &byValInfo, ReturnAddressPtr(OUR_RETURN_ADDRESS), arrayMode);
1654 didOptimize = true;
1655 }
1656 }
1657
1658 if (!didOptimize) {
1659 // If we take slow path more than 10 times without patching then make sure we
1660 // never make that mistake again. Or, if we failed to patch and we have some object
1661 // that intercepts indexed get, then don't even wait until 10 times. For cases
1662 // where we see non-index-intercepting objects, this gives 10 iterations worth of
1663 // opportunity for us to observe that the get_by_val may be polymorphic.
1664 if (++byValInfo.slowPathCount >= 10
1665 || object->structure(vm)->typeInfo().interceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero()) {
1666 // Don't ever try to optimize.
1667 ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationHasIndexedPropertyGeneric));
1668 }
1669 }
1670
1671 uint32_t index = subscript.asUInt32();
1672 if (object->canGetIndexQuickly(index))
1673 return JSValue::encode(JSValue(JSValue::JSTrue));
1674
1675 if (!canAccessArgumentIndexQuickly(*object, index))
1676 arrayProfile->setOutOfBounds();
1677 return JSValue::encode(jsBoolean(object->hasProperty(exec, index)));
1678}
1679
1680EncodedJSValue JIT_OPERATION operationHasIndexedPropertyGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript, ArrayProfile* arrayProfile)
1681{
1682 VM& vm = exec->vm();
1683 NativeCallFrameTracer tracer(&vm, exec);
1684 JSValue baseValue = JSValue::decode(encodedBase);
1685 JSValue subscript = JSValue::decode(encodedSubscript);
1686
1687 ASSERT(baseValue.isObject());
1688 ASSERT(subscript.isUInt32());
1689
1690 JSObject* object = asObject(baseValue);
1691 uint32_t index = subscript.asUInt32();
1692 if (object->canGetIndexQuickly(index))
1693 return JSValue::encode(JSValue(JSValue::JSTrue));
1694
1695 if (!canAccessArgumentIndexQuickly(*object, index))
1696 arrayProfile->setOutOfBounds();
1697 return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript.asUInt32())));
1698}
1699
81345200
A
1700EncodedJSValue JIT_OPERATION operationGetByValString(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedSubscript)
1701{
1702 VM& vm = exec->vm();
1703 NativeCallFrameTracer tracer(&vm, exec);
1704 JSValue baseValue = JSValue::decode(encodedBase);
1705 JSValue subscript = JSValue::decode(encodedSubscript);
1706
1707 JSValue result;
1708 if (LIKELY(subscript.isUInt32())) {
1709 uint32_t i = subscript.asUInt32();
1710 if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i))
1711 result = asString(baseValue)->getIndex(exec, i);
1712 else {
1713 result = baseValue.get(exec, i);
1714 if (!isJSString(baseValue))
1715 ctiPatchCallByReturnAddress(exec->codeBlock(), ReturnAddressPtr(OUR_RETURN_ADDRESS), FunctionPtr(operationGetByValDefault));
1716 }
ed1e77d3
A
1717 } else {
1718 baseValue.requireObjectCoercible(exec);
1719 if (exec->hadException())
1720 return JSValue::encode(jsUndefined());
1721 auto property = subscript.toPropertyKey(exec);
1722 if (exec->hadException())
1723 return JSValue::encode(jsUndefined());
81345200
A
1724 result = baseValue.get(exec, property);
1725 }
1726
1727 return JSValue::encode(result);
1728}
81345200
A
1729
1730EncodedJSValue JIT_OPERATION operationDeleteById(ExecState* exec, EncodedJSValue encodedBase, const Identifier* identifier)
1731{
1732 VM& vm = exec->vm();
1733 NativeCallFrameTracer tracer(&vm, exec);
1734
1735 JSObject* baseObj = JSValue::decode(encodedBase).toObject(exec);
1736 bool couldDelete = baseObj->methodTable(vm)->deleteProperty(baseObj, exec, *identifier);
1737 JSValue result = jsBoolean(couldDelete);
1738 if (!couldDelete && exec->codeBlock()->isStrictMode())
ed1e77d3 1739 vm.throwException(exec, createTypeError(exec, ASCIILiteral("Unable to delete property.")));
81345200
A
1740 return JSValue::encode(result);
1741}
1742
81345200
A
1743EncodedJSValue JIT_OPERATION operationInstanceOf(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedProto)
1744{
1745 VM& vm = exec->vm();
1746 NativeCallFrameTracer tracer(&vm, exec);
1747 JSValue value = JSValue::decode(encodedValue);
1748 JSValue proto = JSValue::decode(encodedProto);
1749
1750 ASSERT(!value.isObject() || !proto.isObject());
1751
1752 bool result = JSObject::defaultHasInstance(exec, value, proto);
1753 return JSValue::encode(jsBoolean(result));
1754}
1755
ed1e77d3 1756int32_t JIT_OPERATION operationSizeFrameForVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t numUsedStackSlots, int32_t firstVarArgOffset)
81345200
A
1757{
1758 VM& vm = exec->vm();
1759 NativeCallFrameTracer tracer(&vm, exec);
1760 JSStack* stack = &exec->interpreter()->stack();
1761 JSValue arguments = JSValue::decode(encodedArguments);
ed1e77d3 1762 return sizeFrameForVarargs(exec, stack, arguments, numUsedStackSlots, firstVarArgOffset);
81345200
A
1763}
1764
ed1e77d3 1765CallFrame* JIT_OPERATION operationSetupVarargsFrame(ExecState* exec, CallFrame* newCallFrame, EncodedJSValue encodedArguments, int32_t firstVarArgOffset, int32_t length)
81345200
A
1766{
1767 VM& vm = exec->vm();
1768 NativeCallFrameTracer tracer(&vm, exec);
81345200 1769 JSValue arguments = JSValue::decode(encodedArguments);
ed1e77d3 1770 setupVarargsFrame(exec, newCallFrame, arguments, firstVarArgOffset, length);
81345200
A
1771 return newCallFrame;
1772}
1773
1774EncodedJSValue JIT_OPERATION operationToObject(ExecState* exec, EncodedJSValue value)
1775{
1776 VM& vm = exec->vm();
1777 NativeCallFrameTracer tracer(&vm, exec);
1778 return JSValue::encode(JSValue::decode(value).toObject(exec));
1779}
1780
1781char* JIT_OPERATION operationSwitchCharWithUnknownKeyType(ExecState* exec, EncodedJSValue encodedKey, size_t tableIndex)
1782{
1783 VM& vm = exec->vm();
1784 NativeCallFrameTracer tracer(&vm, exec);
1785 JSValue key = JSValue::decode(encodedKey);
1786 CodeBlock* codeBlock = exec->codeBlock();
1787
1788 SimpleJumpTable& jumpTable = codeBlock->switchJumpTable(tableIndex);
1789 void* result = jumpTable.ctiDefault.executableAddress();
1790
1791 if (key.isString()) {
1792 StringImpl* value = asString(key)->value(exec).impl();
1793 if (value->length() == 1)
1794 result = jumpTable.ctiForValue((*value)[0]).executableAddress();
1795 }
1796
1797 return reinterpret_cast<char*>(result);
1798}
1799
1800char* JIT_OPERATION operationSwitchImmWithUnknownKeyType(ExecState* exec, EncodedJSValue encodedKey, size_t tableIndex)
1801{
1802 VM& vm = exec->vm();
1803 NativeCallFrameTracer tracer(&vm, exec);
1804 JSValue key = JSValue::decode(encodedKey);
1805 CodeBlock* codeBlock = exec->codeBlock();
1806
1807 SimpleJumpTable& jumpTable = codeBlock->switchJumpTable(tableIndex);
1808 void* result;
1809 if (key.isInt32())
1810 result = jumpTable.ctiForValue(key.asInt32()).executableAddress();
1811 else if (key.isDouble() && key.asDouble() == static_cast<int32_t>(key.asDouble()))
1812 result = jumpTable.ctiForValue(static_cast<int32_t>(key.asDouble())).executableAddress();
1813 else
1814 result = jumpTable.ctiDefault.executableAddress();
1815 return reinterpret_cast<char*>(result);
1816}
1817
1818char* JIT_OPERATION operationSwitchStringWithUnknownKeyType(ExecState* exec, EncodedJSValue encodedKey, size_t tableIndex)
1819{
1820 VM& vm = exec->vm();
1821 NativeCallFrameTracer tracer(&vm, exec);
1822 JSValue key = JSValue::decode(encodedKey);
1823 CodeBlock* codeBlock = exec->codeBlock();
1824
1825 void* result;
1826 StringJumpTable& jumpTable = codeBlock->stringSwitchJumpTable(tableIndex);
1827
1828 if (key.isString()) {
1829 StringImpl* value = asString(key)->value(exec).impl();
1830 result = jumpTable.ctiForValue(value).executableAddress();
1831 } else
1832 result = jumpTable.ctiDefault.executableAddress();
1833
1834 return reinterpret_cast<char*>(result);
1835}
1836
ed1e77d3 1837EncodedJSValue JIT_OPERATION operationResolveScope(ExecState* exec, int32_t scopeReg, int32_t identifierIndex)
81345200
A
1838{
1839 VM& vm = exec->vm();
1840 NativeCallFrameTracer tracer(&vm, exec);
1841 const Identifier& ident = exec->codeBlock()->identifier(identifierIndex);
ed1e77d3
A
1842 JSScope* scope = exec->uncheckedR(scopeReg).Register::scope();
1843 return JSValue::encode(JSScope::resolve(exec, scope, ident));
81345200
A
1844}
1845
1846EncodedJSValue JIT_OPERATION operationGetFromScope(ExecState* exec, Instruction* bytecodePC)
1847{
1848 VM& vm = exec->vm();
1849 NativeCallFrameTracer tracer(&vm, exec);
1850 CodeBlock* codeBlock = exec->codeBlock();
1851 Instruction* pc = bytecodePC;
1852
1853 const Identifier& ident = codeBlock->identifier(pc[3].u.operand);
1854 JSObject* scope = jsCast<JSObject*>(exec->uncheckedR(pc[2].u.operand).jsValue());
1855 ResolveModeAndType modeAndType(pc[4].u.operand);
1856
1857 PropertySlot slot(scope);
1858 if (!scope->getPropertySlot(exec, ident, slot)) {
1859 if (modeAndType.mode() == ThrowIfNotFound)
1860 vm.throwException(exec, createUndefinedVariableError(exec, ident));
1861 return JSValue::encode(jsUndefined());
1862 }
1863
1864 // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time.
1865 if (slot.isCacheableValue() && slot.slotBase() == scope && scope->structure(vm)->propertyAccessesAreCacheable()) {
1866 if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) {
ed1e77d3
A
1867 Structure* structure = scope->structure(vm);
1868 {
1869 ConcurrentJITLocker locker(codeBlock->m_lock);
1870 pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), structure);
1871 pc[6].u.operand = slot.cachedOffset();
1872 }
1873 structure->startWatchingPropertyForReplacements(vm, slot.cachedOffset());
81345200
A
1874 }
1875 }
1876
1877 return JSValue::encode(slot.getValue(exec, ident));
1878}
1879
1880void JIT_OPERATION operationPutToScope(ExecState* exec, Instruction* bytecodePC)
1881{
1882 VM& vm = exec->vm();
1883 NativeCallFrameTracer tracer(&vm, exec);
1884 Instruction* pc = bytecodePC;
1885
1886 CodeBlock* codeBlock = exec->codeBlock();
1887 const Identifier& ident = codeBlock->identifier(pc[2].u.operand);
1888 JSObject* scope = jsCast<JSObject*>(exec->uncheckedR(pc[1].u.operand).jsValue());
1889 JSValue value = exec->r(pc[3].u.operand).jsValue();
1890 ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand);
ed1e77d3
A
1891 if (modeAndType.type() == LocalClosureVar) {
1892 JSLexicalEnvironment* environment = jsCast<JSLexicalEnvironment*>(scope);
1893 environment->variableAt(ScopeOffset(pc[6].u.operand)).set(vm, environment, value);
1894 if (WatchpointSet* set = pc[5].u.watchpointSet)
1895 set->touch("Executed op_put_scope<LocalClosureVar>");
1896 return;
1897 }
81345200
A
1898 if (modeAndType.mode() == ThrowIfNotFound && !scope->hasProperty(exec, ident)) {
1899 exec->vm().throwException(exec, createUndefinedVariableError(exec, ident));
1900 return;
1901 }
1902
1903 PutPropertySlot slot(scope, codeBlock->isStrictMode());
1904 scope->methodTable()->put(scope, exec, ident, value, slot);
1905
1906 if (exec->vm().exception())
1907 return;
1908
ed1e77d3 1909 CommonSlowPaths::tryCachePutToScopeGlobal(exec, codeBlock, pc, scope, modeAndType, slot);
81345200
A
1910}
1911
1912void JIT_OPERATION operationThrow(ExecState* exec, EncodedJSValue encodedExceptionValue)
1913{
1914 VM* vm = &exec->vm();
1915 NativeCallFrameTracer tracer(vm, exec);
1916
1917 JSValue exceptionValue = JSValue::decode(encodedExceptionValue);
1918 vm->throwException(exec, exceptionValue);
1919
ed1e77d3
A
1920 // Results stored out-of-band in vm.targetMachinePCForThrow, vm.callFrameForThrow & vm.vmEntryFrameForThrow
1921 genericUnwind(vm, exec);
81345200
A
1922}
1923
1924void JIT_OPERATION operationFlushWriteBarrierBuffer(ExecState* exec, JSCell* cell)
1925{
1926 VM* vm = &exec->vm();
1927 NativeCallFrameTracer tracer(vm, exec);
1928 vm->heap.flushWriteBarrierBuffer(cell);
1929}
1930
1931void JIT_OPERATION operationOSRWriteBarrier(ExecState* exec, JSCell* cell)
1932{
1933 VM* vm = &exec->vm();
1934 NativeCallFrameTracer tracer(vm, exec);
1935 vm->heap.writeBarrier(cell);
1936}
1937
1938// NB: We don't include the value as part of the barrier because the write barrier elision
1939// phase in the DFG only tracks whether the object being stored to has been barriered. It
1940// would be much more complicated to try to model the value being stored as well.
1941void JIT_OPERATION operationUnconditionalWriteBarrier(ExecState* exec, JSCell* cell)
1942{
1943 VM* vm = &exec->vm();
1944 NativeCallFrameTracer tracer(vm, exec);
1945 vm->heap.writeBarrier(cell);
1946}
1947
1948void JIT_OPERATION operationInitGlobalConst(ExecState* exec, Instruction* pc)
1949{
1950 VM* vm = &exec->vm();
1951 NativeCallFrameTracer tracer(vm, exec);
1952
1953 JSValue value = exec->r(pc[2].u.operand).jsValue();
ed1e77d3 1954 pc[1].u.variablePointer->set(*vm, exec->codeBlock()->globalObject(), value);
81345200
A
1955}
1956
1957void JIT_OPERATION lookupExceptionHandler(VM* vm, ExecState* exec)
1958{
ed1e77d3
A
1959 NativeCallFrameTracer tracer(vm, exec);
1960 genericUnwind(vm, exec);
1961 ASSERT(vm->targetMachinePCForThrow);
1962}
81345200 1963
ed1e77d3
A
1964void JIT_OPERATION lookupExceptionHandlerFromCallerFrame(VM* vm, ExecState* exec)
1965{
1966 VMEntryFrame* vmEntryFrame = vm->topVMEntryFrame;
1967 CallFrame* callerFrame = exec->callerFrame(vmEntryFrame);
1968 ASSERT(callerFrame);
1969
1970 NativeCallFrameTracerWithRestore tracer(vm, vmEntryFrame, callerFrame);
1971 genericUnwind(vm, callerFrame);
81345200
A
1972 ASSERT(vm->targetMachinePCForThrow);
1973}
1974
1975void JIT_OPERATION operationVMHandleException(ExecState* exec)
1976{
1977 VM* vm = &exec->vm();
1978 NativeCallFrameTracer tracer(vm, exec);
ed1e77d3 1979 genericUnwind(vm, exec);
81345200
A
1980}
1981
1982// This function "should" just take the ExecState*, but doing so would make it more difficult
1983// to call from exception check sites. So, unlike all of our other functions, we allow
1984// ourselves to play some gnarly ABI tricks just to simplify the calling convention. This is
1985// particularly safe here since this is never called on the critical path - it's only for
1986// testing.
1987void JIT_OPERATION operationExceptionFuzz()
1988{
81345200
A
1989 // This probably "just works" for GCC also, but I haven't tried.
1990#if COMPILER(CLANG)
1991 ExecState* exec = static_cast<ExecState*>(__builtin_frame_address(1));
ed1e77d3
A
1992 void* returnPC = __builtin_return_address(0);
1993 doExceptionFuzzing(exec, "JITOperations", returnPC);
81345200
A
1994#endif // COMPILER(CLANG)
1995}
1996
ed1e77d3
A
1997EncodedJSValue JIT_OPERATION operationHasGenericProperty(ExecState* exec, EncodedJSValue encodedBaseValue, JSCell* propertyName)
1998{
1999 VM& vm = exec->vm();
2000 NativeCallFrameTracer tracer(&vm, exec);
2001 JSValue baseValue = JSValue::decode(encodedBaseValue);
2002 if (baseValue.isUndefinedOrNull())
2003 return JSValue::encode(jsBoolean(false));
2004
2005 JSObject* base = baseValue.toObject(exec);
2006 return JSValue::encode(jsBoolean(base->hasProperty(exec, asString(propertyName)->toIdentifier(exec))));
2007}
2008
2009EncodedJSValue JIT_OPERATION operationHasIndexedProperty(ExecState* exec, JSCell* baseCell, int32_t subscript)
2010{
2011 VM& vm = exec->vm();
2012 NativeCallFrameTracer tracer(&vm, exec);
2013 JSObject* object = baseCell->toObject(exec, exec->lexicalGlobalObject());
2014 return JSValue::encode(jsBoolean(object->hasProperty(exec, subscript)));
2015}
2016
2017JSCell* JIT_OPERATION operationGetPropertyEnumerator(ExecState* exec, JSCell* cell)
2018{
2019 VM& vm = exec->vm();
2020 NativeCallFrameTracer tracer(&vm, exec);
2021
2022 JSObject* base = cell->toObject(exec, exec->lexicalGlobalObject());
2023
2024 return propertyNameEnumerator(exec, base);
2025}
2026
2027EncodedJSValue JIT_OPERATION operationNextEnumeratorPname(ExecState* exec, JSCell* enumeratorCell, int32_t index)
2028{
2029 VM& vm = exec->vm();
2030 NativeCallFrameTracer tracer(&vm, exec);
2031 JSPropertyNameEnumerator* enumerator = jsCast<JSPropertyNameEnumerator*>(enumeratorCell);
2032 JSString* propertyName = enumerator->propertyNameAtIndex(index);
2033 return JSValue::encode(propertyName ? propertyName : jsNull());
2034}
2035
2036JSCell* JIT_OPERATION operationToIndexString(ExecState* exec, int32_t index)
2037{
2038 VM& vm = exec->vm();
2039 NativeCallFrameTracer tracer(&vm, exec);
2040 return jsString(exec, Identifier::from(exec, index).string());
2041}
2042
2043void JIT_OPERATION operationProcessTypeProfilerLog(ExecState* exec)
2044{
2045 exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("Log Full, called from inside baseline JIT"));
2046}
2047
81345200
A
2048} // extern "C"
2049
2050// Note: getHostCallReturnValueWithExecState() needs to be placed before the
2051// definition of getHostCallReturnValue() below because the Windows build
2052// requires it.
2053extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWithExecState(ExecState* exec)
2054{
2055 if (!exec)
2056 return JSValue::encode(JSValue());
2057 return JSValue::encode(exec->vm().hostCallReturnValue);
2058}
2059
2060#if COMPILER(GCC) && CPU(X86_64)
2061asm (
2062".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
2063HIDE_SYMBOL(getHostCallReturnValue) "\n"
2064SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
2065 "mov %rbp, %rdi\n"
2066 "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
2067);
2068
2069#elif COMPILER(GCC) && CPU(X86)
2070asm (
2071".text" "\n" \
2072".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
2073HIDE_SYMBOL(getHostCallReturnValue) "\n"
2074SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
2075 "push %ebp\n"
2076 "leal -4(%esp), %esp\n"
2077 "push %ebp\n"
2078 "call " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
2079 "leal 8(%esp), %esp\n"
2080 "pop %ebp\n"
2081 "ret\n"
2082);
2083
2084#elif COMPILER(GCC) && CPU(ARM_THUMB2)
2085asm (
2086".text" "\n"
2087".align 2" "\n"
2088".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
2089HIDE_SYMBOL(getHostCallReturnValue) "\n"
2090".thumb" "\n"
2091".thumb_func " THUMB_FUNC_PARAM(getHostCallReturnValue) "\n"
2092SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
2093 "mov r0, r7" "\n"
2094 "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
2095);
2096
2097#elif COMPILER(GCC) && CPU(ARM_TRADITIONAL)
2098asm (
2099".text" "\n"
2100".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
2101HIDE_SYMBOL(getHostCallReturnValue) "\n"
2102INLINE_ARM_FUNCTION(getHostCallReturnValue)
2103SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
2104 "mov r0, r11" "\n"
2105 "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
2106);
2107
2108#elif CPU(ARM64)
2109asm (
2110".text" "\n"
2111".align 2" "\n"
2112".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
2113HIDE_SYMBOL(getHostCallReturnValue) "\n"
2114SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
2115 "mov x0, x29" "\n"
2116 "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
2117);
2118
2119#elif COMPILER(GCC) && CPU(MIPS)
2120
2121#if WTF_MIPS_PIC
2122#define LOAD_FUNCTION_TO_T9(function) \
2123 ".set noreorder" "\n" \
2124 ".cpload $25" "\n" \
2125 ".set reorder" "\n" \
2126 "la $t9, " LOCAL_REFERENCE(function) "\n"
2127#else
2128#define LOAD_FUNCTION_TO_T9(function) "" "\n"
2129#endif
2130
2131asm (
2132".text" "\n"
2133".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
2134HIDE_SYMBOL(getHostCallReturnValue) "\n"
2135SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
2136 LOAD_FUNCTION_TO_T9(getHostCallReturnValueWithExecState)
2137 "move $a0, $fp" "\n"
2138 "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n"
2139);
2140
2141#elif COMPILER(GCC) && CPU(SH4)
2142
2143#define SH4_SCRATCH_REGISTER "r11"
2144
2145asm (
2146".text" "\n"
2147".globl " SYMBOL_STRING(getHostCallReturnValue) "\n"
2148HIDE_SYMBOL(getHostCallReturnValue) "\n"
2149SYMBOL_STRING(getHostCallReturnValue) ":" "\n"
2150 "mov r14, r4" "\n"
2151 "mov.l 2f, " SH4_SCRATCH_REGISTER "\n"
2152 "braf " SH4_SCRATCH_REGISTER "\n"
2153 "nop" "\n"
2154 "1: .balign 4" "\n"
2155 "2: .long " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "-1b\n"
2156);
2157
2158#elif COMPILER(MSVC) && CPU(X86)
2159extern "C" {
2160 __declspec(naked) EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValue()
2161 {
2162 __asm mov [esp + 4], ebp;
2163 __asm jmp getHostCallReturnValueWithExecState
2164 }
2165}
2166#endif
2167
2168} // namespace JSC
2169
2170#endif // ENABLE(JIT)