Commit 0acb42b9 authored by oliver@apple.com's avatar oliver@apple.com

dumpCallFrame is broken in ToT

https://bugs.webkit.org/show_bug.cgi?id=91444

Reviewed by Gavin Barraclough.

Various changes have been made to the SF calling convention, but
dumpCallFrame has not been updated to reflect these changes.
That resulted in both bogus information, as well as numerous
assertions of sadness.

This patch makes dumpCallFrame actually work again and adds the
wonderful feature of telling you the name of the variable that a
register reflects, or what value it contains.

* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::nameForRegister):
    A really innefficient mechanism for finding the name of a local register.
    This should only ever be used by debug code so this should be okay.
* bytecode/CodeBlock.h:
(CodeBlock):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate):
    Debug builds no longer throw away a functions symbol table, this allows
    us to actually perform a register# to name mapping
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
    We weren't propogating the bytecode offset here leading to assertions
    in debug builds when dumping bytecode of DFG compiled code.
* interpreter/Interpreter.cpp:
(JSC):
(JSC::Interpreter::dumpRegisters):
     Rework to actually be correct.
(JSC::getCallerInfo):
     Return the byteocde offset as well now, given we have to determine it
     anyway.
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::retrieveCallerFromVMCode):
* interpreter/Interpreter.h:
(Interpreter):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionDumpCallFrame):
     Give debug builds of JSC a method for calling dumpCallFrame so we can
     inspect a callframe without requiring us to break in a debugger.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@122790 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent eac77675
2012-07-16 Oliver Hunt <oliver@apple.com>
dumpCallFrame is broken in ToT
https://bugs.webkit.org/show_bug.cgi?id=91444
Reviewed by Gavin Barraclough.
Various changes have been made to the SF calling convention, but
dumpCallFrame has not been updated to reflect these changes.
That resulted in both bogus information, as well as numerous
assertions of sadness.
This patch makes dumpCallFrame actually work again and adds the
wonderful feature of telling you the name of the variable that a
register reflects, or what value it contains.
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::nameForRegister):
A really innefficient mechanism for finding the name of a local register.
This should only ever be used by debug code so this should be okay.
* bytecode/CodeBlock.h:
(CodeBlock):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::generate):
Debug builds no longer throw away a functions symbol table, this allows
us to actually perform a register# to name mapping
* dfg/DFGJITCompiler.cpp:
(JSC::DFG::JITCompiler::link):
We weren't propogating the bytecode offset here leading to assertions
in debug builds when dumping bytecode of DFG compiled code.
* interpreter/Interpreter.cpp:
(JSC):
(JSC::Interpreter::dumpRegisters):
Rework to actually be correct.
(JSC::getCallerInfo):
Return the byteocde offset as well now, given we have to determine it
anyway.
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::retrieveCallerFromVMCode):
* interpreter/Interpreter.h:
(Interpreter):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionDumpCallFrame):
Give debug builds of JSC a method for calling dumpCallFrame so we can
inspect a callframe without requiring us to break in a debugger.
2012-07-16 Filip Pizlo <fpizlo@apple.com>
Unreviewed, adding forgotten files.
......
......@@ -163,6 +163,7 @@ EXPORTS
?displayName@JSFunction@JSC@@QAE?BVUString@2@PAVExecState@2@@Z
?dtoa@WTF@@YAXQADNAA_NAAHAAI@Z
?dumpAllOptions@Options@JSC@@SAXPAU_iobuf@@@Z
?dumpCallFrame@Interpreter@JSC@@QAEXPAVExecState@2@@Z
?dumpSampleData@JSGlobalData@JSC@@QAEXPAVExecState@2@@Z
?empty@StringImpl@WTF@@SAPAV12@XZ
?enumerable@PropertyDescriptor@JSC@@QBE_NXZ
......
......@@ -2942,4 +2942,29 @@ bool CodeBlock::usesOpcode(OpcodeID opcodeID)
return false;
}
UString CodeBlock::nameForRegister(int registerNumber)
{
SymbolTable::iterator end = m_symbolTable->end();
for (SymbolTable::iterator ptr = m_symbolTable->begin(); ptr != end; ++ptr) {
if (ptr->second.getIndex() == registerNumber)
return UString(ptr->first);
}
if (needsActivation() && registerNumber == activationRegister())
return "activation";
if (registerNumber == thisRegister())
return "this";
if (usesArguments()) {
if (registerNumber == argumentsRegister())
return "arguments";
if (unmodifiedArgumentsRegister(argumentsRegister()) == registerNumber)
return "real arguments";
}
if (registerNumber < 0) {
int argumentPosition = -registerNumber;
argumentPosition -= RegisterFile::CallFrameHeaderSize + 1;
return String::format("arguments[%3d]", argumentPosition - 1).impl();
}
return "";
}
} // namespace JSC
......@@ -578,7 +578,9 @@ namespace JSC {
void createActivation(CallFrame*);
void clearEvalCache();
UString nameForRegister(int registerNumber);
void addPropertyAccessInstruction(unsigned propertyAccessInstruction)
{
m_propertyAccessInstructions.append(propertyAccessInstruction);
......
......@@ -193,8 +193,10 @@ JSObject* BytecodeGenerator::generate()
if (s_dumpsGeneratedCode)
m_codeBlock->dump(m_scopeChain->globalObject->globalExec());
#ifdef NDEBUG
if ((m_codeType == FunctionCode && !m_codeBlock->needsFullScopeChain() && !m_codeBlock->usesArguments()) || m_codeType == EvalCode)
symbolTable().clear();
#endif
m_codeBlock->shrinkToFit(CodeBlock::EarlyShrink);
......
......@@ -188,6 +188,7 @@ void JITCompiler::link(LinkBuffer& linkBuffer)
CallLinkInfo& info = m_codeBlock->callLinkInfo(i);
info.callType = m_jsCalls[i].m_callType;
info.isDFG = true;
info.bytecodeIndex = m_jsCalls[i].m_codeOrigin.bytecodeIndex;
linkBuffer.link(m_jsCalls[i].m_slowCall, FunctionPtr((m_globalData->getCTIStub(info.callType == CallLinkInfo::Construct ? linkConstructThunkGenerator : linkCallThunkGenerator)).code().executableAddress()));
info.callReturnLocation = linkBuffer.locationOfNearCall(m_jsCalls[i].m_slowCall);
info.hotPathBegin = linkBuffer.locationOf(m_jsCalls[i].m_targetToCheck);
......
......@@ -77,6 +77,8 @@ using namespace std;
namespace JSC {
static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, int& lineNumber, unsigned& bytecodeOffset);
// Returns the depth of the scope chain within a given call frame.
static int depth(CodeBlock* codeBlock, ScopeChainNode* sc)
{
......@@ -624,34 +626,42 @@ void Interpreter::dumpRegisters(CallFrame* callFrame)
CodeBlock* codeBlock = callFrame->codeBlock();
const Register* it;
const Register* end;
JSValue v;
it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - codeBlock->numParameters();
v = (*it).jsValue();
it = callFrame->registers() - RegisterFile::CallFrameHeaderSize - callFrame->argumentCountIncludingThis();
end = callFrame->registers() - RegisterFile::CallFrameHeaderSize;
while (it < end) {
JSValue v = it->jsValue();
int registerNumber = it - callFrame->registers();
UString name = codeBlock->nameForRegister(registerNumber);
#if USE(JSVALUE32_64)
dataLog("[this] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v)); ++it;
dataLog("[r% 3d %14s] | %10p | %-16s 0x%llx \n", registerNumber, name.ascii().data(), it, v.description(), JSValue::encode(v));
#else
dataLog("[this] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v)); ++it;
dataLog("[r% 3d %14s] | %10p | %-16s %p \n", registerNumber, name.ascii().data(), it, v.description(), JSValue::encode(v));
#endif
end = it + max(codeBlock->numParameters() - 1, 0); // - 1 to skip "this"
if (it != end) {
do {
v = (*it).jsValue();
#if USE(JSVALUE32_64)
dataLog("[param] | %10p | %-16s 0x%llx \n", it, v.description(), JSValue::encode(v));
#else
dataLog("[param] | %10p | %-16s %p \n", it, v.description(), JSValue::encode(v));
#endif
++it;
} while (it != end);
it++;
}
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("[ArgumentCount] | %10p | %ld \n", it, callFrame->argumentCount());
++it;
dataLog("[CallerFrame] | %10p | %p \n", it, callFrame->callerFrame());
++it;
dataLog("[Callee] | %10p | %p \n", it, callFrame->callee());
++it;
dataLog("[ScopeChain] | %10p | %p \n", it, callFrame->scopeChain());
++it;
#if ENABLE(JIT)
AbstractPC pc = callFrame->abstractReturnPC(callFrame->globalData());
if (pc.hasJITReturnAddress())
dataLog("[ReturnJITPC] | %10p | %p \n", it, pc.jitReturnAddress().value());
#endif
unsigned bytecodeOffset = 0;
int line = 0;
getCallerInfo(&callFrame->globalData(), callFrame, line, bytecodeOffset);
dataLog("[ReturnVPC] | %10p | %d (line %d)\n", it, bytecodeOffset, line);
++it;
dataLog("[CodeBlock] | %10p | %p \n", it, callFrame->codeBlock());
++it;
dataLog("-----------------------------------------------------------------------------\n");
int registerCount = 0;
......@@ -659,11 +669,13 @@ void Interpreter::dumpRegisters(CallFrame* callFrame)
end = it + codeBlock->m_numVars;
if (it != end) {
do {
v = (*it).jsValue();
JSValue v = it->jsValue();
int registerNumber = it - callFrame->registers();
UString name = codeBlock->nameForRegister(registerNumber);
#if USE(JSVALUE32_64)
dataLog("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
dataLog("[r% 3d %14s] | %10p | %-16s 0x%llx \n", registerNumber, name.ascii().data(), it, v.description(), JSValue::encode(v));
#else
dataLog("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
dataLog("[r% 3d %14s] | %10p | %-16s %p \n", registerNumber, name.ascii().data(), it, v.description(), JSValue::encode(v));
#endif
++it;
++registerCount;
......@@ -674,11 +686,11 @@ void Interpreter::dumpRegisters(CallFrame* callFrame)
end = it + codeBlock->m_numCalleeRegisters - codeBlock->m_numVars;
if (it != end) {
do {
v = (*it).jsValue();
JSValue v = (*it).jsValue();
#if USE(JSVALUE32_64)
dataLog("[r%2d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
dataLog("[r% 3d] | %10p | %-16s 0x%llx \n", registerCount, it, v.description(), JSValue::encode(v));
#else
dataLog("[r%2d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
dataLog("[r% 3d] | %10p | %-16s %p \n", registerCount, it, v.description(), JSValue::encode(v));
#endif
++it;
++registerCount;
......@@ -838,10 +850,10 @@ static int getLineNumberForCallFrame(JSGlobalData* globalData, CallFrame* callFr
#endif
}
static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, int& lineNumber)
static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, int& lineNumber, unsigned& bytecodeOffset)
{
UNUSED_PARAM(globalData);
unsigned bytecodeOffset = 0;
bytecodeOffset = 0;
lineNumber = -1;
ASSERT(!callFrame->hasHostCallFrameFlag());
CallFrame* callerFrame = callFrame->codeBlock() ? callFrame->trueCallerFrame() : callFrame->callerFrame()->removeHostCallFrameFlag();
......@@ -973,7 +985,8 @@ void Interpreter::getStackTrace(JSGlobalData* globalData, Vector<StackFrame>& re
StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), -1, UString()};
results.append(s);
}
callFrame = getCallerInfo(globalData, callFrame, line);
unsigned unusedBytecodeOffset = 0;
callFrame = getCallerInfo(globalData, callFrame, line, unusedBytecodeOffset);
}
}
......@@ -5330,7 +5343,8 @@ JSValue Interpreter::retrieveCallerFromVMCode(CallFrame* callFrame, JSFunction*
return jsNull();
int lineNumber;
CallFrame* callerFrame = getCallerInfo(&callFrame->globalData(), functionCallFrame, lineNumber);
unsigned bytecodeOffset;
CallFrame* callerFrame = getCallerInfo(&callFrame->globalData(), functionCallFrame, lineNumber, bytecodeOffset);
if (!callerFrame)
return jsNull();
JSValue caller = callerFrame->callee();
......@@ -5340,7 +5354,7 @@ JSValue Interpreter::retrieveCallerFromVMCode(CallFrame* callFrame, JSFunction*
// Skip over function bindings.
ASSERT(caller.isObject());
while (asObject(caller)->inherits(&JSBoundFunction::s_info)) {
callerFrame = getCallerInfo(&callFrame->globalData(), callerFrame, lineNumber);
callerFrame = getCallerInfo(&callFrame->globalData(), callerFrame, lineNumber, bytecodeOffset);
if (!callerFrame)
return jsNull();
caller = callerFrame->callee();
......
......@@ -248,6 +248,11 @@ namespace JSC {
void dumpSampleData(ExecState* exec);
void startSampling();
void stopSampling();
#ifndef NDEBUG
JS_EXPORT_PRIVATE void dumpCallFrame(CallFrame*);
#endif
private:
enum ExecutionFlag { Normal, InitializeAndReturn };
......@@ -279,7 +284,6 @@ namespace JSC {
JSValue privateExecute(ExecutionFlag, RegisterFile*, CallFrame*);
void dumpCallFrame(CallFrame*);
void dumpRegisters(CallFrame*);
bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval); }
......
......@@ -88,6 +88,7 @@ static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionGC(ExecState*);
#ifndef NDEBUG
static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState*);
#endif
static EncodedJSValue JSC_HOST_CALL functionVersion(ExecState*);
static EncodedJSValue JSC_HOST_CALL functionRun(ExecState*);
......@@ -194,6 +195,7 @@ protected:
addFunction(globalData, "quit", functionQuit, 0);
addFunction(globalData, "gc", functionGC, 0);
#ifndef NDEBUG
addFunction(globalData, "dumpCallFrame", functionDumpCallFrame, 0);
addFunction(globalData, "releaseExecutableMemory", functionReleaseExecutableMemory, 0);
#endif
addFunction(globalData, "version", functionVersion, 1);
......@@ -281,6 +283,15 @@ EncodedJSValue JSC_HOST_CALL functionPrint(ExecState* exec)
return JSValue::encode(jsUndefined());
}
#ifndef NDEBUG
EncodedJSValue JSC_HOST_CALL functionDumpCallFrame(ExecState* exec)
{
if (!exec->callerFrame()->hasHostCallFrameFlag())
exec->globalData().interpreter->dumpCallFrame(exec->callerFrame());
return JSValue::encode(jsUndefined());
}
#endif
EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
{
fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec)->value(exec).utf8().data());
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment