Title: [147858] trunk
Revision
147858
Author
oli...@apple.com
Date
2013-04-06 15:47:56 -0700 (Sat, 06 Apr 2013)

Log 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/_javascript_Core:

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:

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/API/JSContextRef.cpp (147857 => 147858)


--- trunk/Source/_javascript_Core/API/JSContextRef.cpp	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/_javascript_Core/API/JSContextRef.cpp	2013-04-06 22:47:56 UTC (rev 147858)
@@ -36,6 +36,7 @@
 #include "JSGlobalObject.h"
 #include "JSObject.h"
 #include "Operations.h"
+#include "SourceProvider.h"
 #include <wtf/text/StringBuilder.h>
 #include <wtf/text/StringHash.h>
 
@@ -175,51 +176,38 @@
 {
     ExecState* exec = toJS(ctx);
     JSLockHolder lock(exec);
-
-    unsigned count = 0;
     StringBuilder builder;
-    CallFrame* callFrame = exec;
-    String functionName;
-    if (exec->callee()) {
-        if (asObject(exec->callee())->inherits(&InternalFunction::s_info)) {
-            functionName = asInternalFunction(exec->callee())->name(exec);
-            builder.appendLiteral("#0 ");
-            builder.append(functionName);
-            builder.appendLiteral("() ");
-            count++;
-        }
-    }
-    while (true) {
-        RELEASE_ASSERT(callFrame);
-        int signedLineNumber;
-        intptr_t sourceID;
-        String urlString;
-        JSValue function;
+    Vector<StackFrame> stackTrace;
+    Interpreter::getStackTrace(&exec->globalData(), stackTrace, maxStackSize);
 
-        exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function);
-
-        if (function)
-            functionName = jsCast<JSFunction*>(function)->name(exec);
+    for (size_t i = 0; i < stackTrace.size(); i++) {
+        String urlString;
+        String functionName;
+        StackFrame& frame = stackTrace[i];
+        JSValue function = frame.callee.get();
+        if (frame.callee)
+            functionName = frame.friendlyFunctionName(exec);
         else {
             // Caller is unknown, but if frame is empty we should still add the frame, because
             // something called us, and gave us arguments.
-            if (count)
+            if (i)
                 break;
         }
-        unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0;
+        unsigned lineNumber = frame.line();
         if (!builder.isEmpty())
             builder.append('\n');
         builder.append('#');
-        builder.appendNumber(count);
+        builder.appendNumber(i);
         builder.append(' ');
         builder.append(functionName);
         builder.appendLiteral("() at ");
         builder.append(urlString);
-        builder.append(':');
-        builder.appendNumber(lineNumber);
-        if (!function || ++count == maxStackSize)
+        if (frame.codeType != StackFrameNativeCode) {
+            builder.append(':');
+            builder.appendNumber(lineNumber);
+        }
+        if (!function)
             break;
-        callFrame = callFrame->callerFrame();
     }
     return OpaqueJSString::create(builder.toString()).leakRef();
 }

Modified: trunk/Source/_javascript_Core/ChangeLog (147857 => 147858)


--- trunk/Source/_javascript_Core/ChangeLog	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/_javascript_Core/ChangeLog	2013-04-06 22:47:56 UTC (rev 147858)
@@ -1,3 +1,45 @@
+2013-04-06  Oliver Hunt  <oli...@apple.com>
+
+        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.
+
+        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):
+
 2013-04-06  Geoffrey Garen  <gga...@apple.com>
 
         Removed v8 bindings hooks from IDL files

Modified: trunk/Source/_javascript_Core/_javascript_Core.vcproj/_javascript_Core/_javascript_CoreExports.def (147857 => 147858)


--- trunk/Source/_javascript_Core/_javascript_Core.vcproj/_javascript_Core/_javascript_CoreExports.def	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/_javascript_Core/_javascript_Core.vcproj/_javascript_Core/_javascript_CoreExports.def	2013-04-06 22:47:56 UTC (rev 147858)
@@ -237,7 +237,6 @@
     ?getCallData@JSCell@JSC@@SA?AW4CallType@2@PAV12@AATCallData@2@@Z
     ?getConstructData@JSCell@JSC@@SA?AW4ConstructType@2@PAV12@AATConstructData@2@@Z
     ?getID@SourceProvider@JSC@@AAEXXZ
-    ?getStackTrace@Interpreter@JSC@@SAXPAVJSGlobalData@2@AAV?$Vector@UStackFrame@JSC@@$0A@@WTF@@@Z
     ?getObject@JSCell@JSC@@QAEPAVJSObject@2@XZ
     ?getObjectType@MemoryInstrumentation@WTF@@CAPBDPAVMemoryObjectInfo@2@@Z
     ?getOwnNonIndexPropertyNames@JSObject@JSC@@SAXPAV12@PAVExecState@2@AAVPropertyNameArray@2@W4EnumerationMode@2@@Z

Modified: trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp (147857 => 147858)


--- trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/_javascript_Core/bytecompiler/BytecodeGenerator.cpp	2013-04-06 22:47:56 UTC (rev 147858)
@@ -2055,6 +2055,7 @@
     if (!m_shouldEmitDebugHooks)
         return;
 #endif
+    emitExpressionInfo(charPosition, 0, 0);
     emitOpcode(op_debug);
     instructions().append(debugHookID);
     instructions().append(firstLine);

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.cpp (147857 => 147858)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.cpp	2013-04-06 22:47:56 UTC (rev 147858)
@@ -199,7 +199,7 @@
 }
 
 
-static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, int& lineNumber, unsigned& bytecodeOffset, CodeBlock*& callerOut);
+static CallFrame* getCallerInfo(JSGlobalData*, CallFrame*, unsigned& bytecodeOffset, CodeBlock*& callerOut);
 
 // Returns the depth of the scope chain within a given call frame.
 static int depth(CodeBlock* codeBlock, JSScope* sc)
@@ -422,8 +422,9 @@
 #endif
     unsigned bytecodeOffset = 0;
     int line = 0;
-    CodeBlock* unusedCallerCodeBlock = 0;
-    getCallerInfo(&callFrame->globalData(), callFrame, line, bytecodeOffset, unusedCallerCodeBlock);
+    CodeBlock* callerCodeBlock = 0;
+    getCallerInfo(&callFrame->globalData(), callFrame, bytecodeOffset, callerCodeBlock);
+    line = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset);
     dataLogF("[ReturnVPC]                | %10p | %d (line %d)\n", it, bytecodeOffset, line);
     ++it;
     dataLogF("[CodeBlock]                | %10p | %p \n", it, callFrame->codeBlock());
@@ -507,8 +508,7 @@
     callFrame->globalData().topCallFrame = callerFrame;
     if (callerFrame->hasHostCallFrameFlag())
         return false;
-    int unusedLineNumber = 0;
-    callFrame = getCallerInfo(&callFrame->globalData(), callFrame, unusedLineNumber, bytecodeOffset, codeBlock);
+    callFrame = getCallerInfo(&callFrame->globalData(), callFrame, bytecodeOffset, codeBlock);
     return true;
 }
 
@@ -564,29 +564,27 @@
     exception->putDirect(*globalData, globalData->propertyNames->message, jsString(globalData, message));
 }
 
-static int getLineNumberForCallFrame(JSGlobalData* globalData, CallFrame* callFrame)
+static unsigned getBytecodeOffsetForCallFrame(CallFrame* callFrame)
 {
-    UNUSED_PARAM(globalData);
     callFrame = callFrame->removeHostCallFrameFlag();
     CodeBlock* codeBlock = callFrame->codeBlock();
     if (!codeBlock)
-        return -1;
-#if ENABLE(JIT) || ENABLE(LLINT)
+        return 0;
+#if ENABLE(JIT)
 #if ENABLE(DFG_JIT)
     if (codeBlock->getJITType() == JITCode::DFGJIT)
-        return codeBlock->lineNumberForBytecodeOffset(codeBlock->codeOrigin(callFrame->codeOriginIndexForDFG()).bytecodeIndex);
+        return codeBlock->codeOrigin(callFrame->codeOriginIndexForDFG()).bytecodeIndex;
 #endif
-    return codeBlock->lineNumberForBytecodeOffset(callFrame->bytecodeOffsetForNonDFGCode());
+    return callFrame->bytecodeOffsetForNonDFGCode();
 #else
     return 0;
 #endif
 }
 
-static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, int& lineNumber, unsigned& bytecodeOffset, CodeBlock*& caller)
+static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame, unsigned& bytecodeOffset, CodeBlock*& caller)
 {
     ASSERT_UNUSED(globalData, globalData);
     bytecodeOffset = 0;
-    lineNumber = -1;
     ASSERT(!callFrame->hasHostCallFrameFlag());
     CallFrame* callerFrame = callFrame->codeBlock() ? callFrame->trueCallerFrame() : callFrame->callerFrame()->removeHostCallFrameFlag();
     bool callframeIsHost = callerFrame->addHostCallFrameFlag() == callFrame->callerFrame();
@@ -656,7 +654,6 @@
 
     RELEASE_ASSERT(callerCodeBlock);
     caller = callerCodeBlock;
-    lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset);
     return callerFrame;
 }
 
@@ -682,51 +679,97 @@
     return StackFrameGlobalCode;
 }
 
-void Interpreter::getStackTrace(JSGlobalData* globalData, Vector<StackFrame>& results)
+unsigned StackFrame::line()
 {
+    return codeBlock ? codeBlock->lineNumberForBytecodeOffset(bytecodeOffset) + lineOffset : 0;
+}
+
+unsigned StackFrame::column()
+{
+    if (!code)
+        return 0;
+    int divot = 0;
+    int unusedStartOffset = 0;
+    int unusedEndOffset = 0;
+    expressionInfo(divot, unusedStartOffset, unusedEndOffset);
+    return code->charPositionToColumnNumber(divot);
+}
+
+void StackFrame::expressionInfo(int& divot, int& startOffset, int& endOffset)
+{
+    codeBlock->expressionRangeForBytecodeOffset(bytecodeOffset, divot, startOffset, endOffset);
+    divot += startOffset;
+}
+
+String StackFrame::toString(CallFrame* callFrame)
+{
+    StringBuilder traceBuild;
+    String functionName = friendlyFunctionName(callFrame);
+    String sourceURL = friendlySourceURL();
+    traceBuild.append(functionName);
+    if (!sourceURL.isEmpty()) {
+        if (!functionName.isEmpty())
+            traceBuild.append('@');
+        traceBuild.append(sourceURL);
+        if (codeType != StackFrameNativeCode) {
+            traceBuild.append(':');
+            traceBuild.appendNumber(line());
+        }
+    }
+    return traceBuild.toString().impl();
+}
+
+void Interpreter::getStackTrace(JSGlobalData* globalData, Vector<StackFrame>& results, size_t maxStackSize)
+{
     CallFrame* callFrame = globalData->topCallFrame->removeHostCallFrameFlag();
     if (!callFrame || callFrame == CallFrame::noCaller()) 
         return;
-    int line = getLineNumberForCallFrame(globalData, callFrame);
-
+    unsigned bytecodeOffset = getBytecodeOffsetForCallFrame(callFrame);
     callFrame = callFrame->trueCallFrameFromVMCode();
     if (!callFrame)
         return;
+    CodeBlock* callerCodeBlock = callFrame->codeBlock();
 
-    while (callFrame && callFrame != CallFrame::noCaller()) {
+    while (callFrame && callFrame != CallFrame::noCaller() && maxStackSize--) {
         String sourceURL;
-        if (callFrame->codeBlock()) {
+        if (callerCodeBlock) {
             sourceURL = getSourceURLFromCallFrame(callFrame);
-            StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), getStackFrameCodeType(callFrame), Strong<ExecutableBase>(*globalData, callFrame->codeBlock()->ownerExecutable()), line, sourceURL};
+            StackFrame s = {
+                Strong<JSObject>(*globalData, callFrame->callee()),
+                getStackFrameCodeType(callFrame),
+                Strong<ExecutableBase>(*globalData, callerCodeBlock->ownerExecutable()),
+                Strong<UnlinkedCodeBlock>(*globalData, callerCodeBlock->unlinkedCodeBlock()),
+                callerCodeBlock->source(),
+                callerCodeBlock->ownerExecutable()->lineNo(),
+                callerCodeBlock->sourceOffset(),
+                bytecodeOffset,
+                sourceURL
+            };
             results.append(s);
         } else {
-            StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), -1, String()};
+            StackFrame s = { Strong<JSObject>(*globalData, callFrame->callee()), StackFrameNativeCode, Strong<ExecutableBase>(), Strong<UnlinkedCodeBlock>(), 0, 0, 0, 0, String()};
             results.append(s);
         }
-        unsigned unusedBytecodeOffset = 0;
-        CodeBlock* unusedCallerCodeBlock = 0;
-        callFrame = getCallerInfo(globalData, callFrame, line, unusedBytecodeOffset, unusedCallerCodeBlock);
+        callFrame = getCallerInfo(globalData, callFrame, bytecodeOffset, callerCodeBlock);
     }
 }
 
-void Interpreter::addStackTraceIfNecessary(CallFrame* callFrame, JSObject* error)
+void Interpreter::addStackTraceIfNecessary(CallFrame* callFrame, JSValue error)
 {
     JSGlobalData* globalData = &callFrame->globalData();
     ASSERT(callFrame == globalData->topCallFrame || callFrame == callFrame->lexicalGlobalObject()->globalExec() || callFrame == callFrame->dynamicGlobalObject()->globalExec());
-    if (error->hasProperty(callFrame, globalData->propertyNames->stack))
-        return;
 
     Vector<StackFrame> stackTrace;
     getStackTrace(&callFrame->globalData(), stackTrace);
     
-    if (stackTrace.isEmpty())
+    if (stackTrace.isEmpty() || !error.isObject())
         return;
-    
+    JSObject* errorObject = asObject(error);
     JSGlobalObject* globalObject = 0;
     if (isTerminatedExecutionException(error) || isInterruptedExecutionException(error))
         globalObject = globalData->dynamicGlobalObject;
     else
-        globalObject = error->globalObject();
+        globalObject = errorObject->globalObject();
 
     // FIXME: JSStringJoiner could be more efficient than StringBuilder here.
     StringBuilder builder;
@@ -735,8 +778,10 @@
         if (i != stackTrace.size() - 1)
             builder.append('\n');
     }
-    
-    error->putDirect(*globalData, globalData->propertyNames->stack, jsString(globalData, builder.toString()), ReadOnly | DontDelete);
+
+    if (errorObject->hasProperty(callFrame, globalData->propertyNames->stack))
+        return;
+    errorObject->putDirect(*globalData, globalData->propertyNames->stack, jsString(globalData, builder.toString()), ReadOnly | DontDelete);
 }
 
 NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSValue& exceptionValue, unsigned bytecodeOffset)
@@ -1379,10 +1424,9 @@
     if (!functionCallFrame)
         return jsNull();
     
-    int lineNumber;
     unsigned bytecodeOffset;
     CodeBlock* unusedCallerCodeBlock = 0;
-    CallFrame* callerFrame = getCallerInfo(&callFrame->globalData(), functionCallFrame, lineNumber, bytecodeOffset, unusedCallerCodeBlock);
+    CallFrame* callerFrame = getCallerInfo(&callFrame->globalData(), functionCallFrame, bytecodeOffset, unusedCallerCodeBlock);
     if (!callerFrame)
         return jsNull();
     JSValue caller = callerFrame->callee();
@@ -1392,7 +1436,7 @@
     // Skip over function bindings.
     ASSERT(caller.isObject());
     while (asObject(caller)->inherits(&JSBoundFunction::s_info)) {
-        callerFrame = getCallerInfo(&callFrame->globalData(), callerFrame, lineNumber, bytecodeOffset, unusedCallerCodeBlock);
+        callerFrame = getCallerInfo(&callFrame->globalData(), callerFrame, bytecodeOffset, unusedCallerCodeBlock);
         if (!callerFrame)
             return jsNull();
         caller = callerFrame->callee();

Modified: trunk/Source/_javascript_Core/interpreter/Interpreter.h (147857 => 147858)


--- trunk/Source/_javascript_Core/interpreter/Interpreter.h	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/_javascript_Core/interpreter/Interpreter.h	2013-04-06 22:47:56 UTC (rev 147858)
@@ -79,25 +79,13 @@
         Strong<JSObject> callee;
         StackFrameCodeType codeType;
         Strong<ExecutableBase> executable;
-        int line;
+        Strong<UnlinkedCodeBlock> codeBlock;
+        RefPtr<SourceProvider> code;
+        int lineOffset;
+        unsigned characterOffset;
+        unsigned bytecodeOffset;
         String sourceURL;
-        String toString(CallFrame* callFrame) const
-        {
-            StringBuilder traceBuild;
-            String functionName = friendlyFunctionName(callFrame);
-            String sourceURL = friendlySourceURL();
-            traceBuild.append(functionName);
-            if (!sourceURL.isEmpty()) {
-                if (!functionName.isEmpty())
-                    traceBuild.append('@');
-                traceBuild.append(sourceURL);
-                if (line > -1) {
-                    traceBuild.append(':');
-                    traceBuild.appendNumber(line);
-                }
-            }
-            return traceBuild.toString().impl();
-        }
+        JS_EXPORT_PRIVATE String toString(CallFrame*);
         String friendlySourceURL() const
         {
             String traceLine;
@@ -137,10 +125,9 @@
             }
             return traceLine.isNull() ? emptyString() : traceLine;
         }
-        unsigned friendlyLineNumber() const
-        {
-            return line > -1 ? line : 0;
-        }
+        JS_EXPORT_PRIVATE unsigned line();
+        JS_EXPORT_PRIVATE unsigned column();
+        JS_EXPORT_PRIVATE void expressionInfo(int& divot, int& startOffset, int& endOffset);
     };
 
     class TopCallFrameSetter {
@@ -232,8 +219,8 @@
         NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset);
         NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine, int column);
         static const String getTraceLine(CallFrame*, StackFrameCodeType, const String&, int);
-        JS_EXPORT_PRIVATE static void getStackTrace(JSGlobalData*, Vector<StackFrame>& results);
-        static void addStackTraceIfNecessary(CallFrame*, JSObject* error);
+        JS_EXPORT_PRIVATE static void getStackTrace(JSGlobalData*, Vector<StackFrame>& results, size_t maxStackSize = std::numeric_limits<size_t>::max());
+        static void addStackTraceIfNecessary(CallFrame*, JSValue error);
 
         void dumpSampleData(ExecState* exec);
         void startSampling();

Modified: trunk/Source/_javascript_Core/runtime/Error.cpp (147857 => 147858)


--- trunk/Source/_javascript_Core/runtime/Error.cpp	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/_javascript_Core/runtime/Error.cpp	2013-04-06 22:47:56 UTC (rev 147858)
@@ -155,8 +155,7 @@
 
 JSValue throwError(ExecState* exec, JSValue error)
 {
-    if (error.isObject())
-        return throwError(exec, asObject(error));
+    Interpreter::addStackTraceIfNecessary(exec, error);
     exec->globalData().exception = error;
     return error;
 }

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalData.h (147857 => 147858)


--- trunk/Source/_javascript_Core/runtime/JSGlobalData.h	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalData.h	2013-04-06 22:47:56 UTC (rev 147858)
@@ -54,6 +54,7 @@
 #include <wtf/BumpPointerAllocator.h>
 #include <wtf/Forward.h>
 #include <wtf/HashMap.h>
+#include <wtf/RefCountedArray.h>
 #include <wtf/SimpleStats.h>
 #include <wtf/ThreadSafeRefCounted.h>
 #include <wtf/ThreadSpecific.h>
@@ -81,6 +82,7 @@
     class RegExpCache;
     class SourceProvider;
     class SourceProviderCache;
+    struct StackFrame;
     class Stringifier;
     class Structure;
 #if ENABLE(REGEXP_TRACING)
@@ -328,6 +330,7 @@
         Terminator terminator;
 
         JSValue exception;
+        RefCountedArray<StackFrame> exceptionStack;
 
         const ClassInfo* const jsArrayClassInfo;
         const ClassInfo* const jsFinalObjectClassInfo;

Modified: trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp (147857 => 147858)


--- trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/_javascript_Core/runtime/JSGlobalObject.cpp	2013-04-06 22:47:56 UTC (rev 147858)
@@ -597,6 +597,8 @@
         // to observe time zone changes.
         globalData.resetDateCache();
     }
+    // Clear the exception stack between entries
+    globalData.exceptionStack = RefCountedArray<StackFrame>();
 }
 
 void slowValidateCell(JSGlobalObject* globalObject)

Modified: trunk/Source/WebCore/ChangeLog (147857 => 147858)


--- trunk/Source/WebCore/ChangeLog	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/WebCore/ChangeLog	2013-04-06 22:47:56 UTC (rev 147858)
@@ -1,3 +1,22 @@
+2013-04-06  Oliver Hunt  <oli...@apple.com>
+
+        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.
+
+        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):
+
 2013-04-06  Geoffrey Garen  <gga...@apple.com>
 
         Removed v8 bindings hooks from IDL files

Modified: trunk/Source/WebCore/bindings/js/ScriptCallStackFactory.cpp (147857 => 147858)


--- trunk/Source/WebCore/bindings/js/ScriptCallStackFactory.cpp	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/WebCore/bindings/js/ScriptCallStackFactory.cpp	2013-04-06 22:47:56 UTC (rev 147858)
@@ -58,18 +58,15 @@
     Vector<ScriptCallFrame> frames;
     if (JSC::ExecState* exec = JSMainThreadExecState::currentState()) {
         Vector<StackFrame> stackTrace;
-        Interpreter::getStackTrace(&exec->globalData(), stackTrace);
-        for (Vector<StackFrame>::const_iterator iter = stackTrace.begin(); iter < stackTrace.end(); iter++) {
-            frames.append(ScriptCallFrame(iter->friendlyFunctionName(exec), iter->friendlySourceURL(), iter->friendlyLineNumber()));
-            if (frames.size() >= maxStackSize)
-                break;
-        }
+        Interpreter::getStackTrace(&exec->globalData(), stackTrace, maxStackSize);
+        for (size_t i = 0; i < stackTrace.size(); i++)
+            frames.append(ScriptCallFrame(stackTrace[i].friendlyFunctionName(exec), stackTrace[i].friendlySourceURL(), stackTrace[i].line(), stackTrace[i].column()));
     }
     if (frames.isEmpty() && !emptyIsAllowed) {
         // No frames found. It may happen in the case where
         // a bound function is called from native code for example.
         // Fallback to setting lineNumber to 0, and source and function name to "undefined".
-        frames.append(ScriptCallFrame("undefined", "undefined", 0));
+        frames.append(ScriptCallFrame("undefined", "undefined", 0, 0));
     }
     return ScriptCallStack::create(frames);
 }
@@ -77,30 +74,19 @@
 PassRefPtr<ScriptCallStack> createScriptCallStack(JSC::ExecState* exec, size_t maxStackSize)
 {
     Vector<ScriptCallFrame> frames;
-    CallFrame* callFrame = exec;
-    while (true) {
-        ASSERT(callFrame);
-        int signedLineNumber;
-        intptr_t sourceID;
-        String urlString;
-        JSValue function;
-
-        exec->interpreter()->retrieveLastCaller(callFrame, signedLineNumber, sourceID, urlString, function);
-        String functionName;
-        if (function)
-            functionName = jsCast<JSFunction*>(function)->name(exec);
-        else {
-            // Caller is unknown, but if frames is empty we should still add the frame, because
-            // something called us, and gave us arguments.
-            if (!frames.isEmpty())
-                break;
-        }
-        unsigned lineNumber = signedLineNumber >= 0 ? signedLineNumber : 0;
-        frames.append(ScriptCallFrame(functionName, urlString, lineNumber));
-        if (!function || frames.size() == maxStackSize)
+    Vector<StackFrame> stackTrace;
+    Interpreter::getStackTrace(&exec->globalData(), stackTrace, maxStackSize + 1);
+    for (size_t i = stackTrace.size() == 1 ? 0 : 1; i < stackTrace.size(); i++) {
+        // This early exit is necessary to maintain our old behaviour
+        // but the stack trace we produce now is complete and handles all
+        // ways in which code may be running
+        if (!stackTrace[i].callee && frames.size())
             break;
-        callFrame = callFrame->callerFrame();
+
+        String functionName = stackTrace[i].friendlyFunctionName(exec);
+        frames.append(ScriptCallFrame(functionName, stackTrace[i].sourceURL, stackTrace[i].line(), stackTrace[i].column()));
     }
+
     return ScriptCallStack::create(frames);
 }
 

Modified: trunk/Source/WebCore/inspector/ScriptCallFrame.cpp (147857 => 147858)


--- trunk/Source/WebCore/inspector/ScriptCallFrame.cpp	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/WebCore/inspector/ScriptCallFrame.cpp	2013-04-06 22:47:56 UTC (rev 147858)
@@ -53,7 +53,8 @@
 {
     return m_functionName == o.m_functionName
         && m_scriptName == o.m_scriptName
-        && m_lineNumber == o.m_lineNumber;
+        && m_lineNumber == o.m_lineNumber
+        && m_column == o.m_column;
 }
 
 #if ENABLE(INSPECTOR)

Modified: trunk/Source/WebCore/inspector/ScriptCallFrame.h (147857 => 147858)


--- trunk/Source/WebCore/inspector/ScriptCallFrame.h	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Source/WebCore/inspector/ScriptCallFrame.h	2013-04-06 22:47:56 UTC (rev 147858)
@@ -44,12 +44,13 @@
 
 class ScriptCallFrame  {
 public:
-    ScriptCallFrame(const String& functionName, const String& scriptName, unsigned lineNumber, unsigned column = 0);
+    ScriptCallFrame(const String& functionName, const String& scriptName, unsigned lineNumber, unsigned column);
     ~ScriptCallFrame();
 
     const String& functionName() const { return m_functionName; }
     const String& sourceURL() const { return m_scriptName; }
     unsigned lineNumber() const { return m_lineNumber; }
+    unsigned columnNumber() const { return m_column; }
 
     bool isEqual(const ScriptCallFrame&) const;
 

Modified: trunk/Tools/ChangeLog (147857 => 147858)


--- trunk/Tools/ChangeLog	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Tools/ChangeLog	2013-04-06 22:47:56 UTC (rev 147858)
@@ -1,3 +1,15 @@
+2013-04-06  Oliver Hunt  <oli...@apple.com>
+
+        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.
+
+        The commandline jsc executable no longer requires arguments, so
+        I've made run-jsc work without them.
+
+        * Scripts/run-jsc:
+
 2013-04-06  Ed Bartosh  <bart...@gmail.com>
 
         [EFL] build fails with error: 'UINT_MAX' was not declared in this scope

Modified: trunk/Tools/Scripts/run-jsc (147857 => 147858)


--- trunk/Tools/Scripts/run-jsc	2013-04-06 22:42:32 UTC (rev 147857)
+++ trunk/Tools/Scripts/run-jsc	2013-04-06 22:47:56 UTC (rev 147858)
@@ -42,7 +42,6 @@
 my $verbose = 0;
 GetOptions("count|c=i" => \$count,
            "verbose|v" => \$verbose);
-die "$usage\n" if (@ARGV < 1);
 
 my $jsc = jscProductDir() . "/jsc @ARGV";
 $jsc .= " 2> " . File::Spec->devnull() unless $verbose;
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to