Changeset 96131 in webkit


Ignore:
Timestamp:
Sep 27, 2011 10:58:55 AM (13 years ago)
Author:
commit-queue@webkit.org
Message:

Implement Error.stack
https://bugs.webkit.org/show_bug.cgi?id=66994

Patch by Juan Carlos Montemayor Elosua <j.mont@me.com> on 2011-09-27
Reviewed by Oliver Hunt.

Source/JavaScriptCore:

This patch utilizes topCallFrame to create a stack trace when
an error is thrown. Users will also be able to use the stack()
command in jsc to get arrays with stack trace information.

(JSC::getCallerLine):
(JSC::getSourceURLFromCallFrame):
(JSC::getStackFrameCodeType):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::throwException):

  • interpreter/Interpreter.h:

(JSC::StackFrame::toString):

  • jsc.cpp:

(GlobalObject::finishCreation):
(functionJSCStack):

  • parser/Parser.h:

(JSC::Parser::parse):

  • runtime/CommonIdentifiers.h:
  • runtime/Error.cpp:

(JSC::addErrorInfo):

  • runtime/Error.h:

LayoutTests:

Unit tests that contain both normal and special cases for stack trace
generation.

  • fast/js/exception-properties-expected.txt:
  • fast/js/script-tests/exception-properties.js:
  • fast/js/script-tests/stack-trace.js: Added.

(printStack):
(hostThrower):
(callbacker):
(outer):
(inner):
(evaler):
(normalOuter):
(normalInner):
(scripterInner):
(scripterOuter):

  • fast/js/stack-trace-expected.txt: Added.
  • fast/js/stack-trace.html: Added.
  • platform/chromium/test_expectations.txt:
Location:
trunk
Files:
3 added
14 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r96128 r96131  
     12011-09-27  Juan Carlos Montemayor Elosua  <j.mont@me.com>
     2
     3        Implement Error.stack
     4        https://bugs.webkit.org/show_bug.cgi?id=66994
     5
     6        Reviewed by Oliver Hunt.
     7
     8        Unit tests that contain both normal and special cases for stack trace
     9        generation.
     10
     11        * fast/js/exception-properties-expected.txt:
     12        * fast/js/script-tests/exception-properties.js:
     13        * fast/js/script-tests/stack-trace.js: Added.
     14        (printStack):
     15        (hostThrower):
     16        (callbacker):
     17        (outer):
     18        (inner):
     19        (evaler):
     20        (normalOuter):
     21        (normalInner):
     22        (scripterInner):
     23        (scripterOuter):
     24        * fast/js/stack-trace-expected.txt: Added.
     25        * fast/js/stack-trace.html: Added.
     26        * platform/chromium/test_expectations.txt:
     27
    1282011-09-27  Adrienne Walker  <enne@google.com>
    229
  • trunk/LayoutTests/fast/js/exception-properties-expected.txt

    r93624 r96131  
    55
    66PASS enumerableProperties(error) is []
    7 PASS enumerableProperties(nativeError) is ["line", "sourceId", "sourceURL"]
     7PASS enumerableProperties(nativeError) is ["line", "sourceId", "sourceURL", "jscStack"]
    88PASS Object.getPrototypeOf(nativeError).name is "RangeError"
    99PASS Object.getPrototypeOf(nativeError).message is ""
  • trunk/LayoutTests/fast/js/script-tests/exception-properties.js

    r93624 r96131  
    1717
    1818    shouldBe('enumerableProperties(error)', '[]');
    19     shouldBe('enumerableProperties(nativeError)', '["line", "sourceId", "sourceURL"]');
     19    shouldBe('enumerableProperties(nativeError)', '["line", "sourceId", "sourceURL", "jscStack"]');
    2020
    2121    shouldBe('Object.getPrototypeOf(nativeError).name', '"RangeError"');
  • trunk/LayoutTests/platform/chromium/test_expectations.txt

    r96128 r96131  
    489489// throw.  V8 follows the spec.
    490490WONTFIX SKIP : fast/js/reparsing-semicolon-insertion.html = FAIL
     491
     492// This tests stack-traces that are generated by JSC. This test should
     493// fail since it is specific to jsc.
     494WONTFIX SKIP : fast/js/stack-trace.html = FAIL
    491495
    492496// Rubber-banding is currently a CG only feature.
  • trunk/Source/JavaScriptCore/ChangeLog

    r96087 r96131  
     12011-09-27  Juan Carlos Montemayor Elosua  <j.mont@me.com>
     2
     3        Implement Error.stack
     4        https://bugs.webkit.org/show_bug.cgi?id=66994
     5
     6        Reviewed by Oliver Hunt.
     7
     8        This patch utilizes topCallFrame to create a stack trace when
     9        an error is thrown. Users will also be able to use the stack()
     10        command in jsc to get arrays with stack trace information.
     11
     12        * JavaScriptCore.exp:
     13        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
     14        * interpreter/Interpreter.cpp:
     15        (JSC::getCallerLine):
     16        (JSC::getSourceURLFromCallFrame):
     17        (JSC::getStackFrameCodeType):
     18        (JSC::Interpreter::getStackTrace):
     19        (JSC::Interpreter::throwException):
     20        * interpreter/Interpreter.h:
     21        (JSC::StackFrame::toString):
     22        * jsc.cpp:
     23        (GlobalObject::finishCreation):
     24        (functionJSCStack):
     25        * parser/Parser.h:
     26        (JSC::Parser::parse):
     27        * runtime/CommonIdentifiers.h:
     28        * runtime/Error.cpp:
     29        (JSC::addErrorInfo):
     30        * runtime/Error.h:
     31
    1322011-09-27  Carlos Garcia Campos  <cgarcia@igalia.com>
    233
  • trunk/Source/JavaScriptCore/JavaScriptCore.exp

    r96045 r96131  
    115115__ZN3JSC10throwErrorEPNS_9ExecStateENS_7JSValueE
    116116__ZN3JSC10throwErrorEPNS_9ExecStateEPNS_8JSObjectE
     117__ZN3JSC11Interpreter13getStackTraceEPNS_12JSGlobalDataEiRN3WTF6VectorINS_10StackFrameELm0EEE
    117118__ZN3JSC11JSByteArray13s_defaultInfoE
    118119__ZN3JSC11JSByteArray15createStructureERNS_12JSGlobalDataEPNS_14JSGlobalObjectENS_7JSValueEPKNS_9ClassInfoE
  • trunk/Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def

    r96045 r96131  
    212212    ?getPropertyNames@JSObject@JSC@@UAEXPAVExecState@2@AAVPropertyNameArray@2@W4EnumerationMode@2@@Z
    213213    ?getSlice@ArgList@JSC@@QBEXHAAV12@@Z
     214    ?getStackTrace@Interpreter@JSC@@SAXPAVJSGlobalData@2@HAAV?$Vector@UStackFrame@JSC@@$0A@@WTF@@@Z
    214215    ?getString@JSCell@JSC@@QBE?AVUString@2@PAVExecState@2@@Z
    215216    ?getString@JSCell@JSC@@QBE_NPAVExecState@2@AAVUString@2@@Z
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp

    r95901 r96131  
    4646#include "JSArray.h"
    4747#include "JSByteArray.h"
    48 #include "JSFunction.h"
    4948#include "JSNotAnObject.h"
    5049#include "JSPropertyNameIterator.h"
     
    688687}
    689688
     689static void getCallerLine(JSGlobalData* globalData, CallFrame* callFrame, int& lineNumber)
     690{
     691    (void)globalData;
     692    unsigned bytecodeOffset;
     693    lineNumber = -1;
     694    callFrame = callFrame->removeHostCallFrameFlag();
     695
     696    if (callFrame->callerFrame() == CallFrame::noCaller() || callFrame->callerFrame()->hasHostCallFrameFlag())
     697        return;
     698
     699    CodeBlock* callerCodeBlock = callFrame->callerFrame()->removeHostCallFrameFlag()->codeBlock();
     700
     701#if ENABLE(INTERPRETER)
     702    if (!globalData->canUseJIT())
     703        bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnVPC());
     704#if ENABLE(JIT)
     705    else
     706        bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
     707#endif
     708#else
     709    bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
     710#endif
     711
     712    lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1);
     713}
     714
     715static ALWAYS_INLINE const UString getSourceURLFromCallFrame(CallFrame* callFrame)
     716{
     717    if (callFrame->hasHostCallFrameFlag())
     718        return UString();
     719#if ENABLE(INTERPRETER)
     720    if (!callFrame->globalData().canUseJIT())
     721        return callFrame->codeBlock()->source()->url();
     722#if ENABLE(JIT)
     723    return callFrame->codeBlock()->ownerExecutable()->sourceURL();
     724#endif
     725#else
     726    return callFrame->codeBlock()->ownerExecutable()->sourceURL();
     727#endif
     728}
     729
     730static StackFrameCodeType getStackFrameCodeType(CallFrame* callFrame)
     731{
     732    if (callFrame->hasHostCallFrameFlag())
     733        return StackFrameNativeCode;
     734
     735    switch (callFrame->codeBlock()->codeType()) {
     736    case EvalCode:
     737        return StackFrameEvalCode;
     738    case FunctionCode:
     739        return StackFrameFunctionCode;
     740    case GlobalCode:
     741        return StackFrameGlobalCode;
     742    }
     743    ASSERT_NOT_REACHED();
     744    return StackFrameGlobalCode;
     745}
     746
     747void Interpreter::getStackTrace(JSGlobalData* globalData, int line, Vector<StackFrame>& results)
     748{
     749    int stackLimit = 15;
     750    CallFrame* callFrame = globalData->topCallFrame->removeHostCallFrameFlag();
     751    if (!callFrame || callFrame == CallFrame::noCaller() || !callFrame->codeBlock())
     752        return;
     753    UString sourceURL;
     754    UString traceLevel;
     755
     756    for (int i = 0; i < stackLimit; ++i) {
     757        if (!callFrame || callFrame == CallFrame::noCaller())
     758            break;
     759        if (callFrame->codeBlock()) {
     760            sourceURL = getSourceURLFromCallFrame(callFrame);
     761
     762            StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), Strong<CallFrame>(*globalData, callFrame), getStackFrameCodeType(callFrame), Strong<ExecutableBase>(*globalData, callFrame->codeBlock()->ownerExecutable()), line, sourceURL};
     763
     764            results.append(s);
     765        }
     766        getCallerLine(globalData, callFrame, line);
     767        callFrame = callFrame->callerFrame()->removeHostCallFrameFlag();
     768    }
     769}
     770
    690771NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset)
    691772{
     
    706787            // FIXME: should only really be adding these properties to VM generated exceptions,
    707788            // but the inspector currently requires these for all thrown objects.
    708             addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source());
     789            Vector<StackFrame> stackTrace;
     790            getStackTrace(&callFrame->globalData(), codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), stackTrace);
     791            addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source(), stackTrace);
    709792        }
    710793
  • trunk/Source/JavaScriptCore/interpreter/Interpreter.h

    r95901 r96131  
    3232#include "ArgList.h"
    3333#include "JSCell.h"
     34#include "JSFunction.h"
    3435#include "JSValue.h"
    3536#include "JSObject.h"
     
    4344    class CodeBlock;
    4445    class EvalExecutable;
     46    class ExecutableBase;
    4547    class FunctionExecutable;
    46     class JSFunction;
    4748    class JSGlobalObject;
    4849    class ProgramExecutable;
     
    6364    };
    6465
     66    enum StackFrameCodeType {
     67        StackFrameGlobalCode,
     68        StackFrameEvalCode,
     69        StackFrameFunctionCode,
     70        StackFrameNativeCode
     71    };
     72
     73    struct StackFrame {
     74        Strong<JSObject> callee;
     75        Strong<CallFrame> callFrame;
     76        StackFrameCodeType codeType;
     77        Strong<ExecutableBase> executable;
     78        int line;
     79        UString sourceURL;
     80        UString toString() const
     81        {
     82            bool hasSourceURLInfo = !sourceURL.isNull() && !sourceURL.isEmpty();
     83            bool hasLineInfo = line > -1;
     84            String traceLine;
     85            JSObject* stackFrameCallee = callee.get();
     86
     87            switch (codeType) {
     88            case StackFrameEvalCode:
     89                if (hasSourceURLInfo)
     90                    traceLine = hasLineInfo ? String::format("eval at %s:%d", sourceURL.ascii().data(), line)
     91                                            : String::format("eval at %s", sourceURL.ascii().data());
     92                else
     93                    traceLine = String::format("eval");
     94                break;
     95            case StackFrameNativeCode:
     96                traceLine = "Native code";
     97                break;
     98            case StackFrameFunctionCode:
     99                if (stackFrameCallee && stackFrameCallee->inherits(&JSFunction::s_info)) {
     100                    UString functionName = asFunction(stackFrameCallee)->name(callFrame.get());
     101                    if (hasSourceURLInfo)
     102                        traceLine = hasLineInfo ? String::format("%s at %s:%d", functionName.ascii().data(), sourceURL.ascii().data(), line)
     103                                                : String::format("%s at %s", functionName.ascii().data(), sourceURL.ascii().data());
     104                    else
     105                        traceLine = String::format("%s\n", functionName.ascii().data());
     106                    break;
     107                }
     108            case StackFrameGlobalCode:
     109                traceLine = hasLineInfo ? String::format("at %s:%d", sourceURL.ascii().data(), line)
     110                                        : String::format("at %s", sourceURL.ascii().data());
     111            }
     112            return traceLine.impl();
     113        }
     114    };
     115
    65116    class TopCallFrameSetter {
    66117    public:
     
    129180        NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset);
    130181        NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine);
     182        static const UString getTraceLine(CallFrame*, StackFrameCodeType, const UString&, int);
     183        static void getStackTrace(JSGlobalData*, int line, Vector<StackFrame>& results);
    131184
    132185        void dumpSampleData(ExecState* exec);
  • trunk/Source/JavaScriptCore/jsc.cpp

    r95751 r96131  
    2828#include "ExceptionHelpers.h"
    2929#include "InitializeThreading.h"
     30#include "Interpreter.h"
    3031#include "JSArray.h"
    3132#include "JSFunction.h"
     
    7475static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
    7576static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
     77static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
    7678static EncodedJSValue JSC_HOST_CALL functionGC(ExecState*);
    7779#ifndef NDEBUG
     
    175177        addFunction(globalData, "load", functionLoad, 1);
    176178        addFunction(globalData, "checkSyntax", functionCheckSyntax, 1);
     179        addFunction(globalData, "jscStack", functionJSCStack, 1);
    177180        addFunction(globalData, "readline", functionReadline, 0);
    178181        addFunction(globalData, "preciseTime", functionPreciseTime, 0);
     
    219222{
    220223    fprintf(stderr, "--> %s\n", exec->argument(0).toString(exec).utf8().data());
     224    return JSValue::encode(jsUndefined());
     225}
     226
     227EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
     228{
     229    String trace = "--> Stack trace:\n";
     230    Vector<StackFrame> stackTrace;
     231    Interpreter::getStackTrace(&exec->globalData(), -1, stackTrace);
     232    int i = 0;
     233
     234    for (Vector<StackFrame>::iterator iter = stackTrace.begin(); iter < stackTrace.end(); iter++) {
     235        StackFrame level = *iter;
     236        trace += String::format("    %i   %s\n", i, level.toString().utf8().data());
     237        i++;
     238    }
     239    fprintf(stderr, "%s", trace.utf8().data());
    221240    return JSValue::encode(jsUndefined());
    222241}
  • trunk/Source/JavaScriptCore/parser/Parser.h

    r90159 r96131  
    115115                *exception = createSyntaxError(lexicalGlobalObject, errMsg);
    116116            else
    117                 *exception = addErrorInfo(&lexicalGlobalObject->globalData(), createSyntaxError(lexicalGlobalObject, errMsg), errLine, source);
     117                *exception = addErrorInfo(&lexicalGlobalObject->globalData(), createSyntaxError(lexicalGlobalObject, errMsg), errLine, source, Vector<StackFrame>());
    118118        }
    119119
  • trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h

    r95751 r96131  
    5353    macro(isArray) \
    5454    macro(isPrototypeOf) \
     55    macro(jscStack) \
    5556    macro(length) \
    5657    macro(message) \
  • trunk/Source/JavaScriptCore/runtime/Error.cpp

    r95108 r96131  
    2727#include "ConstructData.h"
    2828#include "ErrorConstructor.h"
     29#include "JSArray.h"
    2930#include "JSFunction.h"
    3031#include "JSGlobalObject.h"
     
    117118}
    118119
    119 JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source)
     120JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source, const Vector<StackFrame>& stackTrace)
    120121{
    121122    intptr_t sourceID = source.provider()->asID();
     
    128129    if (!sourceURL.isNull())
    129130        error->putWithAttributes(globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete);
     131    if (!stackTrace.isEmpty()) {
     132        JSArray* stackTraceArray = JSArray::create(*globalData, globalData->dynamicGlobalObject->arrayStructure());
     133        for (unsigned i = 0; i < stackTrace.size(); i++) {
     134            UString stackLevel =  stackTrace[i].toString();
     135            stackTraceArray->push(globalData->topCallFrame, jsString(globalData, stackLevel));
     136        }
     137        error->putWithAttributes(globalData, globalData->propertyNames->jscStack, stackTraceArray, ReadOnly | DontDelete);
     138    }
    130139
    131140    return error;
    132141}
    133142
    134 JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source)
    135 {
    136     return addErrorInfo(&exec->globalData(), error, line, source);
     143JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source, const Vector<StackFrame>& stackTrace)
     144{
     145    return addErrorInfo(&exec->globalData(), error, line, source, stackTrace);
    137146}
    138147
  • trunk/Source/JavaScriptCore/runtime/Error.h

    r72050 r96131  
    2424#define Error_h
    2525
     26#include "Interpreter.h"
    2627#include "JSObject.h"
    2728#include <stdint.h>
     
    5657    // Methods to add
    5758    bool hasErrorInfo(ExecState*, JSObject* error);
    58     JSObject* addErrorInfo(JSGlobalData*, JSObject* error, int line, const SourceCode&);
     59    JSObject* addErrorInfo(JSGlobalData*, JSObject* error, int line, const SourceCode&, const Vector<StackFrame>&);
    5960    // ExecState wrappers.
    60     JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&);
     61    JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&, const Vector<StackFrame>&);
    6162
    6263    // Methods to throw Errors.
Note: See TracChangeset for help on using the changeset viewer.