Ignore:
Timestamp:
Apr 5, 2013, 4:53:12 PM (12 years ago)
Author:
[email protected]
Message:

Unify the many and varied stack trace mechanisms, and make the result sane.
https://bugs.webkit.org/show_bug.cgi?id=114072

Reviewed by Filip Pizlo.

Source/JavaScriptCore:

Makes JSC::StackFrame record the bytecode offset and other necessary data
rather than requiring us to perform eager evaluation of the line number, etc.
Then remove most of the users of retrieveLastCaller, as most of them were
using it to create a stack trace in a fairly incomplete and inefficient way.

StackFrame now also has a couple of helpers to get the line and column info.

  • API/JSContextRef.cpp:

(JSContextCreateBacktrace):

  • bytecompiler/BytecodeGenerator.cpp:

(JSC::BytecodeGenerator::emitDebugHook):

  • interpreter/Interpreter.cpp:

(JSC):
(JSC::Interpreter::dumpRegisters):
(JSC::Interpreter::unwindCallFrame):
(JSC::getBytecodeOffsetForCallFrame):
(JSC::getCallerInfo):
(JSC::StackFrame::line):
(JSC::StackFrame::column):
(JSC::StackFrame::expressionInfo):
(JSC::StackFrame::toString):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::addStackTraceIfNecessary):
(JSC::Interpreter::retrieveCallerFromVMCode):

  • interpreter/Interpreter.h:

(StackFrame):
(Interpreter):

  • runtime/Error.cpp:

(JSC::throwError):

  • runtime/JSGlobalData.h:

(JSC):
(JSGlobalData):

  • runtime/JSGlobalObject.cpp:

(JSC::DynamicGlobalObjectScope::DynamicGlobalObjectScope):

Source/WebCore:

Now that we've fleshed out the StackFrames from Interpreter::getStackTrace
WebCore can just ask us for a stack trace rather than implementing its own
stack walking.

  • bindings/js/ScriptCallStackFactory.cpp:

(WebCore::createScriptCallStack):

  • inspector/ScriptCallFrame.cpp:

(WebCore::ScriptCallFrame::isEqual):

  • inspector/ScriptCallFrame.h:

(ScriptCallFrame):
(WebCore::ScriptCallFrame::columnNumber):

Tools:

The commandline jsc executable no longer requires arguments, so
I've made run-jsc work without them.

  • Scripts/run-jsc:
Location:
trunk/Source/JavaScriptCore/interpreter
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r147798 r147818  
    200200
    201201
    202 static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, int& lineNumber, unsigned& bytecodeOffset, CodeBlock*& callerOut);
     202static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, unsigned& bytecodeOffset, CodeBlock*& callerOut);
    203203
    204204// Returns the depth of the scope chain within a given call frame.
     
    423423    unsigned bytecodeOffset = 0;
    424424    int line = 0;
    425     CodeBlock* unusedCallerCodeBlock = 0;
    426     getCallerInfo(&callFrame->globalData(), callFrame, line, bytecodeOffset, unusedCallerCodeBlock);
     425    CodeBlock* callerCodeBlock = 0;
     426    getCallerInfo(&callFrame->globalData(), callFrame, bytecodeOffset, callerCodeBlock);
     427    line = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset);
    427428    dataLogF("[ReturnVPC]                | %10p | %d (line %d)\n", it, bytecodeOffset, line);
    428429    ++it;
     
    508509    if (callerFrame->hasHostCallFrameFlag())
    509510        return false;
    510     int unusedLineNumber = 0;
    511     callFrame = getCallerInfo(&callFrame->globalData(), callFrame, unusedLineNumber, bytecodeOffset, codeBlock);
     511    callFrame = getCallerInfo(&callFrame->globalData(), callFrame, bytecodeOffset, codeBlock);
    512512    return true;
    513513}
     
    565565}
    566566
    567 static int getLineNumberForCallFrame(JSGlobalData* globalData, CallFrame* callFrame)
    568 {
    569     UNUSED_PARAM(globalData);
     567static unsigned getBytecodeOffsetForCallFrame(CallFrame* callFrame)
     568{
    570569    callFrame = callFrame->removeHostCallFrameFlag();
    571570    CodeBlock* codeBlock = callFrame->codeBlock();
    572571    if (!codeBlock)
    573572        return -1;
    574 #if ENABLE(JIT) || ENABLE(LLINT)
     573#if ENABLE(JIT)
    575574#if ENABLE(DFG_JIT)
    576575    if (codeBlock->getJITType() == JITCode::DFGJIT)
    577         return codeBlock->lineNumberForBytecodeOffset(codeBlock->codeOrigin(callFrame->codeOriginIndexForDFG()).bytecodeIndex);
    578 #endif
    579     return codeBlock->lineNumberForBytecodeOffset(callFrame->bytecodeOffsetForNonDFGCode());
    580 #endif
    581 }
    582 
    583 static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, int& lineNumber, unsigned& bytecodeOffset, CodeBlock*& caller)
     576        return codeBlock->codeOrigin(callFrame->codeOriginIndexForDFG()).bytecodeIndex;
     577#endif
     578    return callFrame->bytecodeOffsetForNonDFGCode();
     579#endif
     580}
     581
     582static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, unsigned& bytecodeOffset, CodeBlock*& caller)
    584583{
    585584    ASSERT_UNUSED(globalData, globalData);
    586585    bytecodeOffset = 0;
    587     lineNumber = -1;
    588586    ASSERT(!callFrame->hasHostCallFrameFlag());
    589587    CallFrame* callerFrame = callFrame->codeBlock() ? callFrame->trueCallerFrame() : callFrame->callerFrame()->removeHostCallFrameFlag();
     
    655653    RELEASE_ASSERT(callerCodeBlock);
    656654    caller = callerCodeBlock;
    657     lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset);
    658655    return callerFrame;
    659656}
     
    681678}
    682679
    683 void Interpreter::getStackTrace(JSGlobalData* globalData, Vector<StackFrame>& results)
     680unsigned StackFrame::line()
     681{
     682    return codeBlock ? codeBlock->lineNumberForBytecodeOffset(bytecodeOffset) + lineOffset : 0;
     683}
     684
     685unsigned StackFrame::column()
     686{
     687    if (!code)
     688        return 0;
     689    int divot = 0;
     690    int unusedStartOffset = 0;
     691    int unusedEndOffset = 0;
     692    expressionInfo(divot, unusedStartOffset, unusedEndOffset);
     693    return code->charPositionToColumnNumber(divot);
     694}
     695
     696void StackFrame::expressionInfo(int& divot, int& startOffset, int& endOffset)
     697{
     698    codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset);
     699    divot += startOffset;
     700}
     701
     702String StackFrame::toString(CallFrame* callFrame)
     703{
     704    StringBuilder traceBuild;
     705    String functionName = friendlyFunctionName(callFrame);
     706    String sourceURL = friendlySourceURL();
     707    traceBuild.append(functionName);
     708    if (!sourceURL.isEmpty()) {
     709        if (!functionName.isEmpty())
     710            traceBuild.append('@');
     711        traceBuild.append(sourceURL);
     712        if (codeType != StackFrameNativeCode) {
     713            traceBuild.append(':');
     714            traceBuild.appendNumber(line());
     715        }
     716    }
     717    return traceBuild.toString().impl();
     718}
     719
     720void Interpreter::getStackTrace(JSGlobalData* globalData, Vector<StackFrame>& results, size_t maxStackSize)
    684721{
    685722    CallFrame* callFrame = globalData->topCallFrame->removeHostCallFrameFlag();
    686723    if (!callFrame || callFrame == CallFrame::noCaller())
    687724        return;
    688     int line = getLineNumberForCallFrame(globalData, callFrame);
    689 
     725    unsigned bytecodeOffset = getBytecodeOffsetForCallFrame(callFrame);
    690726    callFrame = callFrame->trueCallFrameFromVMCode();
    691727    if (!callFrame)
    692728        return;
    693 
    694     while (callFrame && callFrame != CallFrame::noCaller()) {
     729    CodeBlock* callerCodeBlock = callFrame->codeBlock();
     730
     731    while (callFrame && callFrame != CallFrame::noCaller() && maxStackSize--) {
    695732        String sourceURL;
    696         if (callFrame->codeBlock()) {
     733        if (callerCodeBlock) {
    697734            sourceURL = getSourceURLFromCallFrame(callFrame);
    698             StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), getStackFrameCodeType(callFrame), Strong<ExecutableBase>(*globalData, callFrame->codeBlock()->ownerExecutable()), line, sourceURL};
     735            StackFrame s = {
     736                Strong<JSObject>(*globalData, callFrame->callee()),
     737                getStackFrameCodeType(callFrame),
     738                Strong<ExecutableBase>(*globalData, callerCodeBlock->ownerExecutable()),
     739                Strong<UnlinkedCodeBlock>(*globalData, callerCodeBlock->unlinkedCodeBlock()),
     740                callerCodeBlock->source(),
     741                callerCodeBlock->ownerExecutable()->lineNo(),
     742                callerCodeBlock->sourceOffset(),
     743                bytecodeOffset,
     744                sourceURL
     745            };
    699746            results.append(s);
    700747        } else {
    701             StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), -1, String()};
     748            StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, String()};
    702749            results.append(s);
    703750        }
    704         unsigned unusedBytecodeOffset = 0;
    705         CodeBlock* unusedCallerCodeBlock = 0;
    706         callFrame = getCallerInfo(globalData, callFrame, line, unusedBytecodeOffset, unusedCallerCodeBlock);
    707     }
    708 }
    709 
    710 void Interpreter::addStackTraceIfNecessary(CallFrame* callFrame, JSObject* error)
     751        callFrame = getCallerInfo(globalData, callFrame, bytecodeOffset, callerCodeBlock);
     752    }
     753}
     754
     755void Interpreter::addStackTraceIfNecessary(CallFrame* callFrame, JSValue error)
    711756{
    712757    JSGlobalData* globalData = &callFrame->globalData();
    713758    ASSERT(callFrame == globalData->topCallFrame || callFrame == callFrame->lexicalGlobalObject()->globalExec() || callFrame == callFrame->dynamicGlobalObject()->globalExec());
    714     if (error->hasProperty(callFrame, globalData->propertyNames->stack))
    715         return;
    716759
    717760    Vector<StackFrame> stackTrace;
    718761    getStackTrace(&callFrame->globalData(), stackTrace);
    719762   
    720     if (stackTrace.isEmpty())
     763    if (stackTrace.isEmpty() || !error.isObject())
    721764        return;
    722    
     765    JSObject* errorObject = asObject(error);
    723766    JSGlobalObject* globalObject = 0;
    724767    if (isTerminatedExecutionException(error) || isInterruptedExecutionException(error))
    725768        globalObject = globalData->dynamicGlobalObject;
    726769    else
    727         globalObject = error->globalObject();
     770        globalObject = errorObject->globalObject();
    728771
    729772    // FIXME: JSStringJoiner could be more efficient than StringBuilder here.
     
    734777            builder.append('\n');
    735778    }
    736    
    737     error->putDirect(*globalData, globalData->propertyNames->stack, jsString(globalData, builder.toString()), ReadOnly | DontDelete);
     779
     780    if (errorObject->hasProperty(callFrame, globalData->propertyNames->stack))
     781        return;
     782    errorObject->putDirect(*globalData, globalData->propertyNames->stack, jsString(globalData, builder.toString()), ReadOnly | DontDelete);
    738783}
    739784
     
    13781423        return jsNull();
    13791424   
    1380     int lineNumber;
    13811425    unsigned bytecodeOffset;
    13821426    CodeBlock* unusedCallerCodeBlock = 0;
    1383     CallFrame* callerFrame = getCallerInfo(&callFrame->globalData(), functionCallFrame, lineNumber, bytecodeOffset, unusedCallerCodeBlock);
     1427    CallFrame* callerFrame = getCallerInfo(&callFrame->globalData(), functionCallFrame, bytecodeOffset, unusedCallerCodeBlock);
    13841428    if (!callerFrame)
    13851429        return jsNull();
     
    13911435    ASSERT(caller.isObject());
    13921436    while (asObject(caller)->inherits(&JSBoundFunction::s_info)) {
    1393         callerFrame = getCallerInfo(&callFrame->globalData(), callerFrame, lineNumber, bytecodeOffset, unusedCallerCodeBlock);
     1437        callerFrame = getCallerInfo(&callFrame->globalData(), callerFrame, bytecodeOffset, unusedCallerCodeBlock);
    13941438        if (!callerFrame)
    13951439            return jsNull();
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.h

    r146552 r147818  
    8080        StackFrameCodeType codeType;
    8181        Strong<ExecutableBase> executable;
    82         int line;
     82        Strong<UnlinkedCodeBlock> codeBlock;
     83        RefPtr<SourceProvider> code;
     84        int lineOffset;
     85        unsigned characterOffset;
     86        unsigned bytecodeOffset;
    8387        String sourceURL;
    84         String toString(CallFrame* callFrame) const
    85         {
    86             StringBuilder traceBuild;
    87             String functionName = friendlyFunctionName(callFrame);
    88             String sourceURL = friendlySourceURL();
    89             traceBuild.append(functionName);
    90             if (!sourceURL.isEmpty()) {
    91                 if (!functionName.isEmpty())
    92                     traceBuild.append('@');
    93                 traceBuild.append(sourceURL);
    94                 if (line > -1) {
    95                     traceBuild.append(':');
    96                     traceBuild.appendNumber(line);
    97                 }
    98             }
    99             return traceBuild.toString().impl();
    100         }
     88        JS_EXPORT_PRIVATE String toString(CallFrame*);
    10189        String friendlySourceURL() const
    10290        {
     
    138126            return traceLine.isNull() ? emptyString() : traceLine;
    139127        }
    140         unsigned friendlyLineNumber() const
    141         {
    142             return line > -1 ? line : 0;
    143         }
     128        JS_EXPORT_PRIVATE unsigned line();
     129        JS_EXPORT_PRIVATE unsigned column();
     130        JS_EXPORT_PRIVATE void expressionInfo(int& divot, int& startOffset, int& endOffset);
    144131    };
    145132
     
    233220        NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine, int column);
    234221        static const String getTraceLine(CallFrame*, StackFrameCodeType, const String&, int);
    235         JS_EXPORT_PRIVATE static void getStackTrace(JSGlobalData*, Vector<StackFrame>& results);
    236         static void addStackTraceIfNecessary(CallFrame*, JSObject* error);
     222        JS_EXPORT_PRIVATE static void getStackTrace(JSGlobalData*, Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
     223        static void addStackTraceIfNecessary(CallFrame*, JSValue error);
    237224
    238225        void dumpSampleData(ExecState* exec);
Note: See TracChangeset for help on using the changeset viewer.