summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/interpreter
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-02-24 16:36:50 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-02-24 16:36:50 +0100
commitad0d549d4cc13433f77c1ac8f0ab379c83d93f28 (patch)
treeb34b0daceb7c8e7fdde4b4ec43650ab7caadb0a9 /Source/JavaScriptCore/interpreter
parent03e12282df9aa1e1fb05a8b90f1cfc2e08764cec (diff)
downloadqtwebkit-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.cpp3
-rw-r--r--Source/JavaScriptCore/interpreter/AbstractPC.h2
-rw-r--r--Source/JavaScriptCore/interpreter/CallFrame.cpp47
-rw-r--r--Source/JavaScriptCore/interpreter/CallFrame.h36
-rw-r--r--Source/JavaScriptCore/interpreter/Interpreter.cpp324
-rw-r--r--Source/JavaScriptCore/interpreter/Interpreter.h99
-rw-r--r--Source/JavaScriptCore/interpreter/RegisterFile.h3
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);