diff options
Diffstat (limited to 'Source/JavaScriptCore/interpreter/StackVisitor.cpp')
-rw-r--r-- | Source/JavaScriptCore/interpreter/StackVisitor.cpp | 274 |
1 files changed, 165 insertions, 109 deletions
diff --git a/Source/JavaScriptCore/interpreter/StackVisitor.cpp b/Source/JavaScriptCore/interpreter/StackVisitor.cpp index 6fe792b7e..d922e7f8f 100644 --- a/Source/JavaScriptCore/interpreter/StackVisitor.cpp +++ b/Source/JavaScriptCore/interpreter/StackVisitor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013, 2015 Apple Inc. All rights reserved. + * Copyright (C) 2013 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,11 +26,11 @@ #include "config.h" #include "StackVisitor.h" +#include "Arguments.h" #include "CallFrameInlines.h" -#include "ClonedArguments.h" #include "Executable.h" #include "Interpreter.h" -#include "JSCInlines.h" +#include "Operations.h" #include <wtf/DataLog.h> namespace JSC { @@ -38,20 +38,7 @@ namespace JSC { StackVisitor::StackVisitor(CallFrame* startFrame) { m_frame.m_index = 0; - 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(); + readFrame(startFrame); } void StackVisitor::gotoNextFrame() @@ -61,15 +48,15 @@ void StackVisitor::gotoNextFrame() InlineCallFrame* inlineCallFrame = m_frame.inlineCallFrame(); CodeOrigin* callerCodeOrigin = &inlineCallFrame->caller; readInlinedFrame(m_frame.callFrame(), callerCodeOrigin); - return; - } + + } else #endif // ENABLE(DFG_JIT) - m_frame.m_VMEntryFrame = m_frame.m_CallerVMEntryFrame; - readFrame(m_frame.callerFrame()); + readFrame(m_frame.callerFrame()); } void StackVisitor::readFrame(CallFrame* callFrame) { + ASSERT(!callFrame->isVMEntrySentinel()); if (!callFrame) { m_frame.setToEnd(); return; @@ -117,10 +104,9 @@ void StackVisitor::readNonInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOri { m_frame.m_callFrame = callFrame; m_frame.m_argumentCountIncludingThis = callFrame->argumentCountIncludingThis(); - 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_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 @@ -141,6 +127,7 @@ static int inlinedFrameOffset(CodeOrigin* codeOrigin) void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin) { ASSERT(codeOrigin); + ASSERT(!callFrame->isVMEntrySentinel()); int frameOffset = inlinedFrameOffset(codeOrigin); bool isInlined = !!frameOffset; @@ -149,15 +136,14 @@ void StackVisitor::readInlinedFrame(CallFrame* callFrame, CodeOrigin* codeOrigin m_frame.m_callFrame = callFrame; m_frame.m_inlineCallFrame = inlineCallFrame; - 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_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 @@ -196,7 +182,7 @@ String StackVisitor::Frame::functionName() switch (codeType()) { case CodeType::Eval: - traceLine = ASCIILiteral("eval code"); + traceLine = "eval code"; break; case CodeType::Native: if (callee) @@ -206,7 +192,7 @@ String StackVisitor::Frame::functionName() traceLine = getCalculatedDisplayName(callFrame(), callee).impl(); break; case CodeType::Global: - traceLine = ASCIILiteral("global code"); + traceLine = "global code"; break; } return traceLine.isNull() ? emptyString() : traceLine; @@ -226,7 +212,7 @@ String StackVisitor::Frame::sourceURL() break; } case CodeType::Native: - traceLine = ASCIILiteral("[native code]"); + traceLine = "[native code]"; break; } return traceLine.isNull() ? emptyString() : traceLine; @@ -255,26 +241,48 @@ String StackVisitor::Frame::toString() return traceBuild.toString().impl(); } -ClonedArguments* StackVisitor::Frame::createArguments() +Arguments* StackVisitor::Frame::createArguments() { ASSERT(m_callFrame); CallFrame* physicalFrame = m_callFrame; - ClonedArguments* arguments; - ArgumentsMode mode; - if (Options::enableFunctionDotArguments()) - mode = ArgumentsMode::Cloned; - else - mode = ArgumentsMode::FakeValues; + VM& vm = physicalFrame->vm(); + Arguments* arguments; #if ENABLE(DFG_JIT) if (isInlinedFrame()) { ASSERT(m_inlineCallFrame); - arguments = ClonedArguments::createWithInlineFrame(physicalFrame, physicalFrame, m_inlineCallFrame, mode); + arguments = Arguments::create(vm, physicalFrame, m_inlineCallFrame); + arguments->tearOff(physicalFrame, m_inlineCallFrame); } else #endif - arguments = ClonedArguments::createWithMachineFrame(physicalFrame, physicalFrame, mode); + { + arguments = Arguments::create(vm, physicalFrame); + arguments->tearOff(physicalFrame); + } 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) + return 0; + return jsCast<Arguments*>(result); +} + void StackVisitor::Frame::computeLineAndColumn(unsigned& line, unsigned& column) { CodeBlock* codeBlock = this->codeBlock(); @@ -291,11 +299,8 @@ void StackVisitor::Frame::computeLineAndColumn(unsigned& line, unsigned& column) unsigned divotColumn = 0; retrieveExpressionInfo(divot, unusedStartOffset, unusedEndOffset, divotLine, divotColumn); - line = divotLine + codeBlock->ownerExecutable()->firstLine(); + line = divotLine + codeBlock->ownerExecutable()->lineNo(); 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) @@ -313,106 +318,157 @@ void StackVisitor::Frame::setToEnd() #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(" "); } -template<typename... Types> -void log(unsigned indent, const Types&... values) +static void printif(int indentLevels, const char* format, ...) { - printIndents(indent); - dataLog(values...); -} + va_list argList; + va_start(argList, format); -template<typename... Types> -void logF(unsigned indent, const char* format, const Types&... values) -{ - printIndents(indent); + if (indentLevels) + printIndents(indentLevels); -#if COMPILER(GCC_OR_CLANG) +#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 - dataLogF(format, values...); + WTF::dataLogFV(format, argList); -#if COMPILER(GCC_OR_CLANG) +#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 indent) +void StackVisitor::Frame::print(int indentLevel) { + int i = indentLevel; + if (!this->callFrame()) { - log(indent, "frame 0x0\n"); + printif(i, "frame 0x0\n"); return; } CodeBlock* codeBlock = this->codeBlock(); - logF(indent, "frame %p {\n", this->callFrame()); + printif(i, "frame %p {\n", this->callFrame()); - { - indent++; - - CallFrame* callFrame = m_callFrame; - CallFrame* callerFrame = this->callerFrame(); - void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr; + CallFrame* callFrame = m_callFrame; + CallFrame* callerFrame = this->callerFrame(); + void* returnPC = callFrame->hasReturnPC() ? callFrame->returnPC().value() : nullptr; - log(indent, "name: ", functionName(), "\n"); - log(indent, "sourceURL: ", sourceURL(), "\n"); + printif(i, " name '%s'\n", functionName().utf8().data()); + printif(i, " sourceURL '%s'\n", sourceURL().utf8().data()); + printif(i, " isVMEntrySentinel %d\n", callerFrame->isVMEntrySentinel()); - bool isInlined = false; #if ENABLE(DFG_JIT) - isInlined = isInlinedFrame(); - log(indent, "isInlinedFrame: ", isInlinedFrame(), "\n"); - if (isInlinedFrame()) - logF(indent, "InlineCallFrame: %p\n", m_inlineCallFrame); + printif(i, " isInlinedFrame %d\n", isInlinedFrame()); + if (isInlinedFrame()) + printif(i, " InlineCallFrame %p\n", m_inlineCallFrame); #endif - 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"); + 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()); #if ENABLE(DFG_JIT) - } 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()); - } - } + } else { + unsigned codeOriginIndex = callFrame->locationAsCodeOriginIndex(); + printif(i, " codeOriginIdex %u %p / %zu\n", codeOriginIndex, reinterpret_cast<void*>(codeOriginIndex), codeBlock->codeOrigins().size()); #endif - } - unsigned line = 0; - unsigned column = 0; - computeLineAndColumn(line, column); - log(indent, "line: ", line, "\n"); - log(indent, "column: ", column, "\n"); - - indent--; } - 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 } - log(indent, "}\n"); + printif(i, "}\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 |