diff options
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGOperations.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGOperations.cpp | 2154 |
1 files changed, 987 insertions, 1167 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp index 1305c0a5d..77137275f 100644 --- a/Source/JavaScriptCore/dfg/DFGOperations.cpp +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Apple Inc. All rights reserved. + * Copyright (C) 2011, 2013-2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,314 +26,54 @@ #include "config.h" #include "DFGOperations.h" -#include "Arguments.h" #include "ButterflyInlines.h" +#include "ClonedArguments.h" #include "CodeBlock.h" +#include "CommonSlowPaths.h" #include "CopiedSpaceInlines.h" +#include "DFGDriver.h" +#include "DFGJITCode.h" #include "DFGOSRExit.h" -#include "DFGRepatch.h" #include "DFGThunks.h" +#include "DFGToFTLDeferredCompilationCallback.h" +#include "DFGToFTLForOSREntryDeferredCompilationCallback.h" +#include "DFGWorklist.h" +#include "DirectArguments.h" +#include "FTLForOSREntryJITCode.h" +#include "FTLOSREntry.h" #include "HostCallReturnValue.h" #include "GetterSetter.h" #include "Interpreter.h" #include "JIT.h" #include "JITExceptions.h" -#include "JSActivation.h" -#include "VM.h" -#include "JSNameScope.h" -#include "NameInstance.h" +#include "JSCInlines.h" +#include "JSLexicalEnvironment.h" #include "ObjectConstructor.h" -#include "Operations.h" +#include "Repatch.h" +#include "ScopedArguments.h" #include "StringConstructor.h" +#include "Symbol.h" +#include "TypeProfilerLog.h" +#include "TypedArrayInlines.h" +#include "VM.h" #include <wtf/InlineASM.h> #if ENABLE(JIT) - -#if CPU(MIPS) -#if WTF_MIPS_PIC -#define LOAD_FUNCTION_TO_T9(function) \ - ".set noreorder" "\n" \ - ".cpload $25" "\n" \ - ".set reorder" "\n" \ - "la $t9, " LOCAL_REFERENCE(function) "\n" -#else -#define LOAD_FUNCTION_TO_T9(function) "" "\n" -#endif -#endif - #if ENABLE(DFG_JIT) -#if COMPILER(GCC) && CPU(X86_64) - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, register) \ - asm( \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - "mov (%rsp), %" STRINGIZE(register) "\n" \ - "jmp " LOCAL_REFERENCE(function##WithReturnAddress) "\n" \ - ); -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rsi) -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rcx) -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rcx) -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, r8) - -#elif COMPILER(GCC) && CPU(X86) - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, offset) \ - asm( \ - ".text" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - "mov (%esp), %eax\n" \ - "mov %eax, " STRINGIZE(offset) "(%esp)\n" \ - "jmp " LOCAL_REFERENCE(function##WithReturnAddress) "\n" \ - ); -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 8) -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 16) -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 20) -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 24) - -#elif COMPILER(GCC) && CPU(ARM_THUMB2) - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ - asm ( \ - ".text" "\n" \ - ".align 2" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - ".thumb" "\n" \ - ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - "mov a2, lr" "\n" \ - "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - ); - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ - asm ( \ - ".text" "\n" \ - ".align 2" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - ".thumb" "\n" \ - ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - "mov a4, lr" "\n" \ - "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - ); - -// EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]). -// As a result, return address will be at a 4-byte further location in the following cases. -#if COMPILER_SUPPORTS(EABI) && CPU(ARM) -#define INSTRUCTION_STORE_RETURN_ADDRESS_EJI "str lr, [sp, #4]" -#define INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "str lr, [sp, #8]" -#else -#define INSTRUCTION_STORE_RETURN_ADDRESS_EJI "str lr, [sp, #0]" -#define INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "str lr, [sp, #4]" -#endif - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ - asm ( \ - ".text" "\n" \ - ".align 2" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - ".thumb" "\n" \ - ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - INSTRUCTION_STORE_RETURN_ADDRESS_EJI "\n" \ - "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - ); - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ - asm ( \ - ".text" "\n" \ - ".align 2" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - ".thumb" "\n" \ - ".thumb_func " THUMB_FUNC_PARAM(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "\n" \ - "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - ); - -#elif COMPILER(GCC) && CPU(ARM_TRADITIONAL) - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ - asm ( \ - ".text" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - INLINE_ARM_FUNCTION(function) \ - SYMBOL_STRING(function) ":" "\n" \ - "mov a2, lr" "\n" \ - "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - ); - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ - asm ( \ - ".text" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - INLINE_ARM_FUNCTION(function) \ - SYMBOL_STRING(function) ":" "\n" \ - "mov a4, lr" "\n" \ - "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - ); - -// EncodedJSValue in JSVALUE32_64 is a 64-bit integer. When being compiled in ARM EABI, it must be aligned even-numbered register (r0, r2 or [sp]). -// As a result, return address will be at a 4-byte further location in the following cases. -#if COMPILER_SUPPORTS(EABI) && CPU(ARM) -#define INSTRUCTION_STORE_RETURN_ADDRESS_EJI "str lr, [sp, #4]" -#define INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "str lr, [sp, #8]" -#else -#define INSTRUCTION_STORE_RETURN_ADDRESS_EJI "str lr, [sp, #0]" -#define INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "str lr, [sp, #4]" -#endif - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ - asm ( \ - ".text" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - INLINE_ARM_FUNCTION(function) \ - SYMBOL_STRING(function) ":" "\n" \ - INSTRUCTION_STORE_RETURN_ADDRESS_EJI "\n" \ - "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - ); - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ - asm ( \ - ".text" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - INLINE_ARM_FUNCTION(function) \ - SYMBOL_STRING(function) ":" "\n" \ - INSTRUCTION_STORE_RETURN_ADDRESS_EJCI "\n" \ - "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - ); - -#elif COMPILER(GCC) && CPU(MIPS) - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ - asm( \ - ".text" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ - "move $a1, $ra" "\n" \ - "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - ); - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ - asm( \ - ".text" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ - "move $a3, $ra" "\n" \ - "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - ); - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ - asm( \ - ".text" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ - "sw $ra, 20($sp)" "\n" \ - "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - ); - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ - asm( \ - ".text" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - LOAD_FUNCTION_TO_T9(function##WithReturnAddress) \ - "sw $ra, 24($sp)" "\n" \ - "b " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - ); - -#elif COMPILER(GCC) && CPU(SH4) - -#define SH4_SCRATCH_REGISTER "r11" - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ - asm( \ - ".text" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - "sts pr, r5" "\n" \ - "bra " LOCAL_REFERENCE(function) "WithReturnAddress" "\n" \ - "nop" "\n" \ - ); - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ - asm( \ - ".text" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - "sts pr, r7" "\n" \ - "mov.l 2f, " SH4_SCRATCH_REGISTER "\n" \ - "braf " SH4_SCRATCH_REGISTER "\n" \ - "nop" "\n" \ - "1: .balign 4" "\n" \ - "2: .long " LOCAL_REFERENCE(function) "WithReturnAddress-1b" "\n" \ - ); - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, offset, scratch) \ - asm( \ - ".text" "\n" \ - ".globl " SYMBOL_STRING(function) "\n" \ - HIDE_SYMBOL(function) "\n" \ - SYMBOL_STRING(function) ":" "\n" \ - "sts pr, " scratch "\n" \ - "mov.l " scratch ", @(" STRINGIZE(offset) ", r15)" "\n" \ - "mov.l 2f, " scratch "\n" \ - "braf " scratch "\n" \ - "nop" "\n" \ - "1: .balign 4" "\n" \ - "2: .long " LOCAL_REFERENCE(function) "WithReturnAddress-1b" "\n" \ - ); - -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 0, SH4_SCRATCH_REGISTER) -#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, 4, SH4_SCRATCH_REGISTER) - -#endif - -#define P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ -void* DFG_OPERATION function##WithReturnAddress(ExecState*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ -FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) - -#define J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) \ -EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, JSCell*, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ -FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_ECI(function) - -#define J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) \ -EncodedJSValue DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ -FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(function) - -#define V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) \ -void DFG_OPERATION function##WithReturnAddress(ExecState*, EncodedJSValue, JSCell*, Identifier*, ReturnAddressPtr) REFERENCED_FROM_ASM WTF_INTERNAL; \ -FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) - namespace JSC { namespace DFG { -template<bool strict> +template<bool strict, bool direct> static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, JSValue value) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - + ASSERT(isIndex(index)); + if (direct) { + RELEASE_ASSERT(baseValue.isObject()); + asObject(baseValue)->putDirectIndex(exec, index, value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); + return; + } if (baseValue.isObject()) { JSObject* object = asObject(baseValue); if (object->canSetIndexQuickly(index)) { @@ -341,15 +81,15 @@ static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, return; } - object->methodTable()->putByIndex(object, exec, index, value, strict); + object->methodTable(vm)->putByIndex(object, exec, index, value, strict); return; } baseValue.putByIndex(exec, index, value, strict); } -template<bool strict> -ALWAYS_INLINE static void DFG_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) +template<bool strict, bool direct> +ALWAYS_INLINE static void JIT_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); @@ -359,65 +99,154 @@ ALWAYS_INLINE static void DFG_OPERATION operationPutByValInternal(ExecState* exe JSValue value = JSValue::decode(encodedValue); if (LIKELY(property.isUInt32())) { - putByVal<strict>(exec, baseValue, property.asUInt32(), value); + // Despite its name, JSValue::isUInt32 will return true only for positive boxed int32_t; all those values are valid array indices. + ASSERT(isIndex(property.asUInt32())); + putByVal<strict, direct>(exec, baseValue, property.asUInt32(), value); return; } if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); - if (propertyAsDouble == propertyAsUInt32) { - putByVal<strict>(exec, baseValue, propertyAsUInt32, value); + if (propertyAsDouble == propertyAsUInt32 && isIndex(propertyAsUInt32)) { + putByVal<strict, direct>(exec, baseValue, propertyAsUInt32, value); return; } } - if (isName(property)) { - PutPropertySlot slot(strict); - baseValue.put(exec, jsCast<NameInstance*>(property.asCell())->privateName(), value, slot); + // Don't put to an object if toString throws an exception. + auto propertyName = property.toPropertyKey(exec); + if (vm->exception()) return; - } - // Don't put to an object if toString throws an exception. - Identifier ident(exec, property.toString(exec)->value(exec)); - if (!vm->exception) { - PutPropertySlot slot(strict); - baseValue.put(exec, ident, value, slot); + PutPropertySlot slot(baseValue, strict); + if (direct) { + RELEASE_ASSERT(baseValue.isObject()); + if (Optional<uint32_t> index = parseIndex(propertyName)) + asObject(baseValue)->putDirectIndex(exec, index.value(), value, 0, strict ? PutDirectIndexShouldThrow : PutDirectIndexShouldNotThrow); + else + asObject(baseValue)->putDirect(*vm, propertyName, value, slot); + } else + baseValue.put(exec, propertyName, value, slot); +} + +template<typename ViewClass> +char* newTypedArrayWithSize(ExecState* exec, Structure* structure, int32_t size) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + if (size < 0) { + vm.throwException(exec, createRangeError(exec, ASCIILiteral("Requested length is negative"))); + return 0; } + return bitwise_cast<char*>(ViewClass::create(exec, structure, size)); } extern "C" { -EncodedJSValue DFG_OPERATION operationConvertThis(ExecState* exec, EncodedJSValue encodedOp) +EncodedJSValue JIT_OPERATION operationToThis(ExecState* exec, EncodedJSValue encodedOp) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec)); + return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, NotStrictMode)); } -JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSObject* constructor, int32_t inlineCapacity) +EncodedJSValue JIT_OPERATION operationToThisStrict(ExecState* exec, EncodedJSValue encodedOp) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); -#if !ASSERT_DISABLED - ConstructData constructData; - ASSERT(jsCast<JSFunction*>(constructor)->methodTable()->getConstructData(jsCast<JSFunction*>(constructor), constructData) == ConstructTypeJS); -#endif - - return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->allocationProfile(exec, inlineCapacity)->structure()); + return JSValue::encode(JSValue::decode(encodedOp).toThis(exec, StrictMode)); +} + +JSCell* JIT_OPERATION operationCreateThis(ExecState* exec, JSObject* constructor, int32_t inlineCapacity) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + return constructEmptyObject(exec, jsCast<JSFunction*>(constructor)->rareData(exec, inlineCapacity)->objectAllocationProfile()->structure()); } -JSCell* DFG_OPERATION operationNewObject(ExecState* exec, Structure* structure) +EncodedJSValue JIT_OPERATION operationValueBitAnd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - - return constructEmptyObject(exec, structure); + + JSValue op1 = JSValue::decode(encodedOp1); + JSValue op2 = JSValue::decode(encodedOp2); + + int32_t a = op1.toInt32(exec); + int32_t b = op2.toInt32(exec); + return JSValue::encode(jsNumber(a & b)); +} + +EncodedJSValue JIT_OPERATION operationValueBitOr(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); + + JSValue op1 = JSValue::decode(encodedOp1); + JSValue op2 = JSValue::decode(encodedOp2); + + int32_t a = op1.toInt32(exec); + int32_t b = op2.toInt32(exec); + return JSValue::encode(jsNumber(a | b)); +} + +EncodedJSValue JIT_OPERATION operationValueBitXor(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); + + JSValue op1 = JSValue::decode(encodedOp1); + JSValue op2 = JSValue::decode(encodedOp2); + + int32_t a = op1.toInt32(exec); + int32_t b = op2.toInt32(exec); + return JSValue::encode(jsNumber(a ^ b)); +} + +EncodedJSValue JIT_OPERATION operationValueBitLShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); + + JSValue op1 = JSValue::decode(encodedOp1); + JSValue op2 = JSValue::decode(encodedOp2); + + int32_t a = op1.toInt32(exec); + uint32_t b = op2.toUInt32(exec); + return JSValue::encode(jsNumber(a << (b & 0x1f))); +} + +EncodedJSValue JIT_OPERATION operationValueBitRShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); + + JSValue op1 = JSValue::decode(encodedOp1); + JSValue op2 = JSValue::decode(encodedOp2); + + int32_t a = op1.toInt32(exec); + uint32_t b = op2.toUInt32(exec); + return JSValue::encode(jsNumber(a >> (b & 0x1f))); +} + +EncodedJSValue JIT_OPERATION operationValueBitURShift(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); + + JSValue op1 = JSValue::decode(encodedOp1); + JSValue op2 = JSValue::decode(encodedOp2); + + uint32_t a = op1.toUInt32(exec); + uint32_t b = op2.toUInt32(exec); + return JSValue::encode(jsNumber(static_cast<int32_t>(a >> (b & 0x1f)))); } -EncodedJSValue DFG_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +EncodedJSValue JIT_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); @@ -428,7 +257,7 @@ EncodedJSValue DFG_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue e return JSValue::encode(jsAdd(exec, op1, op2)); } -EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +EncodedJSValue JIT_OPERATION operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); @@ -444,7 +273,46 @@ EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState* exec, Encoded return JSValue::encode(jsAddSlowCase(exec, op1, op2)); } -static inline EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index) +EncodedJSValue JIT_OPERATION operationValueDiv(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); + + JSValue op1 = JSValue::decode(encodedOp1); + JSValue op2 = JSValue::decode(encodedOp2); + + double a = op1.toNumber(exec); + double b = op2.toNumber(exec); + return JSValue::encode(jsNumber(a / b)); +} + +EncodedJSValue JIT_OPERATION operationValueMul(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); + + JSValue op1 = JSValue::decode(encodedOp1); + JSValue op2 = JSValue::decode(encodedOp2); + + double a = op1.toNumber(exec); + double b = op2.toNumber(exec); + return JSValue::encode(jsNumber(a * b)); +} + +EncodedJSValue JIT_OPERATION operationValueSub(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); + + JSValue op1 = JSValue::decode(encodedOp1); + JSValue op2 = JSValue::decode(encodedOp2); + + double a = op1.toNumber(exec); + double b = op2.toNumber(exec); + return JSValue::encode(jsNumber(a - b)); +} + +static ALWAYS_INLINE EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -461,10 +329,10 @@ static inline EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t in return JSValue::encode(JSValue(base).get(exec, index)); } -EncodedJSValue DFG_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) +EncodedJSValue JIT_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); @@ -477,25 +345,32 @@ EncodedJSValue DFG_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue e } else if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); - if (propertyAsUInt32 == propertyAsDouble) + if (propertyAsUInt32 == propertyAsDouble && isIndex(propertyAsUInt32)) return getByVal(exec, base, propertyAsUInt32); } else if (property.isString()) { - if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec))) - return JSValue::encode(result); + Structure& structure = *base->structure(vm); + if (JSCell::canUseFastGetOwnProperty(structure)) { + if (RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec)) { + if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get())) + return JSValue::encode(result); + } + } } } - if (isName(property)) - return JSValue::encode(baseValue.get(exec, jsCast<NameInstance*>(property.asCell())->privateName())); - - Identifier ident(exec, property.toString(exec)->value(exec)); - return JSValue::encode(baseValue.get(exec, ident)); + baseValue.requireObjectCoercible(exec); + if (vm.exception()) + return JSValue::encode(jsUndefined()); + auto propertyName = property.toPropertyKey(exec); + if (vm.exception()) + return JSValue::encode(jsUndefined()); + return JSValue::encode(baseValue.get(exec, propertyName)); } -EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty) +EncodedJSValue JIT_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); JSValue property = JSValue::decode(encodedProperty); @@ -507,18 +382,22 @@ EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState* exec, JSCell* base if (propertyAsUInt32 == propertyAsDouble) return getByVal(exec, base, propertyAsUInt32); } else if (property.isString()) { - if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec))) - return JSValue::encode(result); + Structure& structure = *base->structure(vm); + if (JSCell::canUseFastGetOwnProperty(structure)) { + if (RefPtr<AtomicStringImpl> existingAtomicString = asString(property)->toExistingAtomicString(exec)) { + if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString.get())) + return JSValue::encode(result); + } + } } - if (isName(property)) - return JSValue::encode(JSValue(base).get(exec, jsCast<NameInstance*>(property.asCell())->privateName())); - - Identifier ident(exec, property.toString(exec)->value(exec)); - return JSValue::encode(JSValue(base).get(exec, ident)); + auto propertyName = property.toPropertyKey(exec); + if (vm.exception()) + return JSValue::encode(jsUndefined()); + return JSValue::encode(JSValue(base).get(exec, propertyName)); } -EncodedJSValue DFG_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* base, int32_t index) +ALWAYS_INLINE EncodedJSValue getByValCellInt(ExecState* exec, JSCell* base, int32_t index) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); @@ -532,147 +411,64 @@ EncodedJSValue DFG_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* return JSValue::encode(JSValue(base).get(exec, index)); } -EncodedJSValue DFG_OPERATION operationGetById(ExecState* exec, EncodedJSValue base, Identifier* propertyName) +EncodedJSValue JIT_OPERATION operationGetByValArrayInt(ExecState* exec, JSArray* base, int32_t index) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - JSValue baseValue = JSValue::decode(base); - PropertySlot slot(baseValue); - return JSValue::encode(baseValue.get(exec, *propertyName, slot)); + return getByValCellInt(exec, base, index); } -J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdBuildList); -EncodedJSValue DFG_OPERATION operationGetByIdBuildListWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress) +EncodedJSValue JIT_OPERATION operationGetByValStringInt(ExecState* exec, JSString* base, int32_t index) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - - JSValue baseValue = JSValue::decode(base); - PropertySlot slot(baseValue); - JSValue result = baseValue.get(exec, *propertyName, slot); - - if (accessType == static_cast<AccessType>(stubInfo.accessType)) - dfgBuildGetByIDList(exec, baseValue, *propertyName, slot, stubInfo); - - return JSValue::encode(result); -} - -J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdProtoBuildList); -EncodedJSValue DFG_OPERATION operationGetByIdProtoBuildListWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress) -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - - JSValue baseValue = JSValue::decode(base); - PropertySlot slot(baseValue); - JSValue result = baseValue.get(exec, *propertyName, slot); - - if (accessType == static_cast<AccessType>(stubInfo.accessType)) - dfgBuildGetByIDProtoList(exec, baseValue, *propertyName, slot, stubInfo); - - return JSValue::encode(result); -} - -J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdOptimize); -EncodedJSValue DFG_OPERATION operationGetByIdOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress) -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - - JSValue baseValue = JSValue::decode(base); - PropertySlot slot(baseValue); - JSValue result = baseValue.get(exec, *propertyName, slot); - - if (accessType == static_cast<AccessType>(stubInfo.accessType)) { - if (stubInfo.seen) - dfgRepatchGetByID(exec, baseValue, *propertyName, slot, stubInfo); - else - stubInfo.seen = true; - } - - return JSValue::encode(result); -} - -EncodedJSValue DFG_OPERATION operationCallCustomGetter(ExecState* exec, JSCell* base, PropertySlot::GetValueFunc function, Identifier* ident) -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - return JSValue::encode(function(exec, asObject(base), *ident)); -} - -EncodedJSValue DFG_OPERATION operationCallGetter(ExecState* exec, JSCell* base, JSCell* value) -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - GetterSetter* getterSetter = asGetterSetter(value); - JSObject* getter = getterSetter->getter(); - if (!getter) - return JSValue::encode(jsUndefined()); - CallData callData; - CallType callType = getter->methodTable()->getCallData(getter, callData); - return JSValue::encode(call(exec, getter, callType, callData, asObject(base), ArgList())); + return getByValCellInt(exec, base, index); } -void DFG_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) +void JIT_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - operationPutByValInternal<true>(exec, encodedBase, encodedProperty, encodedValue); + operationPutByValInternal<true, false>(exec, encodedBase, encodedProperty, encodedValue); } -void DFG_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) +void JIT_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue); + operationPutByValInternal<false, false>(exec, encodedBase, encodedProperty, encodedValue); } -void DFG_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) +void JIT_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - operationPutByValInternal<true>(exec, JSValue::encode(cell), encodedProperty, encodedValue); + operationPutByValInternal<true, false>(exec, JSValue::encode(cell), encodedProperty, encodedValue); } -void DFG_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) +void JIT_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - operationPutByValInternal<false>(exec, JSValue::encode(cell), encodedProperty, encodedValue); + operationPutByValInternal<false, false>(exec, JSValue::encode(cell), encodedProperty, encodedValue); } -void DFG_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue) +void JIT_OPERATION operationPutByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); if (index >= 0) { array->putByIndexInline(exec, index, JSValue::decode(encodedValue), true); return; } - PutPropertySlot slot(true); + PutPropertySlot slot(array, true); array->methodTable()->put( array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot); } -void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue) +void JIT_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); @@ -682,12 +478,12 @@ void DFG_OPERATION operationPutByValBeyondArrayBoundsNonStrict(ExecState* exec, return; } - PutPropertySlot slot(false); + PutPropertySlot slot(array, false); array->methodTable()->put( array, exec, Identifier::from(exec, index), JSValue::decode(encodedValue), slot); } -void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, double value) +void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, double value) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); @@ -699,12 +495,12 @@ void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsStrict(ExecState* exe return; } - PutPropertySlot slot(true); + PutPropertySlot slot(array, true); array->methodTable()->put( array, exec, Identifier::from(exec, index), jsValue, slot); } -void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, double value) +void JIT_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, double value) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); @@ -716,351 +512,183 @@ void DFG_OPERATION operationPutDoubleByValBeyondArrayBoundsNonStrict(ExecState* return; } - PutPropertySlot slot(false); + PutPropertySlot slot(array, false); array->methodTable()->put( array, exec, Identifier::from(exec, index), jsValue, slot); } -EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array) +void JIT_OPERATION operationPutByValDirectStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - array->push(exec, JSValue::decode(encodedValue)); - return JSValue::encode(jsNumber(array->length())); + operationPutByValInternal<true, true>(exec, encodedBase, encodedProperty, encodedValue); } -EncodedJSValue DFG_OPERATION operationArrayPushDouble(ExecState* exec, double value, JSArray* array) +void JIT_OPERATION operationPutByValDirectNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - array->push(exec, JSValue(JSValue::EncodeAsDouble, value)); - return JSValue::encode(jsNumber(array->length())); + operationPutByValInternal<false, true>(exec, encodedBase, encodedProperty, encodedValue); } -EncodedJSValue DFG_OPERATION operationArrayPop(ExecState* exec, JSArray* array) -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - return JSValue::encode(array->pop(exec)); -} - -EncodedJSValue DFG_OPERATION operationArrayPopAndRecoverLength(ExecState* exec, JSArray* array) +void JIT_OPERATION operationPutByValDirectCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - array->butterfly()->setPublicLength(array->butterfly()->publicLength() + 1); - - return JSValue::encode(array->pop(exec)); + operationPutByValInternal<true, true>(exec, JSValue::encode(cell), encodedProperty, encodedValue); } - -EncodedJSValue DFG_OPERATION operationRegExpExec(ExecState* exec, JSCell* base, JSCell* argument) -{ - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - - if (!base->inherits(&RegExpObject::s_info)) - return throwVMTypeError(exec); - ASSERT(argument->isString() || argument->isObject()); - JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec); - return JSValue::encode(asRegExpObject(base)->exec(exec, input)); -} - -size_t DFG_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell* argument) -{ - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - - if (!base->inherits(&RegExpObject::s_info)) { - throwTypeError(exec); - return false; - } - - ASSERT(argument->isString() || argument->isObject()); - JSString* input = argument->isString() ? asString(argument) : asObject(argument)->toString(exec); - return asRegExpObject(base)->test(exec, input); -} - -void DFG_OPERATION operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - PutPropertySlot slot(true); - base->methodTable()->put(base, exec, *propertyName, JSValue::decode(encodedValue), slot); -} - -void DFG_OPERATION operationPutByIdNonStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) +void JIT_OPERATION operationPutByValDirectCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - PutPropertySlot slot(false); - base->methodTable()->put(base, exec, *propertyName, JSValue::decode(encodedValue), slot); + operationPutByValInternal<false, true>(exec, JSValue::encode(cell), encodedProperty, encodedValue); } -void DFG_OPERATION operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - PutPropertySlot slot(true); - ASSERT(base->isObject()); - asObject(base)->putDirect(exec->vm(), *propertyName, JSValue::decode(encodedValue), slot); -} - -void DFG_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) +void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); + if (index >= 0) { + array->putDirectIndex(exec, index, JSValue::decode(encodedValue), 0, PutDirectIndexShouldThrow); + return; + } - PutPropertySlot slot(false); - ASSERT(base->isObject()); - asObject(base)->putDirect(exec->vm(), *propertyName, JSValue::decode(encodedValue), slot); + PutPropertySlot slot(array, true); + array->putDirect(exec->vm(), Identifier::from(exec, index), JSValue::decode(encodedValue), slot); } -V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdStrictOptimize); -void DFG_OPERATION operationPutByIdStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) +void JIT_OPERATION operationPutByValDirectBeyondArrayBoundsNonStrict(ExecState* exec, JSObject* array, int32_t index, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - - JSValue value = JSValue::decode(encodedValue); - JSValue baseValue(base); - PutPropertySlot slot(true); - - baseValue.put(exec, *propertyName, value, slot); - - if (accessType != static_cast<AccessType>(stubInfo.accessType)) + if (index >= 0) { + array->putDirectIndex(exec, index, JSValue::decode(encodedValue)); return; + } - if (stubInfo.seen) - dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, NotDirect); - else - stubInfo.seen = true; + PutPropertySlot slot(array, false); + array->putDirect(exec->vm(), Identifier::from(exec, index), JSValue::decode(encodedValue), slot); } -V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdNonStrictOptimize); -void DFG_OPERATION operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) +EncodedJSValue JIT_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - - JSValue value = JSValue::decode(encodedValue); - JSValue baseValue(base); - PutPropertySlot slot(false); - - baseValue.put(exec, *propertyName, value, slot); - - if (accessType != static_cast<AccessType>(stubInfo.accessType)) - return; - - if (stubInfo.seen) - dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, NotDirect); - else - stubInfo.seen = true; + array->push(exec, JSValue::decode(encodedValue)); + return JSValue::encode(jsNumber(array->length())); } -V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectStrictOptimize); -void DFG_OPERATION operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) +EncodedJSValue JIT_OPERATION operationArrayPushDouble(ExecState* exec, double value, JSArray* array) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - - JSValue value = JSValue::decode(encodedValue); - PutPropertySlot slot(true); - - ASSERT(base->isObject()); - asObject(base)->putDirect(exec->vm(), *propertyName, value, slot); - - if (accessType != static_cast<AccessType>(stubInfo.accessType)) - return; - - if (stubInfo.seen) - dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, Direct); - else - stubInfo.seen = true; + array->push(exec, JSValue(JSValue::EncodeAsDouble, value)); + return JSValue::encode(jsNumber(array->length())); } -V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectNonStrictOptimize); -void DFG_OPERATION operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) +EncodedJSValue JIT_OPERATION operationArrayPop(ExecState* exec, JSArray* array) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - - JSValue value = JSValue::decode(encodedValue); - PutPropertySlot slot(false); - - ASSERT(base->isObject()); - asObject(base)->putDirect(exec->vm(), *propertyName, value, slot); - - if (accessType != static_cast<AccessType>(stubInfo.accessType)) - return; - - if (stubInfo.seen) - dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, Direct); - else - stubInfo.seen = true; + return JSValue::encode(array->pop(exec)); } - -V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdStrictBuildList); -void DFG_OPERATION operationPutByIdStrictBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) + +EncodedJSValue JIT_OPERATION operationArrayPopAndRecoverLength(ExecState* exec, JSArray* array) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - - JSValue value = JSValue::decode(encodedValue); - JSValue baseValue(base); - PutPropertySlot slot(true); - - baseValue.put(exec, *propertyName, value, slot); - - if (accessType != static_cast<AccessType>(stubInfo.accessType)) - return; + array->butterfly()->setPublicLength(array->butterfly()->publicLength() + 1); - dfgBuildPutByIdList(exec, baseValue, *propertyName, slot, stubInfo, NotDirect); + return JSValue::encode(array->pop(exec)); } - -V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdNonStrictBuildList); -void DFG_OPERATION operationPutByIdNonStrictBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) + +EncodedJSValue JIT_OPERATION operationRegExpExec(ExecState* exec, JSCell* base, JSCell* argument) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); - StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); + if (!base->inherits(RegExpObject::info())) + return throwVMTypeError(exec); - JSValue value = JSValue::decode(encodedValue); - JSValue baseValue(base); - PutPropertySlot slot(false); - - baseValue.put(exec, *propertyName, value, slot); - - if (accessType != static_cast<AccessType>(stubInfo.accessType)) - return; - - dfgBuildPutByIdList(exec, baseValue, *propertyName, slot, stubInfo, NotDirect); + JSString* input; + if (argument->isString()) + input = asString(argument); + else { + input = JSValue(argument).toStringOrNull(exec); + if (!input) + return JSValue::encode(jsUndefined()); + } + return JSValue::encode(asRegExpObject(base)->exec(exec, input)); } - -V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectStrictBuildList); -void DFG_OPERATION operationPutByIdDirectStrictBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) + +EncodedJSValue JIT_OPERATION operationRegExpExecGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedArgument) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); - - JSValue value = JSValue::decode(encodedValue); - PutPropertySlot slot(true); - - ASSERT(base->isObject()); - asObject(base)->putDirect(exec->vm(), *propertyName, value, slot); - - if (accessType != static_cast<AccessType>(stubInfo.accessType)) - return; - - dfgBuildPutByIdList(exec, base, *propertyName, slot, stubInfo, Direct); -} + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); -V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectNonStrictBuildList); -void DFG_OPERATION operationPutByIdDirectNonStrictBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); + JSValue base = JSValue::decode(encodedBase); + JSValue argument = JSValue::decode(encodedArgument); - StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); - AccessType accessType = static_cast<AccessType>(stubInfo.accessType); + if (!base.inherits(RegExpObject::info())) + return throwVMTypeError(exec); - JSValue value = JSValue::decode(encodedValue); - PutPropertySlot slot(false); - - ASSERT(base->isObject()); - asObject(base)->putDirect(exec->vm(), *propertyName, value, slot); - - if (accessType != static_cast<AccessType>(stubInfo.accessType)) - return; - - dfgBuildPutByIdList(exec, base, *propertyName, slot, stubInfo, Direct); + JSString* input = argument.toStringOrNull(exec); + if (!input) + return JSValue::encode(jsUndefined()); + return JSValue::encode(asRegExpObject(base)->exec(exec, input)); } - -size_t DFG_OPERATION operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) + +size_t JIT_OPERATION operationRegExpTest(ExecState* exec, JSCell* base, JSCell* argument) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - return jsLess<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); -} + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); -size_t DFG_OPERATION operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - return jsLessEq<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); -} + if (!base->inherits(RegExpObject::info())) { + throwTypeError(exec); + return false; + } -size_t DFG_OPERATION operationCompareGreater(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - return jsLess<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1)); + JSString* input; + if (argument->isString()) + input = asString(argument); + else { + input = JSValue(argument).toStringOrNull(exec); + if (!input) + return false; + } + return asRegExpObject(base)->test(exec, input); } -size_t DFG_OPERATION operationCompareGreaterEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +size_t JIT_OPERATION operationRegExpTestGeneric(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedArgument) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - return jsLessEq<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1)); -} + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); -size_t DFG_OPERATION operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - return JSValue::equalSlowCaseInline(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); -} + JSValue base = JSValue::decode(encodedBase); + JSValue argument = JSValue::decode(encodedArgument); -#if USE(JSVALUE64) -EncodedJSValue DFG_OPERATION operationCompareStringEq(ExecState* exec, JSCell* left, JSCell* right) -#else -size_t DFG_OPERATION operationCompareStringEq(ExecState* exec, JSCell* left, JSCell* right) -#endif -{ - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - bool result = asString(left)->value(exec) == asString(right)->value(exec); -#if USE(JSVALUE64) - return JSValue::encode(jsBoolean(result)); -#else - return result; -#endif + if (!base.inherits(RegExpObject::info())) { + throwTypeError(exec); + return false; + } + + JSString* input = argument.toStringOrNull(exec); + if (!input) + return false; + return asRegExpObject(base)->test(exec, input); } -size_t DFG_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +size_t JIT_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); @@ -1074,7 +702,7 @@ size_t DFG_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValu return JSValue::strictEqualSlowCaseInline(exec, op1, op2); } -size_t DFG_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +size_t JIT_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); @@ -1085,474 +713,390 @@ size_t DFG_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue en return JSValue::strictEqual(exec, src1, src2); } -static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializationKind kind) +EncodedJSValue JIT_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value) { - ExecState* exec = execCallee->callerFrame(); VM* vm = &exec->vm(); - - execCallee->setScope(exec->scope()); - execCallee->setCodeBlock(0); - - if (kind == CodeForCall) { - CallData callData; - CallType callType = getCallData(callee, callData); - - ASSERT(callType != CallTypeJS); - - if (callType == CallTypeHost) { - NativeCallFrameTracer tracer(vm, execCallee); - execCallee->setCallee(asObject(callee)); - vm->hostCallReturnValue = JSValue::decode(callData.native.function(execCallee)); - if (vm->exception) - return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); - - return reinterpret_cast<void*>(getHostCallReturnValue); - } + NativeCallFrameTracer tracer(vm, exec); - ASSERT(callType == CallTypeNone); - exec->vm().exception = createNotAFunctionError(exec, callee); - return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); - } + return JSValue::encode(JSValue::decode(value).toPrimitive(exec)); +} - ASSERT(kind == CodeForConstruct); - - ConstructData constructData; - ConstructType constructType = getConstructData(callee, constructData); - - ASSERT(constructType != ConstructTypeJS); +char* JIT_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); - if (constructType == ConstructTypeHost) { - NativeCallFrameTracer tracer(vm, execCallee); - execCallee->setCallee(asObject(callee)); - vm->hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee)); - if (vm->exception) - return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); + return bitwise_cast<char*>(constructArray(exec, arrayStructure, static_cast<JSValue*>(buffer), size)); +} - return reinterpret_cast<void*>(getHostCallReturnValue); - } +char* JIT_OPERATION operationNewEmptyArray(ExecState* exec, Structure* arrayStructure) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); - ASSERT(constructType == ConstructTypeNone); - exec->vm().exception = createNotAConstructorError(exec, callee); - return vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress(); + return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure)); } -inline char* linkFor(ExecState* execCallee, CodeSpecializationKind kind) +char* JIT_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size) { - ExecState* exec = execCallee->callerFrame(); VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - - JSValue calleeAsValue = execCallee->calleeAsValue(); - JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); - if (!calleeAsFunctionCell) - return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); - JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); - execCallee->setScope(callee->scopeUnchecked()); - ExecutableBase* executable = callee->executable(); + if (UNLIKELY(size < 0)) + return bitwise_cast<char*>(exec->vm().throwException(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer.")))); - MacroAssemblerCodePtr codePtr; - CodeBlock* codeBlock = 0; - if (executable->isHostFunction()) - codePtr = executable->generatedJITCodeFor(kind).addressForCall(); - else { - FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); - JSObject* error = functionExecutable->compileFor(execCallee, callee->scope(), kind); - if (error) { - vm->exception = createStackOverflowError(exec); - return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); - } - codeBlock = &functionExecutable->generatedBytecodeFor(kind); - if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) - codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind); - else - codePtr = functionExecutable->generatedJITCodeFor(kind).addressForCall(); - } - CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(execCallee->returnPC()); - if (!callLinkInfo.seenOnce()) - callLinkInfo.setSeen(); - else - dfgLinkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind); - return reinterpret_cast<char*>(codePtr.executableAddress()); + JSArray* result = JSArray::create(*vm, arrayStructure, size); + result->butterfly(); // Ensure that the backing store is in to-space. + return bitwise_cast<char*>(result); } -char* DFG_OPERATION operationLinkCall(ExecState* execCallee) +char* JIT_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, size_t start, size_t size) { - return linkFor(execCallee, CodeForCall); + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + return bitwise_cast<char*>(constructArray(exec, arrayStructure, exec->codeBlock()->constantBuffer(start), size)); } -char* DFG_OPERATION operationLinkConstruct(ExecState* execCallee) +char* JIT_OPERATION operationNewInt8ArrayWithSize( + ExecState* exec, Structure* structure, int32_t length) { - return linkFor(execCallee, CodeForConstruct); + return newTypedArrayWithSize<JSInt8Array>(exec, structure, length); } -inline char* virtualForWithFunction(ExecState* execCallee, CodeSpecializationKind kind, JSCell*& calleeAsFunctionCell) +char* JIT_OPERATION operationNewInt8ArrayWithOneArgument( + ExecState* exec, Structure* structure, EncodedJSValue encodedValue) { - ExecState* exec = execCallee->callerFrame(); - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - JSValue calleeAsValue = execCallee->calleeAsValue(); - calleeAsFunctionCell = getJSFunction(calleeAsValue); - if (UNLIKELY(!calleeAsFunctionCell)) - return reinterpret_cast<char*>(handleHostCall(execCallee, calleeAsValue, kind)); - - JSFunction* function = jsCast<JSFunction*>(calleeAsFunctionCell); - execCallee->setScope(function->scopeUnchecked()); - ExecutableBase* executable = function->executable(); - if (UNLIKELY(!executable->hasJITCodeFor(kind))) { - FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); - JSObject* error = functionExecutable->compileFor(execCallee, function->scope(), kind); - if (error) { - exec->vm().exception = error; - return reinterpret_cast<char*>(vm->getCTIStub(throwExceptionFromCallSlowPathGenerator).code().executableAddress()); - } - } - return reinterpret_cast<char*>(executable->generatedJITCodeWithArityCheckFor(kind).executableAddress()); + return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSInt8Array>(exec, structure, encodedValue, 0, Nullopt)); } -inline char* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) +char* JIT_OPERATION operationNewInt16ArrayWithSize( + ExecState* exec, Structure* structure, int32_t length) { - JSCell* calleeAsFunctionCellIgnored; - return virtualForWithFunction(execCallee, kind, calleeAsFunctionCellIgnored); + return newTypedArrayWithSize<JSInt16Array>(exec, structure, length); } -static bool attemptToOptimizeClosureCall(ExecState* execCallee, JSCell* calleeAsFunctionCell, CallLinkInfo& callLinkInfo) +char* JIT_OPERATION operationNewInt16ArrayWithOneArgument( + ExecState* exec, Structure* structure, EncodedJSValue encodedValue) { - if (!calleeAsFunctionCell) - return false; - - JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); - JSFunction* oldCallee = callLinkInfo.callee.get(); - - if (!oldCallee - || oldCallee->structure() != callee->structure() - || oldCallee->executable() != callee->executable()) - return false; - - ASSERT(callee->executable()->hasJITCodeForCall()); - MacroAssemblerCodePtr codePtr = callee->executable()->generatedJITCodeForCall().addressForCall(); - - CodeBlock* codeBlock; - if (callee->executable()->isHostFunction()) - codeBlock = 0; - else { - codeBlock = &jsCast<FunctionExecutable*>(callee->executable())->generatedBytecodeForCall(); - if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) - return false; - } - - dfgLinkClosureCall( - execCallee, callLinkInfo, codeBlock, - callee->structure(), callee->executable(), codePtr); - - return true; + return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSInt16Array>(exec, structure, encodedValue, 0, Nullopt)); } -char* DFG_OPERATION operationLinkClosureCall(ExecState* execCallee) +char* JIT_OPERATION operationNewInt32ArrayWithSize( + ExecState* exec, Structure* structure, int32_t length) { - JSCell* calleeAsFunctionCell; - char* result = virtualForWithFunction(execCallee, CodeForCall, calleeAsFunctionCell); - CallLinkInfo& callLinkInfo = execCallee->callerFrame()->codeBlock()->getCallLinkInfo(execCallee->returnPC()); - - if (!attemptToOptimizeClosureCall(execCallee, calleeAsFunctionCell, callLinkInfo)) - dfgLinkSlowFor(execCallee, callLinkInfo, CodeForCall); - - return result; -} - -char* DFG_OPERATION operationVirtualCall(ExecState* execCallee) -{ - return virtualFor(execCallee, CodeForCall); + return newTypedArrayWithSize<JSInt32Array>(exec, structure, length); } -char* DFG_OPERATION operationVirtualConstruct(ExecState* execCallee) +char* JIT_OPERATION operationNewInt32ArrayWithOneArgument( + ExecState* exec, Structure* structure, EncodedJSValue encodedValue) { - return virtualFor(execCallee, CodeForConstruct); + return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSInt32Array>(exec, structure, encodedValue, 0, Nullopt)); } -void DFG_OPERATION operationNotifyGlobalVarWrite(WatchpointSet* watchpointSet) +char* JIT_OPERATION operationNewUint8ArrayWithSize( + ExecState* exec, Structure* structure, int32_t length) { - watchpointSet->notifyWrite(); + return newTypedArrayWithSize<JSUint8Array>(exec, structure, length); } -EncodedJSValue DFG_OPERATION operationResolve(ExecState* exec, Identifier* propertyName, ResolveOperations* operations) +char* JIT_OPERATION operationNewUint8ArrayWithOneArgument( + ExecState* exec, Structure* structure, EncodedJSValue encodedValue) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - return JSValue::encode(JSScope::resolve(exec, *propertyName, operations)); + return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint8Array>(exec, structure, encodedValue, 0, Nullopt)); } -EncodedJSValue DFG_OPERATION operationResolveBase(ExecState* exec, Identifier* propertyName, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations) +char* JIT_OPERATION operationNewUint8ClampedArrayWithSize( + ExecState* exec, Structure* structure, int32_t length) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - return JSValue::encode(JSScope::resolveBase(exec, *propertyName, false, operations, putToBaseOperations)); + return newTypedArrayWithSize<JSUint8ClampedArray>(exec, structure, length); } -EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState* exec, Identifier* propertyName, ResolveOperations* operations, PutToBaseOperation* putToBaseOperations) +char* JIT_OPERATION operationNewUint8ClampedArrayWithOneArgument( + ExecState* exec, Structure* structure, EncodedJSValue encodedValue) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - return JSValue::encode(JSScope::resolveBase(exec, *propertyName, true, operations, putToBaseOperations)); + return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint8ClampedArray>(exec, structure, encodedValue, 0, Nullopt)); } -EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState* exec, ResolveOperation* resolveOperation, JSGlobalObject* globalObject, Identifier* propertyName) +char* JIT_OPERATION operationNewUint16ArrayWithSize( + ExecState* exec, Structure* structure, int32_t length) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - ASSERT(globalObject); - UNUSED_PARAM(resolveOperation); - UNUSED_PARAM(globalObject); - ASSERT(resolveOperation->m_operation == ResolveOperation::GetAndReturnGlobalProperty); - return JSValue::encode(JSScope::resolveGlobal(exec, *propertyName, globalObject, resolveOperation)); + return newTypedArrayWithSize<JSUint16Array>(exec, structure, length); } -EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value) +char* JIT_OPERATION operationNewUint16ArrayWithOneArgument( + ExecState* exec, Structure* structure, EncodedJSValue encodedValue) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - return JSValue::encode(JSValue::decode(value).toPrimitive(exec)); + return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint16Array>(exec, structure, encodedValue, 0, Nullopt)); } -char* DFG_OPERATION operationNewArray(ExecState* exec, Structure* arrayStructure, void* buffer, size_t size) +char* JIT_OPERATION operationNewUint32ArrayWithSize( + ExecState* exec, Structure* structure, int32_t length) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - return bitwise_cast<char*>(constructArray(exec, arrayStructure, static_cast<JSValue*>(buffer), size)); + return newTypedArrayWithSize<JSUint32Array>(exec, structure, length); } -char* DFG_OPERATION operationNewEmptyArray(ExecState* exec, Structure* arrayStructure) +char* JIT_OPERATION operationNewUint32ArrayWithOneArgument( + ExecState* exec, Structure* structure, EncodedJSValue encodedValue) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure)); + return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSUint32Array>(exec, structure, encodedValue, 0, Nullopt)); } -char* DFG_OPERATION operationNewArrayWithSize(ExecState* exec, Structure* arrayStructure, int32_t size) +char* JIT_OPERATION operationNewFloat32ArrayWithSize( + ExecState* exec, Structure* structure, int32_t length) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - - if (UNLIKELY(size < 0)) - return bitwise_cast<char*>(throwError(exec, createRangeError(exec, ASCIILiteral("Array size is not a small enough positive integer.")))); - - return bitwise_cast<char*>(JSArray::create(*vm, arrayStructure, size)); + return newTypedArrayWithSize<JSFloat32Array>(exec, structure, length); } -char* DFG_OPERATION operationNewArrayBuffer(ExecState* exec, Structure* arrayStructure, size_t start, size_t size) +char* JIT_OPERATION operationNewFloat32ArrayWithOneArgument( + ExecState* exec, Structure* structure, EncodedJSValue encodedValue) { - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - return bitwise_cast<char*>(constructArray(exec, arrayStructure, exec->codeBlock()->constantBuffer(start), size)); + return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSFloat32Array>(exec, structure, encodedValue, 0, Nullopt)); } -EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr) +char* JIT_OPERATION operationNewFloat64ArrayWithSize( + ExecState* exec, Structure* structure, int32_t length) { - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - RegExp* regexp = static_cast<RegExp*>(regexpPtr); - if (!regexp->isValid()) { - throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor.")); - return JSValue::encode(jsUndefined()); - } - - return JSValue::encode(RegExpObject::create(exec->vm(), exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regexp)); + return newTypedArrayWithSize<JSFloat64Array>(exec, structure, length); } -JSCell* DFG_OPERATION operationCreateActivation(ExecState* exec) +char* JIT_OPERATION operationNewFloat64ArrayWithOneArgument( + ExecState* exec, Structure* structure, EncodedJSValue encodedValue) { - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - JSActivation* activation = JSActivation::create(vm, exec, exec->codeBlock()); - exec->setScope(activation); - return activation; + return reinterpret_cast<char*>(constructGenericTypedArrayViewWithArguments<JSFloat64Array>(exec, structure, encodedValue, 0, Nullopt)); } -JSCell* DFG_OPERATION operationCreateArguments(ExecState* exec) +JSCell* JIT_OPERATION operationCreateActivationDirect(ExecState* exec, Structure* structure, JSScope* scope, SymbolTable* table, EncodedJSValue initialValueEncoded) { + JSValue initialValue = JSValue::decode(initialValueEncoded); + ASSERT(initialValue == jsUndefined() || initialValue == jsTDZValue()); VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - // NB: This needs to be exceedingly careful with top call frame tracking, since it - // may be called from OSR exit, while the state of the call stack is bizarre. - Arguments* result = Arguments::create(vm, exec); - ASSERT(!vm.exception); - return result; + return JSLexicalEnvironment::create(vm, structure, scope, table, initialValue); } -JSCell* DFG_OPERATION operationCreateInlinedArguments( - ExecState* exec, InlineCallFrame* inlineCallFrame) +JSCell* JIT_OPERATION operationCreateDirectArguments(ExecState* exec, Structure* structure, int32_t length, int32_t minCapacity) { VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - // NB: This needs to be exceedingly careful with top call frame tracking, since it - // may be called from OSR exit, while the state of the call stack is bizarre. - Arguments* result = Arguments::create(vm, exec, inlineCallFrame); - ASSERT(!vm.exception); + NativeCallFrameTracer target(&vm, exec); + DirectArguments* result = DirectArguments::create( + vm, structure, length, std::max(length, minCapacity)); + // The caller will store to this object without barriers. Most likely, at this point, this is + // still a young object and so no barriers are needed. But it's good to be careful anyway, + // since the GC should be allowed to do crazy (like pretenuring, for example). + vm.heap.writeBarrier(result); return result; } -void DFG_OPERATION operationTearOffArguments(ExecState* exec, JSCell* argumentsCell, JSCell* activationCell) +JSCell* JIT_OPERATION operationCreateScopedArguments(ExecState* exec, Structure* structure, Register* argumentStart, int32_t length, JSFunction* callee, JSLexicalEnvironment* scope) { - ASSERT(exec->codeBlock()->usesArguments()); - if (activationCell) { - jsCast<Arguments*>(argumentsCell)->didTearOffActivation(exec, jsCast<JSActivation*>(activationCell)); - return; - } - jsCast<Arguments*>(argumentsCell)->tearOff(exec); -} - -void DFG_OPERATION operationTearOffInlinedArguments( - ExecState* exec, JSCell* argumentsCell, JSCell* activationCell, InlineCallFrame* inlineCallFrame) -{ - ASSERT_UNUSED(activationCell, !activationCell); // Currently, we don't inline functions with activations. - jsCast<Arguments*>(argumentsCell)->tearOff(exec, inlineCallFrame); + VM& vm = exec->vm(); + NativeCallFrameTracer target(&vm, exec); + + // We could pass the ScopedArgumentsTable* as an argument. We currently don't because I + // didn't feel like changing the max number of arguments for a slow path call from 6 to 7. + ScopedArgumentsTable* table = scope->symbolTable()->arguments(); + + return ScopedArguments::createByCopyingFrom( + vm, structure, argumentStart, length, callee, table, scope); } -EncodedJSValue DFG_OPERATION operationGetArgumentsLength(ExecState* exec, int32_t argumentsRegister) +JSCell* JIT_OPERATION operationCreateClonedArguments(ExecState* exec, Structure* structure, Register* argumentStart, int32_t length, JSFunction* callee) { VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - // Here we can assume that the argumernts were created. Because otherwise the JIT code would - // have not made this call. - Identifier ident(&vm, "length"); - JSValue baseValue = exec->uncheckedR(argumentsRegister).jsValue(); - PropertySlot slot(baseValue); - return JSValue::encode(baseValue.get(exec, ident, slot)); + NativeCallFrameTracer target(&vm, exec); + return ClonedArguments::createByCopyingFrom( + exec, structure, argumentStart, length, callee); } -EncodedJSValue DFG_OPERATION operationGetArgumentByVal(ExecState* exec, int32_t argumentsRegister, int32_t index) +JSCell* JIT_OPERATION operationCreateDirectArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, int32_t argumentCount) { VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - - JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue(); + NativeCallFrameTracer target(&vm, exec); + + DeferGCForAWhile deferGC(vm.heap); + + CodeBlock* codeBlock; + if (inlineCallFrame) + codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame); + else + codeBlock = exec->codeBlock(); + + unsigned length = argumentCount - 1; + unsigned capacity = std::max(length, static_cast<unsigned>(codeBlock->numParameters() - 1)); + DirectArguments* result = DirectArguments::create( + vm, codeBlock->globalObject()->directArgumentsStructure(), length, capacity); + + result->callee().set(vm, result, callee); - // If there are no arguments, and we're accessing out of bounds, then we have to create the - // arguments in case someone has installed a getter on a numeric property. - if (!argumentsValue) - exec->uncheckedR(argumentsRegister) = argumentsValue = Arguments::create(exec->vm(), exec); + Register* arguments = + exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) + + CallFrame::argumentOffset(0); + for (unsigned i = length; i--;) + result->setIndexQuickly(vm, i, arguments[i].jsValue()); - return JSValue::encode(argumentsValue.get(exec, index)); + return result; } -EncodedJSValue DFG_OPERATION operationGetInlinedArgumentByVal( - ExecState* exec, int32_t argumentsRegister, InlineCallFrame* inlineCallFrame, int32_t index) +JSCell* JIT_OPERATION operationCreateClonedArgumentsDuringExit(ExecState* exec, InlineCallFrame* inlineCallFrame, JSFunction* callee, int32_t argumentCount) { VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - - JSValue argumentsValue = exec->uncheckedR(argumentsRegister).jsValue(); + NativeCallFrameTracer target(&vm, exec); - // If there are no arguments, and we're accessing out of bounds, then we have to create the - // arguments in case someone has installed a getter on a numeric property. - if (!argumentsValue) { - exec->uncheckedR(argumentsRegister) = argumentsValue = - Arguments::create(exec->vm(), exec, inlineCallFrame); - } + DeferGCForAWhile deferGC(vm.heap); - return JSValue::encode(argumentsValue.get(exec, index)); + CodeBlock* codeBlock; + if (inlineCallFrame) + codeBlock = baselineCodeBlockForInlineCallFrame(inlineCallFrame); + else + codeBlock = exec->codeBlock(); + + unsigned length = argumentCount - 1; + ClonedArguments* result = ClonedArguments::createEmpty( + vm, codeBlock->globalObject()->outOfBandArgumentsStructure(), callee); + + Register* arguments = + exec->registers() + (inlineCallFrame ? inlineCallFrame->stackOffset : 0) + + CallFrame::argumentOffset(0); + for (unsigned i = length; i--;) + result->putDirectIndex(exec, i, arguments[i].jsValue()); + + result->putDirect(vm, vm.propertyNames->length, jsNumber(length)); + + return result; } -JSCell* DFG_OPERATION operationNewFunctionNoCheck(ExecState* exec, JSCell* functionExecutable) +void JIT_OPERATION operationCopyRest(ExecState* exec, JSCell* arrayAsCell, Register* argumentStart, unsigned numberOfParamsToSkip, unsigned arraySize) { - ASSERT(functionExecutable->inherits(&FunctionExecutable::s_info)); - VM& vm = exec->vm(); - NativeCallFrameTracer tracer(&vm, exec); - return JSFunction::create(exec, static_cast<FunctionExecutable*>(functionExecutable), exec->scope()); + ASSERT(arraySize); + JSArray* array = jsCast<JSArray*>(arrayAsCell); + ASSERT(arraySize == array->length()); + array->setLength(exec, arraySize); + for (unsigned i = 0; i < arraySize; i++) + array->putDirectIndex(exec, i, argumentStart[i + numberOfParamsToSkip].jsValue()); } -EncodedJSValue DFG_OPERATION operationNewFunction(ExecState* exec, JSCell* functionExecutable) +size_t JIT_OPERATION operationObjectIsObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) { - ASSERT(functionExecutable->inherits(&FunctionExecutable::s_info)); VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - return JSValue::encode(JSFunction::create(exec, static_cast<FunctionExecutable*>(functionExecutable), exec->scope())); + + ASSERT(jsDynamicCast<JSObject*>(object)); + + if (object->structure(vm)->masqueradesAsUndefined(globalObject)) + return false; + if (object->type() == JSFunctionType) + return false; + if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { + CallData callData; + if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) + return false; + } + + return true; } -JSCell* DFG_OPERATION operationNewFunctionExpression(ExecState* exec, JSCell* functionExecutableAsCell) +size_t JIT_OPERATION operationObjectIsFunction(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) { - ASSERT(functionExecutableAsCell->inherits(&FunctionExecutable::s_info)); - VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - FunctionExecutable* functionExecutable = - static_cast<FunctionExecutable*>(functionExecutableAsCell); - return JSFunction::create(exec, functionExecutable, exec->scope()); -} - -size_t DFG_OPERATION operationIsObject(ExecState* exec, EncodedJSValue value) -{ - return jsIsObjectType(exec, JSValue::decode(value)); + ASSERT(jsDynamicCast<JSObject*>(object)); + + if (object->structure(vm)->masqueradesAsUndefined(globalObject)) + return false; + if (object->type() == JSFunctionType) + return true; + if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { + CallData callData; + if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) + return true; + } + + return false; } -size_t DFG_OPERATION operationIsFunction(EncodedJSValue value) +JSCell* JIT_OPERATION operationTypeOfObject(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) { - return jsIsFunctionType(JSValue::decode(value)); -} + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); -JSCell* DFG_OPERATION operationTypeOf(ExecState* exec, JSCell* value) -{ - return jsTypeStringForValue(exec, JSValue(value)).asCell(); + ASSERT(jsDynamicCast<JSObject*>(object)); + + if (object->structure(vm)->masqueradesAsUndefined(globalObject)) + return vm.smallStrings.undefinedString(); + if (object->type() == JSFunctionType) + return vm.smallStrings.functionString(); + if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { + CallData callData; + if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) + return vm.smallStrings.functionString(); + } + + return vm.smallStrings.objectString(); } -void DFG_OPERATION operationReallocateStorageAndFinishPut(ExecState* exec, JSObject* base, Structure* structure, PropertyOffset offset, EncodedJSValue value) +int32_t JIT_OPERATION operationTypeOfObjectAsTypeofType(ExecState* exec, JSGlobalObject* globalObject, JSCell* object) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - ASSERT(structure->outOfLineCapacity() > base->structure()->outOfLineCapacity()); - ASSERT(!vm.heap.storageAllocator().fastPathShouldSucceed(structure->outOfLineCapacity() * sizeof(JSValue))); - base->setStructureAndReallocateStorageIfNecessary(vm, structure); - base->putDirect(vm, offset, JSValue::decode(value)); + ASSERT(jsDynamicCast<JSObject*>(object)); + + if (object->structure(vm)->masqueradesAsUndefined(globalObject)) + return static_cast<int32_t>(TypeofType::Undefined); + if (object->type() == JSFunctionType) + return static_cast<int32_t>(TypeofType::Function); + if (object->inlineTypeFlags() & TypeOfShouldCallGetCallData) { + CallData callData; + if (object->methodTable(vm)->getCallData(object, callData) != CallTypeNone) + return static_cast<int32_t>(TypeofType::Function); + } + + return static_cast<int32_t>(TypeofType::Object); } -char* DFG_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState* exec) +char* JIT_OPERATION operationAllocatePropertyStorageWithInitialCapacity(ExecState* exec) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); return reinterpret_cast<char*>( - Butterfly::createUninitialized(vm, 0, initialOutOfLineCapacity, false, 0)); + Butterfly::createUninitialized(vm, 0, 0, initialOutOfLineCapacity, false, 0)); } -char* DFG_OPERATION operationAllocatePropertyStorage(ExecState* exec, size_t newSize) +char* JIT_OPERATION operationAllocatePropertyStorage(ExecState* exec, size_t newSize) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); return reinterpret_cast<char*>( - Butterfly::createUninitialized(vm, 0, newSize, false, 0)); + Butterfly::createUninitialized(vm, 0, 0, newSize, false, 0)); } -char* DFG_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState* exec, JSObject* object) +char* JIT_OPERATION operationReallocateButterflyToHavePropertyStorageWithInitialCapacity(ExecState* exec, JSObject* object) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); ASSERT(!object->structure()->outOfLineCapacity()); + DeferGC deferGC(vm.heap); Butterfly* result = object->growOutOfLineStorage(vm, 0, initialOutOfLineCapacity); - object->setButterflyWithoutChangingStructure(result); + object->setButterflyWithoutChangingStructure(vm, result); return reinterpret_cast<char*>(result); } -char* DFG_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState* exec, JSObject* object, size_t newSize) +char* JIT_OPERATION operationReallocateButterflyToGrowPropertyStorage(ExecState* exec, JSObject* object, size_t newSize) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); + DeferGC deferGC(vm.heap); Butterfly* result = object->growOutOfLineStorage(vm, object->structure()->outOfLineCapacity(), newSize); - object->setButterflyWithoutChangingStructure(result); + object->setButterflyWithoutChangingStructure(vm, result); return reinterpret_cast<char*>(result); } -char* DFG_OPERATION operationEnsureInt32(ExecState* exec, JSCell* cell) +char* JIT_OPERATION operationEnsureInt32(ExecState* exec, JSCell* cell) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -1563,7 +1107,7 @@ char* DFG_OPERATION operationEnsureInt32(ExecState* exec, JSCell* cell) return reinterpret_cast<char*>(asObject(cell)->ensureInt32(vm).data()); } -char* DFG_OPERATION operationEnsureDouble(ExecState* exec, JSCell* cell) +char* JIT_OPERATION operationEnsureDouble(ExecState* exec, JSCell* cell) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -1574,7 +1118,7 @@ char* DFG_OPERATION operationEnsureDouble(ExecState* exec, JSCell* cell) return reinterpret_cast<char*>(asObject(cell)->ensureDouble(vm).data()); } -char* DFG_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell) +char* JIT_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -1585,45 +1129,42 @@ char* DFG_OPERATION operationEnsureContiguous(ExecState* exec, JSCell* cell) return reinterpret_cast<char*>(asObject(cell)->ensureContiguous(vm).data()); } -char* DFG_OPERATION operationRageEnsureContiguous(ExecState* exec, JSCell* cell) +char* JIT_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); if (!cell->isObject()) return 0; - - return reinterpret_cast<char*>(asObject(cell)->rageEnsureContiguous(vm).data()); + + return reinterpret_cast<char*>(asObject(cell)->ensureArrayStorage(vm)); } -char* DFG_OPERATION operationEnsureArrayStorage(ExecState* exec, JSCell* cell) +StringImpl* JIT_OPERATION operationResolveRope(ExecState* exec, JSString* string) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - - if (!cell->isObject()) - return 0; - return reinterpret_cast<char*>(asObject(cell)->ensureArrayStorage(vm)); + return string->value(exec).impl(); } -StringImpl* DFG_OPERATION operationResolveRope(ExecState* exec, JSString* string) +JSString* JIT_OPERATION operationSingleCharacterString(ExecState* exec, int32_t character) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - - return string->value(exec).impl(); + + return jsSingleCharacterString(exec, static_cast<UChar>(character)); } -JSCell* DFG_OPERATION operationNewStringObject(ExecState* exec, JSString* string, Structure* structure) +JSCell* JIT_OPERATION operationNewStringObject(ExecState* exec, JSString* string, Structure* structure) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - return StringObject::create(exec, structure, string); + return StringObject::create(vm, structure, string); } -JSCell* DFG_OPERATION operationToStringOnCell(ExecState* exec, JSCell* cell) +JSCell* JIT_OPERATION operationToStringOnCell(ExecState* exec, JSCell* cell) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -1631,7 +1172,7 @@ JSCell* DFG_OPERATION operationToStringOnCell(ExecState* exec, JSCell* cell) return JSValue(cell).toString(exec); } -JSCell* DFG_OPERATION operationToString(ExecState* exec, EncodedJSValue value) +JSCell* JIT_OPERATION operationToString(ExecState* exec, EncodedJSValue value) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); @@ -1639,96 +1180,215 @@ JSCell* DFG_OPERATION operationToString(ExecState* exec, EncodedJSValue value) return JSValue::decode(value).toString(exec); } -JSCell* DFG_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSString* right) +JSCell* JIT_OPERATION operationCallStringConstructorOnCell(ExecState* exec, JSCell* cell) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + return stringConstructor(exec, cell); +} + +JSCell* JIT_OPERATION operationCallStringConstructor(ExecState* exec, EncodedJSValue value) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + return stringConstructor(exec, JSValue::decode(value)); +} + +JSCell* JIT_OPERATION operationMakeRope2(ExecState* exec, JSString* left, JSString* right) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - if (static_cast<int32_t>(left->length() + right->length()) < 0) { + if (sumOverflows<int32_t>(left->length(), right->length())) { throwOutOfMemoryError(exec); - return 0; + return nullptr; } return JSRopeString::create(vm, left, right); } -JSCell* DFG_OPERATION operationMakeRope3(ExecState* exec, JSString* a, JSString* b, JSString* c) +JSCell* JIT_OPERATION operationMakeRope3(ExecState* exec, JSString* a, JSString* b, JSString* c) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); - Checked<int32_t, RecordOverflow> length = a->length(); - length += b->length(); - length += c->length(); - if (length.hasOverflowed()) { + if (sumOverflows<int32_t>(a->length(), b->length(), c->length())) { throwOutOfMemoryError(exec); - return 0; + return nullptr; } return JSRopeString::create(vm, a, b, c); } -double DFG_OPERATION operationFModOnInts(int32_t a, int32_t b) +JSCell* JIT_OPERATION operationStrCat2(ExecState* exec, EncodedJSValue a, EncodedJSValue b) { - return fmod(a, b); + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + JSString* str1 = JSValue::decode(a).toString(exec); + ASSERT(!vm.exception()); // Impossible, since we must have been given primitives. + JSString* str2 = JSValue::decode(b).toString(exec); + ASSERT(!vm.exception()); + + if (sumOverflows<int32_t>(str1->length(), str2->length())) { + throwOutOfMemoryError(exec); + return nullptr; + } + + return JSRopeString::create(vm, str1, str2); } + +JSCell* JIT_OPERATION operationStrCat3(ExecState* exec, EncodedJSValue a, EncodedJSValue b, EncodedJSValue c) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + JSString* str1 = JSValue::decode(a).toString(exec); + ASSERT(!vm.exception()); // Impossible, since we must have been given primitives. + JSString* str2 = JSValue::decode(b).toString(exec); + ASSERT(!vm.exception()); + JSString* str3 = JSValue::decode(c).toString(exec); + ASSERT(!vm.exception()); + + if (sumOverflows<int32_t>(str1->length(), str2->length(), str3->length())) { + throwOutOfMemoryError(exec); + return nullptr; + } -JSCell* DFG_OPERATION operationStringFromCharCode(ExecState* exec, int32_t op1) + return JSRopeString::create(vm, str1, str2, str3); +} + +char* JIT_OPERATION operationFindSwitchImmTargetForDouble( + ExecState* exec, EncodedJSValue encodedValue, size_t tableIndex) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); - return JSC::stringFromCharCode(exec, op1); + CodeBlock* codeBlock = exec->codeBlock(); + SimpleJumpTable& table = codeBlock->switchJumpTable(tableIndex); + JSValue value = JSValue::decode(encodedValue); + ASSERT(value.isDouble()); + double asDouble = value.asDouble(); + int32_t asInt32 = static_cast<int32_t>(asDouble); + if (asDouble == asInt32) + return static_cast<char*>(table.ctiForValue(asInt32).executableAddress()); + return static_cast<char*>(table.ctiDefault.executableAddress()); } -DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState* exec, uint32_t callIndex) +char* JIT_OPERATION operationSwitchString(ExecState* exec, size_t tableIndex, JSString* string) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); - JSValue exceptionValue = exec->exception(); - ASSERT(exceptionValue); - - unsigned vPCIndex = exec->codeBlock()->bytecodeOffsetForCallAtIndex(callIndex); - ExceptionHandler handler = genericThrow(vm, exec, exceptionValue, vPCIndex); - ASSERT(handler.catchRoutine); - return dfgHandlerEncoded(handler.callFrame, handler.catchRoutine); + return static_cast<char*>(exec->codeBlock()->stringSwitchJumpTable(tableIndex).ctiForValue(string->value(exec).impl()).executableAddress()); } -DFGHandlerEncoded DFG_OPERATION lookupExceptionHandlerInStub(ExecState* exec, StructureStubInfo* stubInfo) +int32_t JIT_OPERATION operationSwitchStringAndGetBranchOffset(ExecState* exec, size_t tableIndex, JSString* string) { - VM* vm = &exec->vm(); - NativeCallFrameTracer tracer(vm, exec); + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + return exec->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(string->value(exec).impl(), std::numeric_limits<int32_t>::min()); +} + +char* JIT_OPERATION operationGetButterfly(ExecState* exec, JSCell* cell) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + return bitwise_cast<char*>(jsCast<JSObject*>(cell)->butterfly()); +} + +char* JIT_OPERATION operationGetArrayBufferVector(ExecState* exec, JSCell* cell) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); - JSValue exceptionValue = exec->exception(); - ASSERT(exceptionValue); + return bitwise_cast<char*>(jsCast<JSArrayBufferView*>(cell)->vector()); +} + +void JIT_OPERATION operationNotifyWrite(ExecState* exec, WatchpointSet* set) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + + set->touch("Executed NotifyWrite"); +} + +void JIT_OPERATION operationThrowStackOverflowForVarargs(ExecState* exec) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + throwStackOverflowError(exec); +} + +int32_t JIT_OPERATION operationSizeOfVarargs(ExecState* exec, EncodedJSValue encodedArguments, int32_t firstVarArgOffset) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + JSValue arguments = JSValue::decode(encodedArguments); + + return sizeOfVarargs(exec, arguments, firstVarArgOffset); +} + +void JIT_OPERATION operationLoadVarargs(ExecState* exec, int32_t firstElementDest, EncodedJSValue encodedArguments, int32_t offset, int32_t length, int32_t mandatoryMinimum) +{ + VM& vm = exec->vm(); + NativeCallFrameTracer tracer(&vm, exec); + JSValue arguments = JSValue::decode(encodedArguments); - CodeOrigin codeOrigin = stubInfo->codeOrigin; - while (codeOrigin.inlineCallFrame) - codeOrigin = codeOrigin.inlineCallFrame->caller; + loadVarargs(exec, VirtualRegister(firstElementDest), arguments, offset, length); - ExceptionHandler handler = genericThrow(vm, exec, exceptionValue, codeOrigin.bytecodeIndex); - ASSERT(handler.catchRoutine); - return dfgHandlerEncoded(handler.callFrame, handler.catchRoutine); + for (int32_t i = length; i < mandatoryMinimum; ++i) + exec->r(firstElementDest + i) = jsUndefined(); } -size_t DFG_OPERATION dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value) +double JIT_OPERATION operationFModOnInts(int32_t a, int32_t b) +{ + return fmod(a, b); +} + +#if USE(JSVALUE32_64) +double JIT_OPERATION operationRandom(JSGlobalObject* globalObject) +{ + return globalObject->weakRandomNumber(); +} +#endif + +JSCell* JIT_OPERATION operationStringFromCharCode(ExecState* exec, int32_t op1) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - - // toInt32/toUInt32 return the same value; we want the value zero extended to fill the register. - return JSValue::decode(value).toUInt32(exec); + return JSC::stringFromCharCode(exec, op1); } -size_t DFG_OPERATION dfgConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp) +EncodedJSValue JIT_OPERATION operationStringFromCharCodeUntyped(ExecState* exec, EncodedJSValue encodedValue) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); - - return JSValue::decode(encodedOp).toBoolean(exec); + JSValue charValue = JSValue::decode(encodedValue); + int32_t chInt = charValue.toUInt32(exec); + return JSValue::encode(JSC::stringFromCharCode(exec, chInt)); } -void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* debugInfoRaw, void* scratch) +int64_t JIT_OPERATION operationConvertBoxedDoubleToInt52(EncodedJSValue encodedValue) +{ + JSValue value = JSValue::decode(encodedValue); + if (!value.isDouble()) + return JSValue::notInt52; + return tryConvertToInt52(value.asDouble()); +} + +int64_t JIT_OPERATION operationConvertDoubleToInt52(double value) +{ + return tryConvertToInt52(value); +} + +void JIT_OPERATION operationProcessTypeProfilerLogDFG(ExecState* exec) +{ + exec->vm().typeProfilerLog()->processLogEntries(ASCIILiteral("Log Full, called from inside DFG.")); +} + +void JIT_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* debugInfoRaw, void* scratch) { VM* vm = &exec->vm(); NativeCallFrameTracer tracer(vm, exec); @@ -1736,8 +1396,8 @@ void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw); CodeBlock* codeBlock = debugInfo->codeBlock; CodeBlock* alternative = codeBlock->alternative(); - dataLog( - "Speculation failure in ", *codeBlock, " with "); + dataLog("Speculation failure in ", *codeBlock); + dataLog(" @ exit #", vm->osrExitIndex, " (bc#", debugInfo->bytecodeOffset, ", ", exitKindToString(debugInfo->kind), ") with "); if (alternative) { dataLog( "executeCounter = ", alternative->jitExecuteCounter(), @@ -1766,112 +1426,272 @@ void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState* exec, void* dataLog("\n"); } -extern "C" void DFG_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock) +extern "C" void JIT_OPERATION triggerReoptimizationNow(CodeBlock* codeBlock, OSRExitBase* exit) { -#if ENABLE(JIT_VERBOSE_OSR) - dataLog(*codeBlock, ": Entered reoptimize\n"); -#endif + // It's sort of preferable that we don't GC while in here. Anyways, doing so wouldn't + // really be profitable. + DeferGCForAWhile deferGC(codeBlock->vm()->heap); + + if (Options::verboseOSR()) + dataLog(*codeBlock, ": Entered reoptimize\n"); // We must be called with the baseline code block. - ASSERT(JITCode::isBaselineCode(codeBlock->getJITType())); + ASSERT(JITCode::isBaselineCode(codeBlock->jitType())); // If I am my own replacement, then reoptimization has already been triggered. // This can happen in recursive functions. - if (codeBlock->replacement() == codeBlock) + if (codeBlock->replacement() == codeBlock) { + if (Options::verboseOSR()) + dataLog(*codeBlock, ": Not reoptimizing because we've already been jettisoned.\n"); return; - + } + // Otherwise, the replacement must be optimized code. Use this as an opportunity // to check our logic. ASSERT(codeBlock->hasOptimizedReplacement()); - ASSERT(codeBlock->replacement()->getJITType() == JITCode::DFGJIT); + CodeBlock* optimizedCodeBlock = codeBlock->replacement(); + ASSERT(JITCode::isOptimizingJIT(optimizedCodeBlock->jitType())); + + bool didTryToEnterIntoInlinedLoops = false; + for (InlineCallFrame* inlineCallFrame = exit->m_codeOrigin.inlineCallFrame; inlineCallFrame; inlineCallFrame = inlineCallFrame->directCaller.inlineCallFrame) { + if (inlineCallFrame->baselineCodeBlock->ownerScriptExecutable()->didTryToEnterInLoop()) { + didTryToEnterIntoInlinedLoops = true; + break; + } + } - codeBlock->reoptimize(); + // In order to trigger reoptimization, one of two things must have happened: + // 1) We exited more than some number of times. + // 2) We exited and got stuck in a loop, and now we're exiting again. + bool didExitABunch = optimizedCodeBlock->shouldReoptimizeNow(); + bool didGetStuckInLoop = + (codeBlock->checkIfOptimizationThresholdReached() || didTryToEnterIntoInlinedLoops) + && optimizedCodeBlock->shouldReoptimizeFromLoopNow(); + + if (!didExitABunch && !didGetStuckInLoop) { + if (Options::verboseOSR()) + dataLog(*codeBlock, ": Not reoptimizing ", *optimizedCodeBlock, " because it either didn't exit enough or didn't loop enough after exit.\n"); + codeBlock->optimizeAfterLongWarmUp(); + return; + } + + optimizedCodeBlock->jettison(Profiler::JettisonDueToOSRExit, CountReoptimization); } -} // extern "C" -} } // namespace JSC::DFG +#if ENABLE(FTL_JIT) +static bool shouldTriggerFTLCompile(CodeBlock* codeBlock, JITCode* jitCode) +{ + if (codeBlock->baselineVersion()->m_didFailFTLCompilation) { + if (Options::verboseOSR()) + dataLog("Deferring FTL-optimization of ", *codeBlock, " indefinitely because there was an FTL failure.\n"); + jitCode->dontOptimizeAnytimeSoon(codeBlock); + return false; + } -#endif // ENABLE(DFG_JIT) + if (!codeBlock->hasOptimizedReplacement() + && !jitCode->checkIfOptimizationThresholdReached(codeBlock)) { + if (Options::verboseOSR()) + dataLog("Choosing not to FTL-optimize ", *codeBlock, " yet.\n"); + return false; + } + return true; +} -namespace JSC { - -#if COMPILER(GCC) && CPU(X86_64) -asm ( -".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" -HIDE_SYMBOL(getHostCallReturnValue) "\n" -SYMBOL_STRING(getHostCallReturnValue) ":" "\n" - "mov -40(%r13), %r13\n" - "mov %r13, %rdi\n" - "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" -); -#elif COMPILER(GCC) && CPU(X86) -asm ( -".text" "\n" \ -".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" -HIDE_SYMBOL(getHostCallReturnValue) "\n" -SYMBOL_STRING(getHostCallReturnValue) ":" "\n" - "mov -40(%edi), %edi\n" - "mov %edi, 4(%esp)\n" - "jmp " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" -); -#elif COMPILER(GCC) && CPU(ARM_THUMB2) -asm ( -".text" "\n" -".align 2" "\n" -".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" -HIDE_SYMBOL(getHostCallReturnValue) "\n" -".thumb" "\n" -".thumb_func " THUMB_FUNC_PARAM(getHostCallReturnValue) "\n" -SYMBOL_STRING(getHostCallReturnValue) ":" "\n" - "ldr r5, [r5, #-40]" "\n" - "mov r0, r5" "\n" - "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" -); -#elif COMPILER(GCC) && CPU(ARM_TRADITIONAL) -asm ( -".text" "\n" -".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" -HIDE_SYMBOL(getHostCallReturnValue) "\n" -INLINE_ARM_FUNCTION(getHostCallReturnValue) -SYMBOL_STRING(getHostCallReturnValue) ":" "\n" - "ldr r5, [r5, #-40]" "\n" - "mov r0, r5" "\n" - "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" -); -#elif COMPILER(GCC) && CPU(MIPS) -asm( -".text" "\n" -".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" -HIDE_SYMBOL(getHostCallReturnValue) "\n" -SYMBOL_STRING(getHostCallReturnValue) ":" "\n" - LOAD_FUNCTION_TO_T9(getHostCallReturnValueWithExecState) - "lw $s0, -40($s0)" "\n" - "move $a0, $s0" "\n" - "b " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "\n" -); -#elif COMPILER(GCC) && CPU(SH4) -asm( -".text" "\n" -".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" -HIDE_SYMBOL(getHostCallReturnValue) "\n" -SYMBOL_STRING(getHostCallReturnValue) ":" "\n" - "add #-40, r14" "\n" - "mov.l @r14, r14" "\n" - "mov r14, r4" "\n" - "mov.l 2f, " SH4_SCRATCH_REGISTER "\n" - "braf " SH4_SCRATCH_REGISTER "\n" - "nop" "\n" - "1: .balign 4" "\n" - "2: .long " LOCAL_REFERENCE(getHostCallReturnValueWithExecState) "-1b\n" -); -#endif +static void triggerFTLReplacementCompile(VM* vm, CodeBlock* codeBlock, JITCode* jitCode) +{ + Worklist::State worklistState; + if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) { + worklistState = worklist->completeAllReadyPlansForVM( + *vm, CompilationKey(codeBlock->baselineVersion(), FTLMode)); + } else + worklistState = Worklist::NotKnown; + + if (worklistState == Worklist::Compiling) { + jitCode->setOptimizationThresholdBasedOnCompilationResult( + codeBlock, CompilationDeferred); + return; + } + + if (codeBlock->hasOptimizedReplacement()) { + // That's great, we've compiled the code - next time we call this function, + // we'll enter that replacement. + jitCode->optimizeSoon(codeBlock); + return; + } + + if (worklistState == Worklist::Compiled) { + // This means that we finished compiling, but failed somehow; in that case the + // thresholds will be set appropriately. + if (Options::verboseOSR()) + dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n"); + return; + } + + // We need to compile the code. + compile( + *vm, codeBlock->newReplacement(), codeBlock, FTLMode, UINT_MAX, + Operands<JSValue>(), ToFTLDeferredCompilationCallback::create()); + + // If we reached here, the counter has not be reset. Do that now. + jitCode->setOptimizationThresholdBasedOnCompilationResult( + codeBlock, CompilationDeferred); +} + +static void triggerTierUpNowCommon(ExecState* exec, bool inLoop) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); + DeferGC deferGC(vm->heap); + CodeBlock* codeBlock = exec->codeBlock(); + + if (codeBlock->jitType() != JITCode::DFGJIT) { + dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n"); + RELEASE_ASSERT_NOT_REACHED(); + } + + JITCode* jitCode = codeBlock->jitCode()->dfg(); + + if (Options::verboseOSR()) { + dataLog( + *codeBlock, ": Entered triggerTierUpNow with executeCounter = ", + jitCode->tierUpCounter, "\n"); + } + if (inLoop) + jitCode->nestedTriggerIsSet = 1; -extern "C" EncodedJSValue HOST_CALL_RETURN_VALUE_OPTION getHostCallReturnValueWithExecState(ExecState* exec) + if (shouldTriggerFTLCompile(codeBlock, jitCode)) + triggerFTLReplacementCompile(vm, codeBlock, jitCode); +} + +void JIT_OPERATION triggerTierUpNow(ExecState* exec) +{ + triggerTierUpNowCommon(exec, false); +} + +void JIT_OPERATION triggerTierUpNowInLoop(ExecState* exec) { - if (!exec) - return JSValue::encode(JSValue()); - return JSValue::encode(exec->vm().hostCallReturnValue); + triggerTierUpNowCommon(exec, true); +} + +char* JIT_OPERATION triggerOSREntryNow( + ExecState* exec, int32_t bytecodeIndex, int32_t streamIndex) +{ + VM* vm = &exec->vm(); + NativeCallFrameTracer tracer(vm, exec); + DeferGC deferGC(vm->heap); + CodeBlock* codeBlock = exec->codeBlock(); + + if (codeBlock->jitType() != JITCode::DFGJIT) { + dataLog("Unexpected code block in DFG->FTL tier-up: ", *codeBlock, "\n"); + RELEASE_ASSERT_NOT_REACHED(); + } + + JITCode* jitCode = codeBlock->jitCode()->dfg(); + jitCode->nestedTriggerIsSet = 0; + + if (Options::verboseOSR()) { + dataLog( + *codeBlock, ": Entered triggerOSREntryNow with executeCounter = ", + jitCode->tierUpCounter, "\n"); + } + + // - If we don't have an FTL code block, then try to compile one. + // - If we do have an FTL code block, then try to enter for a while. + // - If we couldn't enter for a while, then trigger OSR entry. + + if (!shouldTriggerFTLCompile(codeBlock, jitCode)) + return nullptr; + + if (!jitCode->neverExecutedEntry) { + triggerFTLReplacementCompile(vm, codeBlock, jitCode); + + if (!codeBlock->hasOptimizedReplacement()) + return nullptr; + + if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) { + jitCode->osrEntryRetry++; + return nullptr; + } + } + + // It's time to try to compile code for OSR entry. + Worklist::State worklistState; + if (Worklist* worklist = existingGlobalFTLWorklistOrNull()) { + worklistState = worklist->completeAllReadyPlansForVM( + *vm, CompilationKey(codeBlock->baselineVersion(), FTLForOSREntryMode)); + } else + worklistState = Worklist::NotKnown; + + if (worklistState == Worklist::Compiling) { + jitCode->setOptimizationThresholdBasedOnCompilationResult( + codeBlock, CompilationDeferred); + return nullptr; + } + + if (CodeBlock* entryBlock = jitCode->osrEntryBlock()) { + void* address = FTL::prepareOSREntry( + exec, codeBlock, entryBlock, bytecodeIndex, streamIndex); + if (address) + return static_cast<char*>(address); + + if (jitCode->osrEntryRetry < Options::ftlOSREntryRetryThreshold()) { + jitCode->osrEntryRetry++; + return nullptr; + } + + FTL::ForOSREntryJITCode* entryCode = entryBlock->jitCode()->ftlForOSREntry(); + entryCode->countEntryFailure(); + if (entryCode->entryFailureCount() < + Options::ftlOSREntryFailureCountForReoptimization()) { + jitCode->optimizeSoon(codeBlock); + return nullptr; + } + + // OSR entry failed. Oh no! This implies that we need to retry. We retry + // without exponential backoff and we only do this for the entry code block. + jitCode->clearOSREntryBlock(); + jitCode->osrEntryRetry = 0; + return nullptr; + } + + if (worklistState == Worklist::Compiled) { + // This means that compilation failed and we already set the thresholds. + if (Options::verboseOSR()) + dataLog("Code block ", *codeBlock, " was compiled but it doesn't have an optimized replacement.\n"); + return nullptr; + } + + // We aren't compiling and haven't compiled anything for OSR entry. So, try to compile + // something. + Operands<JSValue> mustHandleValues; + jitCode->reconstruct( + exec, codeBlock, CodeOrigin(bytecodeIndex), streamIndex, mustHandleValues); + CodeBlock* replacementCodeBlock = codeBlock->newReplacement(); + CompilationResult forEntryResult = compile( + *vm, replacementCodeBlock, codeBlock, FTLForOSREntryMode, bytecodeIndex, + mustHandleValues, ToFTLForOSREntryDeferredCompilationCallback::create()); + + if (jitCode->neverExecutedEntry) + triggerFTLReplacementCompile(vm, codeBlock, jitCode); + + if (forEntryResult != CompilationSuccessful) { + jitCode->setOptimizationThresholdBasedOnCompilationResult( + codeBlock, CompilationDeferred); + return nullptr; + } + + // It's possible that the for-entry compile already succeeded. In that case OSR + // entry will succeed unless we ran out of stack. It's not clear what we should do. + // We signal to try again after a while if that happens. + void* address = FTL::prepareOSREntry( + exec, codeBlock, jitCode->osrEntryBlock(), bytecodeIndex, streamIndex); + return static_cast<char*>(address); } -} // namespace JSC +#endif // ENABLE(FTL_JIT) + +} // extern "C" +} } // namespace JSC::DFG + +#endif // ENABLE(DFG_JIT) #endif // ENABLE(JIT) |