diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-24 16:36:50 +0100 |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2012-02-24 16:36:50 +0100 |
commit | ad0d549d4cc13433f77c1ac8f0ab379c83d93f28 (patch) | |
tree | b34b0daceb7c8e7fdde4b4ec43650ab7caadb0a9 /Source/JavaScriptCore/interpreter | |
parent | 03e12282df9aa1e1fb05a8b90f1cfc2e08764cec (diff) | |
download | qtwebkit-ad0d549d4cc13433f77c1ac8f0ab379c83d93f28.tar.gz |
Imported WebKit commit bb52bf3c0119e8a128cd93afe5572413a8617de9 (http://svn.webkit.org/repository/webkit/trunk@108790)
Diffstat (limited to 'Source/JavaScriptCore/interpreter')
-rw-r--r-- | Source/JavaScriptCore/interpreter/AbstractPC.cpp | 3 | ||||
-rw-r--r-- | Source/JavaScriptCore/interpreter/AbstractPC.h | 2 | ||||
-rw-r--r-- | Source/JavaScriptCore/interpreter/CallFrame.cpp | 47 | ||||
-rw-r--r-- | Source/JavaScriptCore/interpreter/CallFrame.h | 36 | ||||
-rw-r--r-- | Source/JavaScriptCore/interpreter/Interpreter.cpp | 324 | ||||
-rw-r--r-- | Source/JavaScriptCore/interpreter/Interpreter.h | 99 | ||||
-rw-r--r-- | Source/JavaScriptCore/interpreter/RegisterFile.h | 3 |
7 files changed, 418 insertions, 96 deletions
diff --git a/Source/JavaScriptCore/interpreter/AbstractPC.cpp b/Source/JavaScriptCore/interpreter/AbstractPC.cpp index 863915bda..755a0e303 100644 --- a/Source/JavaScriptCore/interpreter/AbstractPC.cpp +++ b/Source/JavaScriptCore/interpreter/AbstractPC.cpp @@ -45,7 +45,8 @@ AbstractPC::AbstractPC(JSGlobalData& globalData, ExecState* exec) } #endif -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) + UNUSED_PARAM(globalData); m_pointer = exec->returnVPC(); m_mode = Interpreter; #endif diff --git a/Source/JavaScriptCore/interpreter/AbstractPC.h b/Source/JavaScriptCore/interpreter/AbstractPC.h index dffaaf343..5ed74472e 100644 --- a/Source/JavaScriptCore/interpreter/AbstractPC.h +++ b/Source/JavaScriptCore/interpreter/AbstractPC.h @@ -60,7 +60,7 @@ public: } #endif -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) AbstractPC(Instruction* vPC) : m_pointer(vPC) , m_mode(Interpreter) diff --git a/Source/JavaScriptCore/interpreter/CallFrame.cpp b/Source/JavaScriptCore/interpreter/CallFrame.cpp index 3ef5bd26f..b0e5ea0f6 100644 --- a/Source/JavaScriptCore/interpreter/CallFrame.cpp +++ b/Source/JavaScriptCore/interpreter/CallFrame.cpp @@ -40,7 +40,7 @@ void CallFrame::dumpCaller() JSValue function; interpreter()->retrieveLastCaller(this, signedLineNumber, sourceID, urlString, function); - printf("Callpoint => %s:%d\n", urlString.utf8().data(), signedLineNumber); + dataLog("Callpoint => %s:%d\n", urlString.utf8().data(), signedLineNumber); } RegisterFile* CallFrame::registerFile() @@ -50,6 +50,29 @@ RegisterFile* CallFrame::registerFile() #endif +#if USE(JSVALUE32_64) +unsigned CallFrame::bytecodeOffsetForNonDFGCode() const +{ + ASSERT(codeBlock()); + return currentVPC() - codeBlock()->instructions().begin(); +} + +void CallFrame::setBytecodeOffsetForNonDFGCode(unsigned offset) +{ + ASSERT(codeBlock()); + setCurrentVPC(codeBlock()->instructions().begin() + offset); +} +#else +Instruction* CallFrame::currentVPC() const +{ + return codeBlock()->instructions().begin() + bytecodeOffsetForNonDFGCode(); +} +void CallFrame::setCurrentVPC(Instruction* vpc) +{ + setBytecodeOffsetForNonDFGCode(vpc - codeBlock()->instructions().begin()); +} +#endif + #if ENABLE(DFG_JIT) bool CallFrame::isInlineCallFrameSlow() { @@ -96,15 +119,15 @@ CallFrame* CallFrame::trueCallFrame(AbstractPC pc) if (pc.isSet()) { ReturnAddressPtr currentReturnPC = pc.jitReturnAddress(); - if (!machineCodeBlock->codeOriginForReturn(currentReturnPC, codeOrigin)) - return this; // Not currently in inlined code. + bool hasCodeOrigin = machineCodeBlock->codeOriginForReturn(currentReturnPC, codeOrigin); + ASSERT_UNUSED(hasCodeOrigin, hasCodeOrigin); } else { - unsigned index = codeOriginIndexForDFGWithInlining(); - if (index == UINT_MAX) - return this; // Not currently in inlined code. - + unsigned index = codeOriginIndexForDFG(); codeOrigin = machineCodeBlock->codeOrigin(index); } + + if (!codeOrigin.inlineCallFrame) + return this; // Not currently in inlined code. for (InlineCallFrame* inlineCallFrame = codeOrigin.inlineCallFrame; inlineCallFrame;) { InlineCallFrame* nextInlineCallFrame = inlineCallFrame->caller.inlineCallFrame; @@ -140,10 +163,10 @@ CallFrame* CallFrame::trueCallerFrame() // // machineCaller -> The caller according to the machine, which may be zero or // more frames above the true caller due to inlining. - + // Am I an inline call frame? If so, we're done. if (isInlineCallFrame()) - return callerFrame(); + return callerFrame()->removeHostCallFrameFlag(); // I am a machine call frame, so the question is: is my caller a machine call frame // that has inlines or a machine call frame that doesn't? @@ -153,10 +176,10 @@ CallFrame* CallFrame::trueCallerFrame() ASSERT(!machineCaller->isInlineCallFrame()); // Figure out how we want to get the current code location. - if (hasHostCallFrameFlag() || returnAddressIsInCtiTrampoline(returnPC())) - return machineCaller->trueCallFrameFromVMCode(); + if (!hasReturnPC() || returnAddressIsInCtiTrampoline(returnPC())) + return machineCaller->trueCallFrameFromVMCode()->removeHostCallFrameFlag(); - return machineCaller->trueCallFrame(returnPC()); + return machineCaller->trueCallFrame(returnPC())->removeHostCallFrameFlag(); } #endif diff --git a/Source/JavaScriptCore/interpreter/CallFrame.h b/Source/JavaScriptCore/interpreter/CallFrame.h index 4fadfab28..5bf2b9488 100644 --- a/Source/JavaScriptCore/interpreter/CallFrame.h +++ b/Source/JavaScriptCore/interpreter/CallFrame.h @@ -104,13 +104,30 @@ namespace JSC { CallFrame* callerFrame() const { return this[RegisterFile::CallerFrame].callFrame(); } #if ENABLE(JIT) ReturnAddressPtr returnPC() const { return ReturnAddressPtr(this[RegisterFile::ReturnPC].vPC()); } + bool hasReturnPC() const { return !!this[RegisterFile::ReturnPC].vPC(); } + void clearReturnPC() { registers()[RegisterFile::ReturnPC] = static_cast<Instruction*>(0); } #endif AbstractPC abstractReturnPC(JSGlobalData& globalData) { return AbstractPC(globalData, this); } - unsigned bytecodeOffsetForBaselineJIT() { return this[RegisterFile::ArgumentCount].tag(); } +#if USE(JSVALUE32_64) + unsigned bytecodeOffsetForNonDFGCode() const; + void setBytecodeOffsetForNonDFGCode(unsigned offset); +#else + unsigned bytecodeOffsetForNonDFGCode() const + { + ASSERT(codeBlock()); + return this[RegisterFile::ArgumentCount].tag(); + } + + void setBytecodeOffsetForNonDFGCode(unsigned offset) + { + ASSERT(codeBlock()); + this[RegisterFile::ArgumentCount].tag() = static_cast<int32_t>(offset); + } +#endif #if ENABLE(DFG_JIT) InlineCallFrame* inlineCallFrame() const { return this[RegisterFile::ReturnPC].asInlineCallFrame(); } - unsigned codeOriginIndexForDFGWithInlining() const { return this[RegisterFile::ArgumentCount].tag(); } + unsigned codeOriginIndexForDFG() const { return this[RegisterFile::ArgumentCount].tag(); } #else // This will never be called if !ENABLE(DFG_JIT) since all calls should be guarded by // isInlineCallFrame(). But to make it easier to write code without having a bunch of @@ -121,9 +138,22 @@ namespace JSC { return 0; } #endif -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) Instruction* returnVPC() const { return this[RegisterFile::ReturnPC].vPC(); } #endif +#if USE(JSVALUE32_64) + Instruction* currentVPC() const + { + return bitwise_cast<Instruction*>(this[RegisterFile::ArgumentCount].tag()); + } + void setCurrentVPC(Instruction* vpc) + { + this[RegisterFile::ArgumentCount].tag() = bitwise_cast<int32_t>(vpc); + } +#else + Instruction* currentVPC() const; + void setCurrentVPC(Instruction* vpc); +#endif void setCallerFrame(CallFrame* callerFrame) { static_cast<Register*>(this)[RegisterFile::CallerFrame] = callerFrame; } void setScopeChain(ScopeChainNode* scopeChain) { static_cast<Register*>(this)[RegisterFile::ScopeChain] = scopeChain; } diff --git a/Source/JavaScriptCore/interpreter/Interpreter.cpp b/Source/JavaScriptCore/interpreter/Interpreter.cpp index d42e869f1..336f109c0 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.cpp +++ b/Source/JavaScriptCore/interpreter/Interpreter.cpp @@ -45,7 +45,6 @@ #include "JSActivation.h" #include "JSArray.h" #include "JSByteArray.h" -#include "JSFunction.h" #include "JSNotAnObject.h" #include "JSPropertyNameIterator.h" #include "LiteralParser.h" @@ -60,6 +59,7 @@ #include "Register.h" #include "SamplingTool.h" #include "StrictEvalActivation.h" +#include "StrongInlines.h" #include "UStringConcatenate.h" #include <limits.h> #include <stdio.h> @@ -69,7 +69,7 @@ #include "JIT.h" #endif -#define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND (ENABLE(COMPUTED_GOTO_INTERPRETER) && !defined(__llvm__)) +#define WTF_USE_GCC_COMPUTED_GOTO_WORKAROUND ((ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT)) && !defined(__llvm__)) using namespace std; @@ -83,7 +83,7 @@ static int depth(CodeBlock* codeBlock, ScopeChainNode* sc) return sc->localDepth(); } -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) static NEVER_INLINE JSValue concatenateStrings(ExecState* exec, Register* strings, unsigned count) { return jsString(exec, strings, count); @@ -365,7 +365,7 @@ NEVER_INLINE bool Interpreter::resolveThisAndProperty(CallFrame* callFrame, Inst return false; } -#endif // ENABLE(INTERPRETER) +#endif // ENABLE(CLASSIC_INTERPRETER) ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argumentCountIncludingThis) { @@ -394,7 +394,7 @@ ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newC return newCallFrame; } -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) static NEVER_INLINE bool isInvalidParamForIn(CallFrame* callFrame, JSValue value, JSValue& exceptionData) { if (value.isObject()) @@ -543,36 +543,61 @@ Interpreter::Interpreter() #if !ASSERT_DISABLED , m_initialized(false) #endif - , m_enabled(false) + , m_classicEnabled(false) +{ +} + +Interpreter::~Interpreter() { +#if ENABLE(LLINT) + if (m_classicEnabled) + delete[] m_opcodeTable; +#endif } -void Interpreter::initialize(bool canUseJIT) +void Interpreter::initialize(LLInt::Data* llintData, bool canUseJIT) { -#if ENABLE(COMPUTED_GOTO_INTERPRETER) + UNUSED_PARAM(llintData); + UNUSED_PARAM(canUseJIT); +#if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT) +#if !ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) + // Having LLInt enabled, but not being able to use the JIT, and not having + // a computed goto interpreter, is not supported. Not because we cannot + // support it, but because I decided to draw the line at the number of + // permutations of execution engines that I wanted this code to grok. + ASSERT(canUseJIT); +#endif if (canUseJIT) { +#if ENABLE(LLINT) + m_opcodeTable = llintData->opcodeMap(); + for (int i = 0; i < numOpcodeIDs; ++i) + m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i)); +#else // If the JIT is present, don't use jump destinations for opcodes. for (int i = 0; i < numOpcodeIDs; ++i) { Opcode opcode = bitwise_cast<void*>(static_cast<uintptr_t>(i)); m_opcodeTable[i] = opcode; } +#endif } else { +#if ENABLE(LLINT) + m_opcodeTable = new Opcode[numOpcodeIDs]; +#endif privateExecute(InitializeAndReturn, 0, 0); for (int i = 0; i < numOpcodeIDs; ++i) m_opcodeIDTable.add(m_opcodeTable[i], static_cast<OpcodeID>(i)); - m_enabled = true; + m_classicEnabled = true; } #else - UNUSED_PARAM(canUseJIT); -#if ENABLE(INTERPRETER) - m_enabled = true; +#if ENABLE(CLASSIC_INTERPRETER) + m_classicEnabled = true; #else - m_enabled = false; + m_classicEnabled = false; #endif -#endif // ENABLE(COMPUTED_GOTO_INTERPRETER) +#endif // ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) #if !ASSERT_DISABLED m_initialized = true; #endif @@ -592,10 +617,10 @@ void Interpreter::dumpCallFrame(CallFrame* callFrame) void Interpreter::dumpRegisters(CallFrame* callFrame) { - printf("Register frame: \n\n"); - printf("-----------------------------------------------------------------------------\n"); - printf(" use | address | value \n"); - printf("-----------------------------------------------------------------------------\n"); + dataLog("Register frame: \n\n"); + dataLog("-----------------------------------------------------------------------------\n"); + dataLog(" use | address | value \n"); + dataLog("-----------------------------------------------------------------------------\n"); CodeBlock* codeBlock = callFrame->codeBlock(); const Register* it; @@ -605,30 +630,30 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->numParameters(); v = (*it).jsValue(); #if USE(JSVALUE32_64) - printf("[this] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); ++it; + dataLog("[this] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); ++it; #else - printf("[this] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); ++it; + dataLog("[this] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); ++it; #endif end = it + max(codeBlock->numParameters() - 1, 0); // - 1 to skip "this" if (it != end) { do { v = (*it).jsValue(); #if USE(JSVALUE32_64) - printf("[param] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); + dataLog("[param] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); #else - printf("[param] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); + dataLog("[param] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); #endif ++it; } while (it != end); } - printf("-----------------------------------------------------------------------------\n"); - printf("[CodeBlock] | %10p | %p \n", it, (*it).codeBlock()); ++it; - printf("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it; - printf("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it; - printf("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it; - printf("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it; - printf("[Callee] | %10p | %p \n", it, (*it).function()); ++it; - printf("-----------------------------------------------------------------------------\n"); + dataLog("-----------------------------------------------------------------------------\n"); + dataLog("[CodeBlock] | %10p | %p \n", it, (*it).codeBlock()); ++it; + dataLog("[ScopeChain] | %10p | %p \n", it, (*it).scopeChain()); ++it; + dataLog("[CallerRegisters] | %10p | %d \n", it, (*it).i()); ++it; + dataLog("[ReturnPC] | %10p | %p \n", it, (*it).vPC()); ++it; + dataLog("[ArgumentCount] | %10p | %d \n", it, (*it).i()); ++it; + dataLog("[Callee] | %10p | %p \n", it, (*it).function()); ++it; + dataLog("-----------------------------------------------------------------------------\n"); int registerCount = 0; @@ -637,39 +662,41 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) do { v = (*it).jsValue(); #if USE(JSVALUE32_64) - printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v)); + dataLog("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v)); #else - printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v)); + dataLog("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v)); #endif ++it; ++registerCount; } while (it != end); } - printf("-----------------------------------------------------------------------------\n"); + dataLog("-----------------------------------------------------------------------------\n"); end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numVars; if (it != end) { do { v = (*it).jsValue(); #if USE(JSVALUE32_64) - printf("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v)); + dataLog("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v)); #else - printf("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v)); + dataLog("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v)); #endif ++it; ++registerCount; } while (it != end); } - printf("-----------------------------------------------------------------------------\n"); + dataLog("-----------------------------------------------------------------------------\n"); } #endif bool Interpreter::isOpcode(Opcode opcode) { -#if ENABLE(COMPUTED_GOTO_INTERPRETER) - if (!m_enabled) +#if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT) +#if !ENABLE(LLINT) + if (!m_classicEnabled) return opcode >= 0 && static_cast<OpcodeID>(bitwise_cast<uintptr_t>(opcode)) <= op_end; +#endif return opcode != HashTraits<Opcode>::emptyValue() && !HashTraits<Opcode>::isDeletedValue(opcode) && m_opcodeIDTable.contains(opcode); @@ -724,13 +751,13 @@ NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue ex // the beginning of next instruction to execute. To get an offset // inside the call instruction that triggered the exception we // have to subtract 1. -#if ENABLE(JIT) && ENABLE(INTERPRETER) +#if ENABLE(JIT) && ENABLE(CLASSIC_INTERPRETER) if (callerFrame->globalData().canUseJIT()) - bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnPC()); + bytecodeOffset = codeBlock->bytecodeOffset(callerFrame, callFrame->returnPC()); else bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1; #elif ENABLE(JIT) - bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnPC()); + bytecodeOffset = codeBlock->bytecodeOffset(callerFrame, callFrame->returnPC()); #else bytecodeOffset = codeBlock->bytecodeOffset(callFrame->returnVPC()) - 1; #endif @@ -790,6 +817,154 @@ static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception, exception->putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message)); } +static int getLineNumberForCallFrame(CallFrame* callFrame) +{ + callFrame = callFrame->removeHostCallFrameFlag(); + CodeBlock* codeBlock = callFrame->codeBlock(); + if (!codeBlock) + return -1; +#if ENABLE(INTERPRETER) + if (!globalData->canUseJIT()) + return codeBlock->lineNumberForBytecodeOffset(callFrame->bytecodeOffsetForNonDFGCode() - 1); +#endif +#if ENABLE(JIT) +#if ENABLE(DFG_JIT) + if (codeBlock->getJITType() == JITCode::DFGJIT) + return codeBlock->lineNumberForBytecodeOffset(codeBlock->codeOrigin(callFrame->codeOriginIndexForDFG()).bytecodeIndex); +#endif + return codeBlock->lineNumberForBytecodeOffset(callFrame->bytecodeOffsetForNonDFGCode()); +#endif +} + +static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, int& lineNumber) +{ + UNUSED_PARAM(globalData); + unsigned bytecodeOffset = 0; + lineNumber = -1; + ASSERT(!callFrame->hasHostCallFrameFlag()); + CallFrame* callerFrame = callFrame->codeBlock() ? callFrame->trueCallerFrame() : 0; + bool callframeIsHost = callerFrame->addHostCallFrameFlag() == callFrame->callerFrame(); + ASSERT(!callerFrame->hasHostCallFrameFlag()); + + if (callerFrame == CallFrame::noCaller() || !callerFrame || !callerFrame->codeBlock()) + return callerFrame; + + CodeBlock* callerCodeBlock = callerFrame->codeBlock(); + + if (callframeIsHost) { + // Don't need to deal with inline callframes here as by definition we haven't + // inlined a call with an intervening native call frame. +#if ENABLE(INTERPRETER) + if (!globalData->canUseJIT()) { + bytecodeOffset = callerFrame->bytecodeOffsetForNonDFGCode(); + lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1); + return callerFrame; + } +#endif +#if ENABLE(JIT) +#if ENABLE(DFG_JIT) + if (callerCodeBlock && callerCodeBlock->getJITType() == JITCode::DFGJIT) + bytecodeOffset = callerCodeBlock->codeOrigin(callerFrame->codeOriginIndexForDFG()).bytecodeIndex; + else +#endif + bytecodeOffset = callerFrame->bytecodeOffsetForNonDFGCode(); +#endif + } else { +#if ENABLE(INTERPRETER) + if (!globalData->canUseJIT()) { + bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnVPC()); + lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1); + return callerFrame; + } +#endif +#if ENABLE(JIT) + #if ENABLE(DFG_JIT) + if (callFrame->isInlineCallFrame()) { + InlineCallFrame* icf = callFrame->inlineCallFrame(); + bytecodeOffset = icf->caller.bytecodeIndex; + if (InlineCallFrame* parentCallFrame = icf->caller.inlineCallFrame) { + FunctionExecutable* executable = static_cast<FunctionExecutable*>(parentCallFrame->executable.get()); + CodeBlock* newCodeBlock = executable->baselineCodeBlockFor(parentCallFrame->isCall ? CodeForCall : CodeForConstruct); + ASSERT(newCodeBlock); + ASSERT(newCodeBlock->instructionCount() > bytecodeOffset); + callerCodeBlock = newCodeBlock; + } + } else if (callerCodeBlock && callerCodeBlock->getJITType() == JITCode::DFGJIT) { + CodeOrigin origin; + if (!callerCodeBlock->codeOriginForReturn(callFrame->returnPC(), origin)) + ASSERT_NOT_REACHED(); + bytecodeOffset = origin.bytecodeIndex; + if (InlineCallFrame* icf = origin.inlineCallFrame) { + FunctionExecutable* executable = static_cast<FunctionExecutable*>(icf->executable.get()); + CodeBlock* newCodeBlock = executable->baselineCodeBlockFor(icf->isCall ? CodeForCall : CodeForConstruct); + ASSERT(newCodeBlock); + ASSERT(newCodeBlock->instructionCount() > bytecodeOffset); + callerCodeBlock = newCodeBlock; + } + } else + #endif + bytecodeOffset = callerCodeBlock->bytecodeOffset(callerFrame, callFrame->returnPC()); +#endif + } + + lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset); + return callerFrame; +} + +static ALWAYS_INLINE const UString getSourceURLFromCallFrame(CallFrame* callFrame) +{ + ASSERT(!callFrame->hasHostCallFrameFlag()); +#if ENABLE(INTERPRETER) +#if ENABLE(JIT) + if (callFrame->globalData().canUseJIT()) + return callFrame->codeBlock()->ownerExecutable()->sourceURL(); +#endif + return callFrame->codeBlock()->source()->url(); + +#else + return callFrame->codeBlock()->ownerExecutable()->sourceURL(); +#endif +} + +static StackFrameCodeType getStackFrameCodeType(CallFrame* callFrame) +{ + ASSERT(!callFrame->hasHostCallFrameFlag()); + + switch (callFrame->codeBlock()->codeType()) { + case EvalCode: + return StackFrameEvalCode; + case FunctionCode: + return StackFrameFunctionCode; + case GlobalCode: + return StackFrameGlobalCode; + } + ASSERT_NOT_REACHED(); + return StackFrameGlobalCode; +} + +void Interpreter::getStackTrace(JSGlobalData* globalData, int line, Vector<StackFrame>& results) +{ + CallFrame* callFrame = globalData->topCallFrame->removeHostCallFrameFlag()->trueCallFrameFromVMCode(); + if (!callFrame || callFrame == CallFrame::noCaller()) + return; + + if (line == -1) + line = getLineNumberForCallFrame(callFrame); + + while (callFrame && callFrame != CallFrame::noCaller()) { + UString sourceURL; + if (callFrame->codeBlock()) { + sourceURL = getSourceURLFromCallFrame(callFrame); + StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), getStackFrameCodeType(callFrame), Strong<ExecutableBase>(*globalData, callFrame->codeBlock()->ownerExecutable()), line, sourceURL}; + results.append(s); + } else { + StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), -1, UString()}; + results.append(s); + } + callFrame = getCallerInfo(globalData, callFrame, line); + } +} + NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset) { CodeBlock* codeBlock = callFrame->codeBlock(); @@ -808,7 +983,9 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV // FIXME: should only really be adding these properties to VM generated exceptions, // but the inspector currently requires these for all thrown objects. - addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source()); + Vector<StackFrame> stackTrace; + getStackTrace(&callFrame->globalData(), codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), stackTrace); + addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source(), stackTrace); } isInterrupt = isInterruptedExecutionException(exception) || isTerminatedExecutionException(exception); @@ -1280,15 +1457,15 @@ JSValue Interpreter::execute(CallFrameClosure& closure) m_reentryDepth++; #if ENABLE(JIT) -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) if (closure.newCallFrame->globalData().canUseJIT()) #endif result = closure.functionExecutable->generatedJITCodeForCall().execute(&m_registerFile, closure.newCallFrame, closure.globalData); -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) else #endif #endif -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) result = privateExecute(Normal, &m_registerFile, closure.newCallFrame); #endif m_reentryDepth--; @@ -1386,15 +1563,15 @@ JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSValue m_reentryDepth++; #if ENABLE(JIT) -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) if (callFrame->globalData().canUseJIT()) #endif result = eval->generatedJITCode().execute(&m_registerFile, newCallFrame, scopeChain->globalData); -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) else #endif #endif -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) result = privateExecute(Normal, &m_registerFile, newCallFrame); #endif m_reentryDepth--; @@ -1437,7 +1614,7 @@ NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHook } } -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC) { int dst = vPC[1].u.operand; @@ -1669,35 +1846,35 @@ NEVER_INLINE void Interpreter::uncacheGetByID(CodeBlock*, Instruction* vPC) vPC[4] = 0; } -#endif // ENABLE(INTERPRETER) +#endif // ENABLE(CLASSIC_INTERPRETER) JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFile, CallFrame* callFrame) { // One-time initialization of our address tables. We have to put this code // here because our labels are only in scope inside this function. if (UNLIKELY(flag == InitializeAndReturn)) { - #if ENABLE(COMPUTED_GOTO_INTERPRETER) + #if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) #define LIST_OPCODE_LABEL(id, length) &&id, static Opcode labels[] = { FOR_EACH_OPCODE_ID(LIST_OPCODE_LABEL) }; for (size_t i = 0; i < WTF_ARRAY_LENGTH(labels); ++i) m_opcodeTable[i] = labels[i]; #undef LIST_OPCODE_LABEL - #endif // ENABLE(COMPUTED_GOTO_INTERPRETER) + #endif // ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) return JSValue(); } ASSERT(m_initialized); - ASSERT(m_enabled); + ASSERT(m_classicEnabled); #if ENABLE(JIT) -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) // Mixing Interpreter + JIT is not supported. if (callFrame->globalData().canUseJIT()) #endif ASSERT_NOT_REACHED(); #endif -#if !ENABLE(INTERPRETER) +#if !ENABLE(CLASSIC_INTERPRETER) UNUSED_PARAM(registerFile); UNUSED_PARAM(callFrame); return JSValue(); @@ -1743,20 +1920,31 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi #define SAMPLE(codeBlock, vPC) #endif -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#define UPDATE_BYTECODE_OFFSET() \ + do {\ + callFrame->setBytecodeOffsetForNonDFGCode(vPC - codeBlock->instructions().data() + 1);\ + } while (0) + +#if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto *vPC->u.opcode #if ENABLE(OPCODE_STATS) - #define DEFINE_OPCODE(opcode) opcode: OpcodeStats::recordInstruction(opcode); + #define DEFINE_OPCODE(opcode) \ + opcode:\ + OpcodeStats::recordInstruction(opcode);\ + UPDATE_BYTECODE_OFFSET(); #else - #define DEFINE_OPCODE(opcode) opcode: + #define DEFINE_OPCODE(opcode) opcode: UPDATE_BYTECODE_OFFSET(); #endif NEXT_INSTRUCTION(); #else #define NEXT_INSTRUCTION() SAMPLE(codeBlock, vPC); goto interpreterLoopStart #if ENABLE(OPCODE_STATS) - #define DEFINE_OPCODE(opcode) case opcode: OpcodeStats::recordInstruction(opcode); + #define DEFINE_OPCODE(opcode) \ + case opcode:\ + OpcodeStats::recordInstruction(opcode);\ + UPDATE_BYTECODE_OFFSET(); #else - #define DEFINE_OPCODE(opcode) case opcode: + #define DEFINE_OPCODE(opcode) case opcode: UPDATE_BYTECODE_OFFSET(); #endif while (1) { // iterator loop begins interpreterLoopStart:; @@ -3327,6 +3515,8 @@ skip_id_custom_self: #if USE(GCC_COMPUTED_GOTO_WORKAROUND) skip_put_by_id: #endif + DEFINE_OPCODE(op_put_by_id_transition_direct) + DEFINE_OPCODE(op_put_by_id_transition_normal) DEFINE_OPCODE(op_put_by_id_transition) { /* op_put_by_id_transition base(r) property(id) value(r) oldStructure(sID) newStructure(sID) structureChain(chain) offset(n) direct(b) @@ -4883,7 +5073,7 @@ skip_id_custom_self: vPC += target; NEXT_INSTRUCTION(); } -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) // Appease GCC goto *(&&skip_new_scope); #endif @@ -4899,7 +5089,7 @@ skip_id_custom_self: vPC += OPCODE_LENGTH(op_push_new_scope); NEXT_INSTRUCTION(); } -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) skip_new_scope: #endif DEFINE_OPCODE(op_catch) { @@ -5089,14 +5279,14 @@ skip_id_custom_self: NEXT_INSTRUCTION(); } } -#if !ENABLE(COMPUTED_GOTO_INTERPRETER) +#if !ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) } // iterator loop ends #endif #undef NEXT_INSTRUCTION #undef DEFINE_OPCODE #undef CHECK_FOR_EXCEPTION #undef CHECK_FOR_TIMEOUT -#endif // ENABLE(INTERPRETER) +#endif // ENABLE(CLASSIC_INTERPRETER) } JSValue Interpreter::retrieveArgumentsFromVMCode(CallFrame* callFrame, JSFunction* function) const @@ -5155,15 +5345,15 @@ void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intp if (!callerCodeBlock) return; unsigned bytecodeOffset = 0; -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) if (!callerFrame->globalData().canUseJIT()) bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnVPC()); #if ENABLE(JIT) else - bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC()); + bytecodeOffset = callerCodeBlock->bytecodeOffset(callerFrame, callFrame->returnPC()); #endif #else - bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC()); + bytecodeOffset = callerCodeBlock->bytecodeOffset(callerFrame, callFrame->returnPC()); #endif lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1); sourceID = callerCodeBlock->ownerExecutable()->sourceID(); diff --git a/Source/JavaScriptCore/interpreter/Interpreter.h b/Source/JavaScriptCore/interpreter/Interpreter.h index 884c4248e..51881a565 100644 --- a/Source/JavaScriptCore/interpreter/Interpreter.h +++ b/Source/JavaScriptCore/interpreter/Interpreter.h @@ -31,8 +31,10 @@ #include "ArgList.h" #include "JSCell.h" +#include "JSFunction.h" #include "JSValue.h" #include "JSObject.h" +#include "LLIntData.h" #include "Opcode.h" #include "RegisterFile.h" @@ -42,9 +44,10 @@ namespace JSC { class CodeBlock; class EvalExecutable; + class ExecutableBase; class FunctionExecutable; - class JSFunction; class JSGlobalObject; + class LLIntOffsetsExtractor; class ProgramExecutable; class Register; class ScopeChainNode; @@ -62,6 +65,63 @@ namespace JSC { WillExecuteStatement }; + enum StackFrameCodeType { + StackFrameGlobalCode, + StackFrameEvalCode, + StackFrameFunctionCode, + StackFrameNativeCode + }; + + struct StackFrame { + Strong<JSObject> callee; + StackFrameCodeType codeType; + Strong<ExecutableBase> executable; + int line; + UString sourceURL; + UString toString(CallFrame* callFrame) const + { + bool hasSourceURLInfo = !sourceURL.isNull() && !sourceURL.isEmpty(); + bool hasLineInfo = line > -1; + String traceLine; + JSObject* stackFrameCallee = callee.get(); + + switch (codeType) { + case StackFrameEvalCode: + if (hasSourceURLInfo) { + traceLine = hasLineInfo ? String::format("eval code@%s:%d", sourceURL.ascii().data(), line) + : String::format("eval code@%s", sourceURL.ascii().data()); + } else + traceLine = String::format("eval code"); + break; + case StackFrameNativeCode: { + if (callee) { + UString functionName = getCalculatedDisplayName(callFrame, stackFrameCallee); + traceLine = String::format("%s@[native code]", functionName.ascii().data()); + } else + traceLine = "[native code]"; + break; + } + case StackFrameFunctionCode: { + UString functionName = getCalculatedDisplayName(callFrame, stackFrameCallee); + if (hasSourceURLInfo) { + traceLine = hasLineInfo ? String::format("%s@%s:%d", functionName.ascii().data(), sourceURL.ascii().data(), line) + : String::format("%s@%s", functionName.ascii().data(), sourceURL.ascii().data()); + } else + traceLine = String::format("%s\n", functionName.ascii().data()); + break; + } + case StackFrameGlobalCode: + if (hasSourceURLInfo) { + traceLine = hasLineInfo ? String::format("global code@%s:%d", sourceURL.ascii().data(), line) + : String::format("global code@%s", sourceURL.ascii().data()); + } else + traceLine = String::format("global code"); + + } + return traceLine.impl(); + } + }; + class TopCallFrameSetter { public: TopCallFrameSetter(JSGlobalData& global, CallFrame* callFrame) @@ -90,29 +150,31 @@ namespace JSC { } }; -#if PLATFORM(IOS) // We use a smaller reentrancy limit on iPhone because of the high amount of // stack space required on the web thread. - enum { MaxLargeThreadReentryDepth = 93, MaxSmallThreadReentryDepth = 16 }; +#if PLATFORM(IOS) + enum { MaxLargeThreadReentryDepth = 64, MaxSmallThreadReentryDepth = 16 }; #else enum { MaxLargeThreadReentryDepth = 256, MaxSmallThreadReentryDepth = 16 }; #endif // PLATFORM(IOS) class Interpreter { WTF_MAKE_FAST_ALLOCATED; - friend class JIT; friend class CachedCall; + friend class LLIntOffsetsExtractor; + friend class JIT; public: Interpreter(); + ~Interpreter(); - void initialize(bool canUseJIT); + void initialize(LLInt::Data*, bool canUseJIT); RegisterFile& registerFile() { return m_registerFile; } Opcode getOpcode(OpcodeID id) { ASSERT(m_initialized); -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) || ENABLE(LLINT) return m_opcodeTable[id]; #else return id; @@ -122,9 +184,12 @@ namespace JSC { OpcodeID getOpcodeID(Opcode opcode) { ASSERT(m_initialized); -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if ENABLE(LLINT) + ASSERT(isOpcode(opcode)); + return m_opcodeIDTable.get(opcode); +#elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) ASSERT(isOpcode(opcode)); - if (!m_enabled) + if (!m_classicEnabled) return static_cast<OpcodeID>(bitwise_cast<uintptr_t>(opcode)); return m_opcodeIDTable.get(opcode); @@ -132,6 +197,11 @@ namespace JSC { return opcode; #endif } + + bool classicEnabled() + { + return m_classicEnabled; + } bool isOpcode(Opcode); @@ -151,6 +221,8 @@ namespace JSC { NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset); NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine); + static const UString getTraceLine(CallFrame*, StackFrameCodeType, const UString&, int); + JS_EXPORT_PRIVATE static void getStackTrace(JSGlobalData*, int line, Vector<StackFrame>& results); void dumpSampleData(ExecState* exec); void startSampling(); @@ -162,7 +234,7 @@ namespace JSC { void endRepeatCall(CallFrameClosure&); JSValue execute(CallFrameClosure&); -#if ENABLE(INTERPRETER) +#if ENABLE(CLASSIC_INTERPRETER) NEVER_INLINE bool resolve(CallFrame*, Instruction*, JSValue& exceptionValue); NEVER_INLINE bool resolveSkip(CallFrame*, Instruction*, JSValue& exceptionValue); NEVER_INLINE bool resolveGlobal(CallFrame*, Instruction*, JSValue& exceptionValue); @@ -176,7 +248,7 @@ namespace JSC { void uncacheGetByID(CodeBlock*, Instruction* vPC); void tryCachePutByID(CallFrame*, CodeBlock*, Instruction*, JSValue baseValue, const PutPropertySlot&); void uncachePutByID(CodeBlock*, Instruction* vPC); -#endif // ENABLE(INTERPRETER) +#endif // ENABLE(CLASSIC_INTERPRETER) NEVER_INLINE bool unwindCallFrame(CallFrame*&, JSValue, unsigned& bytecodeOffset, CodeBlock*&); @@ -199,7 +271,10 @@ namespace JSC { RegisterFile m_registerFile; -#if ENABLE(COMPUTED_GOTO_INTERPRETER) +#if ENABLE(LLINT) + Opcode* m_opcodeTable; // Maps OpcodeID => Opcode for compiling + HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling +#elif ENABLE(COMPUTED_GOTO_CLASSIC_INTERPRETER) Opcode m_opcodeTable[numOpcodeIDs]; // Maps OpcodeID => Opcode for compiling HashMap<Opcode, OpcodeID> m_opcodeIDTable; // Maps Opcode => OpcodeID for decompiling #endif @@ -207,7 +282,7 @@ namespace JSC { #if !ASSERT_DISABLED bool m_initialized; #endif - bool m_enabled; + bool m_classicEnabled; }; // This value must not be an object that would require this conversion (WebCore's global object). diff --git a/Source/JavaScriptCore/interpreter/RegisterFile.h b/Source/JavaScriptCore/interpreter/RegisterFile.h index e45b869a1..21ad7fbae 100644 --- a/Source/JavaScriptCore/interpreter/RegisterFile.h +++ b/Source/JavaScriptCore/interpreter/RegisterFile.h @@ -39,6 +39,7 @@ namespace JSC { class ConservativeRoots; class DFGCodeBlocks; + class LLIntOffsetsExtractor; class RegisterFile { WTF_MAKE_NONCOPYABLE(RegisterFile); @@ -81,6 +82,8 @@ namespace JSC { } private: + friend class LLIntOffsetsExtractor; + bool growSlowCase(Register*); void releaseExcessCapacity(); void addToCommittedByteCount(long); |