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

Reviewed by Gavin Barraclough.

Source/JavaScriptCore:

Implement support for stack traces on exception objects.  This is a rewrite
of the core portion of the last stack walking logic, but the mechanical work
of adding the information to an exception comes from the original work by
Juan Carlos Montemayor Elosua.

* interpreter/Interpreter.cpp:
(JSC::getCallerInfo):
(JSC):
(JSC::getSourceURLFromCallFrame):
(JSC::getStackFrameCodeType):
(JSC::Interpreter::getStackTrace):
(JSC::Interpreter::throwException):
(JSC::Interpreter::privateExecute):
* interpreter/Interpreter.h:
(JSC):
(StackFrame):
(JSC::StackFrame::toString):
(Interpreter):
* jsc.cpp:
(GlobalObject::finishCreation):
(functionJSCStack):
* parser/Nodes.h:
(JSC::FunctionBodyNode::setInferredName):
* parser/Parser.h:
(JSC::::parse):
* runtime/CommonIdentifiers.h:
* runtime/Error.cpp:
(JSC::addErrorInfo):
* runtime/Error.h:
(JSC):

LayoutTests:

Add testcases for producing a stack trace on exception objects.

* 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):
(selfRecursive1):
(selfRecursive2):
(selfRecursive3):
(throwError):
(object.get getter1.o.valueOf):
(object.get getter1):
(object.get getter2):
(object.get getter3.o2.valueOf):
(object.get getter3):
(object.nonInlineable.callCount):
(object.nonInlineable):
(object.inlineable):
(yetAnotherInlinedCall):
(makeInlinableCall):
(.try.g):
(h):
(mapTest):
(mapTestDriver):
(dfgFunction):
(try.f):
* fast/js/stack-trace-expected.txt: Added.
* fast/js/stack-trace.html: Added.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@108112 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/interpreter/Interpreter.h b/Source/JavaScriptCore/interpreter/Interpreter.h
index c99b005..6920eb2 100644
--- a/Source/JavaScriptCore/interpreter/Interpreter.h
+++ b/Source/JavaScriptCore/interpreter/Interpreter.h
@@ -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 @@
 
     class CodeBlock;
     class EvalExecutable;
+    class ExecutableBase;
     class FunctionExecutable;
-    class JSFunction;
     class JSGlobalObject;
     class ProgramExecutable;
     class Register;
@@ -62,6 +63,63 @@
         WillExecuteStatement
     };
 
+    enum StackFrameCodeType {
+        StackFrameGlobalCode,
+        StackFrameEvalCode,
+        StackFrameFunctionCode,
+        StackFrameNativeCode
+    };
+
+    struct StackFrame {
+        Strong<JSObject> callee;
+        StackFrameCodeType codeType;
+        Strong<ExecutableBase> executable;
+        int line;
+        UString sourceURL;
+        UString toString(CallFrame* callFrame) 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 code@%s:%d", sourceURL.ascii().data(), line) 
+                                            : String::format("eval code@%s", sourceURL.ascii().data());
+                } else
+                    traceLine = String::format("eval code");
+                break;
+            case StackFrameNativeCode: {
+                if (callee) {
+                    UString functionName = getCalculatedDisplayName(callFrame, stackFrameCallee);
+                    traceLine = String::format("%s@[native code]", functionName.ascii().data());
+                } else
+                    traceLine = "[native code]";
+                break;
+            }
+            case StackFrameFunctionCode: {
+                UString functionName = getCalculatedDisplayName(callFrame, stackFrameCallee);
+                if (hasSourceURLInfo) {
+                    traceLine = hasLineInfo ? String::format("%s@%s:%d", functionName.ascii().data(), sourceURL.ascii().data(), line)
+                                            : String::format("%s@%s", functionName.ascii().data(), sourceURL.ascii().data());
+                } else
+                    traceLine = String::format("%s\n", functionName.ascii().data());
+                break;
+            }
+            case StackFrameGlobalCode:
+                if (hasSourceURLInfo) {
+                    traceLine = hasLineInfo ? String::format("global code@%s:%d", sourceURL.ascii().data(), line)
+                                            : String::format("global code@%s", sourceURL.ascii().data());
+                } else
+                    traceLine = String::format("global code");
+                    
+            }
+            return traceLine.impl();
+        }
+    };
+
     class TopCallFrameSetter {
     public:
         TopCallFrameSetter(JSGlobalData& global, CallFrame* callFrame)
@@ -151,6 +209,8 @@
 
         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);
+        JS_EXPORT_PRIVATE static void getStackTrace(JSGlobalData*, int line, Vector<StackFrame>& results);
 
         void dumpSampleData(ExecState* exec);
         void startSampling();