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;