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