Implement Error.stack
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Sep 2011 17:58:55 +0000 (17:58 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 27 Sep 2011 17:58:55 +0000 (17:58 +0000)
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.

* JavaScriptCore.exp:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
* interpreter/Interpreter.cpp:
(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:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@96131 268f45cc-cd09-0410-ab3c-d52691b4dbfc

17 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/js/exception-properties-expected.txt
LayoutTests/fast/js/script-tests/exception-properties.js
LayoutTests/fast/js/script-tests/stack-trace.js [new file with mode: 0644]
LayoutTests/fast/js/stack-trace-expected.txt [new file with mode: 0644]
LayoutTests/fast/js/stack-trace.html [new file with mode: 0644]
LayoutTests/platform/chromium/test_expectations.txt
Source/JavaScriptCore/ChangeLog
Source/JavaScriptCore/JavaScriptCore.exp
Source/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def
Source/JavaScriptCore/interpreter/Interpreter.cpp
Source/JavaScriptCore/interpreter/Interpreter.h
Source/JavaScriptCore/jsc.cpp
Source/JavaScriptCore/parser/Parser.h
Source/JavaScriptCore/runtime/CommonIdentifiers.h
Source/JavaScriptCore/runtime/Error.cpp
Source/JavaScriptCore/runtime/Error.h

index 0ef217c..264f756 100644 (file)
@@ -1,3 +1,30 @@
+2011-09-27  Juan Carlos Montemayor Elosua  <j.mont@me.com>
+
+        Implement Error.stack
+        https://bugs.webkit.org/show_bug.cgi?id=66994
+
+        Reviewed by Oliver Hunt.
+
+        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:
+
 2011-09-27  Adrienne Walker  <enne@google.com>
 
         [Chromium] Layout Test compositing/video-page-visibility.html is failing on GPU linux
index 36d7e84..2a5cb81 100644 (file)
@@ -4,7 +4,7 @@ On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE
 
 
 PASS enumerableProperties(error) is []
-PASS enumerableProperties(nativeError) is ["line", "sourceId", "sourceURL"]
+PASS enumerableProperties(nativeError) is ["line", "sourceId", "sourceURL", "jscStack"]
 PASS Object.getPrototypeOf(nativeError).name is "RangeError"
 PASS Object.getPrototypeOf(nativeError).message is ""
 PASS successfullyParsed is true
index 4a2a102..16926b3 100644 (file)
@@ -16,7 +16,7 @@ try {
     var error = new Error("message");
 
     shouldBe('enumerableProperties(error)', '[]');
-    shouldBe('enumerableProperties(nativeError)', '["line", "sourceId", "sourceURL"]');
+    shouldBe('enumerableProperties(nativeError)', '["line", "sourceId", "sourceURL", "jscStack"]');
 
     shouldBe('Object.getPrototypeOf(nativeError).name', '"RangeError"');
     shouldBe('Object.getPrototypeOf(nativeError).message', '""');
diff --git a/LayoutTests/fast/js/script-tests/stack-trace.js b/LayoutTests/fast/js/script-tests/stack-trace.js
new file mode 100644 (file)
index 0000000..fa68c81
--- /dev/null
@@ -0,0 +1,42 @@
+description(
+'This test checks stack trace corectness in special cases.'
+);
+
+function printStack(stackTrace) {
+       debug("--> Stack Trace:")
+       var i = 0;
+       for (var level in stackTrace) {
+               debug("    " + i + "   " + stackTrace[level].substring(0, stackTrace[level].indexOf('file:')) + stackTrace[level].substring(stackTrace[level].lastIndexOf('/')+1));
+               i++;
+       }
+       debug('');
+}
+
+function hostThrower() { Element.prototype.appendChild.call({ }, [{ }]);  }
+function callbacker(f) { [0].map(f); }
+function outer(errorName) { inner(errorName); }
+function inner(errorName) { throw new Error("Error in " + errorName); }
+function evaler(code) { eval(code); }
+function normalOuter() { normalInner(); }
+function normalInner() { if(thisVarDoesntExist) failIfTrue("shouldFailBeforeThis") };
+function scripterInner() { htmlInner(); }
+function scripterOuter() { htmlOuter(); }
+                                                                       // Expected functions in stack trace
+// Normal Case
+try { normalOuter() } catch (e) { printStack(e.jscStack) }                     // normalOuter -> normalInner
+
+// Eval Case
+try { evaler("inner('inner eval');"); } catch (e) { printStack(e.jscStack) }   // evaler -> eval -> inner
+try { evaler("outer('outer eval');"); } catch (e) { printStack(e.jscStack) }   // evaler -> eval -> outer -> inner
+
+// Function Callback Case
+try { callbacker(inner('inner map')); } catch (e) { printStack(e.jscStack); }   // callbacker -> map -> inner
+try { callbacker(outer('outer map')); } catch (e) { printStack(e.jscStack); }   // callbacker -> map -> outer -> inner
+
+// Host Code Case
+try { hostThrower(); } catch (e) { printStack(e.jscStack); }                    // hostThrower
+
+try { scripterInner(); } catch (e) { printStack(e.jscStack) }                   // program -> scripter -> inner
+try { scripterOuter(); } catch (e) { printStack(e.jscStack) }                   // program -> scripter -> outer -> inner
+
+successfullyParsed = true;
diff --git a/LayoutTests/fast/js/stack-trace-expected.txt b/LayoutTests/fast/js/stack-trace-expected.txt
new file mode 100644 (file)
index 0000000..9174ca7
--- /dev/null
@@ -0,0 +1,48 @@
+This test checks stack trace corectness in special cases.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+--> Stack Trace:
+    0   normalInner at stack-trace.js:21
+    1   normalOuter at stack-trace.js:20
+    2   at stack-trace.js:26
+
+--> Stack Trace:
+    0   inner at stack-trace.js:18
+    1   eval
+    2   evaler at stack-trace.js
+    3   at stack-trace.js:29
+
+--> Stack Trace:
+    0   inner at stack-trace.js:18
+    1   outer at stack-trace.js:17
+    2   eval
+    3   evaler at stack-trace.js
+    4   at stack-trace.js:30
+
+--> Stack Trace:
+    0   inner at stack-trace.js:18
+    1   at stack-trace.js:33
+
+--> Stack Trace:
+    0   inner at stack-trace.js:18
+    1   outer at stack-trace.js:17
+    2   at stack-trace.js:34
+
+--> Stack Trace:
+    0   hostThrower at stack-trace.js:15
+    1   at stack-trace.js:37
+
+--> Stack Trace:
+    0   htmlInner at stack-trace.html:10
+    1   scripterInner at stack-trace.js:22
+    2   at stack-trace.js:39
+
+--> Stack Trace:
+    0   htmlInner at stack-trace.html:10
+    1   htmlOuter at stack-trace.html:11
+    2   scripterOuter at stack-trace.js:23
+    3   at stack-trace.js:40
+
+
diff --git a/LayoutTests/fast/js/stack-trace.html b/LayoutTests/fast/js/stack-trace.html
new file mode 100644 (file)
index 0000000..e08c910
--- /dev/null
@@ -0,0 +1,14 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+       <link rel="stylesheet" href="resources/js-test-style.css">
+       <script src="resources/js-test-pre.js"></script>
+</head>
+<body>
+       <p id="description"></p>
+       <p id="console"></p>
+       <script>function htmlInner() { throw new Error("Error in HTML"); }</script>
+       <script>function htmlOuter() { htmlInner(); }</script>
+       <script src="script-tests/stack-trace.js"></script>
+</body>
+</html>
index a25e246..13958b7 100644 (file)
@@ -489,6 +489,10 @@ WONTFIX SKIP : fast/frames/cross-site-this.html = FAIL
 // throw.  V8 follows the spec.
 WONTFIX SKIP : fast/js/reparsing-semicolon-insertion.html = FAIL
 
+// This tests stack-traces that are generated by JSC. This test should
+// fail since it is specific to jsc.
+WONTFIX SKIP : fast/js/stack-trace.html = FAIL
+
 // Rubber-banding is currently a CG only feature.
 WONTFIX CPU GPU : platform/chromium/rubberbanding = FAIL
 WONTFIX CPU GPU : platform/chromium-gpu/compositing/rubberbanding = IMAGE
index b656057..85d4999 100644 (file)
@@ -1,3 +1,34 @@
+2011-09-27  Juan Carlos Montemayor Elosua  <j.mont@me.com>
+
+        Implement Error.stack
+        https://bugs.webkit.org/show_bug.cgi?id=66994
+
+        Reviewed by Oliver Hunt.
+
+        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.
+
+        * JavaScriptCore.exp:
+        * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def:
+        * interpreter/Interpreter.cpp:
+        (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:
+
 2011-09-27  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         [GTK] Reorganize header files
index ec942d4..65c8dc9 100644 (file)
@@ -114,6 +114,7 @@ __ZN3JSC10JSFunction6s_infoE
 __ZN3JSC10JSFunctionC1EPNS_9ExecStateEPNS_14JSGlobalObjectEPNS_9StructureE
 __ZN3JSC10throwErrorEPNS_9ExecStateENS_7JSValueE
 __ZN3JSC10throwErrorEPNS_9ExecStateEPNS_8JSObjectE
+__ZN3JSC11Interpreter13getStackTraceEPNS_12JSGlobalDataEiRN3WTF6VectorINS_10StackFrameELm0EEE
 __ZN3JSC11JSByteArray13s_defaultInfoE
 __ZN3JSC11JSByteArray15createStructureERNS_12JSGlobalDataEPNS_14JSGlobalObjectENS_7JSValueEPKNS_9ClassInfoE
 __ZN3JSC11JSByteArrayC1EPNS_9ExecStateEPNS_9StructureEPN3WTF9ByteArrayE
index ff326d3..b2d02d9 100644 (file)
@@ -211,6 +211,7 @@ EXPORTS
     ?getPropertyDescriptor@JSObject@JSC@@QAE_NPAVExecState@2@ABVIdentifier@2@AAVPropertyDescriptor@2@@Z
     ?getPropertyNames@JSObject@JSC@@UAEXPAVExecState@2@AAVPropertyNameArray@2@W4EnumerationMode@2@@Z
     ?getSlice@ArgList@JSC@@QBEXHAAV12@@Z
+    ?getStackTrace@Interpreter@JSC@@SAXPAVJSGlobalData@2@HAAV?$Vector@UStackFrame@JSC@@$0A@@WTF@@@Z
     ?getString@JSCell@JSC@@QBE?AVUString@2@PAVExecState@2@@Z
     ?getString@JSCell@JSC@@QBE_NPAVExecState@2@AAVUString@2@@Z
     ?getter@PropertyDescriptor@JSC@@QBE?AVJSValue@2@XZ
index 9f0aa30..da49469 100644 (file)
@@ -45,7 +45,6 @@
 #include "JSActivation.h"
 #include "JSArray.h"
 #include "JSByteArray.h"
-#include "JSFunction.h"
 #include "JSNotAnObject.h"
 #include "JSPropertyNameIterator.h"
 #include "LiteralParser.h"
@@ -687,6 +686,88 @@ static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception,
     exception->putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message));
 }
 
+static void getCallerLine(JSGlobalData* globalData, CallFrame* callFrame, int& lineNumber)
+{
+    (void)globalData;
+    unsigned bytecodeOffset;
+    lineNumber = -1;
+    callFrame = callFrame->removeHostCallFrameFlag();
+
+    if (callFrame->callerFrame() == CallFrame::noCaller() || callFrame->callerFrame()->hasHostCallFrameFlag())
+        return;
+
+    CodeBlock* callerCodeBlock = callFrame->callerFrame()->removeHostCallFrameFlag()->codeBlock();
+
+#if ENABLE(INTERPRETER)
+    if (!globalData->canUseJIT())
+        bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnVPC());
+#if ENABLE(JIT)
+    else
+        bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
+#endif
+#else
+    bytecodeOffset = callerCodeBlock->bytecodeOffset(callFrame->returnPC());
+#endif
+
+    lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset - 1);
+}
+
+static ALWAYS_INLINE const UString getSourceURLFromCallFrame(CallFrame* callFrame) 
+{
+    if (callFrame->hasHostCallFrameFlag())
+        return UString();
+#if ENABLE(INTERPRETER)
+    if (!callFrame->globalData().canUseJIT())
+        return callFrame->codeBlock()->source()->url();
+#if ENABLE(JIT)
+    return callFrame->codeBlock()->ownerExecutable()->sourceURL();
+#endif
+#else
+    return callFrame->codeBlock()->ownerExecutable()->sourceURL();
+#endif
+}
+
+static StackFrameCodeType getStackFrameCodeType(CallFrame* callFrame)
+{
+    if (callFrame->hasHostCallFrameFlag()) 
+        return StackFrameNativeCode;
+
+    switch (callFrame->codeBlock()->codeType()) {
+    case EvalCode:
+        return StackFrameEvalCode;
+    case FunctionCode:
+        return StackFrameFunctionCode;
+    case GlobalCode:
+        return StackFrameGlobalCode;
+    }
+    ASSERT_NOT_REACHED();
+    return StackFrameGlobalCode;
+}
+
+void Interpreter::getStackTrace(JSGlobalData* globalData, int line, Vector<StackFrame>& results)
+{
+    int stackLimit = 15;
+    CallFrame* callFrame = globalData->topCallFrame->removeHostCallFrameFlag();
+    if (!callFrame || callFrame == CallFrame::noCaller() || !callFrame->codeBlock()) 
+        return;
+    UString sourceURL;
+    UString traceLevel;
+
+    for (int i = 0; i < stackLimit; ++i) {
+        if (!callFrame || callFrame == CallFrame::noCaller())
+            break;
+        if (callFrame->codeBlock()) {
+            sourceURL = getSourceURLFromCallFrame(callFrame);
+
+            StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), Strong<CallFrame>(*globalData, callFrame), getStackFrameCodeType(callFrame), Strong<ExecutableBase>(*globalData, callFrame->codeBlock()->ownerExecutable()), line, sourceURL};
+
+            results.append(s);
+        }
+        getCallerLine(globalData, callFrame, line);
+        callFrame = callFrame->callerFrame()->removeHostCallFrameFlag();
+    }
+}
+
 NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset)
 {
     CodeBlock* codeBlock = callFrame->codeBlock();
@@ -705,7 +786,9 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV
 
             // FIXME: should only really be adding these properties to VM generated exceptions,
             // but the inspector currently requires these for all thrown objects.
-            addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source());
+            Vector<StackFrame> stackTrace;
+            getStackTrace(&callFrame->globalData(), codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), stackTrace);
+            addErrorInfo(callFrame, exception, codeBlock->lineNumberForBytecodeOffset(bytecodeOffset), codeBlock->ownerExecutable()->source(), stackTrace);
         }
 
         isInterrupt = isInterruptedExecutionException(exception) || isTerminatedExecutionException(exception);
index fd7f624..f3365a7 100644 (file)
@@ -31,6 +31,7 @@
 
 #include "ArgList.h"
 #include "JSCell.h"
+#include "JSFunction.h"
 #include "JSValue.h"
 #include "JSObject.h"
 #include "Opcode.h"
@@ -42,8 +43,8 @@ namespace JSC {
 
     class CodeBlock;
     class EvalExecutable;
+    class ExecutableBase;
     class FunctionExecutable;
-    class JSFunction;
     class JSGlobalObject;
     class ProgramExecutable;
     class Register;
@@ -62,6 +63,56 @@ namespace JSC {
         WillExecuteStatement
     };
 
+    enum StackFrameCodeType {
+        StackFrameGlobalCode,
+        StackFrameEvalCode,
+        StackFrameFunctionCode,
+        StackFrameNativeCode
+    };
+
+    struct StackFrame {
+        Strong<JSObject> callee;
+        Strong<CallFrame> callFrame;
+        StackFrameCodeType codeType;
+        Strong<ExecutableBase> executable;
+        int line;
+        UString sourceURL;
+        UString toString() const
+        {
+            bool hasSourceURLInfo = !sourceURL.isNull() && !sourceURL.isEmpty();
+            bool hasLineInfo = line > -1;
+            String traceLine;
+            JSObject* stackFrameCallee = callee.get();
+
+            switch (codeType) {
+            case StackFrameEvalCode:
+                if (hasSourceURLInfo) 
+                    traceLine = hasLineInfo ? String::format("eval at %s:%d", sourceURL.ascii().data(), line) 
+                                            : String::format("eval at %s", sourceURL.ascii().data());
+                else
+                    traceLine = String::format("eval");
+                break;
+            case StackFrameNativeCode:
+                traceLine = "Native code";
+                break;
+            case StackFrameFunctionCode:
+                if (stackFrameCallee && stackFrameCallee->inherits(&JSFunction::s_info)) {
+                    UString functionName = asFunction(stackFrameCallee)->name(callFrame.get());
+                    if (hasSourceURLInfo) 
+                        traceLine = hasLineInfo ? String::format("%s at %s:%d", functionName.ascii().data(), sourceURL.ascii().data(), line)
+                                                : String::format("%s at %s", functionName.ascii().data(), sourceURL.ascii().data());
+                    else
+                        traceLine = String::format("%s\n", functionName.ascii().data());
+                    break;
+                }
+            case StackFrameGlobalCode:
+                traceLine = hasLineInfo ? String::format("at %s:%d", sourceURL.ascii().data(), line)
+                                        : String::format("at %s", sourceURL.ascii().data());
+            }
+            return traceLine.impl();
+        }
+    };
+
     class TopCallFrameSetter {
     public:
         TopCallFrameSetter(JSGlobalData& global, CallFrame* callFrame)
@@ -128,6 +179,8 @@ namespace JSC {
         NEVER_INLINE JSValue callEval(CallFrame*, RegisterFile*, Register* argv, int argc, int registerOffset);
         NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset);
         NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine);
+        static const UString getTraceLine(CallFrame*, StackFrameCodeType, const UString&, int);
+        static void getStackTrace(JSGlobalData*, int line, Vector<StackFrame>& results);
 
         void dumpSampleData(ExecState* exec);
         void startSampling();
index 9b753e2..ca522a4 100644 (file)
@@ -27,6 +27,7 @@
 #include "CurrentTime.h"
 #include "ExceptionHelpers.h"
 #include "InitializeThreading.h"
+#include "Interpreter.h"
 #include "JSArray.h"
 #include "JSFunction.h"
 #include "JSLock.h"
@@ -73,6 +74,7 @@ static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>&
 
 static EncodedJSValue JSC_HOST_CALL functionPrint(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionDebug(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState*);
 static EncodedJSValue JSC_HOST_CALL functionGC(ExecState*);
 #ifndef NDEBUG
 static EncodedJSValue JSC_HOST_CALL functionReleaseExecutableMemory(ExecState*);
@@ -174,6 +176,7 @@ protected:
         addFunction(globalData, "run", functionRun, 1);
         addFunction(globalData, "load", functionLoad, 1);
         addFunction(globalData, "checkSyntax", functionCheckSyntax, 1);
+        addFunction(globalData, "jscStack", functionJSCStack, 1);
         addFunction(globalData, "readline", functionReadline, 0);
         addFunction(globalData, "preciseTime", functionPreciseTime, 0);
 #if ENABLE(SAMPLING_FLAGS)
@@ -221,6 +224,22 @@ EncodedJSValue JSC_HOST_CALL functionDebug(ExecState* exec)
     return JSValue::encode(jsUndefined());
 }
 
+EncodedJSValue JSC_HOST_CALL functionJSCStack(ExecState* exec)
+{
+    String trace = "--> Stack trace:\n";
+    Vector<StackFrame> stackTrace;
+    Interpreter::getStackTrace(&exec->globalData(), -1, stackTrace);
+    int i = 0;
+
+    for (Vector<StackFrame>::iterator iter = stackTrace.begin(); iter < stackTrace.end(); iter++) {
+        StackFrame level = *iter;
+        trace += String::format("    %i   %s\n", i, level.toString().utf8().data());
+        i++;
+    }
+    fprintf(stderr, "%s", trace.utf8().data());
+    return JSValue::encode(jsUndefined());
+}
+
 EncodedJSValue JSC_HOST_CALL functionGC(ExecState* exec)
 {
     JSLock lock(SilenceAssertionsOnly);
index 2dbd27c..cc3a8ed 100644 (file)
@@ -114,7 +114,7 @@ namespace JSC {
             else if (isEvalNode<ParsedNode>())
                 *exception = createSyntaxError(lexicalGlobalObject, errMsg);
             else
-                *exception = addErrorInfo(&lexicalGlobalObject->globalData(), createSyntaxError(lexicalGlobalObject, errMsg), errLine, source);
+                *exception = addErrorInfo(&lexicalGlobalObject->globalData(), createSyntaxError(lexicalGlobalObject, errMsg), errLine, source, Vector<StackFrame>());
         }
 
         m_arena.reset();
index 9ade142..be8ce3e 100644 (file)
@@ -52,6 +52,7 @@
     macro(input) \
     macro(isArray) \
     macro(isPrototypeOf) \
+    macro(jscStack) \
     macro(length) \
     macro(message) \
     macro(multiline) \
index 0081135..c6eb408 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "ConstructData.h"
 #include "ErrorConstructor.h"
+#include "JSArray.h"
 #include "JSFunction.h"
 #include "JSGlobalObject.h"
 #include "JSObject.h"
@@ -116,7 +117,7 @@ JSObject* createURIError(ExecState* exec, const UString& message)
     return createURIError(exec->lexicalGlobalObject(), message);
 }
 
-JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source)
+JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source, const Vector<StackFrame>& stackTrace)
 {
     intptr_t sourceID = source.provider()->asID();
     const UString& sourceURL = source.provider()->url();
@@ -127,13 +128,21 @@ JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, cons
         error->putWithAttributes(globalData, Identifier(globalData, sourceIdPropertyName), jsNumber((double)sourceID), ReadOnly | DontDelete);
     if (!sourceURL.isNull())
         error->putWithAttributes(globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete);
+    if (!stackTrace.isEmpty()) {
+        JSArray* stackTraceArray = JSArray::create(*globalData, globalData->dynamicGlobalObject->arrayStructure());
+        for (unsigned i = 0; i < stackTrace.size(); i++) {
+            UString stackLevel =  stackTrace[i].toString();
+            stackTraceArray->push(globalData->topCallFrame, jsString(globalData, stackLevel)); 
+        }
+        error->putWithAttributes(globalData, globalData->propertyNames->jscStack, stackTraceArray, ReadOnly | DontDelete);
+    }
 
     return error;
 }
 
-JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source)
+JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source, const Vector<StackFrame>& stackTrace)
 {
-    return addErrorInfo(&exec->globalData(), error, line, source);
+    return addErrorInfo(&exec->globalData(), error, line, source, stackTrace);
 }
 
 bool hasErrorInfo(ExecState* exec, JSObject* error)
index c0f9d32..f4a6d8c 100644 (file)
@@ -23,6 +23,7 @@
 #ifndef Error_h
 #define Error_h
 
+#include "Interpreter.h"
 #include "JSObject.h"
 #include <stdint.h>
 
@@ -55,9 +56,9 @@ namespace JSC {
 
     // Methods to add 
     bool hasErrorInfo(ExecState*, JSObject* error);
-    JSObject* addErrorInfo(JSGlobalData*, JSObject* error, int line, const SourceCode&);
+    JSObject* addErrorInfo(JSGlobalData*, JSObject* error, int line, const SourceCode&, const Vector<StackFrame>&);
     // ExecState wrappers.
-    JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&);
+    JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&, const Vector<StackFrame>&);
 
     // Methods to throw Errors.
     JSValue throwError(ExecState*, JSValue);