#include "config.h"
#include "DFGOperations.h"
#if ENABLE(DFG_JIT)
#include "CodeBlock.h"
#include "DFGRepatch.h"
#include "Interpreter.h"
#include "JSByteArray.h"
#include "JSGlobalData.h"
#include "Operations.h"
#define FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, register) \
asm( \
".globl _" STRINGIZE(function) "\n" \
"_" STRINGIZE(function) ":" "\n" \
"mov (%rsp), %" STRINGIZE(register) "\n" \
"jmp _" STRINGIZE(function) "WithReturnAddress" "\n" \
);
#define FUNCTION_WRAPPER_WITH_ARG2_RETURN_ADDRESS(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rsi)
#define FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, rcx)
#define FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(function) FUNCTION_WRAPPER_WITH_RETURN_ADDRESS(function, r8)
namespace JSC { namespace DFG {
static inline void putByVal(ExecState* exec, JSValue baseValue, uint32_t index, JSValue value)
{
JSGlobalData* globalData = &exec->globalData();
if (isJSArray(globalData, baseValue)) {
JSArray* array = asArray(baseValue);
if (array->canSetIndex(index)) {
array->setIndex(*globalData, index, value);
return;
}
array->JSArray::put(exec, index, value);
return;
}
if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(index)) {
JSByteArray* byteArray = asByteArray(baseValue);
if (value.isInt32()) {
byteArray->setIndex(index, value.asInt32());
return;
}
double dValue = 0;
if (value.getNumber(dValue)) {
byteArray->setIndex(index, dValue);
return;
}
}
baseValue.put(exec, index, value);
}
template<bool strict>
ALWAYS_INLINE static void 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();
Identifier ident(exec, property.toString(exec));
if (!globalData->exception) {
PutPropertySlot slot(strict);
baseValue.put(exec, ident, value, slot);
}
}
extern "C" {
EncodedJSValue operationConvertThis(ExecState* exec, EncodedJSValue encodedOp)
{
return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec));
}
EncodedJSValue operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
JSValue op1 = JSValue::decode(encodedOp1);
JSValue op2 = JSValue::decode(encodedOp2);
if (op1.isInt32() && op2.isInt32()) {
int64_t result64 = static_cast<int64_t>(op1.asInt32()) + static_cast<int64_t>(op2.asInt32());
int32_t result32 = static_cast<int32_t>(result64);
if (LIKELY(result32 == result64))
return JSValue::encode(jsNumber(result32));
return JSValue::encode(jsNumber((double)result64));
}
double number1;
double number2;
if (op1.getNumber(number1) && op2.getNumber(number2))
return JSValue::encode(jsNumber(number1 + number2));
return JSValue::encode(jsAddSlowCase(exec, op1, op2));
}
EncodedJSValue operationArithAdd(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
double num1 = JSValue::decode(encodedOp1).uncheckedGetNumber();
double num2 = JSValue::decode(encodedOp2).uncheckedGetNumber();
return JSValue::encode(jsNumber(num1 + num2));
}
EncodedJSValue operationArithSub(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
double num1 = JSValue::decode(encodedOp1).uncheckedGetNumber();
double num2 = JSValue::decode(encodedOp2).uncheckedGetNumber();
return JSValue::encode(jsNumber(num1 - num2));
}
EncodedJSValue operationArithMul(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
double num1 = JSValue::decode(encodedOp1).uncheckedGetNumber();
double num2 = JSValue::decode(encodedOp2).uncheckedGetNumber();
return JSValue::encode(jsNumber(num1 * num2));
}
EncodedJSValue operationArithDiv(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
double num1 = JSValue::decode(encodedOp1).uncheckedGetNumber();
double num2 = JSValue::decode(encodedOp2).uncheckedGetNumber();
return JSValue::encode(jsNumber(num1 / num2));
}
EncodedJSValue operationArithMod(EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
double num1 = JSValue::decode(encodedOp1).uncheckedGetNumber();
double num2 = JSValue::decode(encodedOp2).uncheckedGetNumber();
return JSValue::encode(jsNumber(fmod(num1, num2)));
}
static inline EncodedJSValue getByVal(ExecState* exec, JSCell* base, uint32_t index)
{
JSGlobalData* globalData = &exec->globalData();
if (isJSArray(globalData, base) && asArray(base)->canGetIndex(index))
return JSValue::encode(asArray(base)->getIndex(index));
if (isJSString(globalData, base) && asString(base)->canGetIndex(index))
return JSValue::encode(asString(base)->getIndex(exec, index));
if (isJSByteArray(globalData, base) && asByteArray(base)->canAccessIndex(index))
return JSValue::encode(asByteArray(base)->getIndex(exec, index));
return JSValue::encode(JSValue(base).get(exec, index));
}
EncodedJSValue 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 operationGetById(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName)
{
JSValue baseValue = JSValue::decode(encodedBase);
PropertySlot slot(baseValue);
return JSValue::encode(baseValue.get(exec, *propertyName, slot));
}
EncodedJSValue operationGetMethodOptimizeWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr);
FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetMethodOptimize);
EncodedJSValue operationGetMethodOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
{
JSValue baseValue = JSValue::decode(encodedBase);
PropertySlot slot(baseValue);
JSValue result = baseValue.get(exec, *propertyName, slot);
MethodCallLinkInfo& methodInfo = exec->codeBlock()->getMethodCallLinkInfo(returnAddress);
if (methodInfo.seenOnce())
dfgRepatchGetMethod(exec, baseValue, *propertyName, slot, methodInfo);
else
methodInfo.setSeen();
return JSValue::encode(result);
}
EncodedJSValue operationGetByIdBuildListWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr);
FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdBuildList);
EncodedJSValue operationGetByIdBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
{
JSValue baseValue = JSValue::decode(encodedBase);
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);
}
EncodedJSValue operationGetByIdProtoBuildListWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr);
FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdProtoBuildList);
EncodedJSValue operationGetByIdProtoBuildListWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
{
JSValue baseValue = JSValue::decode(encodedBase);
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);
}
EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ExecState*, EncodedJSValue, Identifier*, ReturnAddressPtr);
FUNCTION_WRAPPER_WITH_ARG4_RETURN_ADDRESS(operationGetByIdOptimize);
EncodedJSValue operationGetByIdOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
{
JSValue baseValue = JSValue::decode(encodedBase);
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 operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
{
operationPutByValInternal<true>(exec, encodedBase, encodedProperty, encodedValue);
}
void operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
{
operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue);
}
void operationPutByValBeyondArrayBounds(ExecState* exec, JSArray* array, int32_t index, EncodedJSValue encodedValue)
{
ASSERT(!array->canSetIndex(index));
array->JSArray::put(exec, index, JSValue::decode(encodedValue));
}
void operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
{
PutPropertySlot slot(true);
JSValue::decode(encodedBase).put(exec, *propertyName, JSValue::decode(encodedValue), slot);
}
void operationPutByIdNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
{
PutPropertySlot slot(false);
JSValue::decode(encodedBase).put(exec, *propertyName, JSValue::decode(encodedValue), slot);
}
void operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
{
PutPropertySlot slot(true);
JSValue::decode(encodedBase).putDirect(exec, *propertyName, JSValue::decode(encodedValue), slot);
}
void operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName)
{
PutPropertySlot slot(false);
JSValue::decode(encodedBase).putDirect(exec, *propertyName, JSValue::decode(encodedValue), slot);
}
void operationPutByIdStrictOptimizeWithReturnAddress(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr);
FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdStrictOptimize);
void operationPutByIdStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
{
JSValue value = JSValue::decode(encodedValue);
JSValue base = JSValue::decode(encodedBase);
PutPropertySlot slot(true);
base.put(exec, *propertyName, value, slot);
StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
if (stubInfo.seen)
dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, NotDirect);
else
stubInfo.seen = true;
}
void operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr);
FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdNonStrictOptimize);
void operationPutByIdNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
{
JSValue value = JSValue::decode(encodedValue);
JSValue base = JSValue::decode(encodedBase);
PutPropertySlot slot(false);
base.put(exec, *propertyName, value, slot);
StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
if (stubInfo.seen)
dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, NotDirect);
else
stubInfo.seen = true;
}
void operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr);
FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdDirectStrictOptimize);
void operationPutByIdDirectStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
{
JSValue value = JSValue::decode(encodedValue);
JSValue base = JSValue::decode(encodedBase);
PutPropertySlot slot(true);
base.putDirect(exec, *propertyName, value, slot);
StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
if (stubInfo.seen)
dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, Direct);
else
stubInfo.seen = true;
}
void operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ExecState*, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr);
FUNCTION_WRAPPER_WITH_ARG5_RETURN_ADDRESS(operationPutByIdDirectNonStrictOptimize);
void operationPutByIdDirectNonStrictOptimizeWithReturnAddress(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* propertyName, ReturnAddressPtr returnAddress)
{
JSValue value = JSValue::decode(encodedValue);
JSValue base = JSValue::decode(encodedBase);
PutPropertySlot slot(false);
base.putDirect(exec, *propertyName, value, slot);
StructureStubInfo& stubInfo = exec->codeBlock()->getStubInfo(returnAddress);
if (stubInfo.seen)
dfgRepatchPutByID(exec, base, *propertyName, slot, stubInfo, Direct);
else
stubInfo.seen = true;
}
RegisterSizedBoolean operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
return jsLess<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
}
RegisterSizedBoolean operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
return jsLessEq<true>(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
}
RegisterSizedBoolean operationCompareGreater(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
return jsLess<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1));
}
RegisterSizedBoolean operationCompareGreaterEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
return jsLessEq<false>(exec, JSValue::decode(encodedOp2), JSValue::decode(encodedOp1));
}
RegisterSizedBoolean operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
return JSValue::equalSlowCaseInline(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
}
RegisterSizedBoolean 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);
}
RegisterSizedBoolean operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
{
return JSValue::strictEqual(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
}
EncodedJSValue getHostCallReturnValue();
EncodedJSValue getHostCallReturnValueWithExecState(ExecState*);
asm (
".globl _" STRINGIZE(getHostCallReturnValue) "\n"
"_" STRINGIZE(getHostCallReturnValue) ":" "\n"
"mov -40(%r13), %r13\n"
"mov %r13, %rdi\n"
"jmp _" STRINGIZE(getHostCallReturnValueWithExecState) "\n"
);
EncodedJSValue 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();
if (kind == CodeForCall) {
CallData callData;
CallType callType = getCallData(callee, callData);
ASSERT(callType != CallTypeJS);
if (callType == CallTypeHost) {
if (!globalData->interpreter->registerFile().grow(execCallee->registers())) {
globalData->exception = createStackOverflowError(exec);
return 0;
}
execCallee->setScopeChain(exec->scopeChain());
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) {
if (!globalData->interpreter->registerFile().grow(execCallee->registers())) {
globalData->exception = createStackOverflowError(exec);
return 0;
}
execCallee->setScopeChain(exec->scopeChain());
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(*globalData, calleeAsValue);
if (!calleeAsFunctionCell)
return handleHostCall(execCallee, calleeAsValue, kind);
JSFunction* callee = asFunction(calleeAsFunctionCell);
ExecutableBase* executable = callee->executable();
MacroAssemblerCodePtr codePtr;
CodeBlock* codeBlock = 0;
if (executable->isHostFunction())
codePtr = executable->generatedJITCodeFor(kind).addressForCall();
else {
execCallee->setScopeChain(callee->scope());
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->generatedJITCodeFor(kind).addressForCall();
else
codePtr = functionExecutable->generatedJITCodeWithArityCheckFor(kind);
}
CallLinkInfo& callLinkInfo = exec->codeBlock()->getCallLinkInfo(returnAddress);
if (!callLinkInfo.seenOnce())
callLinkInfo.setSeen();
else
dfgLinkFor(execCallee, callLinkInfo, codeBlock, callee, codePtr, kind);
return codePtr.executableAddress();
}
void* operationLinkCallWithReturnAddress(ExecState*, ReturnAddressPtr);
FUNCTION_WRAPPER_WITH_ARG2_RETURN_ADDRESS(operationLinkCall);
void* operationLinkCallWithReturnAddress(ExecState* execCallee, ReturnAddressPtr returnAddress)
{
return linkFor(execCallee, returnAddress, CodeForCall);
}
void* operationLinkConstructWithReturnAddress(ExecState*, ReturnAddressPtr);
FUNCTION_WRAPPER_WITH_ARG2_RETURN_ADDRESS(operationLinkConstruct);
void* operationLinkConstructWithReturnAddress(ExecState* execCallee, ReturnAddressPtr returnAddress)
{
return linkFor(execCallee, returnAddress, CodeForConstruct);
}
inline void* virtualFor(ExecState* execCallee, CodeSpecializationKind kind)
{
ExecState* exec = execCallee->callerFrame();
JSGlobalData* globalData = &exec->globalData();
JSValue calleeAsValue = execCallee->calleeAsValue();
JSCell* calleeAsFunctionCell = getJSFunction(*globalData, 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* operationVirtualCall(ExecState* execCallee)
{
return virtualFor(execCallee, CodeForCall);
}
void* operationVirtualConstruct(ExecState* execCallee)
{
return virtualFor(execCallee, CodeForConstruct);
}
EncodedJSValue operationInstanceOf(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, EncodedJSValue encodedPrototype)
{
JSValue value = JSValue::decode(encodedValue);
JSValue base = JSValue::decode(encodedBase);
JSValue prototype = JSValue::decode(encodedPrototype);
ASSERT(base.isCell());
ASSERT(!value.isCell()
|| !prototype.isCell()
|| !prototype.isObject()
|| (base.asCell()->structure()->typeInfo().flags() & (ImplementsHasInstance | OverridesHasInstance)) != ImplementsHasInstance);
TypeInfo typeInfo(UnspecifiedType);
if (!base.isObject() || !(typeInfo = asObject(base)->structure()->typeInfo()).implementsHasInstance()) {
throwError(exec, createInvalidParamError(exec, "instanceof", base));
return JSValue::encode(jsUndefined());
}
return JSValue::encode(jsBoolean(asObject(base)->hasInstance(exec, value, prototype)));
}
EncodedJSValue 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 operationResolveBase(ExecState* exec, Identifier* propertyName)
{
return JSValue::encode(resolveBase(exec, *propertyName, exec->scopeChain(), false));
}
EncodedJSValue 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);
}
void operationThrowHasInstanceError(ExecState* exec, EncodedJSValue encodedBase)
{
JSValue base = JSValue::decode(encodedBase);
ASSERT(!base.isObject() || !asObject(base)->structure()->typeInfo().implementsHasInstance());
throwError(exec, createInvalidParamError(exec, "instanceof", base));
}
DFGHandler lookupExceptionHandler(ExecState* exec, ReturnAddressPtr faultLocation)
{
JSValue exceptionValue = exec->exception();
ASSERT(exceptionValue);
unsigned vPCIndex = exec->codeBlock()->bytecodeOffset(faultLocation);
HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, vPCIndex);
void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught;
ASSERT(catchRoutine);
return DFGHandler(exec, catchRoutine);
}
double dfgConvertJSValueToNumber(ExecState* exec, EncodedJSValue value)
{
return JSValue::decode(value).toNumber(exec);
}
int32_t dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
{
return JSValue::decode(value).toInt32(exec);
}
RegisterSizedBoolean dfgConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp)
{
return JSValue::decode(encodedOp).toBoolean(exec);
}
} } }
#endif