summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/dfg/DFGOperations.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGOperations.cpp')
-rw-r--r--Source/JavaScriptCore/dfg/DFGOperations.cpp2154
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)