1/*
2 * Copyright (C) 2011, 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 "DFGOperations.h"
28
29#include "Arguments.h"
30#include "ButterflyInlines.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 "FTLForOSREntryJITCode.h"
42#include "FTLOSREntry.h"
43#include "HostCallReturnValue.h"
44#include "GetterSetter.h"
45#include "Interpreter.h"
46#include "JIT.h"
47#include "JITExceptions.h"
48#include "JSActivation.h"
49#include "VM.h"
50#include "JSNameScope.h"
51#include "NameInstance.h"
52#include "ObjectConstructor.h"
53#include "JSCInlines.h"
54#include "Repatch.h"
55#include "StringConstructor.h"
56#include "TypedArrayInlines.h"
57#include <wtf/InlineASM.h>
58
59#if ENABLE(JIT)
60#if ENABLE(DFG_JIT)
61
62namespace JSC { namespace DFG {
63
64template<bool strict, bool direct>
65static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, JSValue value)
66{
67    VM& vm = exec->vm();
68    NativeCallFrameTracer tracer(&vm, exec);
69    if (direct) {
70        RELEASE_ASSERT(baseValue.isObject());
71        asObject(baseValue)->putDirectIndex(exec, index, value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow);
72        return;
73    }
74    if (baseValue.isObject()) {
75        JSObject* object = asObject(baseValue);
76        if (object->canSetIndexQuickly(index)) {
77            object->setIndexQuickly(vm, index, value);
78            return;
79        }
80
81        object->methodTable(vm)->putByIndex(object, exec, index, value, strict);
82        return;
83    }
84
85    baseValue.putByIndex(exec, index, value, strict);
86}
87
88template<bool strict, bool direct>
89ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
90{
91    VM* vm = &exec->vm();
92    NativeCallFrameTracer tracer(vm, exec);
93
94    JSValue baseValue = JSValue::decode(encodedBase);
95    JSValue property = JSValue::decode(encodedProperty);
96    JSValue value = JSValue::decode(encodedValue);
97
98    if (LIKELY(property.isUInt32())) {
99        putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value);
100        return;
101    }
102
103    if (property.isDouble()) {
104        double propertyAsDouble = property.asDouble();
105        uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
106        if (propertyAsDouble == propertyAsUInt32) {
107            putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value);
108            return;
109        }
110    }
111
112    if (isName(property)) {
113        PutPropertySlot slot(baseValue, strict);
114        if (direct) {
115            RELEASE_ASSERT(baseValue.isObject());
116            asObject(baseValue)->putDirect(*vm, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
117        } else
118            baseValue.put(exec, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
119        return;
120    }
121
122    // Don't put to an object if toString throws an exception.
123    Identifier ident = property.toString(exec)->toIdentifier(exec);
124    if (!vm->exception()) {
125        PutPropertySlot slot(baseValue, strict);
126        if (direct) {
127            RELEASE_ASSERT(baseValue.isObject());
128            asObject(baseValue)->putDirect(*vm, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot);
129        } else
130            baseValue.put(exec, ident, value, slot);
131    }
132}
133
134template<typename ViewClass>
135char* newTypedArrayWithSize(ExecState* exec, Structure* structure, int32_t size)
136{
137    VM& vm = exec->vm();
138    NativeCallFrameTracer tracer(&vm, exec);
139    if (size < 0) {
140        vm.throwException(exec, createRangeError(exec, "Requested length is negative"));
141        return 0;
142    }
143    return bitwise_cast<char*>(ViewClass::create(exec, structure, size));
144}
145
146template<typename ViewClass>
147char* newTypedArrayWithOneArgument(
148    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
149{
150    VM& vm = exec->vm();
151    NativeCallFrameTracer tracer(&vm, exec);
152
153    JSValue value = JSValue::decode(encodedValue);
154
155    if (JSArrayBuffer* jsBuffer = jsDynamicCast<JSArrayBuffer*>(value)) {
156        RefPtr<ArrayBuffer> buffer = jsBuffer->impl();
157
158        if (buffer->byteLength() % ViewClass::elementSize) {
159            vm.throwException(exec, createRangeError(exec, "ArrayBuffer length minus the byteOffset is not a multiple of the element size"));
160            return 0;
161        }
162        return bitwise_cast<char*>(
163            ViewClass::create(
164                exec, structure, buffer, 0, buffer->byteLength() / ViewClass::elementSize));
165    }
166
167    if (JSObject* object = jsDynamicCast<JSObject*>(value)) {
168        unsigned length = object->get(exec, vm.propertyNames->length).toUInt32(exec);
169        if (exec->hadException())
170            return 0;
171
172        ViewClass* result = ViewClass::createUninitialized(exec, structure, length);
173        if (!result)
174            return 0;
175
176        if (!result->set(exec, object, 0, length))
177            return 0;
178
179        return bitwise_cast<char*>(result);
180    }
181
182    int length;
183    if (value.isInt32())
184        length = value.asInt32();
185    else if (!value.isNumber()) {
186        vm.throwException(exec, createTypeError(exec, "Invalid array length argument"));
187        return 0;
188    } else {
189        length = static_cast<int>(value.asNumber());
190        if (length != value.asNumber()) {
191            vm.throwException(exec, createTypeError(exec, "Invalid array length argument (fractional lengths not allowed)"));
192            return 0;
193        }
194    }
195
196    if (length < 0) {
197        vm.throwException(exec, createRangeError(exec, "Requested length is negative"));
198        return 0;
199    }
200
201    return bitwise_cast<char*>(ViewClass::create(exec, structure, length));
202}
203
204extern "C" {
205
206EncodedJSValue JIT_OPERATION operationToThis(ExecState* exec, EncodedJSValue encodedOp)
207{
208    VM* vm = &exec->vm();
209    NativeCallFrameTracer tracer(vm, exec);
210
211    return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, NotStrictMode));
212}
213
214EncodedJSValue JIT_OPERATION operationToThisStrict(ExecState* exec, EncodedJSValue encodedOp)
215{
216    VM* vm = &exec->vm();
217    NativeCallFrameTracer tracer(vm, exec);
218
219    return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, StrictMode));
220}
221
222JSCell* JIT_OPERATION operationCreateThis(ExecState* exec, JSObject* constructor, int32_t inlineCapacity)
223{
224    VM& vm = exec->vm();
225    NativeCallFrameTracer tracer(&vm, exec);
226
227#if !ASSERT_DISABLED
228    ConstructData constructData;
229    ASSERT(jsCast<JSFunction*>(constructor)->methodTable(vm)->getConstructData(jsCast<JSFunction*>(constructor), constructData) == ConstructTypeJS);
230#endif
231
232    return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->allocationProfile(exec, inlineCapacity)->structure());
233}
234
235EncodedJSValue JIT_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
236{
237    VM* vm = &exec->vm();
238    NativeCallFrameTracer tracer(vm, exec);
239
240    JSValue op1 = JSValue::decode(encodedOp1);
241    JSValue op2 = JSValue::decode(encodedOp2);
242
243    return JSValue::encode(jsAdd(exec, op1, op2));
244}
245
246EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
247{
248    VM* vm = &exec->vm();
249    NativeCallFrameTracer tracer(vm, exec);
250
251    JSValue op1 = JSValue::decode(encodedOp1);
252    JSValue op2 = JSValue::decode(encodedOp2);
253
254    ASSERT(!op1.isNumber() || !op2.isNumber());
255
256    if (op1.isString() && !op2.isObject())
257        return JSValue::encode(jsString(exec, asString(op1), op2.toString(exec)));
258
259    return JSValue::encode(jsAddSlowCase(exec, op1, op2));
260}
261
262static ALWAYS_INLINE EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index)
263{
264    VM& vm = exec->vm();
265    NativeCallFrameTracer tracer(&vm, exec);
266
267    if (base->isObject()) {
268        JSObject* object = asObject(base);
269        if (object->canGetIndexQuickly(index))
270            return JSValue::encode(object->getIndexQuickly(index));
271    }
272
273    if (isJSString(base) && asString(base)->canGetIndex(index))
274        return JSValue::encode(asString(base)->getIndex(exec, index));
275
276    return JSValue::encode(JSValue(base).get(exec, index));
277}
278
279EncodedJSValue JIT_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty)
280{
281    VM& vm = exec->vm();
282    NativeCallFrameTracer tracer(&vm, exec);
283
284    JSValue baseValue = JSValue::decode(encodedBase);
285    JSValue property = JSValue::decode(encodedProperty);
286
287    if (LIKELY(baseValue.isCell())) {
288        JSCell* base = baseValue.asCell();
289
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)
296                return getByVal(exec, base, propertyAsUInt32);
297        } else if (property.isString()) {
298            Structure& structure = *base->structure(vm);
299            if (JSCell::canUseFastGetOwnProperty(structure)) {
300                if (JSValue result = base->fastGetOwnProperty(vm, structure, asString(property)->value(exec)))
301                    return JSValue::encode(result);
302            }
303        }
304    }
305
306    if (isName(property))
307        return JSValue::encode(baseValue.get(exec, jsCast<NameInstance*>(property.asCell())->privateName()));
308
309    Identifier ident = property.toString(exec)->toIdentifier(exec);
310    return JSValue::encode(baseValue.get(exec, ident));
311}
312
313EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty)
314{
315    VM& vm = exec->vm();
316    NativeCallFrameTracer tracer(&vm, exec);
317
318    JSValue property = JSValue::decode(encodedProperty);
319
320    if (property.isUInt32())
321        return getByVal(exec, base, property.asUInt32());
322    if (property.isDouble()) {
323        double propertyAsDouble = property.asDouble();
324        uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble);
325        if (propertyAsUInt32 == propertyAsDouble)
326            return getByVal(exec, base, propertyAsUInt32);
327    } else if (property.isString()) {
328        Structure& structure = *base->structure(vm);
329        if (JSCell::canUseFastGetOwnProperty(structure)) {
330            if (JSValue result = base->fastGetOwnProperty(vm, structure, asString(property)->value(exec)))
331                return JSValue::encode(result);
332        }
333    }
334
335    if (isName(property))
336        return JSValue::encode(JSValue(base).get(exec, jsCast<NameInstance*>(property.asCell())->privateName()));
337
338    Identifier ident = property.toString(exec)->toIdentifier(exec);
339    return JSValue::encode(JSValue(base).get(exec, ident));
340}
341
342ALWAYS_INLINE EncodedJSValue getByValCellInt(ExecState* exec, JSCell* base, int32_t index)
343{
344    VM* vm = &exec->vm();
345    NativeCallFrameTracer tracer(vm, exec);
346
347    if (index < 0) {
348        // Go the slowest way possible becase negative indices don't use indexed storage.
349        return JSValue::encode(JSValue(base).get(exec, Identifier::from(exec, index)));
350    }
351
352    // Use this since we know that the value is out of bounds.
353    return JSValue::encode(JSValue(base).get(exec, index));
354}
355
356EncodedJSValue JIT_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* base, int32_t index)
357{
358    return getByValCellInt(exec, base, index);
359}
360
361EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState* exec, JSString* base, int32_t index)
362{
363    return getByValCellInt(exec, base, index);
364}
365
366void JIT_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
367{
368    VM* vm = &exec->vm();
369    NativeCallFrameTracer tracer(vm, exec);
370
371    operationPutByValInternal<true, false>(exec, encodedBase, encodedProperty, encodedValue);
372}
373
374void JIT_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
375{
376    VM* vm = &exec->vm();
377    NativeCallFrameTracer tracer(vm, exec);
378
379    operationPutByValInternal<false, false>(exec, encodedBase, encodedProperty, encodedValue);
380}
381
382void JIT_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
383{
384    VM* vm = &exec->vm();
385    NativeCallFrameTracer tracer(vm, exec);
386
387    operationPutByValInternal<true, false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
388}
389
390void JIT_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
391{
392    VM* vm = &exec->vm();
393    NativeCallFrameTracer tracer(vm, exec);
394
395    operationPutByValInternal<false, false>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
396}
397
398void JIT_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
399{
400    VM& vm = exec->vm();
401    NativeCallFrameTracer tracer(&vm, exec);
402
403    if (index >= 0) {
404        array->putByIndexInline(exec, index, JSValue::decode(encodedValue), true);
405        return;
406    }
407
408    PutPropertySlot slot(array, true);
409    array->methodTable()->put(
410        array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
411}
412
413void JIT_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
414{
415    VM* vm = &exec->vm();
416    NativeCallFrameTracer tracer(vm, exec);
417
418    if (index >= 0) {
419        array->putByIndexInline(exec, index, JSValue::decode(encodedValue), false);
420        return;
421    }
422
423    PutPropertySlot slot(array, false);
424    array->methodTable()->put(
425        array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
426}
427
428void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, double value)
429{
430    VM* vm = &exec->vm();
431    NativeCallFrameTracer tracer(vm, exec);
432
433    JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
434
435    if (index >= 0) {
436        array->putByIndexInline(exec, index, jsValue, true);
437        return;
438    }
439
440    PutPropertySlot slot(array, true);
441    array->methodTable()->put(
442        array, exec, Identifier::from(exec, index), jsValue, slot);
443}
444
445void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, double value)
446{
447    VM* vm = &exec->vm();
448    NativeCallFrameTracer tracer(vm, exec);
449
450    JSValue jsValue = JSValue(JSValue::EncodeAsDouble, value);
451
452    if (index >= 0) {
453        array->putByIndexInline(exec, index, jsValue, false);
454        return;
455    }
456
457    PutPropertySlot slot(array, false);
458    array->methodTable()->put(
459        array, exec, Identifier::from(exec, index), jsValue, slot);
460}
461
462void JIT_OPERATION operationPutByValDirectStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
463{
464    VM* vm = &exec->vm();
465    NativeCallFrameTracer tracer(vm, exec);
466
467    operationPutByValInternal<true, true>(exec, encodedBase, encodedProperty, encodedValue);
468}
469
470void JIT_OPERATION operationPutByValDirectNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
471{
472    VM* vm = &exec->vm();
473    NativeCallFrameTracer tracer(vm, exec);
474
475    operationPutByValInternal<false, true>(exec, encodedBase, encodedProperty, encodedValue);
476}
477
478void JIT_OPERATION operationPutByValDirectCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
479{
480    VM* vm = &exec->vm();
481    NativeCallFrameTracer tracer(vm, exec);
482
483    operationPutByValInternal<true, true>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
484}
485
486void JIT_OPERATION operationPutByValDirectCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
487{
488    VM* vm = &exec->vm();
489    NativeCallFrameTracer tracer(vm, exec);
490
491    operationPutByValInternal<false, true>(exec, JSValue::encode(cell), encodedProperty, encodedValue);
492}
493
494void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
495{
496    VM* vm = &exec->vm();
497    NativeCallFrameTracer tracer(vm, exec);
498    if (index >= 0) {
499        array->putDirectIndex(exec, index, JSValue::decode(encodedValue), 0, PutDirectIndexShouldThrow);
500        return;
501    }
502
503    PutPropertySlot slot(array, true);
504    array->putDirect(exec->vm(), Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
505}
506
507void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue)
508{
509    VM* vm = &exec->vm();
510    NativeCallFrameTracer tracer(vm, exec);
511
512    if (index >= 0) {
513        array->putDirectIndex(exec, index, JSValue::decode(encodedValue));
514        return;
515    }
516
517    PutPropertySlot slot(array, false);
518    array->putDirect(exec->vm(), Identifier::from(exec, index), JSValue::decode(encodedValue), slot);
519}
520
521EncodedJSValue JIT_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array)
522{
523    VM* vm = &exec->vm();
524    NativeCallFrameTracer tracer(vm, exec);
525
526    array->push(exec, JSValue::decode(encodedValue));
527    return JSValue::encode(jsNumber(array->length()));
528}
529
530EncodedJSValue JIT_OPERATION operationArrayPushDouble(ExecState* exec, double value, JSArray* array)
531{
532    VM* vm = &exec->vm();
533    NativeCallFrameTracer tracer(vm, exec);
534
535    array->push(exec, JSValue(JSValue::EncodeAsDouble, value));
536    return JSValue::encode(jsNumber(array->length()));
537}
538
539EncodedJSValue JIT_OPERATION operationArrayPop(ExecState* exec, JSArray* array)
540{
541    VM* vm = &exec->vm();
542    NativeCallFrameTracer tracer(vm, exec);
543
544    return JSValue::encode(array->pop(exec));
545}
546
547EncodedJSValue JIT_OPERATION operationArrayPopAndRecoverLength(ExecState* exec, JSArray* array)
548{
549    VM* vm = &exec->vm();
550    NativeCallFrameTracer tracer(vm, exec);
551
552    array->butterfly()->setPublicLength(array->butterfly()->publicLength() + 1);
553
554    return JSValue::encode(array->pop(exec));
555}
556
557EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState* exec, JSCell* base, JSCell* argument)
558{
559    VM& vm = exec->vm();
560    NativeCallFrameTracer tracer(&vm, exec);
561
562    if (!base->inherits(RegExpObject::info()))
563        return throwVMTypeError(exec);
564
565    ASSERT(argument->isString() || argument->isObject());
566    JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec);
567    return JSValue::encode(asRegExpObject(base)->exec(exec, input));
568}
569
570size_t JIT_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell* argument)
571{
572    VM& vm = exec->vm();
573    NativeCallFrameTracer tracer(&vm, exec);
574
575    if (!base->inherits(RegExpObject::info())) {
576        throwTypeError(exec);
577        return false;
578    }
579
580    ASSERT(argument->isString() || argument->isObject());
581    JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec);
582    return asRegExpObject(base)->test(exec, input);
583}
584
585size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
586{
587    VM* vm = &exec->vm();
588    NativeCallFrameTracer tracer(vm, exec);
589
590    JSValue op1 = JSValue::decode(encodedOp1);
591    JSValue op2 = JSValue::decode(encodedOp2);
592
593    ASSERT(op1.isCell());
594    ASSERT(op2.isCell());
595
596    return JSValue::strictEqualSlowCaseInline(exec, op1, op2);
597}
598
599size_t JIT_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
600{
601    VM* vm = &exec->vm();
602    NativeCallFrameTracer tracer(vm, exec);
603
604    JSValue src1 = JSValue::decode(encodedOp1);
605    JSValue src2 = JSValue::decode(encodedOp2);
606
607    return JSValue::strictEqual(exec, src1, src2);
608}
609
610EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value)
611{
612    VM* vm = &exec->vm();
613    NativeCallFrameTracer tracer(vm, exec);
614
615    return JSValue::encode(JSValue::decode(value).toPrimitive(exec));
616}
617
618char* JIT_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size)
619{
620    VM* vm = &exec->vm();
621    NativeCallFrameTracer tracer(vm, exec);
622
623    return bitwise_cast<char*>(constructArray(exec, arrayStructure, static_cast<JSValue*>(buffer), size));
624}
625
626char* JIT_OPERATION operationNewEmptyArray(ExecState* exec, Structure* arrayStructure)
627{
628    VM* vm = &exec->vm();
629    NativeCallFrameTracer tracer(vm, exec);
630
631    return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure));
632}
633
634char* JIT_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size)
635{
636    VM* vm = &exec->vm();
637    NativeCallFrameTracer tracer(vm, exec);
638
639    if (UNLIKELY(size < 0))
640        return bitwise_cast<char*>(exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer."))));
641
642    return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure, size));
643}
644
645char* JIT_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, size_t start, size_t size)
646{
647    VM& vm = exec->vm();
648    NativeCallFrameTracer tracer(&vm, exec);
649    return bitwise_cast<char*>(constructArray(exec, arrayStructure, exec->codeBlock()->constantBuffer(start), size));
650}
651
652char* JIT_OPERATION operationNewInt8ArrayWithSize(
653    ExecState* exec, Structure* structure, int32_t length)
654{
655    return newTypedArrayWithSize<JSInt8Array>(exec, structure, length);
656}
657
658char* JIT_OPERATION operationNewInt8ArrayWithOneArgument(
659    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
660{
661    return newTypedArrayWithOneArgument<JSInt8Array>(exec, structure, encodedValue);
662}
663
664char* JIT_OPERATION operationNewInt16ArrayWithSize(
665    ExecState* exec, Structure* structure, int32_t length)
666{
667    return newTypedArrayWithSize<JSInt16Array>(exec, structure, length);
668}
669
670char* JIT_OPERATION operationNewInt16ArrayWithOneArgument(
671    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
672{
673    return newTypedArrayWithOneArgument<JSInt16Array>(exec, structure, encodedValue);
674}
675
676char* JIT_OPERATION operationNewInt32ArrayWithSize(
677    ExecState* exec, Structure* structure, int32_t length)
678{
679    return newTypedArrayWithSize<JSInt32Array>(exec, structure, length);
680}
681
682char* JIT_OPERATION operationNewInt32ArrayWithOneArgument(
683    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
684{
685    return newTypedArrayWithOneArgument<JSInt32Array>(exec, structure, encodedValue);
686}
687
688char* JIT_OPERATION operationNewUint8ArrayWithSize(
689    ExecState* exec, Structure* structure, int32_t length)
690{
691    return newTypedArrayWithSize<JSUint8Array>(exec, structure, length);
692}
693
694char* JIT_OPERATION operationNewUint8ArrayWithOneArgument(
695    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
696{
697    return newTypedArrayWithOneArgument<JSUint8Array>(exec, structure, encodedValue);
698}
699
700char* JIT_OPERATION operationNewUint8ClampedArrayWithSize(
701    ExecState* exec, Structure* structure, int32_t length)
702{
703    return newTypedArrayWithSize<JSUint8ClampedArray>(exec, structure, length);
704}
705
706char* JIT_OPERATION operationNewUint8ClampedArrayWithOneArgument(
707    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
708{
709    return newTypedArrayWithOneArgument<JSUint8ClampedArray>(exec, structure, encodedValue);
710}
711
712char* JIT_OPERATION operationNewUint16ArrayWithSize(
713    ExecState* exec, Structure* structure, int32_t length)
714{
715    return newTypedArrayWithSize<JSUint16Array>(exec, structure, length);
716}
717
718char* JIT_OPERATION operationNewUint16ArrayWithOneArgument(
719    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
720{
721    return newTypedArrayWithOneArgument<JSUint16Array>(exec, structure, encodedValue);
722}
723
724char* JIT_OPERATION operationNewUint32ArrayWithSize(
725    ExecState* exec, Structure* structure, int32_t length)
726{
727    return newTypedArrayWithSize<JSUint32Array>(exec, structure, length);
728}
729
730char* JIT_OPERATION operationNewUint32ArrayWithOneArgument(
731    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
732{
733    return newTypedArrayWithOneArgument<JSUint32Array>(exec, structure, encodedValue);
734}
735
736char* JIT_OPERATION operationNewFloat32ArrayWithSize(
737    ExecState* exec, Structure* structure, int32_t length)
738{
739    return newTypedArrayWithSize<JSFloat32Array>(exec, structure, length);
740}
741
742char* JIT_OPERATION operationNewFloat32ArrayWithOneArgument(
743    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
744{
745    return newTypedArrayWithOneArgument<JSFloat32Array>(exec, structure, encodedValue);
746}
747
748char* JIT_OPERATION operationNewFloat64ArrayWithSize(
749    ExecState* exec, Structure* structure, int32_t length)
750{
751    return newTypedArrayWithSize<JSFloat64Array>(exec, structure, length);
752}
753
754char* JIT_OPERATION operationNewFloat64ArrayWithOneArgument(
755    ExecState* exec, Structure* structure, EncodedJSValue encodedValue)
756{
757    return newTypedArrayWithOneArgument<JSFloat64Array>(exec, structure, encodedValue);
758}
759
760JSCell* JIT_OPERATION operationCreateInlinedArguments(
761    ExecState* exec, InlineCallFrame* inlineCallFrame)
762{
763    VM& vm = exec->vm();
764    NativeCallFrameTracer tracer(&vm, exec);
765    // NB: This needs to be exceedingly careful with top call frame tracking, since it
766    // may be called from OSR exit, while the state of the call stack is bizarre.
767    Arguments* result = Arguments::create(vm, exec, inlineCallFrame);
768    ASSERT(!vm.exception());
769    return result;
770}
771
772JSCell* JIT_OPERATION operationCreateInlinedArgumentsDuringOSRExit(ExecState* exec, InlineCallFrame* inlineCallFrame)
773{
774    DeferGCForAWhile(exec->vm().heap);
775    return operationCreateInlinedArguments(exec, inlineCallFrame);
776}
777
778void JIT_OPERATION operationTearOffInlinedArguments(
779    ExecState* exec, JSCell* argumentsCell, JSCell* activationCell, InlineCallFrame* inlineCallFrame)
780{
781    ASSERT_UNUSED(activationCell, !activationCell); // Currently, we don't inline functions with activations.
782    jsCast<Arguments*>(argumentsCell)->tearOff(exec, inlineCallFrame);
783}
784
785EncodedJSValue JIT_OPERATION operationGetArgumentByVal(ExecState* exec, int32_t argumentsRegister, int32_t index)
786{
787    VM& vm = exec->vm();
788    NativeCallFrameTracer tracer(&vm, exec);
789
790    JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue();
791
792    // If there are no arguments, and we're accessing out of bounds, then we have to create the
793    // arguments in case someone has installed a getter on a numeric property.
794    if (!argumentsValue)
795        exec->uncheckedR(argumentsRegister) = argumentsValue = Arguments::create(exec->vm(), exec);
796
797    return JSValue::encode(argumentsValue.get(exec, index));
798}
799
800EncodedJSValue JIT_OPERATION operationGetInlinedArgumentByVal(
801    ExecState* exec, int32_t argumentsRegister, InlineCallFrame* inlineCallFrame, int32_t index)
802{
803    VM& vm = exec->vm();
804    NativeCallFrameTracer tracer(&vm, exec);
805
806    JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue();
807
808    // If there are no arguments, and we're accessing out of bounds, then we have to create the
809    // arguments in case someone has installed a getter on a numeric property.
810    if (!argumentsValue) {
811        exec->uncheckedR(argumentsRegister) = argumentsValue =
812            Arguments::create(exec->vm(), exec, inlineCallFrame);
813    }
814
815    return JSValue::encode(argumentsValue.get(exec, index));
816}
817
818JSCell* JIT_OPERATION operationNewFunctionNoCheck(ExecState* exec, JSCell* functionExecutable)
819{
820    ASSERT(functionExecutable->inherits(FunctionExecutable::info()));
821    VM& vm = exec->vm();
822    NativeCallFrameTracer tracer(&vm, exec);
823    return JSFunction::create(vm, static_cast<FunctionExecutable*>(functionExecutable), exec->scope());
824}
825
826size_t JIT_OPERATION operationIsObject(ExecState* exec, EncodedJSValue value)
827{
828    return jsIsObjectType(exec, JSValue::decode(value));
829}
830
831size_t JIT_OPERATION operationIsFunction(EncodedJSValue value)
832{
833    return jsIsFunctionType(JSValue::decode(value));
834}
835
836JSCell* JIT_OPERATION operationTypeOf(ExecState* exec, JSCell* value)
837{
838    VM& vm = exec->vm();
839    NativeCallFrameTracer tracer(&vm, exec);
840    return jsTypeStringForValue(exec, JSValue(value)).asCell();
841}
842
843char* JIT_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState* exec)
844{
845    VM& vm = exec->vm();
846    NativeCallFrameTracer tracer(&vm, exec);
847
848    return reinterpret_cast<char*>(
849        Butterfly::createUninitialized(vm, 0, 0, initialOutOfLineCapacity, false, 0));
850}
851
852char* JIT_OPERATION operationAllocatePropertyStorage(ExecState* exec, size_t newSize)
853{
854    VM& vm = exec->vm();
855    NativeCallFrameTracer tracer(&vm, exec);
856
857    return reinterpret_cast<char*>(
858        Butterfly::createUninitialized(vm, 0, 0, newSize, false, 0));
859}
860
861char* JIT_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState* exec, JSObject* object)
862{
863    VM& vm = exec->vm();
864    NativeCallFrameTracer tracer(&vm, exec);
865
866    ASSERT(!object->structure()->outOfLineCapacity());
867    DeferGC deferGC(vm.heap);
868    Butterfly* result = object->growOutOfLineStorage(vm, 0, initialOutOfLineCapacity);
869    object->setButterflyWithoutChangingStructure(vm, result);
870    return reinterpret_cast<char*>(result);
871}
872
873char* JIT_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState* exec, JSObject* object, size_t newSize)
874{
875    VM& vm = exec->vm();
876    NativeCallFrameTracer tracer(&vm, exec);
877
878    DeferGC deferGC(vm.heap);
879    Butterfly* result = object->growOutOfLineStorage(vm, object->structure()->outOfLineCapacity(), newSize);
880    object->setButterflyWithoutChangingStructure(vm, result);
881    return reinterpret_cast<char*>(result);
882}
883
884char* JIT_OPERATION operationEnsureInt32(ExecState* exec, JSCell* cell)
885{
886    VM& vm = exec->vm();
887    NativeCallFrameTracer tracer(&vm, exec);
888
889    if (!cell->isObject())
890        return 0;
891
892    return reinterpret_cast<char*>(asObject(cell)->ensureInt32(vm).data());
893}
894
895char* JIT_OPERATION operationEnsureDouble(ExecState* exec, JSCell* cell)
896{
897    VM& vm = exec->vm();
898    NativeCallFrameTracer tracer(&vm, exec);
899
900    if (!cell->isObject())
901        return 0;
902
903    return reinterpret_cast<char*>(asObject(cell)->ensureDouble(vm).data());
904}
905
906char* JIT_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell)
907{
908    VM& vm = exec->vm();
909    NativeCallFrameTracer tracer(&vm, exec);
910
911    if (!cell->isObject())
912        return 0;
913
914    return reinterpret_cast<char*>(asObject(cell)->ensureContiguous(vm).data());
915}
916
917char* JIT_OPERATION operationRageEnsureContiguous(ExecState* exec, JSCell* cell)
918{
919    VM& vm = exec->vm();
920    NativeCallFrameTracer tracer(&vm, exec);
921
922    if (!cell->isObject())
923        return 0;
924
925    return reinterpret_cast<char*>(asObject(cell)->rageEnsureContiguous(vm).data());
926}
927
928char* JIT_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell)
929{
930    VM& vm = exec->vm();
931    NativeCallFrameTracer tracer(&vm, exec);
932
933    if (!cell->isObject())
934        return 0;
935
936    return reinterpret_cast<char*>(asObject(cell)->ensureArrayStorage(vm));
937}
938
939StringImpl* JIT_OPERATION operationResolveRope(ExecState* exec, JSString* string)
940{
941    VM& vm = exec->vm();
942    NativeCallFrameTracer tracer(&vm, exec);
943
944    return string->value(exec).impl();
945}
946
947JSString* JIT_OPERATION operationSingleCharacterString(ExecState* exec, int32_t character)
948{
949    VM& vm = exec->vm();
950    NativeCallFrameTracer tracer(&vm, exec);
951
952    return jsSingleCharacterString(exec, static_cast<UChar>(character));
953}
954
955JSCell* JIT_OPERATION operationNewStringObject(ExecState* exec, JSString* string, Structure* structure)
956{
957    VM& vm = exec->vm();
958    NativeCallFrameTracer tracer(&vm, exec);
959
960    return StringObject::create(vm, structure, string);
961}
962
963JSCell* JIT_OPERATION operationToStringOnCell(ExecState* exec, JSCell* cell)
964{
965    VM& vm = exec->vm();
966    NativeCallFrameTracer tracer(&vm, exec);
967
968    return JSValue(cell).toString(exec);
969}
970
971JSCell* JIT_OPERATION operationToString(ExecState* exec, EncodedJSValue value)
972{
973    VM& vm = exec->vm();
974    NativeCallFrameTracer tracer(&vm, exec);
975
976    return JSValue::decode(value).toString(exec);
977}
978
979JSCell* JIT_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSString* right)
980{
981    VM& vm = exec->vm();
982    NativeCallFrameTracer tracer(&vm, exec);
983
984    if (sumOverflows<int32_t>(left->length(), right->length())) {
985        throwOutOfMemoryError(exec);
986        return nullptr;
987    }
988
989    return JSRopeString::create(vm, left, right);
990}
991
992JSCell* JIT_OPERATION operationMakeRope3(ExecState* exec, JSString* a, JSString* b, JSString* c)
993{
994    VM& vm = exec->vm();
995    NativeCallFrameTracer tracer(&vm, exec);
996
997    if (sumOverflows<int32_t>(a->length(), b->length(), c->length())) {
998        throwOutOfMemoryError(exec);
999        return nullptr;
1000    }
1001
1002    return JSRopeString::create(vm, a, b, c);
1003}
1004
1005char* JIT_OPERATION operationFindSwitchImmTargetForDouble(
1006    ExecState* exec, EncodedJSValue encodedValue, size_t tableIndex)
1007{
1008    CodeBlock* codeBlock = exec->codeBlock();
1009    SimpleJumpTable& table = codeBlock->switchJumpTable(tableIndex);
1010    JSValue value = JSValue::decode(encodedValue);
1011    ASSERT(value.isDouble());
1012    double asDouble = value.asDouble();
1013    int32_t asInt32 = static_cast<int32_t>(asDouble);
1014    if (asDouble == asInt32)
1015        return static_cast<char*>(table.ctiForValue(asInt32).executableAddress());
1016    return static_cast<char*>(table.ctiDefault.executableAddress());
1017}
1018
1019char* JIT_OPERATION operationSwitchString(ExecState* exec, size_t tableIndex, JSString* string)
1020{
1021    VM& vm = exec->vm();
1022    NativeCallFrameTracer tracer(&vm, exec);
1023
1024    return static_cast<char*>(exec->codeBlock()->stringSwitchJumpTable(tableIndex).ctiForValue(string->value(exec).impl()).executableAddress());
1025}
1026
1027void JIT_OPERATION operationNotifyWrite(ExecState* exec, VariableWatchpointSet* set, EncodedJSValue encodedValue)
1028{
1029    VM& vm = exec->vm();
1030    NativeCallFrameTracer tracer(&vm, exec);
1031    JSValue value = JSValue::decode(encodedValue);
1032
1033    set->notifyWrite(vm, value);
1034}
1035
1036double JIT_OPERATION operationFModOnInts(int32_t a, int32_t b)
1037{
1038    return fmod(a, b);
1039}
1040
1041JSCell* JIT_OPERATION operationStringFromCharCode(ExecState* exec, int32_t op1)
1042{
1043    VM* vm = &exec->vm();
1044    NativeCallFrameTracer tracer(vm, exec);
1045    return JSC::stringFromCharCode(exec, op1);
1046}
1047
1048int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue encodedValue)
1049{
1050    JSValue value = JSValue::decode(encodedValue);
1051    if (!value.isDouble())
1052        return JSValue::notInt52;
1053    return tryConvertToInt52(value.asDouble());
1054}
1055
1056int64_t JIT_OPERATION operationConvertDoubleToInt52(double value)
1057{
1058    return tryConvertToInt52(value);
1059}
1060
1061size_t JIT_OPERATION dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
1062{
1063    VM* vm = &exec->vm();
1064    NativeCallFrameTracer tracer(vm, exec);
1065
1066    // toInt32/toUInt32 return the same value; we want the value zero extended to fill the register.
1067    return JSValue::decode(value).toUInt32(exec);
1068}
1069
1070void JIT_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* debugInfoRaw, void* scratch)
1071{
1072    VM* vm = &exec->vm();
1073    NativeCallFrameTracer tracer(vm, exec);
1074
1075    SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw);
1076    CodeBlock* codeBlock = debugInfo->codeBlock;
1077    CodeBlock* alternative = codeBlock->alternative();
1078    dataLog("Speculation failure in ", *codeBlock);
1079    dataLog(" @ exit #", vm->osrExitIndex, " (bc#", debugInfo->bytecodeOffset, ", ", exitKindToString(debugInfo->kind), ") with ");
1080    if (alternative) {
1081        dataLog(
1082            "executeCounter = ", alternative->jitExecuteCounter(),
1083            ", reoptimizationRetryCounter = ", alternative->reoptimizationRetryCounter(),
1084            ", optimizationDelayCounter = ", alternative->optimizationDelayCounter());
1085    } else
1086        dataLog("no alternative code block (i.e. we've been jettisoned)");
1087    dataLog(", osrExitCounter = ", codeBlock->osrExitCounter(), "\n");
1088    dataLog("    GPRs at time of exit:");
1089    char* scratchPointer = static_cast<char*>(scratch);
1090    for (unsigned i = 0; i < GPRInfo::numberOfRegisters; ++i) {
1091        GPRReg gpr = GPRInfo::toRegister(i);
1092        dataLog(" ", GPRInfo::debugName(gpr), ":", RawPointer(*reinterpret_cast_ptr<void**>(scratchPointer)));
1093        scratchPointer += sizeof(EncodedJSValue);
1094    }
1095    dataLog("\n");
1096    dataLog("    FPRs at time of exit:");
1097    for (unsigned i = 0; i < FPRInfo::numberOfRegisters; ++i) {
1098        FPRReg fpr = FPRInfo::toRegister(i);
1099        dataLog(" ", FPRInfo::debugName(fpr), ":");
1100        uint64_t bits = *reinterpret_cast_ptr<uint64_t*>(scratchPointer);
1101        double value = *reinterpret_cast_ptr<double*>(scratchPointer);
1102        dataLogF("%llx:%lf", static_cast<long long>(bits), value);
1103        scratchPointer += sizeof(EncodedJSValue);
1104    }
1105    dataLog("\n");
1106}
1107
1108extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock)
1109{
1110    // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't
1111    // really be profitable.
1112    DeferGCForAWhile deferGC(codeBlock->vm()->heap);
1113
1114    if (Options::verboseOSR())
1115        dataLog(*codeBlock, ": Entered reoptimize\n");
1116    // We must be called with the baseline code block.
1117    ASSERT(JITCode::isBaselineCode(codeBlock->jitType()));
1118
1119    // If I am my own replacement, then reoptimization has already been triggered.
1120    // This can happen in recursive functions.
1121    if (codeBlock->replacement() == codeBlock) {
1122        if (Options::verboseOSR())
1123            dataLog(*codeBlock, ": Not reoptimizing because we've already been jettisoned.\n");
1124        return;
1125    }
1126
1127    // Otherwise, the replacement must be optimized code. Use this as an opportunity
1128    // to check our logic.
1129    ASSERT(codeBlock->hasOptimizedReplacement());
1130    CodeBlock* optimizedCodeBlock = codeBlock->replacement();
1131    ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType()));
1132
1133    // In order to trigger reoptimization, one of two things must have happened:
1134    // 1) We exited more than some number of times.
1135    // 2) We exited and got stuck in a loop, and now we're exiting again.
1136    bool didExitABunch = optimizedCodeBlock->shouldReoptimizeNow();
1137    bool didGetStuckInLoop =
1138        codeBlock->checkIfOptimizationThresholdReached()
1139        && optimizedCodeBlock->shouldReoptimizeFromLoopNow();
1140
1141    if (!didExitABunch && !didGetStuckInLoop) {
1142        if (Options::verboseOSR())
1143            dataLog(*codeBlock, ": Not reoptimizing ", *optimizedCodeBlock, " because it either didn't exit enough or didn't loop enough after exit.\n");
1144        codeBlock->optimizeAfterLongWarmUp();
1145        return;
1146    }
1147
1148    optimizedCodeBlock->jettison(Profiler::JettisonDueToOSRExit, CountReoptimization);
1149}
1150
1151#if ENABLE(FTL_JIT)
1152static void triggerFTLReplacementCompile(VM* vm, CodeBlock* codeBlock, JITCode* jitCode)
1153{
1154    if (codeBlock->baselineVersion()->m_didFailFTLCompilation) {
1155        if (Options::verboseOSR())
1156            dataLog("Deferring FTL-optimization of ", *codeBlock, " indefinitely because there was an FTL failure.\n");
1157        jitCode->dontOptimizeAnytimeSoon(codeBlock);
1158        return;
1159    }
1160
1161    if (!jitCode->checkIfOptimizationThresholdReached(codeBlock)) {
1162        if (Options::verboseOSR())
1163            dataLog("Choosing not to FTL-optimize ", *codeBlock, " yet.\n");
1164        return;
1165    }
1166
1167    Worklist::State worklistState;
1168    if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) {
1169        worklistState = worklist->completeAllReadyPlansForVM(
1170            *vm, CompilationKey(codeBlock->baselineVersion(), FTLMode));
1171    } else
1172        worklistState = Worklist::NotKnown;
1173
1174    if (worklistState == Worklist::Compiling) {
1175        jitCode->setOptimizationThresholdBasedOnCompilationResult(
1176            codeBlock, CompilationDeferred);
1177        return;
1178    }
1179
1180    if (codeBlock->hasOptimizedReplacement()) {
1181        // That's great, we've compiled the code - next time we call this function,
1182        // we'll enter that replacement.
1183        jitCode->optimizeSoon(codeBlock);
1184        return;
1185    }
1186
1187    if (worklistState == Worklist::Compiled) {
1188        // This means that we finished compiling, but failed somehow; in that case the
1189        // thresholds will be set appropriately.
1190        if (Options::verboseOSR())
1191            dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
1192        return;
1193    }
1194
1195    // We need to compile the code.
1196    compile(
1197        *vm, codeBlock->newReplacement().get(), codeBlock, FTLMode, UINT_MAX,
1198        Operands<JSValue>(), ToFTLDeferredCompilationCallback::create(codeBlock));
1199}
1200
1201void JIT_OPERATION triggerTierUpNow(ExecState* exec)
1202{
1203    VM* vm = &exec->vm();
1204    NativeCallFrameTracer tracer(vm, exec);
1205    DeferGC deferGC(vm->heap);
1206    CodeBlock* codeBlock = exec->codeBlock();
1207
1208    JITCode* jitCode = codeBlock->jitCode()->dfg();
1209
1210    if (Options::verboseOSR()) {
1211        dataLog(
1212            *codeBlock, ": Entered triggerTierUpNow with executeCounter = ",
1213            jitCode->tierUpCounter, "\n");
1214    }
1215
1216    triggerFTLReplacementCompile(vm, codeBlock, jitCode);
1217}
1218
1219char* JIT_OPERATION triggerOSREntryNow(
1220    ExecState* exec, int32_t bytecodeIndex, int32_t streamIndex)
1221{
1222    VM* vm = &exec->vm();
1223    NativeCallFrameTracer tracer(vm, exec);
1224    DeferGC deferGC(vm->heap);
1225    CodeBlock* codeBlock = exec->codeBlock();
1226
1227    JITCode* jitCode = codeBlock->jitCode()->dfg();
1228
1229    if (Options::verboseOSR()) {
1230        dataLog(
1231            *codeBlock, ": Entered triggerTierUpNow with executeCounter = ",
1232            jitCode->tierUpCounter, "\n");
1233    }
1234
1235    // - If we don't have an FTL code block, then try to compile one.
1236    // - If we do have an FTL code block, then try to enter for a while.
1237    // - If we couldn't enter for a while, then trigger OSR entry.
1238
1239    triggerFTLReplacementCompile(vm, codeBlock, jitCode);
1240
1241    if (!codeBlock->hasOptimizedReplacement())
1242        return 0;
1243
1244    if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) {
1245        jitCode->osrEntryRetry++;
1246        return 0;
1247    }
1248
1249    // It's time to try to compile code for OSR entry.
1250    Worklist::State worklistState;
1251    if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) {
1252        worklistState = worklist->completeAllReadyPlansForVM(
1253            *vm, CompilationKey(codeBlock->baselineVersion(), FTLForOSREntryMode));
1254    } else
1255        worklistState = Worklist::NotKnown;
1256
1257    if (worklistState == Worklist::Compiling)
1258        return 0;
1259
1260    if (CodeBlock* entryBlock = jitCode->osrEntryBlock.get()) {
1261        void* address = FTL::prepareOSREntry(
1262            exec, codeBlock, entryBlock, bytecodeIndex, streamIndex);
1263        if (address)
1264            return static_cast<char*>(address);
1265
1266        FTL::ForOSREntryJITCode* entryCode = entryBlock->jitCode()->ftlForOSREntry();
1267        entryCode->countEntryFailure();
1268        if (entryCode->entryFailureCount() <
1269            Options::ftlOSREntryFailureCountForReoptimization())
1270            return 0;
1271
1272        // OSR entry failed. Oh no! This implies that we need to retry. We retry
1273        // without exponential backoff and we only do this for the entry code block.
1274        jitCode->osrEntryBlock.clear();
1275        jitCode->osrEntryRetry = 0;
1276        return 0;
1277    }
1278
1279    if (worklistState == Worklist::Compiled) {
1280        // This means that compilation failed and we already set the thresholds.
1281        if (Options::verboseOSR())
1282            dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n");
1283        return 0;
1284    }
1285
1286    // We aren't compiling and haven't compiled anything for OSR entry. So, try to compile
1287    // something.
1288    Operands<JSValue> mustHandleValues;
1289    jitCode->reconstruct(
1290        exec, codeBlock, CodeOrigin(bytecodeIndex), streamIndex, mustHandleValues);
1291    RefPtr<CodeBlock> replacementCodeBlock = codeBlock->newReplacement();
1292    CompilationResult forEntryResult = compile(
1293        *vm, replacementCodeBlock.get(), codeBlock, FTLForOSREntryMode, bytecodeIndex,
1294        mustHandleValues, ToFTLForOSREntryDeferredCompilationCallback::create(codeBlock));
1295
1296    if (forEntryResult != CompilationSuccessful) {
1297        ASSERT(forEntryResult == CompilationDeferred || replacementCodeBlock->hasOneRef());
1298        return 0;
1299    }
1300
1301    // It's possible that the for-entry compile already succeeded. In that case OSR
1302    // entry will succeed unless we ran out of stack. It's not clear what we should do.
1303    // We signal to try again after a while if that happens.
1304    void* address = FTL::prepareOSREntry(
1305        exec, codeBlock, jitCode->osrEntryBlock.get(), bytecodeIndex, streamIndex);
1306    return static_cast<char*>(address);
1307}
1308#endif // ENABLE(FTL_JIT)
1309
1310} // extern "C"
1311} } // namespace JSC::DFG
1312
1313#endif // ENABLE(DFG_JIT)
1314
1315#endif // ENABLE(JIT)
1316