2 * Copyright (C) 2011, 2013-2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "DFGOperations.h"
29 #include "ButterflyInlines.h"
30 #include "ClonedArguments.h"
31 #include "CodeBlock.h"
32 #include "CommonSlowPaths.h"
33 #include "CopiedSpaceInlines.h"
34 #include "DFGDriver.h"
35 #include "DFGJITCode.h"
36 #include "DFGOSRExit.h"
37 #include "DFGThunks.h"
38 #include "DFGToFTLDeferredCompilationCallback.h"
39 #include "DFGToFTLForOSREntryDeferredCompilationCallback.h"
40 #include "DFGWorklist.h"
41 #include "DirectArguments.h"
42 #include "FTLForOSREntryJITCode.h"
43 #include "FTLOSREntry.h"
44 #include "HostCallReturnValue.h"
45 #include "GetterSetter.h"
46 #include "Interpreter.h"
48 #include "JITExceptions.h"
49 #include "JSCInlines.h"
50 #include "JSLexicalEnvironment.h"
51 #include "JSNameScope.h"
52 #include "ObjectConstructor.h"
54 #include "ScopedArguments.h"
55 #include "StringConstructor.h"
57 #include "TypeProfilerLog.h"
58 #include "TypedArrayInlines.h"
60 #include <wtf/InlineASM.h>
65 namespace JSC
{ namespace DFG
{
67 template<bool strict
, bool direct
>
68 static inline void putByVal(ExecState
* exec
, JSValue baseValue
, uint32_t index
, JSValue value
)
71 NativeCallFrameTracer
tracer(&vm
, exec
);
72 ASSERT(isIndex(index
));
74 RELEASE_ASSERT(baseValue
.isObject());
75 asObject(baseValue
)->putDirectIndex(exec
, index
, value
, 0, strict
? PutDirectIndexShouldThrow
: PutDirectIndexShouldNotThrow
);
78 if (baseValue
.isObject()) {
79 JSObject
* object
= asObject(baseValue
);
80 if (object
->canSetIndexQuickly(index
)) {
81 object
->setIndexQuickly(vm
, index
, value
);
85 object
->methodTable(vm
)->putByIndex(object
, exec
, index
, value
, strict
);
89 baseValue
.putByIndex(exec
, index
, value
, strict
);
92 template<bool strict
, bool direct
>
93 ALWAYS_INLINE
static void JIT_OPERATION
operationPutByValInternal(ExecState
* exec
, EncodedJSValue encodedBase
, EncodedJSValue encodedProperty
, EncodedJSValue encodedValue
)
96 NativeCallFrameTracer
tracer(vm
, exec
);
98 JSValue baseValue
= JSValue::decode(encodedBase
);
99 JSValue property
= JSValue::decode(encodedProperty
);
100 JSValue value
= JSValue::decode(encodedValue
);
102 if (LIKELY(property
.isUInt32())) {
103 // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices.
104 ASSERT(isIndex(property
.asUInt32()));
105 putByVal
<strict
, direct
>(exec
, baseValue
, property
.asUInt32(), value
);
109 if (property
.isDouble()) {
110 double propertyAsDouble
= property
.asDouble();
111 uint32_t propertyAsUInt32
= static_cast<uint32_t>(propertyAsDouble
);
112 if (propertyAsDouble
== propertyAsUInt32
&& isIndex(propertyAsUInt32
)) {
113 putByVal
<strict
, direct
>(exec
, baseValue
, propertyAsUInt32
, value
);
118 // Don't put to an object if toString throws an exception.
119 auto propertyName
= property
.toPropertyKey(exec
);
123 PutPropertySlot
slot(baseValue
, strict
);
125 RELEASE_ASSERT(baseValue
.isObject());
126 if (Optional
<uint32_t> index
= parseIndex(propertyName
))
127 asObject(baseValue
)->putDirectIndex(exec
, index
.value(), value
, 0, strict
? PutDirectIndexShouldThrow
: PutDirectIndexShouldNotThrow
);
129 asObject(baseValue
)->putDirect(*vm
, propertyName
, value
, slot
);
131 baseValue
.put(exec
, propertyName
, value
, slot
);
134 template<typename ViewClass
>
135 char* newTypedArrayWithSize(ExecState
* exec
, Structure
* structure
, int32_t size
)
138 NativeCallFrameTracer
tracer(&vm
, exec
);
140 vm
.throwException(exec
, createRangeError(exec
, ASCIILiteral("Requested length is negative")));
143 return bitwise_cast
<char*>(ViewClass::create(exec
, structure
, size
));
146 template<typename ViewClass
>
147 char* newTypedArrayWithOneArgument(
148 ExecState
* exec
, Structure
* structure
, EncodedJSValue encodedValue
)
151 NativeCallFrameTracer
tracer(&vm
, exec
);
153 JSValue value
= JSValue::decode(encodedValue
);
155 if (JSArrayBuffer
* jsBuffer
= jsDynamicCast
<JSArrayBuffer
*>(value
)) {
156 RefPtr
<ArrayBuffer
> buffer
= jsBuffer
->impl();
158 if (buffer
->byteLength() % ViewClass::elementSize
) {
159 vm
.throwException(exec
, createRangeError(exec
, ASCIILiteral("ArrayBuffer length minus the byteOffset is not a multiple of the element size")));
162 return bitwise_cast
<char*>(
164 exec
, structure
, buffer
, 0, buffer
->byteLength() / ViewClass::elementSize
));
167 if (JSObject
* object
= jsDynamicCast
<JSObject
*>(value
)) {
168 unsigned length
= object
->get(exec
, vm
.propertyNames
->length
).toUInt32(exec
);
169 if (exec
->hadException())
172 ViewClass
* result
= ViewClass::createUninitialized(exec
, structure
, length
);
176 if (!result
->set(exec
, object
, 0, length
))
179 return bitwise_cast
<char*>(result
);
184 length
= value
.asInt32();
185 else if (!value
.isNumber()) {
186 vm
.throwException(exec
, createTypeError(exec
, ASCIILiteral("Invalid array length argument")));
189 length
= static_cast<int>(value
.asNumber());
190 if (length
!= value
.asNumber()) {
191 vm
.throwException(exec
, createTypeError(exec
, ASCIILiteral("Invalid array length argument (fractional lengths not allowed)")));
197 vm
.throwException(exec
, createRangeError(exec
, ASCIILiteral("Requested length is negative")));
201 return bitwise_cast
<char*>(ViewClass::create(exec
, structure
, length
));
206 EncodedJSValue JIT_OPERATION
operationToThis(ExecState
* exec
, EncodedJSValue encodedOp
)
208 VM
* vm
= &exec
->vm();
209 NativeCallFrameTracer
tracer(vm
, exec
);
211 return JSValue::encode(JSValue::decode(encodedOp
).toThis(exec
, NotStrictMode
));
214 EncodedJSValue JIT_OPERATION
operationToThisStrict(ExecState
* exec
, EncodedJSValue encodedOp
)
216 VM
* vm
= &exec
->vm();
217 NativeCallFrameTracer
tracer(vm
, exec
);
219 return JSValue::encode(JSValue::decode(encodedOp
).toThis(exec
, StrictMode
));
222 JSCell
* JIT_OPERATION
operationCreateThis(ExecState
* exec
, JSObject
* constructor
, int32_t inlineCapacity
)
225 NativeCallFrameTracer
tracer(&vm
, exec
);
228 ConstructData constructData
;
229 ASSERT(jsCast
<JSFunction
*>(constructor
)->methodTable(vm
)->getConstructData(jsCast
<JSFunction
*>(constructor
), constructData
) == ConstructTypeJS
);
232 return constructEmptyObject(exec
, jsCast
<JSFunction
*>(constructor
)->rareData(exec
, inlineCapacity
)->allocationProfile()->structure());
235 EncodedJSValue JIT_OPERATION
operationValueAdd(ExecState
* exec
, EncodedJSValue encodedOp1
, EncodedJSValue encodedOp2
)
237 VM
* vm
= &exec
->vm();
238 NativeCallFrameTracer
tracer(vm
, exec
);
240 JSValue op1
= JSValue::decode(encodedOp1
);
241 JSValue op2
= JSValue::decode(encodedOp2
);
243 return JSValue::encode(jsAdd(exec
, op1
, op2
));
246 EncodedJSValue JIT_OPERATION
operationValueAddNotNumber(ExecState
* exec
, EncodedJSValue encodedOp1
, EncodedJSValue encodedOp2
)
248 VM
* vm
= &exec
->vm();
249 NativeCallFrameTracer
tracer(vm
, exec
);
251 JSValue op1
= JSValue::decode(encodedOp1
);
252 JSValue op2
= JSValue::decode(encodedOp2
);
254 ASSERT(!op1
.isNumber() || !op2
.isNumber());
256 if (op1
.isString() && !op2
.isObject())
257 return JSValue::encode(jsString(exec
, asString(op1
), op2
.toString(exec
)));
259 return JSValue::encode(jsAddSlowCase(exec
, op1
, op2
));
262 static ALWAYS_INLINE EncodedJSValue
getByVal(ExecState
* exec
, JSCell
* base
, uint32_t index
)
265 NativeCallFrameTracer
tracer(&vm
, exec
);
267 if (base
->isObject()) {
268 JSObject
* object
= asObject(base
);
269 if (object
->canGetIndexQuickly(index
))
270 return JSValue::encode(object
->getIndexQuickly(index
));
273 if (isJSString(base
) && asString(base
)->canGetIndex(index
))
274 return JSValue::encode(asString(base
)->getIndex(exec
, index
));
276 return JSValue::encode(JSValue(base
).get(exec
, index
));
279 EncodedJSValue JIT_OPERATION
operationGetByVal(ExecState
* exec
, EncodedJSValue encodedBase
, EncodedJSValue encodedProperty
)
282 NativeCallFrameTracer
tracer(&vm
, exec
);
284 JSValue baseValue
= JSValue::decode(encodedBase
);
285 JSValue property
= JSValue::decode(encodedProperty
);
287 if (LIKELY(baseValue
.isCell())) {
288 JSCell
* base
= baseValue
.asCell();
290 if (property
.isUInt32()) {
291 return getByVal(exec
, base
, property
.asUInt32());
292 } else if (property
.isDouble()) {
293 double propertyAsDouble
= property
.asDouble();
294 uint32_t propertyAsUInt32
= static_cast<uint32_t>(propertyAsDouble
);
295 if (propertyAsUInt32
== propertyAsDouble
&& isIndex(propertyAsUInt32
))
296 return getByVal(exec
, base
, propertyAsUInt32
);
297 } else if (property
.isString()) {
298 Structure
& structure
= *base
->structure(vm
);
299 if (JSCell::canUseFastGetOwnProperty(structure
)) {
300 if (RefPtr
<AtomicStringImpl
> existingAtomicString
= asString(property
)->toExistingAtomicString(exec
)) {
301 if (JSValue result
= base
->fastGetOwnProperty(vm
, structure
, existingAtomicString
.get()))
302 return JSValue::encode(result
);
308 baseValue
.requireObjectCoercible(exec
);
309 if (exec
->hadException())
310 return JSValue::encode(jsUndefined());
311 auto propertyName
= property
.toPropertyKey(exec
);
312 if (exec
->hadException())
313 return JSValue::encode(jsUndefined());
314 return JSValue::encode(baseValue
.get(exec
, propertyName
));
317 EncodedJSValue JIT_OPERATION
operationGetByValCell(ExecState
* exec
, JSCell
* base
, EncodedJSValue encodedProperty
)
320 NativeCallFrameTracer
tracer(&vm
, exec
);
322 JSValue property
= JSValue::decode(encodedProperty
);
324 if (property
.isUInt32())
325 return getByVal(exec
, base
, property
.asUInt32());
326 if (property
.isDouble()) {
327 double propertyAsDouble
= property
.asDouble();
328 uint32_t propertyAsUInt32
= static_cast<uint32_t>(propertyAsDouble
);
329 if (propertyAsUInt32
== propertyAsDouble
)
330 return getByVal(exec
, base
, propertyAsUInt32
);
331 } else if (property
.isString()) {
332 Structure
& structure
= *base
->structure(vm
);
333 if (JSCell::canUseFastGetOwnProperty(structure
)) {
334 if (RefPtr
<AtomicStringImpl
> existingAtomicString
= asString(property
)->toExistingAtomicString(exec
)) {
335 if (JSValue result
= base
->fastGetOwnProperty(vm
, structure
, existingAtomicString
.get()))
336 return JSValue::encode(result
);
341 auto propertyName
= property
.toPropertyKey(exec
);
342 if (exec
->hadException())
343 return JSValue::encode(jsUndefined());
344 return JSValue::encode(JSValue(base
).get(exec
, propertyName
));
347 ALWAYS_INLINE EncodedJSValue
getByValCellInt(ExecState
* exec
, JSCell
* base
, int32_t index
)
349 VM
* vm
= &exec
->vm();
350 NativeCallFrameTracer
tracer(vm
, exec
);
353 // Go the slowest way possible becase negative indices don't use indexed storage.
354 return JSValue::encode(JSValue(base
).get(exec
, Identifier::from(exec
, index
)));
357 // Use this since we know that the value is out of bounds.
358 return JSValue::encode(JSValue(base
).get(exec
, index
));
361 EncodedJSValue JIT_OPERATION
operationGetByValArrayInt(ExecState
* exec
, JSArray
* base
, int32_t index
)
363 return getByValCellInt(exec
, base
, index
);
366 EncodedJSValue JIT_OPERATION
operationGetByValStringInt(ExecState
* exec
, JSString
* base
, int32_t index
)
368 return getByValCellInt(exec
, base
, index
);
371 void JIT_OPERATION
operationPutByValStrict(ExecState
* exec
, EncodedJSValue encodedBase
, EncodedJSValue encodedProperty
, EncodedJSValue encodedValue
)
373 VM
* vm
= &exec
->vm();
374 NativeCallFrameTracer
tracer(vm
, exec
);
376 operationPutByValInternal
<true, false>(exec
, encodedBase
, encodedProperty
, encodedValue
);
379 void JIT_OPERATION
operationPutByValNonStrict(ExecState
* exec
, EncodedJSValue encodedBase
, EncodedJSValue encodedProperty
, EncodedJSValue encodedValue
)
381 VM
* vm
= &exec
->vm();
382 NativeCallFrameTracer
tracer(vm
, exec
);
384 operationPutByValInternal
<false, false>(exec
, encodedBase
, encodedProperty
, encodedValue
);
387 void JIT_OPERATION
operationPutByValCellStrict(ExecState
* exec
, JSCell
* cell
, EncodedJSValue encodedProperty
, EncodedJSValue encodedValue
)
389 VM
* vm
= &exec
->vm();
390 NativeCallFrameTracer
tracer(vm
, exec
);
392 operationPutByValInternal
<true, false>(exec
, JSValue::encode(cell
), encodedProperty
, encodedValue
);
395 void JIT_OPERATION
operationPutByValCellNonStrict(ExecState
* exec
, JSCell
* cell
, EncodedJSValue encodedProperty
, EncodedJSValue encodedValue
)
397 VM
* vm
= &exec
->vm();
398 NativeCallFrameTracer
tracer(vm
, exec
);
400 operationPutByValInternal
<false, false>(exec
, JSValue::encode(cell
), encodedProperty
, encodedValue
);
403 void JIT_OPERATION
operationPutByValBeyondArrayBoundsStrict(ExecState
* exec
, JSObject
* array
, int32_t index
, EncodedJSValue encodedValue
)
406 NativeCallFrameTracer
tracer(&vm
, exec
);
409 array
->putByIndexInline(exec
, index
, JSValue::decode(encodedValue
), true);
413 PutPropertySlot
slot(array
, true);
414 array
->methodTable()->put(
415 array
, exec
, Identifier::from(exec
, index
), JSValue::decode(encodedValue
), slot
);
418 void JIT_OPERATION
operationPutByValBeyondArrayBoundsNonStrict(ExecState
* exec
, JSObject
* array
, int32_t index
, EncodedJSValue encodedValue
)
420 VM
* vm
= &exec
->vm();
421 NativeCallFrameTracer
tracer(vm
, exec
);
424 array
->putByIndexInline(exec
, index
, JSValue::decode(encodedValue
), false);
428 PutPropertySlot
slot(array
, false);
429 array
->methodTable()->put(
430 array
, exec
, Identifier::from(exec
, index
), JSValue::decode(encodedValue
), slot
);
433 void JIT_OPERATION
operationPutDoubleByValBeyondArrayBoundsStrict(ExecState
* exec
, JSObject
* array
, int32_t index
, double value
)
435 VM
* vm
= &exec
->vm();
436 NativeCallFrameTracer
tracer(vm
, exec
);
438 JSValue jsValue
= JSValue(JSValue::EncodeAsDouble
, value
);
441 array
->putByIndexInline(exec
, index
, jsValue
, true);
445 PutPropertySlot
slot(array
, true);
446 array
->methodTable()->put(
447 array
, exec
, Identifier::from(exec
, index
), jsValue
, slot
);
450 void JIT_OPERATION
operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState
* exec
, JSObject
* array
, int32_t index
, double value
)
452 VM
* vm
= &exec
->vm();
453 NativeCallFrameTracer
tracer(vm
, exec
);
455 JSValue jsValue
= JSValue(JSValue::EncodeAsDouble
, value
);
458 array
->putByIndexInline(exec
, index
, jsValue
, false);
462 PutPropertySlot
slot(array
, false);
463 array
->methodTable()->put(
464 array
, exec
, Identifier::from(exec
, index
), jsValue
, slot
);
467 void JIT_OPERATION
operationPutByValDirectStrict(ExecState
* exec
, EncodedJSValue encodedBase
, EncodedJSValue encodedProperty
, EncodedJSValue encodedValue
)
469 VM
* vm
= &exec
->vm();
470 NativeCallFrameTracer
tracer(vm
, exec
);
472 operationPutByValInternal
<true, true>(exec
, encodedBase
, encodedProperty
, encodedValue
);
475 void JIT_OPERATION
operationPutByValDirectNonStrict(ExecState
* exec
, EncodedJSValue encodedBase
, EncodedJSValue encodedProperty
, EncodedJSValue encodedValue
)
477 VM
* vm
= &exec
->vm();
478 NativeCallFrameTracer
tracer(vm
, exec
);
480 operationPutByValInternal
<false, true>(exec
, encodedBase
, encodedProperty
, encodedValue
);
483 void JIT_OPERATION
operationPutByValDirectCellStrict(ExecState
* exec
, JSCell
* cell
, EncodedJSValue encodedProperty
, EncodedJSValue encodedValue
)
485 VM
* vm
= &exec
->vm();
486 NativeCallFrameTracer
tracer(vm
, exec
);
488 operationPutByValInternal
<true, true>(exec
, JSValue::encode(cell
), encodedProperty
, encodedValue
);
491 void JIT_OPERATION
operationPutByValDirectCellNonStrict(ExecState
* exec
, JSCell
* cell
, EncodedJSValue encodedProperty
, EncodedJSValue encodedValue
)
493 VM
* vm
= &exec
->vm();
494 NativeCallFrameTracer
tracer(vm
, exec
);
496 operationPutByValInternal
<false, true>(exec
, JSValue::encode(cell
), encodedProperty
, encodedValue
);
499 void JIT_OPERATION
operationPutByValDirectBeyondArrayBoundsStrict(ExecState
* exec
, JSObject
* array
, int32_t index
, EncodedJSValue encodedValue
)
501 VM
* vm
= &exec
->vm();
502 NativeCallFrameTracer
tracer(vm
, exec
);
504 array
->putDirectIndex(exec
, index
, JSValue::decode(encodedValue
), 0, PutDirectIndexShouldThrow
);
508 PutPropertySlot
slot(array
, true);
509 array
->putDirect(exec
->vm(), Identifier::from(exec
, index
), JSValue::decode(encodedValue
), slot
);
512 void JIT_OPERATION
operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState
* exec
, JSObject
* array
, int32_t index
, EncodedJSValue encodedValue
)
514 VM
* vm
= &exec
->vm();
515 NativeCallFrameTracer
tracer(vm
, exec
);
518 array
->putDirectIndex(exec
, index
, JSValue::decode(encodedValue
));
522 PutPropertySlot
slot(array
, false);
523 array
->putDirect(exec
->vm(), Identifier::from(exec
, index
), JSValue::decode(encodedValue
), slot
);
526 EncodedJSValue JIT_OPERATION
operationArrayPush(ExecState
* exec
, EncodedJSValue encodedValue
, JSArray
* array
)
528 VM
* vm
= &exec
->vm();
529 NativeCallFrameTracer
tracer(vm
, exec
);
531 array
->push(exec
, JSValue::decode(encodedValue
));
532 return JSValue::encode(jsNumber(array
->length()));
535 EncodedJSValue JIT_OPERATION
operationArrayPushDouble(ExecState
* exec
, double value
, JSArray
* array
)
537 VM
* vm
= &exec
->vm();
538 NativeCallFrameTracer
tracer(vm
, exec
);
540 array
->push(exec
, JSValue(JSValue::EncodeAsDouble
, value
));
541 return JSValue::encode(jsNumber(array
->length()));
544 EncodedJSValue JIT_OPERATION
operationArrayPop(ExecState
* exec
, JSArray
* array
)
546 VM
* vm
= &exec
->vm();
547 NativeCallFrameTracer
tracer(vm
, exec
);
549 return JSValue::encode(array
->pop(exec
));
552 EncodedJSValue JIT_OPERATION
operationArrayPopAndRecoverLength(ExecState
* exec
, JSArray
* array
)
554 VM
* vm
= &exec
->vm();
555 NativeCallFrameTracer
tracer(vm
, exec
);
557 array
->butterfly()->setPublicLength(array
->butterfly()->publicLength() + 1);
559 return JSValue::encode(array
->pop(exec
));
562 EncodedJSValue JIT_OPERATION
operationRegExpExec(ExecState
* exec
, JSCell
* base
, JSCell
* argument
)
565 NativeCallFrameTracer
tracer(&vm
, exec
);
567 if (!base
->inherits(RegExpObject::info()))
568 return throwVMTypeError(exec
);
570 ASSERT(argument
->isString() || argument
->isObject());
571 JSString
* input
= argument
->isString() ? asString(argument
) : asObject(argument
)->toString(exec
);
572 return JSValue::encode(asRegExpObject(base
)->exec(exec
, input
));
575 size_t JIT_OPERATION
operationRegExpTest(ExecState
* exec
, JSCell
* base
, JSCell
* argument
)
578 NativeCallFrameTracer
tracer(&vm
, exec
);
580 if (!base
->inherits(RegExpObject::info())) {
581 throwTypeError(exec
);
585 ASSERT(argument
->isString() || argument
->isObject());
586 JSString
* input
= argument
->isString() ? asString(argument
) : asObject(argument
)->toString(exec
);
587 return asRegExpObject(base
)->test(exec
, input
);
590 size_t JIT_OPERATION
operationCompareStrictEqCell(ExecState
* exec
, EncodedJSValue encodedOp1
, EncodedJSValue encodedOp2
)
592 VM
* vm
= &exec
->vm();
593 NativeCallFrameTracer
tracer(vm
, exec
);
595 JSValue op1
= JSValue::decode(encodedOp1
);
596 JSValue op2
= JSValue::decode(encodedOp2
);
598 ASSERT(op1
.isCell());
599 ASSERT(op2
.isCell());
601 return JSValue::strictEqualSlowCaseInline(exec
, op1
, op2
);
604 size_t JIT_OPERATION
operationCompareStrictEq(ExecState
* exec
, EncodedJSValue encodedOp1
, EncodedJSValue encodedOp2
)
606 VM
* vm
= &exec
->vm();
607 NativeCallFrameTracer
tracer(vm
, exec
);
609 JSValue src1
= JSValue::decode(encodedOp1
);
610 JSValue src2
= JSValue::decode(encodedOp2
);
612 return JSValue::strictEqual(exec
, src1
, src2
);
615 EncodedJSValue JIT_OPERATION
operationToPrimitive(ExecState
* exec
, EncodedJSValue value
)
617 VM
* vm
= &exec
->vm();
618 NativeCallFrameTracer
tracer(vm
, exec
);
620 return JSValue::encode(JSValue::decode(value
).toPrimitive(exec
));
623 char* JIT_OPERATION
operationNewArray(ExecState
* exec
, Structure
* arrayStructure
, void* buffer
, size_t size
)
625 VM
* vm
= &exec
->vm();
626 NativeCallFrameTracer
tracer(vm
, exec
);
628 return bitwise_cast
<char*>(constructArray(exec
, arrayStructure
, static_cast<JSValue
*>(buffer
), size
));
631 char* JIT_OPERATION
operationNewEmptyArray(ExecState
* exec
, Structure
* arrayStructure
)
633 VM
* vm
= &exec
->vm();
634 NativeCallFrameTracer
tracer(vm
, exec
);
636 return bitwise_cast
<char*>(JSArray::create(*vm
, arrayStructure
));
639 char* JIT_OPERATION
operationNewArrayWithSize(ExecState
* exec
, Structure
* arrayStructure
, int32_t size
)
641 VM
* vm
= &exec
->vm();
642 NativeCallFrameTracer
tracer(vm
, exec
);
644 if (UNLIKELY(size
< 0))
645 return bitwise_cast
<char*>(exec
->vm().throwException(exec
, createRangeError(exec
, ASCIILiteral("Array size is not a small enough positive integer."))));
647 return bitwise_cast
<char*>(JSArray::create(*vm
, arrayStructure
, size
));
650 char* JIT_OPERATION
operationNewArrayBuffer(ExecState
* exec
, Structure
* arrayStructure
, size_t start
, size_t size
)
653 NativeCallFrameTracer
tracer(&vm
, exec
);
654 return bitwise_cast
<char*>(constructArray(exec
, arrayStructure
, exec
->codeBlock()->constantBuffer(start
), size
));
657 char* JIT_OPERATION
operationNewInt8ArrayWithSize(
658 ExecState
* exec
, Structure
* structure
, int32_t length
)
660 return newTypedArrayWithSize
<JSInt8Array
>(exec
, structure
, length
);
663 char* JIT_OPERATION
operationNewInt8ArrayWithOneArgument(
664 ExecState
* exec
, Structure
* structure
, EncodedJSValue encodedValue
)
666 return newTypedArrayWithOneArgument
<JSInt8Array
>(exec
, structure
, encodedValue
);
669 char* JIT_OPERATION
operationNewInt16ArrayWithSize(
670 ExecState
* exec
, Structure
* structure
, int32_t length
)
672 return newTypedArrayWithSize
<JSInt16Array
>(exec
, structure
, length
);
675 char* JIT_OPERATION
operationNewInt16ArrayWithOneArgument(
676 ExecState
* exec
, Structure
* structure
, EncodedJSValue encodedValue
)
678 return newTypedArrayWithOneArgument
<JSInt16Array
>(exec
, structure
, encodedValue
);
681 char* JIT_OPERATION
operationNewInt32ArrayWithSize(
682 ExecState
* exec
, Structure
* structure
, int32_t length
)
684 return newTypedArrayWithSize
<JSInt32Array
>(exec
, structure
, length
);
687 char* JIT_OPERATION
operationNewInt32ArrayWithOneArgument(
688 ExecState
* exec
, Structure
* structure
, EncodedJSValue encodedValue
)
690 return newTypedArrayWithOneArgument
<JSInt32Array
>(exec
, structure
, encodedValue
);
693 char* JIT_OPERATION
operationNewUint8ArrayWithSize(
694 ExecState
* exec
, Structure
* structure
, int32_t length
)
696 return newTypedArrayWithSize
<JSUint8Array
>(exec
, structure
, length
);
699 char* JIT_OPERATION
operationNewUint8ArrayWithOneArgument(
700 ExecState
* exec
, Structure
* structure
, EncodedJSValue encodedValue
)
702 return newTypedArrayWithOneArgument
<JSUint8Array
>(exec
, structure
, encodedValue
);
705 char* JIT_OPERATION
operationNewUint8ClampedArrayWithSize(
706 ExecState
* exec
, Structure
* structure
, int32_t length
)
708 return newTypedArrayWithSize
<JSUint8ClampedArray
>(exec
, structure
, length
);
711 char* JIT_OPERATION
operationNewUint8ClampedArrayWithOneArgument(
712 ExecState
* exec
, Structure
* structure
, EncodedJSValue encodedValue
)
714 return newTypedArrayWithOneArgument
<JSUint8ClampedArray
>(exec
, structure
, encodedValue
);
717 char* JIT_OPERATION
operationNewUint16ArrayWithSize(
718 ExecState
* exec
, Structure
* structure
, int32_t length
)
720 return newTypedArrayWithSize
<JSUint16Array
>(exec
, structure
, length
);
723 char* JIT_OPERATION
operationNewUint16ArrayWithOneArgument(
724 ExecState
* exec
, Structure
* structure
, EncodedJSValue encodedValue
)
726 return newTypedArrayWithOneArgument
<JSUint16Array
>(exec
, structure
, encodedValue
);
729 char* JIT_OPERATION
operationNewUint32ArrayWithSize(
730 ExecState
* exec
, Structure
* structure
, int32_t length
)
732 return newTypedArrayWithSize
<JSUint32Array
>(exec
, structure
, length
);
735 char* JIT_OPERATION
operationNewUint32ArrayWithOneArgument(
736 ExecState
* exec
, Structure
* structure
, EncodedJSValue encodedValue
)
738 return newTypedArrayWithOneArgument
<JSUint32Array
>(exec
, structure
, encodedValue
);
741 char* JIT_OPERATION
operationNewFloat32ArrayWithSize(
742 ExecState
* exec
, Structure
* structure
, int32_t length
)
744 return newTypedArrayWithSize
<JSFloat32Array
>(exec
, structure
, length
);
747 char* JIT_OPERATION
operationNewFloat32ArrayWithOneArgument(
748 ExecState
* exec
, Structure
* structure
, EncodedJSValue encodedValue
)
750 return newTypedArrayWithOneArgument
<JSFloat32Array
>(exec
, structure
, encodedValue
);
753 char* JIT_OPERATION
operationNewFloat64ArrayWithSize(
754 ExecState
* exec
, Structure
* structure
, int32_t length
)
756 return newTypedArrayWithSize
<JSFloat64Array
>(exec
, structure
, length
);
759 char* JIT_OPERATION
operationNewFloat64ArrayWithOneArgument(
760 ExecState
* exec
, Structure
* structure
, EncodedJSValue encodedValue
)
762 return newTypedArrayWithOneArgument
<JSFloat64Array
>(exec
, structure
, encodedValue
);
765 JSCell
* JIT_OPERATION
operationCreateActivationDirect(ExecState
* exec
, Structure
* structure
, JSScope
* scope
, SymbolTable
* table
)
768 NativeCallFrameTracer
tracer(&vm
, exec
);
769 return JSLexicalEnvironment::create(vm
, structure
, scope
, table
);
772 JSCell
* JIT_OPERATION
operationCreateDirectArguments(ExecState
* exec
, Structure
* structure
, int32_t length
, int32_t minCapacity
)
775 NativeCallFrameTracer
target(&vm
, exec
);
776 DirectArguments
* result
= DirectArguments::create(
777 vm
, structure
, length
, std::max(length
, minCapacity
));
778 // The caller will store to this object without barriers. Most likely, at this point, this is
779 // still a young object and so no barriers are needed. But it's good to be careful anyway,
780 // since the GC should be allowed to do crazy (like pretenuring, for example).
781 vm
.heap
.writeBarrier(result
);
785 JSCell
* JIT_OPERATION
operationCreateScopedArguments(ExecState
* exec
, Structure
* structure
, Register
* argumentStart
, int32_t length
, JSFunction
* callee
, JSLexicalEnvironment
* scope
)
788 NativeCallFrameTracer
target(&vm
, exec
);
790 // We could pass the ScopedArgumentsTable* as an argument. We currently don't because I
791 // didn't feel like changing the max number of arguments for a slow path call from 6 to 7.
792 ScopedArgumentsTable
* table
= scope
->symbolTable()->arguments();
794 return ScopedArguments::createByCopyingFrom(
795 vm
, structure
, argumentStart
, length
, callee
, table
, scope
);
798 JSCell
* JIT_OPERATION
operationCreateClonedArguments(ExecState
* exec
, Structure
* structure
, Register
* argumentStart
, int32_t length
, JSFunction
* callee
)
801 NativeCallFrameTracer
target(&vm
, exec
);
802 return ClonedArguments::createByCopyingFrom(
803 exec
, structure
, argumentStart
, length
, callee
);
806 JSCell
* JIT_OPERATION
operationCreateDirectArgumentsDuringExit(ExecState
* exec
, InlineCallFrame
* inlineCallFrame
, JSFunction
* callee
, int32_t argumentCount
)
809 NativeCallFrameTracer
target(&vm
, exec
);
811 DeferGCForAWhile
deferGC(vm
.heap
);
813 CodeBlock
* codeBlock
;
815 codeBlock
= baselineCodeBlockForInlineCallFrame(inlineCallFrame
);
817 codeBlock
= exec
->codeBlock();
819 unsigned length
= argumentCount
- 1;
820 unsigned capacity
= std::max(length
, static_cast<unsigned>(codeBlock
->numParameters() - 1));
821 DirectArguments
* result
= DirectArguments::create(
822 vm
, codeBlock
->globalObject()->directArgumentsStructure(), length
, capacity
);
824 result
->callee().set(vm
, result
, callee
);
826 Register
* arguments
=
827 exec
->registers() + (inlineCallFrame
? inlineCallFrame
->stackOffset
: 0) +
828 CallFrame::argumentOffset(0);
829 for (unsigned i
= length
; i
--;)
830 result
->setIndexQuickly(vm
, i
, arguments
[i
].jsValue());
835 JSCell
* JIT_OPERATION
operationCreateClonedArgumentsDuringExit(ExecState
* exec
, InlineCallFrame
* inlineCallFrame
, JSFunction
* callee
, int32_t argumentCount
)
838 NativeCallFrameTracer
target(&vm
, exec
);
840 DeferGCForAWhile
deferGC(vm
.heap
);
842 CodeBlock
* codeBlock
;
844 codeBlock
= baselineCodeBlockForInlineCallFrame(inlineCallFrame
);
846 codeBlock
= exec
->codeBlock();
848 unsigned length
= argumentCount
- 1;
849 ClonedArguments
* result
= ClonedArguments::createEmpty(
850 vm
, codeBlock
->globalObject()->outOfBandArgumentsStructure(), callee
);
852 Register
* arguments
=
853 exec
->registers() + (inlineCallFrame
? inlineCallFrame
->stackOffset
: 0) +
854 CallFrame::argumentOffset(0);
855 for (unsigned i
= length
; i
--;)
856 result
->putDirectIndex(exec
, i
, arguments
[i
].jsValue());
858 result
->putDirect(vm
, vm
.propertyNames
->length
, jsNumber(length
));
863 size_t JIT_OPERATION
operationObjectIsObject(ExecState
* exec
, JSGlobalObject
* globalObject
, JSCell
* object
)
866 NativeCallFrameTracer
tracer(&vm
, exec
);
868 ASSERT(jsDynamicCast
<JSObject
*>(object
));
870 if (object
->structure(vm
)->masqueradesAsUndefined(globalObject
))
872 if (object
->type() == JSFunctionType
)
874 if (object
->inlineTypeFlags() & TypeOfShouldCallGetCallData
) {
876 if (object
->methodTable(vm
)->getCallData(object
, callData
) != CallTypeNone
)
883 size_t JIT_OPERATION
operationObjectIsFunction(ExecState
* exec
, JSGlobalObject
* globalObject
, JSCell
* object
)
886 NativeCallFrameTracer
tracer(&vm
, exec
);
888 ASSERT(jsDynamicCast
<JSObject
*>(object
));
890 if (object
->structure(vm
)->masqueradesAsUndefined(globalObject
))
892 if (object
->type() == JSFunctionType
)
894 if (object
->inlineTypeFlags() & TypeOfShouldCallGetCallData
) {
896 if (object
->methodTable(vm
)->getCallData(object
, callData
) != CallTypeNone
)
903 JSCell
* JIT_OPERATION
operationTypeOfObject(ExecState
* exec
, JSGlobalObject
* globalObject
, JSCell
* object
)
906 NativeCallFrameTracer
tracer(&vm
, exec
);
908 ASSERT(jsDynamicCast
<JSObject
*>(object
));
910 if (object
->structure(vm
)->masqueradesAsUndefined(globalObject
))
911 return vm
.smallStrings
.undefinedString();
912 if (object
->type() == JSFunctionType
)
913 return vm
.smallStrings
.functionString();
914 if (object
->inlineTypeFlags() & TypeOfShouldCallGetCallData
) {
916 if (object
->methodTable(vm
)->getCallData(object
, callData
) != CallTypeNone
)
917 return vm
.smallStrings
.functionString();
920 return vm
.smallStrings
.objectString();
923 int32_t JIT_OPERATION
operationTypeOfObjectAsTypeofType(ExecState
* exec
, JSGlobalObject
* globalObject
, JSCell
* object
)
926 NativeCallFrameTracer
tracer(&vm
, exec
);
928 ASSERT(jsDynamicCast
<JSObject
*>(object
));
930 if (object
->structure(vm
)->masqueradesAsUndefined(globalObject
))
931 return static_cast<int32_t>(TypeofType::Undefined
);
932 if (object
->type() == JSFunctionType
)
933 return static_cast<int32_t>(TypeofType::Function
);
934 if (object
->inlineTypeFlags() & TypeOfShouldCallGetCallData
) {
936 if (object
->methodTable(vm
)->getCallData(object
, callData
) != CallTypeNone
)
937 return static_cast<int32_t>(TypeofType::Function
);
940 return static_cast<int32_t>(TypeofType::Object
);
943 char* JIT_OPERATION
operationAllocatePropertyStorageWithInitialCapacity(ExecState
* exec
)
946 NativeCallFrameTracer
tracer(&vm
, exec
);
948 return reinterpret_cast<char*>(
949 Butterfly::createUninitialized(vm
, 0, 0, initialOutOfLineCapacity
, false, 0));
952 char* JIT_OPERATION
operationAllocatePropertyStorage(ExecState
* exec
, size_t newSize
)
955 NativeCallFrameTracer
tracer(&vm
, exec
);
957 return reinterpret_cast<char*>(
958 Butterfly::createUninitialized(vm
, 0, 0, newSize
, false, 0));
961 char* JIT_OPERATION
operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState
* exec
, JSObject
* object
)
964 NativeCallFrameTracer
tracer(&vm
, exec
);
966 ASSERT(!object
->structure()->outOfLineCapacity());
967 DeferGC
deferGC(vm
.heap
);
968 Butterfly
* result
= object
->growOutOfLineStorage(vm
, 0, initialOutOfLineCapacity
);
969 object
->setButterflyWithoutChangingStructure(vm
, result
);
970 return reinterpret_cast<char*>(result
);
973 char* JIT_OPERATION
operationReallocateButterflyToGrowPropertyStorage(ExecState
* exec
, JSObject
* object
, size_t newSize
)
976 NativeCallFrameTracer
tracer(&vm
, exec
);
978 DeferGC
deferGC(vm
.heap
);
979 Butterfly
* result
= object
->growOutOfLineStorage(vm
, object
->structure()->outOfLineCapacity(), newSize
);
980 object
->setButterflyWithoutChangingStructure(vm
, result
);
981 return reinterpret_cast<char*>(result
);
984 char* JIT_OPERATION
operationEnsureInt32(ExecState
* exec
, JSCell
* cell
)
987 NativeCallFrameTracer
tracer(&vm
, exec
);
989 if (!cell
->isObject())
992 return reinterpret_cast<char*>(asObject(cell
)->ensureInt32(vm
).data());
995 char* JIT_OPERATION
operationEnsureDouble(ExecState
* exec
, JSCell
* cell
)
998 NativeCallFrameTracer
tracer(&vm
, exec
);
1000 if (!cell
->isObject())
1003 return reinterpret_cast<char*>(asObject(cell
)->ensureDouble(vm
).data());
1006 char* JIT_OPERATION
operationEnsureContiguous(ExecState
* exec
, JSCell
* cell
)
1008 VM
& vm
= exec
->vm();
1009 NativeCallFrameTracer
tracer(&vm
, exec
);
1011 if (!cell
->isObject())
1014 return reinterpret_cast<char*>(asObject(cell
)->ensureContiguous(vm
).data());
1017 char* JIT_OPERATION
operationEnsureArrayStorage(ExecState
* exec
, JSCell
* cell
)
1019 VM
& vm
= exec
->vm();
1020 NativeCallFrameTracer
tracer(&vm
, exec
);
1022 if (!cell
->isObject())
1025 return reinterpret_cast<char*>(asObject(cell
)->ensureArrayStorage(vm
));
1028 StringImpl
* JIT_OPERATION
operationResolveRope(ExecState
* exec
, JSString
* string
)
1030 VM
& vm
= exec
->vm();
1031 NativeCallFrameTracer
tracer(&vm
, exec
);
1033 return string
->value(exec
).impl();
1036 JSString
* JIT_OPERATION
operationSingleCharacterString(ExecState
* exec
, int32_t character
)
1038 VM
& vm
= exec
->vm();
1039 NativeCallFrameTracer
tracer(&vm
, exec
);
1041 return jsSingleCharacterString(exec
, static_cast<UChar
>(character
));
1044 JSCell
* JIT_OPERATION
operationNewStringObject(ExecState
* exec
, JSString
* string
, Structure
* structure
)
1046 VM
& vm
= exec
->vm();
1047 NativeCallFrameTracer
tracer(&vm
, exec
);
1049 return StringObject::create(vm
, structure
, string
);
1052 JSCell
* JIT_OPERATION
operationToStringOnCell(ExecState
* exec
, JSCell
* cell
)
1054 VM
& vm
= exec
->vm();
1055 NativeCallFrameTracer
tracer(&vm
, exec
);
1057 return JSValue(cell
).toString(exec
);
1060 JSCell
* JIT_OPERATION
operationToString(ExecState
* exec
, EncodedJSValue value
)
1062 VM
& vm
= exec
->vm();
1063 NativeCallFrameTracer
tracer(&vm
, exec
);
1065 return JSValue::decode(value
).toString(exec
);
1068 JSCell
* JIT_OPERATION
operationCallStringConstructorOnCell(ExecState
* exec
, JSCell
* cell
)
1070 VM
& vm
= exec
->vm();
1071 NativeCallFrameTracer
tracer(&vm
, exec
);
1073 return stringConstructor(exec
, cell
);
1076 JSCell
* JIT_OPERATION
operationCallStringConstructor(ExecState
* exec
, EncodedJSValue value
)
1078 VM
& vm
= exec
->vm();
1079 NativeCallFrameTracer
tracer(&vm
, exec
);
1081 return stringConstructor(exec
, JSValue::decode(value
));
1084 JSCell
* JIT_OPERATION
operationMakeRope2(ExecState
* exec
, JSString
* left
, JSString
* right
)
1086 VM
& vm
= exec
->vm();
1087 NativeCallFrameTracer
tracer(&vm
, exec
);
1089 if (sumOverflows
<int32_t>(left
->length(), right
->length())) {
1090 throwOutOfMemoryError(exec
);
1094 return JSRopeString::create(vm
, left
, right
);
1097 JSCell
* JIT_OPERATION
operationMakeRope3(ExecState
* exec
, JSString
* a
, JSString
* b
, JSString
* c
)
1099 VM
& vm
= exec
->vm();
1100 NativeCallFrameTracer
tracer(&vm
, exec
);
1102 if (sumOverflows
<int32_t>(a
->length(), b
->length(), c
->length())) {
1103 throwOutOfMemoryError(exec
);
1107 return JSRopeString::create(vm
, a
, b
, c
);
1110 char* JIT_OPERATION
operationFindSwitchImmTargetForDouble(
1111 ExecState
* exec
, EncodedJSValue encodedValue
, size_t tableIndex
)
1113 CodeBlock
* codeBlock
= exec
->codeBlock();
1114 SimpleJumpTable
& table
= codeBlock
->switchJumpTable(tableIndex
);
1115 JSValue value
= JSValue::decode(encodedValue
);
1116 ASSERT(value
.isDouble());
1117 double asDouble
= value
.asDouble();
1118 int32_t asInt32
= static_cast<int32_t>(asDouble
);
1119 if (asDouble
== asInt32
)
1120 return static_cast<char*>(table
.ctiForValue(asInt32
).executableAddress());
1121 return static_cast<char*>(table
.ctiDefault
.executableAddress());
1124 char* JIT_OPERATION
operationSwitchString(ExecState
* exec
, size_t tableIndex
, JSString
* string
)
1126 VM
& vm
= exec
->vm();
1127 NativeCallFrameTracer
tracer(&vm
, exec
);
1129 return static_cast<char*>(exec
->codeBlock()->stringSwitchJumpTable(tableIndex
).ctiForValue(string
->value(exec
).impl()).executableAddress());
1132 int32_t JIT_OPERATION
operationSwitchStringAndGetBranchOffset(ExecState
* exec
, size_t tableIndex
, JSString
* string
)
1134 VM
& vm
= exec
->vm();
1135 NativeCallFrameTracer
tracer(&vm
, exec
);
1137 return exec
->codeBlock()->stringSwitchJumpTable(tableIndex
).offsetForValue(string
->value(exec
).impl(), std::numeric_limits
<int32_t>::min());
1140 void JIT_OPERATION
operationNotifyWrite(ExecState
* exec
, WatchpointSet
* set
)
1142 VM
& vm
= exec
->vm();
1143 NativeCallFrameTracer
tracer(&vm
, exec
);
1145 set
->touch("Executed NotifyWrite");
1148 void JIT_OPERATION
operationThrowStackOverflowForVarargs(ExecState
* exec
)
1150 VM
& vm
= exec
->vm();
1151 NativeCallFrameTracer
tracer(&vm
, exec
);
1152 throwStackOverflowError(exec
);
1155 int32_t JIT_OPERATION
operationSizeOfVarargs(ExecState
* exec
, EncodedJSValue encodedArguments
, int32_t firstVarArgOffset
)
1157 VM
& vm
= exec
->vm();
1158 NativeCallFrameTracer
tracer(&vm
, exec
);
1159 JSValue arguments
= JSValue::decode(encodedArguments
);
1161 return sizeOfVarargs(exec
, arguments
, firstVarArgOffset
);
1164 void JIT_OPERATION
operationLoadVarargs(ExecState
* exec
, int32_t firstElementDest
, EncodedJSValue encodedArguments
, int32_t offset
, int32_t length
, int32_t mandatoryMinimum
)
1166 VM
& vm
= exec
->vm();
1167 NativeCallFrameTracer
tracer(&vm
, exec
);
1168 JSValue arguments
= JSValue::decode(encodedArguments
);
1170 loadVarargs(exec
, VirtualRegister(firstElementDest
), arguments
, offset
, length
);
1172 for (int32_t i
= length
; i
< mandatoryMinimum
; ++i
)
1173 exec
->r(firstElementDest
+ i
) = jsUndefined();
1176 double JIT_OPERATION
operationFModOnInts(int32_t a
, int32_t b
)
1181 JSCell
* JIT_OPERATION
operationStringFromCharCode(ExecState
* exec
, int32_t op1
)
1183 VM
* vm
= &exec
->vm();
1184 NativeCallFrameTracer
tracer(vm
, exec
);
1185 return JSC::stringFromCharCode(exec
, op1
);
1188 int64_t JIT_OPERATION
operationConvertBoxedDoubleToInt52(EncodedJSValue encodedValue
)
1190 JSValue value
= JSValue::decode(encodedValue
);
1191 if (!value
.isDouble())
1192 return JSValue::notInt52
;
1193 return tryConvertToInt52(value
.asDouble());
1196 int64_t JIT_OPERATION
operationConvertDoubleToInt52(double value
)
1198 return tryConvertToInt52(value
);
1201 void JIT_OPERATION
operationProcessTypeProfilerLogDFG(ExecState
* exec
)
1203 exec
->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("Log Full, called from inside DFG."));
1206 size_t JIT_OPERATION
dfgConvertJSValueToInt32(ExecState
* exec
, EncodedJSValue value
)
1208 VM
* vm
= &exec
->vm();
1209 NativeCallFrameTracer
tracer(vm
, exec
);
1211 // toInt32/toUInt32 return the same value; we want the value zero extended to fill the register.
1212 return JSValue::decode(value
).toUInt32(exec
);
1215 void JIT_OPERATION
debugOperationPrintSpeculationFailure(ExecState
* exec
, void* debugInfoRaw
, void* scratch
)
1217 VM
* vm
= &exec
->vm();
1218 NativeCallFrameTracer
tracer(vm
, exec
);
1220 SpeculationFailureDebugInfo
* debugInfo
= static_cast<SpeculationFailureDebugInfo
*>(debugInfoRaw
);
1221 CodeBlock
* codeBlock
= debugInfo
->codeBlock
;
1222 CodeBlock
* alternative
= codeBlock
->alternative();
1223 dataLog("Speculation failure in ", *codeBlock
);
1224 dataLog(" @ exit #", vm
->osrExitIndex
, " (bc#", debugInfo
->bytecodeOffset
, ", ", exitKindToString(debugInfo
->kind
), ") with ");
1227 "executeCounter = ", alternative
->jitExecuteCounter(),
1228 ", reoptimizationRetryCounter = ", alternative
->reoptimizationRetryCounter(),
1229 ", optimizationDelayCounter = ", alternative
->optimizationDelayCounter());
1231 dataLog("no alternative code block (i.e. we've been jettisoned)");
1232 dataLog(", osrExitCounter = ", codeBlock
->osrExitCounter(), "\n");
1233 dataLog(" GPRs at time of exit:");
1234 char* scratchPointer
= static_cast<char*>(scratch
);
1235 for (unsigned i
= 0; i
< GPRInfo::numberOfRegisters
; ++i
) {
1236 GPRReg gpr
= GPRInfo::toRegister(i
);
1237 dataLog(" ", GPRInfo::debugName(gpr
), ":", RawPointer(*reinterpret_cast_ptr
<void**>(scratchPointer
)));
1238 scratchPointer
+= sizeof(EncodedJSValue
);
1241 dataLog(" FPRs at time of exit:");
1242 for (unsigned i
= 0; i
< FPRInfo::numberOfRegisters
; ++i
) {
1243 FPRReg fpr
= FPRInfo::toRegister(i
);
1244 dataLog(" ", FPRInfo::debugName(fpr
), ":");
1245 uint64_t bits
= *reinterpret_cast_ptr
<uint64_t*>(scratchPointer
);
1246 double value
= *reinterpret_cast_ptr
<double*>(scratchPointer
);
1247 dataLogF("%llx:%lf", static_cast<long long>(bits
), value
);
1248 scratchPointer
+= sizeof(EncodedJSValue
);
1253 extern "C" void JIT_OPERATION
triggerReoptimizationNow(CodeBlock
* codeBlock
, OSRExitBase
* exit
)
1255 // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't
1256 // really be profitable.
1257 DeferGCForAWhile
deferGC(codeBlock
->vm()->heap
);
1259 if (Options::verboseOSR())
1260 dataLog(*codeBlock
, ": Entered reoptimize\n");
1261 // We must be called with the baseline code block.
1262 ASSERT(JITCode::isBaselineCode(codeBlock
->jitType()));
1264 // If I am my own replacement, then reoptimization has already been triggered.
1265 // This can happen in recursive functions.
1266 if (codeBlock
->replacement() == codeBlock
) {
1267 if (Options::verboseOSR())
1268 dataLog(*codeBlock
, ": Not reoptimizing because we've already been jettisoned.\n");
1272 // Otherwise, the replacement must be optimized code. Use this as an opportunity
1273 // to check our logic.
1274 ASSERT(codeBlock
->hasOptimizedReplacement());
1275 CodeBlock
* optimizedCodeBlock
= codeBlock
->replacement();
1276 ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock
->jitType()));
1278 bool didTryToEnterIntoInlinedLoops
= false;
1279 for (InlineCallFrame
* inlineCallFrame
= exit
->m_codeOrigin
.inlineCallFrame
; inlineCallFrame
; inlineCallFrame
= inlineCallFrame
->caller
.inlineCallFrame
) {
1280 if (inlineCallFrame
->executable
->didTryToEnterInLoop()) {
1281 didTryToEnterIntoInlinedLoops
= true;
1286 // In order to trigger reoptimization, one of two things must have happened:
1287 // 1) We exited more than some number of times.
1288 // 2) We exited and got stuck in a loop, and now we're exiting again.
1289 bool didExitABunch
= optimizedCodeBlock
->shouldReoptimizeNow();
1290 bool didGetStuckInLoop
=
1291 (codeBlock
->checkIfOptimizationThresholdReached() || didTryToEnterIntoInlinedLoops
)
1292 && optimizedCodeBlock
->shouldReoptimizeFromLoopNow();
1294 if (!didExitABunch
&& !didGetStuckInLoop
) {
1295 if (Options::verboseOSR())
1296 dataLog(*codeBlock
, ": Not reoptimizing ", *optimizedCodeBlock
, " because it either didn't exit enough or didn't loop enough after exit.\n");
1297 codeBlock
->optimizeAfterLongWarmUp();
1301 optimizedCodeBlock
->jettison(Profiler::JettisonDueToOSRExit
, CountReoptimization
);
1305 static void triggerFTLReplacementCompile(VM
* vm
, CodeBlock
* codeBlock
, JITCode
* jitCode
)
1307 if (codeBlock
->baselineVersion()->m_didFailFTLCompilation
) {
1308 if (Options::verboseOSR())
1309 dataLog("Deferring FTL-optimization of ", *codeBlock
, " indefinitely because there was an FTL failure.\n");
1310 jitCode
->dontOptimizeAnytimeSoon(codeBlock
);
1314 if (!jitCode
->checkIfOptimizationThresholdReached(codeBlock
)) {
1315 if (Options::verboseOSR())
1316 dataLog("Choosing not to FTL-optimize ", *codeBlock
, " yet.\n");
1320 Worklist::State worklistState
;
1321 if (Worklist
* worklist
= existingGlobalFTLWorklistOrNull()) {
1322 worklistState
= worklist
->completeAllReadyPlansForVM(
1323 *vm
, CompilationKey(codeBlock
->baselineVersion(), FTLMode
));
1325 worklistState
= Worklist::NotKnown
;
1327 if (worklistState
== Worklist::Compiling
) {
1328 jitCode
->setOptimizationThresholdBasedOnCompilationResult(
1329 codeBlock
, CompilationDeferred
);
1333 if (codeBlock
->hasOptimizedReplacement()) {
1334 // That's great, we've compiled the code - next time we call this function,
1335 // we'll enter that replacement.
1336 jitCode
->optimizeSoon(codeBlock
);
1340 if (worklistState
== Worklist::Compiled
) {
1341 // This means that we finished compiling, but failed somehow; in that case the
1342 // thresholds will be set appropriately.
1343 if (Options::verboseOSR())
1344 dataLog("Code block ", *codeBlock
, " was compiled but it doesn't have an optimized replacement.\n");
1348 // We need to compile the code.
1350 *vm
, codeBlock
->newReplacement().get(), codeBlock
, FTLMode
, UINT_MAX
,
1351 Operands
<JSValue
>(), ToFTLDeferredCompilationCallback::create(codeBlock
));
1354 static void triggerTierUpNowCommon(ExecState
* exec
, bool inLoop
)
1356 VM
* vm
= &exec
->vm();
1357 NativeCallFrameTracer
tracer(vm
, exec
);
1358 DeferGC
deferGC(vm
->heap
);
1359 CodeBlock
* codeBlock
= exec
->codeBlock();
1361 if (codeBlock
->jitType() != JITCode::DFGJIT
) {
1362 dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock
, "\n");
1363 RELEASE_ASSERT_NOT_REACHED();
1366 JITCode
* jitCode
= codeBlock
->jitCode()->dfg();
1368 if (Options::verboseOSR()) {
1370 *codeBlock
, ": Entered triggerTierUpNow with executeCounter = ",
1371 jitCode
->tierUpCounter
, "\n");
1374 jitCode
->nestedTriggerIsSet
= 1;
1376 triggerFTLReplacementCompile(vm
, codeBlock
, jitCode
);
1379 void JIT_OPERATION
triggerTierUpNow(ExecState
* exec
)
1381 triggerTierUpNowCommon(exec
, false);
1384 void JIT_OPERATION
triggerTierUpNowInLoop(ExecState
* exec
)
1386 triggerTierUpNowCommon(exec
, true);
1389 char* JIT_OPERATION
triggerOSREntryNow(
1390 ExecState
* exec
, int32_t bytecodeIndex
, int32_t streamIndex
)
1392 VM
* vm
= &exec
->vm();
1393 NativeCallFrameTracer
tracer(vm
, exec
);
1394 DeferGC
deferGC(vm
->heap
);
1395 CodeBlock
* codeBlock
= exec
->codeBlock();
1397 if (codeBlock
->jitType() != JITCode::DFGJIT
) {
1398 dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock
, "\n");
1399 RELEASE_ASSERT_NOT_REACHED();
1402 JITCode
* jitCode
= codeBlock
->jitCode()->dfg();
1403 jitCode
->nestedTriggerIsSet
= 0;
1405 if (Options::verboseOSR()) {
1407 *codeBlock
, ": Entered triggerOSREntryNow with executeCounter = ",
1408 jitCode
->tierUpCounter
, "\n");
1411 // - If we don't have an FTL code block, then try to compile one.
1412 // - If we do have an FTL code block, then try to enter for a while.
1413 // - If we couldn't enter for a while, then trigger OSR entry.
1415 triggerFTLReplacementCompile(vm
, codeBlock
, jitCode
);
1417 if (!codeBlock
->hasOptimizedReplacement())
1420 if (jitCode
->osrEntryRetry
< Options::ftlOSREntryRetryThreshold()) {
1421 jitCode
->osrEntryRetry
++;
1425 // It's time to try to compile code for OSR entry.
1426 Worklist::State worklistState
;
1427 if (Worklist
* worklist
= existingGlobalFTLWorklistOrNull()) {
1428 worklistState
= worklist
->completeAllReadyPlansForVM(
1429 *vm
, CompilationKey(codeBlock
->baselineVersion(), FTLForOSREntryMode
));
1431 worklistState
= Worklist::NotKnown
;
1433 if (worklistState
== Worklist::Compiling
)
1436 if (CodeBlock
* entryBlock
= jitCode
->osrEntryBlock
.get()) {
1437 void* address
= FTL::prepareOSREntry(
1438 exec
, codeBlock
, entryBlock
, bytecodeIndex
, streamIndex
);
1440 return static_cast<char*>(address
);
1442 FTL::ForOSREntryJITCode
* entryCode
= entryBlock
->jitCode()->ftlForOSREntry();
1443 entryCode
->countEntryFailure();
1444 if (entryCode
->entryFailureCount() <
1445 Options::ftlOSREntryFailureCountForReoptimization())
1448 // OSR entry failed. Oh no! This implies that we need to retry. We retry
1449 // without exponential backoff and we only do this for the entry code block.
1450 jitCode
->osrEntryBlock
= nullptr;
1451 jitCode
->osrEntryRetry
= 0;
1455 if (worklistState
== Worklist::Compiled
) {
1456 // This means that compilation failed and we already set the thresholds.
1457 if (Options::verboseOSR())
1458 dataLog("Code block ", *codeBlock
, " was compiled but it doesn't have an optimized replacement.\n");
1462 // We aren't compiling and haven't compiled anything for OSR entry. So, try to compile
1464 Operands
<JSValue
> mustHandleValues
;
1465 jitCode
->reconstruct(
1466 exec
, codeBlock
, CodeOrigin(bytecodeIndex
), streamIndex
, mustHandleValues
);
1467 RefPtr
<CodeBlock
> replacementCodeBlock
= codeBlock
->newReplacement();
1468 CompilationResult forEntryResult
= compile(
1469 *vm
, replacementCodeBlock
.get(), codeBlock
, FTLForOSREntryMode
, bytecodeIndex
,
1470 mustHandleValues
, ToFTLForOSREntryDeferredCompilationCallback::create(codeBlock
));
1472 if (forEntryResult
!= CompilationSuccessful
) {
1473 ASSERT(forEntryResult
== CompilationDeferred
|| replacementCodeBlock
->hasOneRef());
1477 // It's possible that the for-entry compile already succeeded. In that case OSR
1478 // entry will succeed unless we ran out of stack. It's not clear what we should do.
1479 // We signal to try again after a while if that happens.
1480 void* address
= FTL::prepareOSREntry(
1481 exec
, codeBlock
, jitCode
->osrEntryBlock
.get(), bytecodeIndex
, streamIndex
);
1482 return static_cast<char*>(address
);
1484 #endif // ENABLE(FTL_JIT)
1487 } } // namespace JSC::DFG
1489 #endif // ENABLE(DFG_JIT)
1491 #endif // ENABLE(JIT)