Commit 3980d396 authored by oliver@apple.com's avatar oliver@apple.com
Browse files

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/JavaScriptCore:

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:

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@147818 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent d0be74de
......@@ -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 @@ JSStringRef JSContextCreateBacktrace(JSContextRef ctx, unsigned maxStackSize)
{
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();
}
......
2013-04-05 Oliver Hunt <oliver@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-05 Mark Hahnenberg <mhahnenberg@apple.com>
 
tryCacheGetByID sets StructureStubInfo accessType to an incorrect value
......@@ -2055,6 +2055,7 @@ void BytecodeGenerator::emitDebugHook(DebugHookID debugHookID, int firstLine, in
if (!m_shouldEmitDebugHooks)
return;
#endif
emitExpressionInfo(charPosition, 0, 0);
emitOpcode(op_debug);
instructions().append(debugHookID);
instructions().append(firstLine);
......
......@@ -199,7 +199,7 @@ Interpreter::StackPolicy::StackPolicy(Interpreter& interpreter, const StackBound
}
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 @@ void Interpreter::dumpRegisters(CallFrame* callFrame)
#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 @@ NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue ex
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,27 +564,25 @@ static void appendSourceToError(CallFrame* callFrame, ErrorInstance* exception,
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)
#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();
#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();
......@@ -654,7 +652,6 @@ static CallFrame* getCallerInfo(JSGlobalData* globalData, CallFrame* callFrame,
RELEASE_ASSERT(callerCodeBlock);
caller = callerCodeBlock;
lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(bytecodeOffset);
return callerFrame;
}
......@@ -680,51 +677,97 @@ static StackFrameCodeType getStackFrameCodeType(CallFrame* callFrame)
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;
......@@ -733,8 +776,10 @@ void Interpreter::addStackTraceIfNecessary(CallFrame* callFrame, JSObject* error
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)
......@@ -1377,10 +1422,9 @@ JSValue Interpreter::retrieveCallerFromVMCode(CallFrame* callFrame, JSFunction*
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();
......@@ -1390,7 +1434,7 @@ JSValue Interpreter::retrieveCallerFromVMCode(CallFrame* callFrame, JSFunction*
// 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();
......
......@@ -79,25 +79,13 @@ namespace JSC {
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 @@ namespace JSC {
}
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 @@ namespace JSC {
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();
......
......@@ -155,8 +155,7 @@ bool hasErrorInfo(ExecState* exec, JSObject* error)
JSValue throwError(ExecState* exec, JSValue error)
{
if (error.isObject())
return throwError(exec, asObject(error));
Interpreter::addStackTraceIfNecessary(exec, error);
exec->globalData().exception = error;
return error;
}
......
......@@ -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 @@ namespace JSC {
class RegExpCache;
class SourceProvider;
class SourceProviderCache;
struct StackFrame;
class Stringifier;
class Structure;
#if ENABLE(REGEXP_TRACING)
......@@ -328,6 +330,7 @@ namespace JSC {
Terminator terminator;
JSValue exception;
RefCountedArray<StackFrame> exceptionStack;
const ClassInfo* const jsArrayClassInfo;
const ClassInfo* const jsFinalObjectClassInfo;
......
......@@ -597,6 +597,8 @@ DynamicGlobalObjectScope::DynamicGlobalObjectScope(JSGlobalData& globalData, JSG
// to observe time zone changes.
globalData.resetDateCache();
}
// Clear the exception stack between entries
globalData.exceptionStack = RefCountedArray<StackFrame>();
}
void slowValidateCell(JSGlobalObject* globalObject)
......
2013-04-05 Oliver Hunt <oliver@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-05 Beth Dakin <bdakin@apple.com>
 
Setting a header or footer should cause a relayout
......@@ -58,18 +58,15 @@ PassRefPtr<ScriptCallStack> createScriptCallStack(size_t maxStackSize, bool empt
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,18 @@ PassRefPtr<ScriptCallStack> createScriptCallStack(size_t maxStackSize, bool empt
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 = 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);
}
......
......@@ -53,7 +53,8 @@ bool ScriptCallFrame::isEqual(const ScriptCallFrame& o) const
{
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)
......
......@@ -44,12 +44,13 @@ class InspectorObject;
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;
......
2013-04-05 Oliver Hunt <oliver@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-05 Chris Fleizach <cfleizach@apple.com>
 
AX: Make SVG Group containers accessible elements
......@@ -42,7 +42,6 @@ my $count = 1;
my $verbose = 0;
GetOptions("count|c=i" => \$count,
"verbose|v" => \$verbose);
die "$usage\n" if (@ARGV < 1);