Index: third_party/WebKit/JavaScriptCore/VM/Machine.cpp |
=================================================================== |
--- third_party/WebKit/JavaScriptCore/VM/Machine.cpp (revision 5302) |
+++ third_party/WebKit/JavaScriptCore/VM/Machine.cpp (working copy) |
@@ -580,24 +580,25 @@ |
return true; |
} |
-NEVER_INLINE JSValue* Machine::callEval(CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, RegisterFile* registerFile, int argv, int argc, JSValue*& exceptionValue) |
+NEVER_INLINE JSValue* Machine::callEval(CallFrame* callFrame, RegisterFile* registerFile, Register* argv, int argc, int registerOffset, JSValue*& exceptionValue) |
{ |
if (argc < 2) |
return jsUndefined(); |
- JSValue* program = callFrame[argv + 1].jsValue(callFrame); |
+ JSValue* program = argv[1].jsValue(callFrame); |
if (!program->isString()) |
return program; |
UString programSource = asString(program)->value(); |
+ ScopeChainNode* scopeChain = callFrame->scopeChain(); |
CodeBlock* codeBlock = callFrame->codeBlock(); |
RefPtr<EvalNode> evalNode = codeBlock->evalCodeCache.get(callFrame, programSource, scopeChain, exceptionValue); |
JSValue* result = jsUndefined(); |
if (evalNode) |
- result = callFrame->globalData().machine->execute(evalNode.get(), callFrame, thisObj, callFrame->registers() - registerFile->start() + argv + 1 + RegisterFile::CallFrameHeaderSize, scopeChain, &exceptionValue); |
+ result = callFrame->globalData().machine->execute(evalNode.get(), callFrame, callFrame->thisValue()->toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue); |
return result; |
} |
@@ -655,17 +656,13 @@ |
#ifndef NDEBUG |
-void Machine::dumpCallFrame(const RegisterFile* registerFile, CallFrame* callFrame) |
+void Machine::dumpCallFrame(CallFrame* callFrame) |
{ |
- JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject(); |
- |
- CodeBlock* codeBlock = callFrame->codeBlock(); |
- codeBlock->dump(globalObject->globalExec()); |
- |
- dumpRegisters(registerFile, callFrame); |
+ callFrame->codeBlock()->dump(callFrame); |
+ dumpRegisters(callFrame); |
} |
-void Machine::dumpRegisters(const RegisterFile* registerFile, CallFrame* callFrame) |
+void Machine::dumpRegisters(CallFrame* callFrame) |
{ |
printf("Register frame: \n\n"); |
printf("----------------------------------------------------\n"); |
@@ -673,6 +670,7 @@ |
printf("----------------------------------------------------\n"); |
CodeBlock* codeBlock = callFrame->codeBlock(); |
+ RegisterFile* registerFile = &callFrame->scopeChain()->globalObject()->globalData()->machine->registerFile(); |
const Register* it; |
const Register* end; |
@@ -1023,7 +1021,7 @@ |
return execute(evalNode, callFrame, thisObj, m_registerFile.size() + evalNode->byteCode(scopeChain).numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception); |
} |
-JSValue* Machine::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, int registerOffset, ScopeChainNode* scopeChain, JSValue** exception) |
+JSValue* Machine::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue** exception) |
{ |
ASSERT(!scopeChain->globalData->exception); |
@@ -1069,13 +1067,13 @@ |
} |
Register* oldEnd = m_registerFile.end(); |
- Register* newEnd = m_registerFile.start() + registerOffset + codeBlock->numCalleeRegisters; |
+ Register* newEnd = m_registerFile.start() + globalRegisterOffset + codeBlock->numCalleeRegisters; |
if (!m_registerFile.grow(newEnd)) { |
*exception = createStackOverflowError(callFrame); |
return jsNull(); |
} |
- CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + registerOffset); |
+ CallFrame* newCallFrame = CallFrame::create(m_registerFile.start() + globalRegisterOffset); |
// a 0 codeBlock indicates a built-in caller |
newCallFrame[codeBlock->thisRegister] = thisObj; |
@@ -3264,7 +3262,7 @@ |
NEXT_OPCODE; |
} |
BEGIN_OPCODE(op_call_eval) { |
- /* call_eval dst(r) func(r) thisVal(r) firstArg(r) argCount(n) |
+ /* call_eval dst(r) func(r) argCount(n) registerOffset(n) |
Call a function named "eval" with no explicit "this" value |
(which may therefore be the eval operator). If register |
@@ -3277,30 +3275,28 @@ |
int dst = vPC[1].u.operand; |
int func = vPC[2].u.operand; |
- int thisVal = vPC[3].u.operand; |
- int firstArg = vPC[4].u.operand; |
- int argCount = vPC[5].u.operand; |
+ int argCount = vPC[3].u.operand; |
+ int registerOffset = vPC[4].u.operand; |
JSValue* funcVal = callFrame[func].jsValue(callFrame); |
- JSValue* baseVal = callFrame[thisVal].jsValue(callFrame); |
- ScopeChainNode* scopeChain = callFrame->scopeChain(); |
- if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) { |
- JSObject* thisObject = asObject(callFrame[callFrame->codeBlock()->thisRegister].jsValue(callFrame)); |
- JSValue* result = callEval(callFrame, thisObject, scopeChain, registerFile, firstArg, argCount, exceptionValue); |
+ Register* newCallFrame = callFrame->registers() + registerOffset; |
+ Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount; |
+ JSValue* thisValue = argv[0].jsValue(callFrame); |
+ JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject(); |
+ |
+ if (thisValue == globalObject && funcVal == globalObject->evalFunction()) { |
+ JSValue* result = callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue); |
if (exceptionValue) |
goto vm_throw; |
- |
callFrame[dst] = result; |
- vPC += 7; |
+ vPC += 5; |
NEXT_OPCODE; |
} |
- // We didn't find the blessed version of eval, so reset vPC and process |
- // this instruction as a normal function call, supplying the proper 'this' |
- // value. |
- callFrame[thisVal] = baseVal->toThisObject(callFrame); |
+ // We didn't find the blessed version of eval, so process this |
+ // instruction as a normal function call. |
#if HAVE(COMPUTED_GOTO) |
// Hack around gcc performance quirk by performing an indirect goto |
@@ -3311,48 +3307,20 @@ |
// fall through to op_call |
} |
BEGIN_OPCODE(op_call) { |
- /* call dst(r) func(r) thisVal(r) firstArg(r) argCount(n) registerOffset(n) |
+ /* call dst(r) func(r) argCount(n) registerOffset(n) |
- Perform a function call. Specifically, call register func |
- with a "this" value of register thisVal, and put the result |
- in register dst. |
- |
- The arguments start at register firstArg and go up to |
- argCount, but the "this" value is considered an implicit |
- first argument, so the argCount should be one greater than |
- the number of explicit arguments passed, and the register |
- after firstArg should contain the actual first |
- argument. This opcode will copy from the thisVal register |
- to the firstArg register, unless the register index of |
- thisVal is the special missing this object marker, which is |
- 2^31-1; in that case, the global object will be used as the |
- "this" value. |
- |
- If func is a native code function, then this opcode calls |
- it and returns the value immediately. |
- |
- But if it is a JS function, then the current scope chain |
- and code block is set to the function's, and we slide the |
- register window so that the arguments would form the first |
- few local registers of the called function's register |
- window. In addition, a call frame header is written |
- immediately before the arguments; see the call frame |
- documentation for an explanation of how many registers a |
- call frame takes and what they contain. That many registers |
- before the firstArg register will be overwritten by the |
- call. In addition, any registers higher than firstArg + |
- argCount may be overwritten. Once this setup is complete, |
- execution continues from the called function's first |
- argument, and does not return until a "ret" opcode is |
- encountered. |
+ Perform a function call. |
+ |
+ registerOffset is the distance the callFrame pointer should move |
+ before the VM initializes the new call frame's header. |
+ |
+ dst is where op_ret should store its result. |
*/ |
int dst = vPC[1].u.operand; |
int func = vPC[2].u.operand; |
- int thisVal = vPC[3].u.operand; |
- int firstArg = vPC[4].u.operand; |
- int argCount = vPC[5].u.operand; |
- int registerOffset = vPC[6].u.operand; |
+ int argCount = vPC[3].u.operand; |
+ int registerOffset = vPC[4].u.operand; |
JSValue* v = callFrame[func].jsValue(callFrame); |
@@ -3364,8 +3332,6 @@ |
FunctionBodyNode* functionBodyNode = callData.js.functionBody; |
CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain); |
- callFrame[firstArg] = thisVal == missingThisObjectMarker() ? callFrame->globalThisValue() : callFrame[thisVal].jsValue(callFrame); |
- |
CallFrame* previousCallFrame = callFrame; |
callFrame = slideRegisterWindowForCall(newCodeBlock, registerFile, callFrame, registerOffset, argCount); |
@@ -3375,7 +3341,7 @@ |
goto vm_throw; |
} |
- callFrame->init(newCodeBlock, vPC + 7, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v)); |
+ callFrame->init(newCodeBlock, vPC + 5, callDataScopeChain, previousCallFrame, dst, argCount, asFunction(v)); |
vPC = newCodeBlock->instructions.begin(); |
#if ENABLE(OPCODE_STATS) |
@@ -3386,13 +3352,18 @@ |
} |
if (callType == CallTypeHost) { |
- JSValue* thisValue = thisVal == missingThisObjectMarker() ? callFrame->globalThisValue() : callFrame[thisVal].jsValue(callFrame); |
- ArgList args(callFrame->registers() + firstArg + 1, argCount - 1); |
- |
ScopeChainNode* scopeChain = callFrame->scopeChain(); |
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset); |
- newCallFrame->init(0, vPC + 7, scopeChain, callFrame, dst, argCount, 0); |
+ newCallFrame->init(0, vPC + 5, scopeChain, callFrame, dst, argCount, 0); |
+ Register* thisRegister = newCallFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount; |
+ ArgList args(thisRegister + 1, argCount - 1); |
+ |
+ // FIXME: All host methods should be calling toThisObject, but this is not presently the case. |
+ JSValue* thisValue = thisRegister->jsValue(callFrame); |
+ if (thisValue == jsNull()) |
+ thisValue = callFrame->globalThisValue(); |
+ |
JSValue* returnValue; |
{ |
SamplingTool::HostCallRecord callRecord(m_sampler); |
@@ -3402,7 +3373,7 @@ |
callFrame[dst] = returnValue; |
- vPC += 7; |
+ vPC += 5; |
NEXT_OPCODE; |
} |
@@ -3572,28 +3543,28 @@ |
NEXT_OPCODE; |
} |
BEGIN_OPCODE(op_construct) { |
- /* construct dst(r) constr(r) constrProto(r) firstArg(r) argCount(n) registerOffset(n) |
+ /* construct dst(r) func(r) argCount(n) registerOffset(n) proto(r) thisRegister(r) |
- Invoke register "constr" as a constructor. For JS |
+ Invoke register "func" as a constructor. For JS |
functions, the calling convention is exactly as for the |
"call" opcode, except that the "this" value is a newly |
- created Object. For native constructors, a null "this" |
- value is passed. In either case, the firstArg and argCount |
+ created Object. For native constructors, no "this" |
+ value is passed. In either case, the argCount and registerOffset |
registers are interpreted as for the "call" opcode. |
- Register constrProto must contain the prototype property of |
- register constsr. This is to enable polymorphic inline |
+ Register proto must contain the prototype property of |
+ register func. This is to enable polymorphic inline |
caching of this lookup. |
*/ |
int dst = vPC[1].u.operand; |
- int constr = vPC[2].u.operand; |
- int constrProto = vPC[3].u.operand; |
- int firstArg = vPC[4].u.operand; |
- int argCount = vPC[5].u.operand; |
- int registerOffset = vPC[6].u.operand; |
+ int func = vPC[2].u.operand; |
+ int argCount = vPC[3].u.operand; |
+ int registerOffset = vPC[4].u.operand; |
+ int proto = vPC[5].u.operand; |
+ int thisRegister = vPC[6].u.operand; |
- JSValue* v = callFrame[constr].jsValue(callFrame); |
+ JSValue* v = callFrame[func].jsValue(callFrame); |
ConstructData constructData; |
ConstructType constructType = v->getConstructData(constructData); |
@@ -3604,14 +3575,14 @@ |
CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain); |
StructureID* structure; |
- JSValue* prototype = callFrame[constrProto].jsValue(callFrame); |
+ JSValue* prototype = callFrame[proto].jsValue(callFrame); |
if (prototype->isObject()) |
structure = asObject(prototype)->inheritorID(); |
else |
structure = callDataScopeChain->globalObject()->emptyObjectStructure(); |
JSObject* newObject = new (globalData) JSObject(structure); |
- callFrame[firstArg] = newObject; // "this" value |
+ callFrame[thisRegister] = newObject; // "this" value |
CallFrame* previousCallFrame = callFrame; |
@@ -3633,7 +3604,7 @@ |
} |
if (constructType == ConstructTypeHost) { |
- ArgList args(callFrame->registers() + firstArg + 1, argCount - 1); |
+ ArgList args(callFrame->registers() + thisRegister + 1, argCount - 1); |
ScopeChainNode* scopeChain = callFrame->scopeChain(); |
CallFrame* newCallFrame = CallFrame::create(callFrame->registers() + registerOffset); |
@@ -4325,13 +4296,19 @@ |
// to get the address of the ctiVMThrowTrampoline function. It's also |
// good to keep the code size down by leaving as much of the exception |
// handling code out of line as possible. |
-static NEVER_INLINE void setUpThrowTrampolineReturnAddress(JSGlobalData* globalData, void*& returnAddress) |
+static NEVER_INLINE void returnToThrowTrampoline(JSGlobalData* globalData, void* exceptionLocation, void*& returnAddressSlot) |
{ |
ASSERT(globalData->exception); |
- globalData->throwReturnAddress = returnAddress; |
- ctiSetReturnAddress(&returnAddress, reinterpret_cast<void*>(ctiVMThrowTrampoline)); |
+ globalData->exceptionLocation = exceptionLocation; |
+ ctiSetReturnAddress(&returnAddressSlot, reinterpret_cast<void*>(ctiVMThrowTrampoline)); |
} |
+static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalData* globalData, void* exceptionLocation, void*& returnAddressSlot) |
+{ |
+ globalData->exception = createStackOverflowError(callFrame); |
+ returnToThrowTrampoline(globalData, exceptionLocation, returnAddressSlot); |
+} |
+ |
#define VM_THROW_EXCEPTION() \ |
do { \ |
VM_THROW_EXCEPTION_AT_END(); \ |
@@ -4344,7 +4321,7 @@ |
return pair.i; \ |
} while (0) |
#define VM_THROW_EXCEPTION_AT_END() \ |
- setUpThrowTrampolineReturnAddress(ARG_globalData, CTI_RETURN_ADDRESS) |
+ returnToThrowTrampoline(ARG_globalData, CTI_RETURN_ADDRESS, CTI_RETURN_ADDRESS) |
#define VM_CHECK_EXCEPTION() \ |
do { \ |
@@ -4452,13 +4429,6 @@ |
} |
} |
-NEVER_INLINE void Machine::throwStackOverflowPreviousFrame(CallFrame* callFrame, JSGlobalData* globalData, void*& returnAddress) |
-{ |
- globalData->exception = createStackOverflowError(callFrame->callerFrame()); |
- globalData->throwReturnAddress = callFrame->returnPC(); |
- ctiSetReturnAddress(&returnAddress, reinterpret_cast<void*>(ctiVMThrowTrampoline)); |
-} |
- |
void Machine::cti_register_file_check(CTI_ARGS) |
{ |
CTI_STACK_HACK(); |
@@ -4466,8 +4436,11 @@ |
if (LIKELY(ARG_registerFile->grow(ARG_callFrame + ARG_callFrame->codeBlock()->numCalleeRegisters))) |
return; |
- ARG_setCallFrame(ARG_callFrame->callerFrame()); |
- throwStackOverflowPreviousFrame(ARG_callFrame, ARG_globalData, CTI_RETURN_ADDRESS); |
+ // Rewind to the previous call frame because op_call already optimistically |
+ // moved the call frame forward. |
+ CallFrame* oldCallFrame = ARG_callFrame->callerFrame(); |
+ ARG_setCallFrame(oldCallFrame); |
+ throwStackOverflowError(oldCallFrame, ARG_globalData, oldCallFrame->returnPC(), CTI_RETURN_ADDRESS); |
} |
int Machine::cti_op_loop_if_less(CTI_ARGS) |
@@ -4744,8 +4717,12 @@ |
Register* r = callFrame->registers() + omittedArgCount; |
Register* newEnd = r + newCodeBlock->numCalleeRegisters; |
if (!ARG_registerFile->grow(newEnd)) { |
- ARG_globalData->exception = createStackOverflowError(oldCallFrame); |
- VM_THROW_EXCEPTION_2(); |
+ // Rewind to the previous call frame because op_call already optimistically |
+ // moved the call frame forward. |
+ ARG_setCallFrame(oldCallFrame); |
+ throwStackOverflowError(oldCallFrame, ARG_globalData, CTI_RETURN_ADDRESS, CTI_RETURN_ADDRESS); |
+ VoidPtrPairValue pair = {{ 0, 0 }}; |
+ return pair.i; |
} |
Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount; |
@@ -4810,7 +4787,7 @@ |
{ |
SamplingTool::HostCallRecord callRecord(CTI_SAMPLER); |
- // All host methods should be calling toThisObject, but this is not presently the case. |
+ // FIXME: All host methods should be calling toThisObject, but this is not presently the case. |
JSValue* thisValue = argv[0].jsValue(callFrame); |
if (thisValue == jsNull()) |
thisValue = callFrame->globalThisValue(); |
@@ -4934,8 +4911,8 @@ |
#endif |
StructureID* structure; |
- if (ARG_src5->isObject()) |
- structure = asObject(ARG_src5)->inheritorID(); |
+ if (ARG_src4->isObject()) |
+ structure = asObject(ARG_src4)->inheritorID(); |
else |
structure = asFunction(ARG_src1)->m_scopeChain.node()->globalObject()->emptyObjectStructure(); |
return new (ARG_globalData) JSObject(structure); |
@@ -4949,13 +4926,13 @@ |
JSValue* constrVal = ARG_src1; |
int argCount = ARG_int3; |
- int firstArg = ARG_int6; |
+ int thisRegister = ARG_int5; |
ConstructData constructData; |
ConstructType constructType = constrVal->getConstructData(constructData); |
if (constructType == ConstructTypeHost) { |
- ArgList argList(callFrame->registers() + firstArg + 1, argCount - 1); |
+ ArgList argList(callFrame->registers() + thisRegister + 1, argCount - 1); |
JSValue* returnValue; |
{ |
@@ -4969,7 +4946,7 @@ |
ASSERT(constructType == ConstructTypeNone); |
- ARG_globalData->exception = createNotAConstructorError(callFrame, constrVal, ARG_instr4, callFrame->codeBlock()); |
+ ARG_globalData->exception = createNotAConstructorError(callFrame, constrVal, ARG_instr6, callFrame->codeBlock()); |
VM_THROW_EXCEPTION(); |
} |
@@ -5568,20 +5545,21 @@ |
CallFrame* callFrame = ARG_callFrame; |
RegisterFile* registerFile = ARG_registerFile; |
- CodeBlock* codeBlock = callFrame->codeBlock(); |
- ScopeChainNode* scopeChain = callFrame->scopeChain(); |
Machine* machine = ARG_globalData->machine; |
JSValue* funcVal = ARG_src1; |
int registerOffset = ARG_int2; |
int argCount = ARG_int3; |
- JSValue* baseVal = ARG_src5; |
- if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) { |
- JSObject* thisObject = callFrame[codeBlock->thisRegister].jsValue(callFrame)->toThisObject(callFrame); |
+ Register* newCallFrame = callFrame->registers() + registerOffset; |
+ Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount; |
+ JSValue* thisValue = argv[0].jsValue(callFrame); |
+ JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject(); |
+ |
+ if (thisValue == globalObject && funcVal == globalObject->evalFunction()) { |
JSValue* exceptionValue = noValue(); |
- JSValue* result = machine->callEval(callFrame, thisObject, scopeChain, registerFile, registerOffset - RegisterFile::CallFrameHeaderSize - argCount, argCount, exceptionValue); |
+ JSValue* result = machine->callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue); |
if (UNLIKELY(exceptionValue != noValue())) { |
ARG_globalData->exception = exceptionValue; |
VM_THROW_EXCEPTION_AT_END(); |
@@ -5944,15 +5922,16 @@ |
CallFrame* callFrame = ARG_callFrame; |
CodeBlock* codeBlock = callFrame->codeBlock(); |
+ JSGlobalData* globalData = ARG_globalData; |
- ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(ARG_globalData->throwReturnAddress)); |
- unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(ARG_globalData->throwReturnAddress); |
+ ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(globalData->exceptionLocation)); |
+ unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(globalData->exceptionLocation); |
- JSValue* exceptionValue = ARG_globalData->exception; |
+ JSValue* exceptionValue = globalData->exception; |
ASSERT(exceptionValue); |
- ARG_globalData->exception = noValue(); |
+ globalData->exception = noValue(); |
- Instruction* handlerVPC = ARG_globalData->machine->throwException(callFrame, exceptionValue, codeBlock->instructions.begin() + vPCIndex, false); |
+ Instruction* handlerVPC = globalData->machine->throwException(callFrame, exceptionValue, codeBlock->instructions.begin() + vPCIndex, false); |
if (!handlerVPC) { |
*ARG_exception = exceptionValue; |