summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/interpreter/StackVisitor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/interpreter/StackVisitor.cpp')
-rw-r--r--Source/JavaScriptCore/interpreter/StackVisitor.cpp433
1 files changed, 232 insertions, 201 deletions
diff --git a/Source/JavaScriptCore/interpreter/StackVisitor.cpp b/Source/JavaScriptCore/interpreter/StackVisitor.cpp
index d922e7f8f..aae6daa78 100644
--- a/Source/JavaScriptCore/interpreter/StackVisitor.cpp
+++ b/Source/JavaScriptCore/interpreter/StackVisitor.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013 Apple Inc. All rights reserved.
+ * Copyright (C) 2013, 2015-2016 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,42 +26,88 @@
#include "config.h"
#include "StackVisitor.h"
-#include "Arguments.h"
-#include "CallFrameInlines.h"
-#include "Executable.h"
+#include "ClonedArguments.h"
+#include "DebuggerPrimitives.h"
+#include "InlineCallFrame.h"
#include "Interpreter.h"
-#include "Operations.h"
-#include <wtf/DataLog.h>
+#include "JSCInlines.h"
+#include "JSWebAssemblyCallee.h"
+#include <wtf/text/StringBuilder.h>
namespace JSC {
StackVisitor::StackVisitor(CallFrame* startFrame)
{
m_frame.m_index = 0;
- readFrame(startFrame);
+ m_frame.m_isWasmFrame = false;
+ CallFrame* topFrame;
+ if (startFrame) {
+ m_frame.m_VMEntryFrame = startFrame->vm().topVMEntryFrame;
+ topFrame = startFrame->vm().topCallFrame;
+
+ if (topFrame && static_cast<void*>(m_frame.m_VMEntryFrame) == static_cast<void*>(topFrame)) {
+ topFrame = vmEntryRecord(m_frame.m_VMEntryFrame)->m_prevTopCallFrame;
+ m_frame.m_VMEntryFrame = vmEntryRecord(m_frame.m_VMEntryFrame)->m_prevTopVMEntryFrame;
+ }
+ } 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()
{
+ m_frame.m_index++;
#if ENABLE(DFG_JIT)
if (m_frame.isInlinedFrame()) {
InlineCallFrame* inlineCallFrame = m_frame.inlineCallFrame();
- CodeOrigin* callerCodeOrigin = &inlineCallFrame->caller;
- readInlinedFrame(m_frame.callFrame(), callerCodeOrigin);
-
- } else
+ CodeOrigin* callerCodeOrigin = inlineCallFrame->getCallerSkippingTailCalls();
+ if (!callerCodeOrigin) {
+ while (inlineCallFrame) {
+ readInlinedFrame(m_frame.callFrame(), &inlineCallFrame->directCaller);
+ inlineCallFrame = m_frame.inlineCallFrame();
+ }
+ m_frame.m_VMEntryFrame = m_frame.m_CallerVMEntryFrame;
+ readFrame(m_frame.callerFrame());
+ } else
+ readInlinedFrame(m_frame.callFrame(), callerCodeOrigin);
+ return;
+ }
#endif // ENABLE(DFG_JIT)
- readFrame(m_frame.callerFrame());
+ m_frame.m_VMEntryFrame = m_frame.m_CallerVMEntryFrame;
+ readFrame(m_frame.callerFrame());
+}
+
+void StackVisitor::unwindToMachineCodeBlockFrame()
+{
+#if ENABLE(DFG_JIT)
+ if (m_frame.isInlinedFrame()) {
+ CodeOrigin codeOrigin = m_frame.inlineCallFrame()->directCaller;
+ while (codeOrigin.inlineCallFrame)
+ codeOrigin = codeOrigin.inlineCallFrame->directCaller;
+ readNonInlinedFrame(m_frame.callFrame(), &codeOrigin);
+ }
+#endif
}
void StackVisitor::readFrame(CallFrame* callFrame)
{
- ASSERT(!callFrame->isVMEntrySentinel());
if (!callFrame) {
m_frame.setToEnd();
return;
}
+ if (callFrame->callee()->isAnyWasmCallee(callFrame->vm())) {
+ readNonInlinedFrame(callFrame);
+ return;
+ }
+
#if !ENABLE(DFG_JIT)
readNonInlinedFrame(callFrame);
@@ -81,7 +127,7 @@ void StackVisitor::readFrame(CallFrame* callFrame)
return;
}
- unsigned index = callFrame->locationAsCodeOriginIndex();
+ CallSiteIndex index = callFrame->callSiteIndex();
ASSERT(codeBlock->canGetCodeOrigin(index));
if (!codeBlock->canGetCodeOrigin(index)) {
// See assertion above. In release builds, we try to protect ourselves
@@ -104,13 +150,26 @@ void StackVisitor::readNonInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOri
{
m_frame.m_callFrame = callFrame;
m_frame.m_argumentCountIncludingThis = callFrame->argumentCountIncludingThis();
- m_frame.m_callerFrame = callFrame->callerFrameSkippingVMEntrySentinel();
- 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
- : callFrame->locationAsBytecodeOffset();
+ 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_isWasmFrame = false;
+
+ JSCell* callee = callFrame->callee();
+ m_frame.m_callee = callee;
+
+ if (callee->isAnyWasmCallee(*callee->vm())) {
+ m_frame.m_isWasmFrame = true;
+ m_frame.m_codeBlock = nullptr;
+ m_frame.m_bytecodeOffset = 0;
+ } else {
+ m_frame.m_codeBlock = callFrame->codeBlock();
+ m_frame.m_bytecodeOffset = !m_frame.codeBlock() ? 0
+ : codeOrigin ? codeOrigin->bytecodeIndex
+ : callFrame->bytecodeOffset();
+
+ }
+
#if ENABLE(DFG_JIT)
m_frame.m_inlineCallFrame = 0;
#endif
@@ -127,7 +186,7 @@ static int inlinedFrameOffset(CodeOrigin* codeOrigin)
void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin)
{
ASSERT(codeOrigin);
- ASSERT(!callFrame->isVMEntrySentinel());
+ m_frame.m_isWasmFrame = false;
int frameOffset = inlinedFrameOffset(codeOrigin);
bool isInlined = !!frameOffset;
@@ -136,14 +195,15 @@ void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin
m_frame.m_callFrame = callFrame;
m_frame.m_inlineCallFrame = inlineCallFrame;
- m_frame.m_argumentCountIncludingThis = inlineCallFrame->arguments.size();
- m_frame.m_codeBlock = inlineCallFrame->baselineCodeBlock();
+ 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.get();
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
@@ -158,14 +218,24 @@ void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin
}
#endif // ENABLE(DFG_JIT)
+bool StackVisitor::Frame::isWasmFrame() const
+{
+ return m_isWasmFrame;
+}
+
StackVisitor::Frame::CodeType StackVisitor::Frame::codeType() const
{
- if (!isJSFrame())
+ if (isWasmFrame())
+ return CodeType::Wasm;
+
+ if (!codeBlock())
return CodeType::Native;
switch (codeBlock()->codeType()) {
case EvalCode:
return CodeType::Eval;
+ case ModuleCode:
+ return CodeType::Module;
case FunctionCode:
return CodeType::Function;
case GlobalCode:
@@ -175,50 +245,88 @@ StackVisitor::Frame::CodeType StackVisitor::Frame::codeType() const
return CodeType::Global;
}
-String StackVisitor::Frame::functionName()
+RegisterAtOffsetList* StackVisitor::Frame::calleeSaveRegisters()
+{
+ if (isInlinedFrame())
+ return nullptr;
+
+#if ENABLE(JIT) && NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
+
+#if ENABLE(WEBASSEMBLY)
+ if (isWasmFrame()) {
+ if (JSCell* callee = this->callee()) {
+ if (JSWebAssemblyCallee* wasmCallee = jsDynamicCast<JSWebAssemblyCallee*>(*callee->vm(), callee))
+ return wasmCallee->calleeSaveRegisters();
+ // Other wasm callees (e.g, stubs) don't use callee save registers, so nothing needs
+ // to be restored for them.
+ }
+
+ return nullptr;
+ }
+#endif // ENABLE(WEBASSEMBLY)
+
+ if (CodeBlock* codeBlock = this->codeBlock())
+ return codeBlock->calleeSaveRegisters();
+
+#endif // ENABLE(JIT) && NUMBER_OF_CALLEE_SAVES_REGISTERS > 0
+
+ return nullptr;
+}
+
+String StackVisitor::Frame::functionName() const
{
String traceLine;
- JSObject* callee = this->callee();
+ JSCell* callee = this->callee();
switch (codeType()) {
+ case CodeType::Wasm:
+ traceLine = ASCIILiteral("wasm code");
+ break;
case CodeType::Eval:
- traceLine = "eval code";
+ traceLine = ASCIILiteral("eval code");
+ break;
+ case CodeType::Module:
+ traceLine = ASCIILiteral("module code");
break;
case CodeType::Native:
if (callee)
- traceLine = getCalculatedDisplayName(callFrame(), callee).impl();
+ traceLine = getCalculatedDisplayName(callFrame()->vm(), jsCast<JSObject*>(callee)).impl();
break;
case CodeType::Function:
- traceLine = getCalculatedDisplayName(callFrame(), callee).impl();
+ traceLine = getCalculatedDisplayName(callFrame()->vm(), jsCast<JSObject*>(callee)).impl();
break;
case CodeType::Global:
- traceLine = "global code";
+ traceLine = ASCIILiteral("global code");
break;
}
return traceLine.isNull() ? emptyString() : traceLine;
}
-String StackVisitor::Frame::sourceURL()
+String StackVisitor::Frame::sourceURL() const
{
String traceLine;
switch (codeType()) {
case CodeType::Eval:
+ case CodeType::Module:
case CodeType::Function:
case CodeType::Global: {
- String sourceURL = codeBlock()->ownerExecutable()->sourceURL();
+ String sourceURL = codeBlock()->ownerScriptExecutable()->sourceURL();
if (!sourceURL.isEmpty())
traceLine = sourceURL.impl();
break;
}
case CodeType::Native:
- traceLine = "[native code]";
+ traceLine = ASCIILiteral("[native code]");
+ break;
+ case CodeType::Wasm:
+ traceLine = ASCIILiteral("[wasm code]");
break;
}
return traceLine.isNull() ? emptyString() : traceLine;
}
-String StackVisitor::Frame::toString()
+String StackVisitor::Frame::toString() const
{
StringBuilder traceBuild;
String functionName = this->functionName();
@@ -228,7 +336,7 @@ String StackVisitor::Frame::toString()
if (!functionName.isEmpty())
traceBuild.append('@');
traceBuild.append(sourceURL);
- if (isJSFrame()) {
+ if (hasLineAndColumnInfo()) {
unsigned line = 0;
unsigned column = 0;
computeLineAndColumn(line, column);
@@ -241,49 +349,39 @@ String StackVisitor::Frame::toString()
return traceBuild.toString().impl();
}
-Arguments* StackVisitor::Frame::createArguments()
+intptr_t StackVisitor::Frame::sourceID()
+{
+ if (CodeBlock* codeBlock = this->codeBlock())
+ return codeBlock->ownerScriptExecutable()->sourceID();
+ return noSourceID;
+}
+
+ClonedArguments* StackVisitor::Frame::createArguments()
{
ASSERT(m_callFrame);
CallFrame* physicalFrame = m_callFrame;
- VM& vm = physicalFrame->vm();
- Arguments* arguments;
+ ClonedArguments* arguments;
+ ArgumentsMode mode;
+ if (Options::useFunctionDotArguments())
+ 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()
+bool StackVisitor::Frame::hasLineAndColumnInfo() const
{
- 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)
- return 0;
- return jsCast<Arguments*>(result);
+ return !!codeBlock();
}
-void StackVisitor::Frame::computeLineAndColumn(unsigned& line, unsigned& column)
+void StackVisitor::Frame::computeLineAndColumn(unsigned& line, unsigned& column) const
{
CodeBlock* codeBlock = this->codeBlock();
if (!codeBlock) {
@@ -299,11 +397,14 @@ void StackVisitor::Frame::computeLineAndColumn(unsigned& line, unsigned& column)
unsigned divotColumn = 0;
retrieveExpressionInfo(divot, unusedStartOffset, unusedEndOffset, divotLine, divotColumn);
- line = divotLine + codeBlock->ownerExecutable()->lineNo();
+ line = divotLine + codeBlock->ownerScriptExecutable()->firstLine();
column = divotColumn + (divotLine ? 1 : codeBlock->firstLineColumnOffset());
+
+ if (codeBlock->ownerScriptExecutable()->hasOverrideLineNumber())
+ line = codeBlock->ownerScriptExecutable()->overrideLineNumber();
}
-void StackVisitor::Frame::retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column)
+void StackVisitor::Frame::retrieveExpressionInfo(int& divot, int& startOffset, int& endOffset, unsigned& line, unsigned& column) const
{
CodeBlock* codeBlock = this->codeBlock();
codeBlock->unlinkedCodeBlock()->expressionRangeForBytecodeOffset(bytecodeOffset(), divot, startOffset, endOffset, line, column);
@@ -316,159 +417,89 @@ void StackVisitor::Frame::setToEnd()
#if ENABLE(DFG_JIT)
m_inlineCallFrame = 0;
#endif
+ m_isWasmFrame = false;
}
-#ifndef NDEBUG
-
-static const char* jitTypeName(JITCode::JITType jitType)
+void StackVisitor::Frame::dump(PrintStream& out, Indenter indent) const
{
- 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>";
+ dump(out, indent, [] (PrintStream&) { });
}
-static void printIndents(int levels)
+void StackVisitor::Frame::dump(PrintStream& out, Indenter indent, std::function<void(PrintStream&)> prefix) const
{
- while (levels--)
- dataLogFString(" ");
-}
-
-static void printif(int indentLevels, const char* format, ...)
-{
- va_list argList;
- va_start(argList, format);
-
- if (indentLevels)
- printIndents(indentLevels);
-
-#if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0))
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wformat-nonliteral"
-#pragma GCC diagnostic ignored "-Wmissing-format-attribute"
-#endif
-
- WTF::dataLogFV(format, argList);
-
-#if COMPILER(CLANG) || (COMPILER(GCC) && GCC_VERSION_AT_LEAST(4, 6, 0))
-#pragma GCC diagnostic pop
-#endif
-
- va_end(argList);
-}
-
-void StackVisitor::Frame::print(int indentLevel)
-{
- int i = indentLevel;
-
if (!this->callFrame()) {
- printif(i, "frame 0x0\n");
+ out.print(indent, "frame 0x0\n");
return;
}
CodeBlock* codeBlock = this->codeBlock();
- printif(i, "frame %p {\n", this->callFrame());
+ out.print(indent);
+ prefix(out);
+ out.print("frame ", RawPointer(this->callFrame()), " {\n");
- 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());
+ out.print(indent, "name: ", functionName(), "\n");
+ out.print(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();
+ out.print(indent, "isInlinedFrame: ", isInlinedFrame(), "\n");
+ if (isInlinedFrame())
+ out.print(indent, "InlineCallFrame: ", RawPointer(m_inlineCallFrame), "\n");
#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());
+ out.print(indent, "callee: ", RawPointer(callee()), "\n");
+ out.print(indent, "returnPC: ", RawPointer(returnPC), "\n");
+ out.print(indent, "callerFrame: ", RawPointer(callerFrame), "\n");
+ unsigned locationRawBits = callFrame->callSiteAsRawBits();
+ out.print(indent, "rawLocationBits: ", static_cast<uintptr_t>(locationRawBits),
+ " ", RawPointer(reinterpret_cast<void*>(locationRawBits)), "\n");
+ out.print(indent, "codeBlock: ", RawPointer(codeBlock));
+ if (codeBlock)
+ out.print(" ", *codeBlock);
+ out.print("\n");
+ if (codeBlock && !isInlined) {
+ indent++;
+
+ if (callFrame->callSiteBitsAreBytecodeOffset()) {
+ unsigned bytecodeOffset = callFrame->bytecodeOffset();
+ out.print(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 {
+ out.print(indent, "hasCodeOrigins: ", codeBlock->hasCodeOrigins(), "\n");
+ if (codeBlock->hasCodeOrigins()) {
+ CallSiteIndex callSiteIndex = callFrame->callSiteIndex();
+ out.print(indent, "callSiteIndex: ", callSiteIndex.bits(), " of ", codeBlock->codeOrigins().size(), "\n");
+
+ JITCode::JITType jitType = codeBlock->jitType();
+ if (jitType != JITCode::FTLJIT) {
+ JITCode* jitCode = codeBlock->jitCode().get();
+ out.print(indent, "jitCode: ", RawPointer(jitCode),
+ " start ", RawPointer(jitCode->start()),
+ " end ", RawPointer(jitCode->end()), "\n");
+ }
+ }
#endif
+ }
+ unsigned line = 0;
+ unsigned column = 0;
+ computeLineAndColumn(line, column);
+ out.print(indent, "line: ", line, "\n");
+ out.print(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
+ out.print(indent, "vmEntryFrame: ", RawPointer(vmEntryFrame()), "\n");
+ indent--;
}
- printif(i, "}\n");
+ out.print(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