/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2015 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
#include "config.h"
#include "StackVisitor.h"
-#include "Arguments.h"
#include "CallFrameInlines.h"
+#include "ClonedArguments.h"
#include "Executable.h"
#include "Interpreter.h"
#include "JSCInlines.h"
StackVisitor::StackVisitor(CallFrame* startFrame)
{
m_frame.m_index = 0;
- readFrame(startFrame);
+ CallFrame* topFrame;
+ if (startFrame) {
+ m_frame.m_VMEntryFrame = startFrame->vm().topVMEntryFrame;
+ topFrame = startFrame->vm().topCallFrame;
+ } else {
+ m_frame.m_VMEntryFrame = 0;
+ topFrame = 0;
+ }
+ m_frame.m_callerIsVMEntryFrame = false;
+ readFrame(topFrame);
+
+ // Find the frame the caller wants to start unwinding from.
+ while (m_frame.callFrame() && m_frame.callFrame() != startFrame)
+ gotoNextFrame();
}
void StackVisitor::gotoNextFrame()
InlineCallFrame* inlineCallFrame = m_frame.inlineCallFrame();
CodeOrigin* callerCodeOrigin = &inlineCallFrame->caller;
readInlinedFrame(m_frame.callFrame(), callerCodeOrigin);
-
- } else
+ return;
+ }
#endif // ENABLE(DFG_JIT)
- readFrame(m_frame.callerFrame());
+ m_frame.m_VMEntryFrame = m_frame.m_CallerVMEntryFrame;
+ readFrame(m_frame.callerFrame());
}
void StackVisitor::readFrame(CallFrame* callFrame)
{
- ASSERT(!callFrame->isVMEntrySentinel());
if (!callFrame) {
m_frame.setToEnd();
return;
{
m_frame.m_callFrame = callFrame;
m_frame.m_argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
- m_frame.m_callerFrame = callFrame->callerFrameSkippingVMEntrySentinel();
+ m_frame.m_CallerVMEntryFrame = m_frame.m_VMEntryFrame;
+ m_frame.m_callerFrame = callFrame->callerFrame(m_frame.m_CallerVMEntryFrame);
+ m_frame.m_callerIsVMEntryFrame = m_frame.m_CallerVMEntryFrame != m_frame.m_VMEntryFrame;
m_frame.m_callee = callFrame->callee();
- m_frame.m_scope = callFrame->scope();
m_frame.m_codeBlock = callFrame->codeBlock();
m_frame.m_bytecodeOffset = !m_frame.codeBlock() ? 0
: codeOrigin ? codeOrigin->bytecodeIndex
void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin)
{
ASSERT(codeOrigin);
- ASSERT(!callFrame->isVMEntrySentinel());
int frameOffset = inlinedFrameOffset(codeOrigin);
bool isInlined = !!frameOffset;
m_frame.m_callFrame = callFrame;
m_frame.m_inlineCallFrame = inlineCallFrame;
- m_frame.m_argumentCountIncludingThis = inlineCallFrame->arguments.size();
+ if (inlineCallFrame->argumentCountRegister.isValid())
+ m_frame.m_argumentCountIncludingThis = callFrame->r(inlineCallFrame->argumentCountRegister.offset()).unboxedInt32();
+ else
+ m_frame.m_argumentCountIncludingThis = inlineCallFrame->arguments.size();
m_frame.m_codeBlock = inlineCallFrame->baselineCodeBlock();
m_frame.m_bytecodeOffset = codeOrigin->bytecodeIndex;
JSFunction* callee = inlineCallFrame->calleeForCallFrame(callFrame);
- m_frame.m_scope = callee->scope();
m_frame.m_callee = callee;
- ASSERT(m_frame.scope());
ASSERT(m_frame.callee());
// The callerFrame just needs to be non-null to indicate that we
switch (codeType()) {
case CodeType::Eval:
- traceLine = "eval code";
+ traceLine = ASCIILiteral("eval code");
break;
case CodeType::Native:
if (callee)
traceLine = getCalculatedDisplayName(callFrame(), callee).impl();
break;
case CodeType::Global:
- traceLine = "global code";
+ traceLine = ASCIILiteral("global code");
break;
}
return traceLine.isNull() ? emptyString() : traceLine;
break;
}
case CodeType::Native:
- traceLine = "[native code]";
+ traceLine = ASCIILiteral("[native code]");
break;
}
return traceLine.isNull() ? emptyString() : traceLine;
return traceBuild.toString().impl();
}
-Arguments* StackVisitor::Frame::createArguments()
+ClonedArguments* StackVisitor::Frame::createArguments()
{
ASSERT(m_callFrame);
CallFrame* physicalFrame = m_callFrame;
- VM& vm = physicalFrame->vm();
- Arguments* arguments;
+ ClonedArguments* arguments;
+ ArgumentsMode mode;
+ if (Options::enableFunctionDotArguments())
+ mode = ArgumentsMode::Cloned;
+ else
+ mode = ArgumentsMode::FakeValues;
#if ENABLE(DFG_JIT)
if (isInlinedFrame()) {
ASSERT(m_inlineCallFrame);
- arguments = Arguments::create(vm, physicalFrame, m_inlineCallFrame);
- arguments->tearOff(physicalFrame, m_inlineCallFrame);
+ arguments = ClonedArguments::createWithInlineFrame(physicalFrame, physicalFrame, m_inlineCallFrame, mode);
} else
#endif
- {
- arguments = Arguments::create(vm, physicalFrame);
- arguments->tearOff(physicalFrame);
- }
+ arguments = ClonedArguments::createWithMachineFrame(physicalFrame, physicalFrame, mode);
return arguments;
}
-Arguments* StackVisitor::Frame::existingArguments()
-{
- if (codeBlock()->codeType() != FunctionCode)
- return 0;
- if (!codeBlock()->usesArguments())
- return 0;
-
- VirtualRegister reg;
-
-#if ENABLE(DFG_JIT)
- if (isInlinedFrame())
- reg = inlineCallFrame()->argumentsRegister;
- else
-#endif // ENABLE(DFG_JIT)
- reg = codeBlock()->argumentsRegister();
-
- JSValue result = callFrame()->r(unmodifiedArgumentsRegister(reg).offset()).jsValue();
- if (!result || !result.isCell()) // Protect against Undefined in case we throw in op_enter.
- return 0;
- return jsCast<Arguments*>(result);
-}
-
void StackVisitor::Frame::computeLineAndColumn(unsigned& line, unsigned& column)
{
CodeBlock* codeBlock = this->codeBlock();
unsigned divotColumn = 0;
retrieveExpressionInfo(divot, unusedStartOffset, unusedEndOffset, divotLine, divotColumn);
- line = divotLine + codeBlock->ownerExecutable()->lineNo();
+ line = divotLine + codeBlock->ownerExecutable()->firstLine();
column = divotColumn + (divotLine ? 1 : codeBlock->firstLineColumnOffset());
+
+ if (codeBlock->ownerExecutable()->hasOverrideLineNumber())
+ line = codeBlock->ownerExecutable()->overrideLineNumber();
}
void StackVisitor::Frame::retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column)
#endif
}
-#ifndef NDEBUG
-
-static const char* jitTypeName(JITCode::JITType jitType)
-{
- switch (jitType) {
- case JITCode::None: return "None";
- case JITCode::HostCallThunk: return "HostCallThunk";
- case JITCode::InterpreterThunk: return "InterpreterThunk";
- case JITCode::BaselineJIT: return "BaselineJIT";
- case JITCode::DFGJIT: return "DFGJIT";
- case JITCode::FTLJIT: return "FTLJIT";
- }
- return "<unknown>";
-}
-
static void printIndents(int levels)
{
while (levels--)
dataLogFString(" ");
}
-static void printif(int indentLevels, const char* format, ...)
+template<typename... Types>
+void log(unsigned indent, const Types&... values)
{
- va_list argList;
- va_start(argList, format);
+ printIndents(indent);
+ dataLog(values...);
+}
- if (indentLevels)
- printIndents(indentLevels);
+template<typename... Types>
+void logF(unsigned indent, const char* format, const Types&... values)
+{
+ printIndents(indent);
#if COMPILER(CLANG) || COMPILER(GCC)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wmissing-format-attribute"
#endif
- WTF::dataLogFV(format, argList);
+ dataLogF(format, values...);
#if COMPILER(CLANG) || COMPILER(GCC)
#pragma GCC diagnostic pop
#endif
-
- va_end(argList);
}
-void StackVisitor::Frame::print(int indentLevel)
+void StackVisitor::Frame::print(int indent)
{
- int i = indentLevel;
-
if (!this->callFrame()) {
- printif(i, "frame 0x0\n");
+ log(indent, "frame 0x0\n");
return;
}
CodeBlock* codeBlock = this->codeBlock();
- printif(i, "frame %p {\n", this->callFrame());
+ logF(indent, "frame %p {\n", this->callFrame());
- CallFrame* callFrame = m_callFrame;
- CallFrame* callerFrame = this->callerFrame();
- void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr;
+ {
+ indent++;
+
+ CallFrame* callFrame = m_callFrame;
+ CallFrame* callerFrame = this->callerFrame();
+ void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr;
- printif(i, " name '%s'\n", functionName().utf8().data());
- printif(i, " sourceURL '%s'\n", sourceURL().utf8().data());
- printif(i, " isVMEntrySentinel %d\n", callerFrame->isVMEntrySentinel());
+ log(indent, "name: ", functionName(), "\n");
+ log(indent, "sourceURL: ", sourceURL(), "\n");
+ bool isInlined = false;
#if ENABLE(DFG_JIT)
- printif(i, " isInlinedFrame %d\n", isInlinedFrame());
- if (isInlinedFrame())
- printif(i, " InlineCallFrame %p\n", m_inlineCallFrame);
+ isInlined = isInlinedFrame();
+ log(indent, "isInlinedFrame: ", isInlinedFrame(), "\n");
+ if (isInlinedFrame())
+ logF(indent, "InlineCallFrame: %p\n", m_inlineCallFrame);
#endif
- printif(i, " callee %p\n", callee());
- printif(i, " returnPC %p\n", returnPC);
- printif(i, " callerFrame %p\n", callerFrame);
- unsigned locationRawBits = callFrame->locationAsRawBits();
- printif(i, " rawLocationBits %u 0x%x\n", locationRawBits, locationRawBits);
- printif(i, " codeBlock %p\n", codeBlock);
- if (codeBlock) {
- JITCode::JITType jitType = codeBlock->jitType();
- if (callFrame->hasLocationAsBytecodeOffset()) {
- unsigned bytecodeOffset = callFrame->locationAsBytecodeOffset();
- printif(i, " bytecodeOffset %u %p / %zu\n", bytecodeOffset, reinterpret_cast<void*>(bytecodeOffset), codeBlock->instructions().size());
+ logF(indent, "callee: %p\n", callee());
+ logF(indent, "returnPC: %p\n", returnPC);
+ logF(indent, "callerFrame: %p\n", callerFrame);
+ unsigned locationRawBits = callFrame->locationAsRawBits();
+ logF(indent, "rawLocationBits: %u 0x%x\n", locationRawBits, locationRawBits);
+ logF(indent, "codeBlock: %p ", codeBlock);
+ if (codeBlock)
+ dataLog(*codeBlock);
+ dataLog("\n");
+ if (codeBlock && !isInlined) {
+ indent++;
+
+ if (callFrame->hasLocationAsBytecodeOffset()) {
+ unsigned bytecodeOffset = callFrame->locationAsBytecodeOffset();
+ log(indent, "bytecodeOffset: ", bytecodeOffset, " of ", codeBlock->instructions().size(), "\n");
#if ENABLE(DFG_JIT)
- } else {
- unsigned codeOriginIndex = callFrame->locationAsCodeOriginIndex();
- printif(i, " codeOriginIdex %u %p / %zu\n", codeOriginIndex, reinterpret_cast<void*>(codeOriginIndex), codeBlock->codeOrigins().size());
+ } else {
+ log(indent, "hasCodeOrigins: ", codeBlock->hasCodeOrigins(), "\n");
+ if (codeBlock->hasCodeOrigins()) {
+ unsigned codeOriginIndex = callFrame->locationAsCodeOriginIndex();
+ log(indent, "codeOriginIndex: ", codeOriginIndex, " of ", codeBlock->codeOrigins().size(), "\n");
+
+ JITCode::JITType jitType = codeBlock->jitType();
+ if (jitType != JITCode::FTLJIT) {
+ JITCode* jitCode = codeBlock->jitCode().get();
+ logF(indent, "jitCode: %p start %p end %p\n", jitCode, jitCode->start(), jitCode->end());
+ }
+ }
#endif
+ }
+ unsigned line = 0;
+ unsigned column = 0;
+ computeLineAndColumn(line, column);
+ log(indent, "line: ", line, "\n");
+ log(indent, "column: ", column, "\n");
+
+ indent--;
}
- unsigned line = 0;
- unsigned column = 0;
- computeLineAndColumn(line, column);
- printif(i, " line %d\n", line);
- printif(i, " column %d\n", column);
- printif(i, " jitType %d <%s> isOptimizingJIT %d\n", jitType, jitTypeName(jitType), JITCode::isOptimizingJIT(jitType));
-#if ENABLE(DFG_JIT)
- printif(i, " hasCodeOrigins %d\n", codeBlock->hasCodeOrigins());
- if (codeBlock->hasCodeOrigins()) {
- JITCode* jitCode = codeBlock->jitCode().get();
- printif(i, " jitCode %p start %p end %p\n", jitCode, jitCode->start(), jitCode->end());
- }
-#endif
+ indent--;
}
- printif(i, "}\n");
+ log(indent, "}\n");
}
-#endif // NDEBUG
-
} // namespace JSC
-
-#ifndef NDEBUG
-using JSC::StackVisitor;
-
-// For debugging use
-JS_EXPORT_PRIVATE void debugPrintCallFrame(JSC::CallFrame*);
-JS_EXPORT_PRIVATE void debugPrintStack(JSC::CallFrame* topCallFrame);
-
-class DebugPrintFrameFunctor {
-public:
- enum Action {
- PrintOne,
- PrintAll
- };
-
- DebugPrintFrameFunctor(Action action)
- : m_action(action)
- {
- }
-
- StackVisitor::Status operator()(StackVisitor& visitor)
- {
- visitor->print(2);
- return m_action == PrintAll ? StackVisitor::Continue : StackVisitor::Done;
- }
-
-private:
- Action m_action;
-};
-
-void debugPrintCallFrame(JSC::CallFrame* callFrame)
-{
- if (!callFrame)
- return;
- DebugPrintFrameFunctor functor(DebugPrintFrameFunctor::PrintOne);
- callFrame->iterate(functor);
-}
-
-void debugPrintStack(JSC::CallFrame* topCallFrame)
-{
- if (!topCallFrame)
- return;
- DebugPrintFrameFunctor functor(DebugPrintFrameFunctor::PrintAll);
- topCallFrame->iterate(functor);
-}
-
-#endif // !NDEBUG