diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-01-06 14:44:00 +0100 |
commit | 40736c5763bf61337c8c14e16d8587db021a87d4 (patch) | |
tree | b17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/JavaScriptCore/dfg/DFGOperations.cpp | |
download | qtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz |
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGOperations.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGOperations.cpp | 838 |
1 files changed, 838 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGOperations.cpp b/Source/JavaScriptCore/dfg/DFGOperations.cpp new file mode 100644 index 000000000..7b4ef3f88 --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGOperations.cpp @@ -0,0 +1,838 @@ +/* + * Copyright (C) 2011 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "DFGOperations.h" + +#if ENABLE(DFG_JIT) + +#include "CodeBlock.h" +#include "DFGOSRExit.h" +#include "DFGRepatch.h" +#include "InlineASM.h" +#include "Interpreter.h" +#include "JSByteArray.h" +#include "JSGlobalData.h" +#include "Operations.h" + +#if CPU(X86_64) + +#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, register) \ + asm( \ + ".globl " SYMBOL_STRING(function) "\n" \ + SYMBOL_STRING(function) ":" "\n" \ + "mov (%rsp), %" STRINGIZE(register) "\n" \ + "jmp " SYMBOL_STRING_RELOCATION(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 CPU(X86) + +#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, offset) \ + asm( \ + ".globl " SYMBOL_STRING(function) "\n" \ + SYMBOL_STRING(function) ":" "\n" \ + "mov (%esp), %eax\n" \ + "mov %eax, " STRINGIZE(offset) "(%esp)\n" \ + "jmp " SYMBOL_STRING_RELOCATION(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" \ + "cpy a2, lr" "\n" \ + "b " SYMBOL_STRING_RELOCATION(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" \ + "cpy a4, lr" "\n" \ + "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \ + ); + +#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" \ + "str lr, [sp, #0]" "\n" \ + "b " SYMBOL_STRING_RELOCATION(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" \ + "str lr, [sp, #4]" "\n" \ + "b " SYMBOL_STRING_RELOCATION(function) "WithReturnAddress" "\n" \ + ); + +#endif + +#define P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(function) \ +void* DFG_OPERATION function##WithReturnAddress(ExecState*, ReturnAddressPtr); \ +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); \ +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); \ +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); \ +FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(function) + +namespace JSC { namespace DFG { + +static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, JSValue value) +{ + JSGlobalData* globalData = &exec->globalData(); + + if (isJSArray(baseValue)) { + JSArray* array = asArray(baseValue); + if (array->canSetIndex(index)) { + array->setIndex(*globalData, index, value); + return; + } + + JSArray::putByIndex(array, exec, index, value); + return; + } + + if (isJSByteArray(baseValue) && asByteArray(baseValue)->canAccessIndex(index)) { + JSByteArray* byteArray = asByteArray(baseValue); + // FIXME: the JITstub used to relink this to an optimized form! + if (value.isInt32()) { + byteArray->setIndex(index, value.asInt32()); + return; + } + + if (value.isNumber()) { + byteArray->setIndex(index, value.asNumber()); + return; + } + } + + baseValue.put(exec, index, value); +} + +template<bool strict> +ALWAYS_INLINE static void DFG_OPERATION operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) +{ + JSValue baseValue = JSValue::decode(encodedBase); + JSValue property = JSValue::decode(encodedProperty); + JSValue value = JSValue::decode(encodedValue); + + if (LIKELY(property.isUInt32())) { + putByVal(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(exec, baseValue, propertyAsUInt32, value); + return; + } + } + + JSGlobalData* globalData = &exec->globalData(); + + // Don't put to an object if toString throws an exception. + Identifier ident(exec, property.toString(exec)); + if (!globalData->exception) { + PutPropertySlot slot(strict); + baseValue.put(exec, ident, value, slot); + } +} + +extern "C" { + +EncodedJSValue DFG_OPERATION operationConvertThis(ExecState* exec, EncodedJSValue encodedOp) +{ + return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec)); +} + +inline JSCell* createThis(ExecState* exec, JSCell* prototype, JSFunction* constructor) +{ +#if !ASSERT_DISABLED + ConstructData constructData; + ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS); +#endif + + JSGlobalData& globalData = exec->globalData(); + + Structure* structure; + if (prototype->isObject()) + structure = asObject(prototype)->inheritorID(globalData); + else + structure = constructor->scope()->globalObject->emptyObjectStructure(); + + return constructEmptyObject(exec, structure); +} + +JSCell* DFG_OPERATION operationCreateThis(ExecState* exec, JSCell* prototype) +{ + return createThis(exec, prototype, asFunction(exec->callee())); +} + +JSCell* DFG_OPERATION operationCreateThisInlined(ExecState* exec, JSCell* prototype, JSCell* constructor) +{ + return createThis(exec, prototype, static_cast<JSFunction*>(constructor)); +} + +JSCell* DFG_OPERATION operationNewObject(ExecState* exec) +{ + return constructEmptyObject(exec); +} + +EncodedJSValue DFG_OPERATION operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + JSValue op1 = JSValue::decode(encodedOp1); + JSValue op2 = JSValue::decode(encodedOp2); + + return JSValue::encode(jsAdd(exec, op1, op2)); +} + +EncodedJSValue DFG_OPERATION operationValueAddNotNumber(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + JSValue op1 = JSValue::decode(encodedOp1); + JSValue op2 = JSValue::decode(encodedOp2); + + ASSERT(!op1.isNumber() || !op2.isNumber()); + + if (op1.isString()) { + if (op2.isString()) + return JSValue::encode(jsString(exec, asString(op1), asString(op2))); + return JSValue::encode(jsString(exec, asString(op1), op2.toPrimitiveString(exec))); + } + + return JSValue::encode(jsAddSlowCase(exec, op1, op2)); +} + +static inline EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index) +{ + // FIXME: the JIT used to handle these in compiled code! + if (isJSArray(base) && asArray(base)->canGetIndex(index)) + return JSValue::encode(asArray(base)->getIndex(index)); + + // FIXME: the JITstub used to relink this to an optimized form! + if (isJSString(base) && asString(base)->canGetIndex(index)) + return JSValue::encode(asString(base)->getIndex(exec, index)); + + // FIXME: the JITstub used to relink this to an optimized form! + if (isJSByteArray(base) && asByteArray(base)->canAccessIndex(index)) + return JSValue::encode(asByteArray(base)->getIndex(exec, index)); + + return JSValue::encode(JSValue(base).get(exec, index)); +} + +EncodedJSValue DFG_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) +{ + JSValue baseValue = JSValue::decode(encodedBase); + JSValue property = JSValue::decode(encodedProperty); + + if (LIKELY(baseValue.isCell())) { + JSCell* base = baseValue.asCell(); + + if (property.isUInt32()) { + return getByVal(exec, base, property.asUInt32()); + } else if (property.isDouble()) { + double propertyAsDouble = property.asDouble(); + uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); + 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); + } + } + + Identifier ident(exec, property.toString(exec)); + return JSValue::encode(baseValue.get(exec, ident)); +} + +EncodedJSValue DFG_OPERATION operationGetByValCell(ExecState* exec, JSCell* base, EncodedJSValue encodedProperty) +{ + JSValue property = JSValue::decode(encodedProperty); + + if (property.isUInt32()) + return getByVal(exec, base, property.asUInt32()); + if (property.isDouble()) { + double propertyAsDouble = property.asDouble(); + uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); + 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); + } + + Identifier ident(exec, property.toString(exec)); + return JSValue::encode(JSValue(base).get(exec, ident)); +} + +EncodedJSValue DFG_OPERATION operationGetById(ExecState* exec, EncodedJSValue base, Identifier* propertyName) +{ + JSValue baseValue = JSValue::decode(base); + PropertySlot slot(baseValue); + return JSValue::encode(baseValue.get(exec, *propertyName, slot)); +} + +J_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJI(operationGetByIdBuildList); +EncodedJSValue DFG_OPERATION operationGetByIdBuildListWithReturnAddress(ExecState* exec, EncodedJSValue base, Identifier* propertyName, ReturnAddressPtr returnAddress) +{ + JSValue baseValue = JSValue::decode(base); + PropertySlot slot(baseValue); + JSValue result = baseValue.get(exec, *propertyName, slot); + + StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); + 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) +{ + JSValue baseValue = JSValue::decode(base); + PropertySlot slot(baseValue); + JSValue result = baseValue.get(exec, *propertyName, slot); + + StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); + 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) +{ + JSValue baseValue = JSValue::decode(base); + PropertySlot slot(baseValue); + JSValue result = baseValue.get(exec, *propertyName, slot); + + StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); + if (stubInfo.seen) + dfgRepatchGetByID(exec, baseValue, *propertyName, slot, stubInfo); + else + stubInfo.seen = true; + + return JSValue::encode(result); +} + +void DFG_OPERATION operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) +{ + operationPutByValInternal<true>(exec, encodedBase, encodedProperty, encodedValue); +} + +void DFG_OPERATION operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) +{ + operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue); +} + +void DFG_OPERATION operationPutByValCellStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) +{ + operationPutByValInternal<true>(exec, JSValue::encode(cell), encodedProperty, encodedValue); +} + +void DFG_OPERATION operationPutByValCellNonStrict(ExecState* exec, JSCell* cell, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) +{ + operationPutByValInternal<false>(exec, JSValue::encode(cell), encodedProperty, encodedValue); +} + +void DFG_OPERATION operationPutByValBeyondArrayBounds(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue) +{ + // We should only get here if index is outside the existing vector. + ASSERT(!array->canSetIndex(index)); + JSArray::putByIndex(array, exec, index, JSValue::decode(encodedValue)); +} + +EncodedJSValue DFG_OPERATION operationArrayPush(ExecState* exec, EncodedJSValue encodedValue, JSArray* array) +{ + array->push(exec, JSValue::decode(encodedValue)); + return JSValue::encode(jsNumber(array->length())); +} + +EncodedJSValue DFG_OPERATION operationArrayPop(ExecState*, JSArray* array) +{ + return JSValue::encode(array->pop()); +} + +void DFG_OPERATION operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) +{ + 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) +{ + PutPropertySlot slot(false); + base->methodTable()->put(base, exec, *propertyName, JSValue::decode(encodedValue), slot); +} + +void DFG_OPERATION operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) +{ + PutPropertySlot slot(true); + JSValue(base).putDirect(exec, *propertyName, JSValue::decode(encodedValue), slot); +} + +void DFG_OPERATION operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName) +{ + PutPropertySlot slot(false); + JSValue(base).putDirect(exec, *propertyName, 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) +{ + JSValue value = JSValue::decode(encodedValue); + JSValue baseValue(base); + PutPropertySlot slot(true); + + baseValue.put(exec, *propertyName, value, slot); + + StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); + if (stubInfo.seen) + dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, NotDirect); + else + stubInfo.seen = true; +} + +V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdNonStrictOptimize); +void DFG_OPERATION operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) +{ + JSValue value = JSValue::decode(encodedValue); + JSValue baseValue(base); + PutPropertySlot slot(false); + + baseValue.put(exec, *propertyName, value, slot); + + StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); + if (stubInfo.seen) + dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, NotDirect); + else + stubInfo.seen = true; +} + +V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectStrictOptimize); +void DFG_OPERATION operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) +{ + JSValue value = JSValue::decode(encodedValue); + JSValue baseValue(base); + PutPropertySlot slot(true); + + baseValue.putDirect(exec, *propertyName, value, slot); + + StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); + if (stubInfo.seen) + dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, Direct); + else + stubInfo.seen = true; +} + +V_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_EJCI(operationPutByIdDirectNonStrictOptimize); +void DFG_OPERATION operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, JSCell* base, Identifier* propertyName, ReturnAddressPtr returnAddress) +{ + JSValue value = JSValue::decode(encodedValue); + JSValue baseValue(base); + PutPropertySlot slot(false); + + baseValue.putDirect(exec, *propertyName, value, slot); + + StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress); + if (stubInfo.seen) + dfgRepatchPutByID(exec, baseValue, *propertyName, slot, stubInfo, Direct); + else + stubInfo.seen = true; +} + +size_t DFG_OPERATION operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + return jsLess<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); +} + +size_t DFG_OPERATION operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + return jsLessEq<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); +} + +size_t DFG_OPERATION operationCompareGreater(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + return jsLess<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1)); +} + +size_t DFG_OPERATION operationCompareGreaterEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + return jsLessEq<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1)); +} + +size_t DFG_OPERATION operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + return JSValue::equalSlowCaseInline(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); +} + +size_t DFG_OPERATION operationCompareStrictEqCell(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + JSValue op1 = JSValue::decode(encodedOp1); + JSValue op2 = JSValue::decode(encodedOp2); + + ASSERT(op1.isCell()); + ASSERT(op2.isCell()); + + return JSValue::strictEqualSlowCaseInline(exec, op1, op2); +} + +size_t DFG_OPERATION operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) +{ + return JSValue::strictEqual(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); +} + +EncodedJSValue DFG_OPERATION getHostCallReturnValue(); +EncodedJSValue DFG_OPERATION getHostCallReturnValueWithExecState(ExecState*); + +#if CPU(X86_64) +asm ( +".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" +SYMBOL_STRING(getHostCallReturnValue) ":" "\n" + "mov -40(%r13), %r13\n" + "mov %r13, %rdi\n" + "jmp " SYMBOL_STRING_RELOCATION(getHostCallReturnValueWithExecState) "\n" +); +#elif CPU(X86) +asm ( +".globl " SYMBOL_STRING(getHostCallReturnValue) "\n" +SYMBOL_STRING(getHostCallReturnValue) ":" "\n" + "mov -40(%edi), %edi\n" + "mov %edi, 4(%esp)\n" + "jmp " SYMBOL_STRING_RELOCATION(getHostCallReturnValueWithExecState) "\n" +); +#elif 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" + "cpy r0, r5" "\n" + "b " SYMBOL_STRING_RELOCATION(getHostCallReturnValueWithExecState) "\n" +); +#endif + +EncodedJSValue DFG_OPERATION getHostCallReturnValueWithExecState(ExecState* exec) +{ + return JSValue::encode(exec->globalData().hostCallReturnValue); +} + +static void* handleHostCall(ExecState* execCallee, JSValue callee, CodeSpecializationKind kind) +{ + ExecState* exec = execCallee->callerFrame(); + JSGlobalData* globalData = &exec->globalData(); + + execCallee->setScopeChain(exec->scopeChain()); + execCallee->setCodeBlock(0); + + if (kind == CodeForCall) { + CallData callData; + CallType callType = getCallData(callee, callData); + + ASSERT(callType != CallTypeJS); + + if (callType == CallTypeHost) { + globalData->hostCallReturnValue = JSValue::decode(callData.native.function(execCallee)); + if (globalData->exception) + return 0; + + return reinterpret_cast<void*>(getHostCallReturnValue); + } + + ASSERT(callType == CallTypeNone); + exec->globalData().exception = createNotAFunctionError(exec, callee); + return 0; + } + + ASSERT(kind == CodeForConstruct); + + ConstructData constructData; + ConstructType constructType = getConstructData(callee, constructData); + + ASSERT(constructType != ConstructTypeJS); + + if (constructType == ConstructTypeHost) { + globalData->hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee)); + if (globalData->exception) + return 0; + + return reinterpret_cast<void*>(getHostCallReturnValue); + } + + ASSERT(constructType == ConstructTypeNone); + exec->globalData().exception = createNotAConstructorError(exec, callee); + return 0; +} + +inline void* linkFor(ExecState* execCallee, ReturnAddressPtr returnAddress, CodeSpecializationKind kind) +{ + ExecState* exec = execCallee->callerFrame(); + JSGlobalData* globalData = &exec->globalData(); + JSValue calleeAsValue = execCallee->calleeAsValue(); + JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); + if (!calleeAsFunctionCell) + return handleHostCall(execCallee, calleeAsValue, kind); + + JSFunction* callee = asFunction(calleeAsFunctionCell); + execCallee->setScopeChain(callee->scopeUnchecked()); + ExecutableBase* executable = callee->executable(); + + 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) { + globalData->exception = createStackOverflowError(exec); + return 0; + } + codeBlock = &functionExecutable->generatedBytecodeFor(kind); + if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->m_numParameters)) + codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind); + else + codePtr = functionExecutable->generatedJITCodeFor(kind).addressForCall(); + } + CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(returnAddress); + if (!callLinkInfo.seenOnce()) + callLinkInfo.setSeen(); + else + dfgLinkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind); + return codePtr.executableAddress(); +} + +P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(operationLinkCall); +void* DFG_OPERATION operationLinkCallWithReturnAddress(ExecState* execCallee, ReturnAddressPtr returnAddress) +{ + return linkFor(execCallee, returnAddress, CodeForCall); +} + +P_FUNCTION_WRAPPER_WITH_RETURN_ADDRESS_E(operationLinkConstruct); +void* DFG_OPERATION operationLinkConstructWithReturnAddress(ExecState* execCallee, ReturnAddressPtr returnAddress) +{ + return linkFor(execCallee, returnAddress, CodeForConstruct); +} + +inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind) +{ + ExecState* exec = execCallee->callerFrame(); + JSValue calleeAsValue = execCallee->calleeAsValue(); + JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); + if (UNLIKELY(!calleeAsFunctionCell)) + return handleHostCall(execCallee, calleeAsValue, kind); + + JSFunction* function = asFunction(calleeAsFunctionCell); + execCallee->setScopeChain(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->globalData().exception = error; + return 0; + } + } + return executable->generatedJITCodeWithArityCheckFor(kind).executableAddress(); +} + +void* DFG_OPERATION operationVirtualCall(ExecState* execCallee) +{ + return virtualFor(execCallee, CodeForCall); +} + +void* DFG_OPERATION operationVirtualConstruct(ExecState* execCallee) +{ + return virtualFor(execCallee, CodeForConstruct); +} + +EncodedJSValue DFG_OPERATION operationResolve(ExecState* exec, Identifier* propertyName) +{ + ScopeChainNode* scopeChain = exec->scopeChain(); + ScopeChainIterator iter = scopeChain->begin(); + ScopeChainIterator end = scopeChain->end(); + ASSERT(iter != end); + + do { + JSObject* record = iter->get(); + PropertySlot slot(record); + if (record->getPropertySlot(exec, *propertyName, slot)) + return JSValue::encode(slot.getValue(exec, *propertyName)); + } while (++iter != end); + + return throwVMError(exec, createUndefinedVariableError(exec, *propertyName)); +} + +EncodedJSValue DFG_OPERATION operationResolveBase(ExecState* exec, Identifier* propertyName) +{ + return JSValue::encode(resolveBase(exec, *propertyName, exec->scopeChain(), false)); +} + +EncodedJSValue DFG_OPERATION operationResolveBaseStrictPut(ExecState* exec, Identifier* propertyName) +{ + JSValue base = resolveBase(exec, *propertyName, exec->scopeChain(), true); + if (!base) + throwError(exec, createErrorForInvalidGlobalAssignment(exec, propertyName->ustring())); + return JSValue::encode(base); +} + +EncodedJSValue DFG_OPERATION operationResolveGlobal(ExecState* exec, GlobalResolveInfo* resolveInfo, Identifier* propertyName) +{ + JSGlobalObject* globalObject = exec->lexicalGlobalObject(); + + PropertySlot slot(globalObject); + if (globalObject->getPropertySlot(exec, *propertyName, slot)) { + JSValue result = slot.getValue(exec, *propertyName); + + if (slot.isCacheableValue() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { + resolveInfo->structure.set(exec->globalData(), exec->codeBlock()->ownerExecutable(), globalObject->structure()); + resolveInfo->offset = slot.cachedOffset(); + } + + return JSValue::encode(result); + } + + return throwVMError(exec, createUndefinedVariableError(exec, *propertyName)); +} + +EncodedJSValue DFG_OPERATION operationToPrimitive(ExecState* exec, EncodedJSValue value) +{ + return JSValue::encode(JSValue::decode(value).toPrimitive(exec)); +} + +EncodedJSValue DFG_OPERATION operationStrCat(ExecState* exec, void* start, size_t size) +{ + return JSValue::encode(jsString(exec, static_cast<Register*>(start), size)); +} + +EncodedJSValue DFG_OPERATION operationNewArray(ExecState* exec, void* start, size_t size) +{ + return JSValue::encode(constructArray(exec, static_cast<JSValue*>(start), size)); +} + +EncodedJSValue DFG_OPERATION operationNewArrayBuffer(ExecState* exec, size_t start, size_t size) +{ + return JSValue::encode(constructArray(exec, exec->codeBlock()->constantBuffer(start), size)); +} + +EncodedJSValue DFG_OPERATION operationNewRegexp(ExecState* exec, void* regexpPtr) +{ + 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->globalData(), exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regexp)); +} + +DFGHandlerEncoded DFG_OPERATION lookupExceptionHandler(ExecState* exec, uint32_t callIndex) +{ + JSValue exceptionValue = exec->exception(); + ASSERT(exceptionValue); + + unsigned vPCIndex = exec->codeBlock()->bytecodeOffsetForCallAtIndex(callIndex); + HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, vPCIndex); + + void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught; + ASSERT(catchRoutine); + return dfgHandlerEncoded(exec, catchRoutine); +} + +double DFG_OPERATION dfgConvertJSValueToNumber(ExecState* exec, EncodedJSValue value) +{ + return JSValue::decode(value).toNumber(exec); +} + +size_t DFG_OPERATION dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value) +{ + // toInt32/toUInt32 return the same value; we want the value zero extended to fill the register. + return JSValue::decode(value).toUInt32(exec); +} + +size_t DFG_OPERATION dfgConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp) +{ + return JSValue::decode(encodedOp).toBoolean(exec); +} + +#if DFG_ENABLE(VERBOSE_SPECULATION_FAILURE) +void DFG_OPERATION debugOperationPrintSpeculationFailure(ExecState*, void* debugInfoRaw) +{ + SpeculationFailureDebugInfo* debugInfo = static_cast<SpeculationFailureDebugInfo*>(debugInfoRaw); + CodeBlock* codeBlock = debugInfo->codeBlock; + CodeBlock* alternative = codeBlock->alternative(); + printf("Speculation failure in %p at @%u with executeCounter = %d, reoptimizationRetryCounter = %u, optimizationDelayCounter = %u, success/fail %u/%u\n", codeBlock, debugInfo->nodeIndex, alternative ? alternative->executeCounter() : 0, alternative ? alternative->reoptimizationRetryCounter() : 0, alternative ? alternative->optimizationDelayCounter() : 0, codeBlock->speculativeSuccessCounter(), codeBlock->speculativeFailCounter()); +} +#endif + +} // extern "C" +} } // namespace JSC::DFG + +#endif |