aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLars Knoll <lars.knoll@digia.com>2013-05-22 10:47:36 +0200
committerSimon Hausmann <simon.hausmann@digia.com>2013-05-22 12:27:21 +0200
commitd7f2868e427299c1cb9ec33b3c1939c6ad4e78a7 (patch)
tree9e642a0f8f238c6f70afa4fb70c286a92a701b1c
parent3bd678c76d8ab699e79e5a3cfe43cff2db03fb8f (diff)
Add support for generating stack traces to QV4::ExecutionEngine
This makes it possible to remove the v8::StackTrace API Change-Id: I53eee022a1030f0f6bf9a9268ca7cd3d5975724d Reviewed-by: Simon Hausmann <simon.hausmann@digia.com>
-rw-r--r--src/imports/testlib/main.cpp24
-rw-r--r--src/qml/qml/v4/qv4engine.cpp38
-rw-r--r--src/qml/qml/v4/qv4engine_p.h9
-rw-r--r--src/qml/qml/v4/qv4v8.cpp72
-rw-r--r--src/qml/qml/v4/qv4v8_p.h110
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp118
-rw-r--r--src/qml/qml/v8/qv8qobjectwrapper.cpp14
-rw-r--r--src/qml/qml/v8/qv8valuetypewrapper.cpp12
8 files changed, 109 insertions, 288 deletions
diff --git a/src/imports/testlib/main.cpp b/src/imports/testlib/main.cpp
index d854a26af5..1192861856 100644
--- a/src/imports/testlib/main.cpp
+++ b/src/imports/testlib/main.cpp
@@ -106,22 +106,22 @@ public Q_SLOTS:
QQmlV4Handle callerFile(int frameIndex = 0) const
{
- v8::Handle<v8::StackTrace> stacks = v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
- int count = stacks->GetFrameCount();
- if (count >= frameIndex + 1) {
- v8::Handle<v8::StackFrame> frame = stacks->GetFrame(frameIndex + 1);
- return QQmlV4Handle(frame->GetScriptNameOrSourceURL()->v4Value());
- }
+ QQmlEngine *engine = qmlEngine(this);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine->handle());
+
+ QVector<QV4::ExecutionEngine::StackFrame> stack = v4->stackTrace(frameIndex + 1);
+ if (stack.size() > frameIndex)
+ return QQmlV4Handle(QV4::Value::fromString(v4->newString(stack.at(frameIndex).source.url())));
return QQmlV4Handle();
}
int callerLine(int frameIndex = 0) const
{
- v8::Handle<v8::StackTrace> stacks = v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kDetailed);
- int count = stacks->GetFrameCount();
- if (count >= frameIndex + 1) {
- v8::Handle<v8::StackFrame> frame = stacks->GetFrame(frameIndex + 1);
- return frame->GetLineNumber();
- }
+ QQmlEngine *engine = qmlEngine(this);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine->handle());
+
+ QVector<QV4::ExecutionEngine::StackFrame> stack = v4->stackTrace(frameIndex + 1);
+ if (stack.size() > frameIndex)
+ return stack.at(frameIndex).line;
return -1;
}
};
diff --git a/src/qml/qml/v4/qv4engine.cpp b/src/qml/qml/v4/qv4engine.cpp
index d0604d93d6..8fafddf182 100644
--- a/src/qml/qml/v4/qv4engine.cpp
+++ b/src/qml/qml/v4/qv4engine.cpp
@@ -540,6 +540,44 @@ Object *ExecutionEngine::qmlContextObject() const
return static_cast<CallContext *>(ctx)->activation;
}
+QVector<ExecutionEngine::StackFrame> ExecutionEngine::stackTrace(int frameLimit) const
+{
+ QVector<StackFrame> stack;
+
+ QV4::ExecutionContext *c = current;
+ while (c && frameLimit) {
+ if (CallContext *c = c->asCallContext()) {
+ StackFrame frame;
+ frame.source = c->function->function->sourceFile;
+ frame.function = c->function->name->toQString();
+ frame.line = -1;
+ frame.column = -1;
+ stack.append(frame);
+ --frameLimit;
+ }
+ c = c->parent;
+ }
+ return stack;
+}
+
+ExecutionEngine::StackFrame ExecutionEngine::currentStackFrame() const
+{
+ StackFrame frame;
+ frame.line = -1;
+ frame.column = -1;
+
+ QV4::ExecutionContext *c = current;
+ while (c) {
+ if (CallContext *c = c->asCallContext()) {
+ frame.source = c->function->function->sourceFile;
+ frame.function = c->function->name->toQString();
+ return frame;
+ }
+ c = c->parent;
+ }
+ return frame;
+}
+
void ExecutionEngine::requireArgumentsAccessors(int n)
{
if (n <= argumentsAccessors.size())
diff --git a/src/qml/qml/v4/qv4engine_p.h b/src/qml/qml/v4/qv4engine_p.h
index be74de6d38..6d1ae60da2 100644
--- a/src/qml/qml/v4/qv4engine_p.h
+++ b/src/qml/qml/v4/qv4engine_p.h
@@ -271,6 +271,15 @@ struct Q_QML_EXPORT ExecutionEngine
Object *qmlContextObject() const;
+ struct StackFrame {
+ QUrl source;
+ QString function;
+ int line;
+ int column;
+ };
+ QVector<StackFrame> stackTrace(int frameLimit = -1) const;
+ StackFrame currentStackFrame() const;
+
void requireArgumentsAccessors(int n);
void markObjects();
diff --git a/src/qml/qml/v4/qv4v8.cpp b/src/qml/qml/v4/qv4v8.cpp
index 40a5c5f157..e730eb1a17 100644
--- a/src/qml/qml/v4/qv4v8.cpp
+++ b/src/qml/qml/v4/qv4v8.cpp
@@ -282,78 +282,6 @@ void Script::SetData(Handle<String> data)
}
-Handle<StackFrame> StackTrace::GetFrame(uint32_t index) const
-{
- if (index >= (uint)frames.size())
- return Handle<StackFrame>();
- return frames.at(index);
-}
-
-int StackTrace::GetFrameCount() const
-{
- return frames.size();
-}
-
-Handle<Array> StackTrace::AsArray()
-{
- Q_UNIMPLEMENTED();
- return Handle<Array>();
-}
-
-Handle<StackTrace> StackTrace::CurrentStackTrace(int frame_limit, StackTrace::StackTraceOptions options)
-{
- StackTrace *trace = new StackTrace;
- QV4::ExecutionEngine *engine = currentEngine();
- QV4::ExecutionContext *current = engine->current;
- while (current && frame_limit) {
- if (CallContext *c = current->asCallContext()) {
- StackFrame *frame = new StackFrame(QV4::Value::fromString(current, c->currentFileName().url()),
- QV4::Value::fromString(c->function->name),
- c->currentLineNumber(), 0);
- trace->frames.append(v8::Handle<v8::StackFrame>(frame));
- --frame_limit;
- }
- current = current->parent;
- }
-
- return Handle<StackTrace>(trace);
-}
-
-
-int StackFrame::GetLineNumber() const
-{
- return m_lineNumber;
-}
-
-int StackFrame::GetColumn() const
-{
- return m_columnNumber;
-}
-
-Handle<String> StackFrame::GetScriptName() const
-{
- return m_scriptName.value();
-}
-
-Handle<String> StackFrame::GetScriptNameOrSourceURL() const
-{
- return m_scriptName.value();
-}
-
-Handle<String> StackFrame::GetFunctionName() const
-{
- return m_functionName.value();
-}
-
-StackFrame::StackFrame(Handle<String> script, Handle<String> function, int line, int column)
- : m_lineNumber(line)
- , m_columnNumber(column)
-{
- m_scriptName = script->v4Value();
- m_functionName = function->v4Value();
-}
-
-
bool Value::IsUndefined() const
{
return ConstValuePtr(this)->isUndefined();
diff --git a/src/qml/qml/v4/qv4v8_p.h b/src/qml/qml/v4/qv4v8_p.h
index dcd44d5916..002c31cd90 100644
--- a/src/qml/qml/v4/qv4v8_p.h
+++ b/src/qml/qml/v4/qv4v8_p.h
@@ -122,8 +122,6 @@ class FunctionTemplate;
class ObjectTemplate;
class Data;
class AccessorInfo;
-class StackTrace;
-class StackFrame;
class Isolate;
class TryCatch;
@@ -554,114 +552,6 @@ private:
DEFINE_REFCOUNTED_HANDLE_OPERATIONS(Script)
-/**
- * Representation of a JavaScript stack trace. The information collected is a
- * snapshot of the execution stack and the information remains valid after
- * execution continues.
- */
-class V8EXPORT StackTrace : public QSharedData
-{
- public:
- /**
- * Flags that determine what information is placed captured for each
- * StackFrame when grabbing the current stack trace.
- */
- enum StackTraceOptions {
- kLineNumber = 1,
- kColumnOffset = 1 << 1 | kLineNumber,
- kScriptName = 1 << 2,
- kFunctionName = 1 << 3,
- kIsEval = 1 << 4,
- kIsConstructor = 1 << 5,
- kScriptNameOrSourceURL = 1 << 6,
- kOverview = kLineNumber | kColumnOffset | kScriptName | kFunctionName,
- kDetailed = kOverview | kIsEval | kIsConstructor | kScriptNameOrSourceURL
- };
-
- /**
- * Returns a StackFrame at a particular index.
- */
- Handle<StackFrame> GetFrame(uint32_t index) const;
-
- /**
- * Returns the number of StackFrames.
- */
- int GetFrameCount() const;
-
- /**
- * Returns StackTrace as a v8::Array that contains StackFrame objects.
- */
- Handle<Array> AsArray();
-
- /**
- * Grab a snapshot of the current JavaScript execution stack.
- *
- * \param frame_limit The maximum number of stack frames we want to capture.
- * \param options Enumerates the set of things we will capture for each
- * StackFrame.
- */
- static Handle<StackTrace> CurrentStackTrace(
- int frame_limit,
- StackTraceOptions options = kOverview);
-
- private:
- QVector<Handle<StackFrame> > frames;
-};
-
-DEFINE_REFCOUNTED_HANDLE_OPERATIONS(StackTrace)
-
-
-/**
- * A single JavaScript stack frame.
- */
-class V8EXPORT StackFrame : public QSharedData {
- public:
- /**
- * Returns the number, 1-based, of the line for the associate function call.
- * This method will return Message::kNoLineNumberInfo if it is unable to
- * retrieve the line number, or if kLineNumber was not passed as an option
- * when capturing the StackTrace.
- */
- int GetLineNumber() const;
-
- /**
- * Returns the 1-based column offset on the line for the associated function
- * call.
- * This method will return Message::kNoColumnInfo if it is unable to retrieve
- * the column number, or if kColumnOffset was not passed as an option when
- * capturing the StackTrace.
- */
- int GetColumn() const;
-
- /**
- * Returns the name of the resource that contains the script for the
- * function for this StackFrame.
- */
- Handle<String> GetScriptName() const;
-
- /**
- * Returns the name of the resource that contains the script for the
- * function for this StackFrame or sourceURL value if the script name
- * is undefined and its source ends with //@ sourceURL=... string.
- */
- Handle<String> GetScriptNameOrSourceURL() const;
-
- /**
- * Returns the name of the function associated with this stack frame.
- */
- Handle<String> GetFunctionName() const;
-
-private:
- friend class StackTrace;
- StackFrame(Handle<String> script, Handle<String> function, int line, int column);
- int m_lineNumber;
- int m_columnNumber;
- QV4::PersistentValue m_scriptName;
- QV4::PersistentValue m_functionName;
-};
-
-DEFINE_REFCOUNTED_HANDLE_OPERATIONS(StackFrame)
-
// --- Value ---
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index a24fb5d25a..88f7d28aa6 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -74,39 +74,22 @@ enum ConsoleLogTypes {
Error
};
-static void jsContext(QString &file, int *line, QString &function) {
- v8::Handle<v8::StackTrace> stackTrace = v8::StackTrace::CurrentStackTrace(1);
- if (stackTrace->GetFrameCount()) {
- v8::Handle<v8::StackFrame> frame = stackTrace->GetFrame(0);
- file = frame->GetScriptName()->v4Value().toQString();
- *line = frame->GetLineNumber();
- function = frame->GetFunctionName()->v4Value().toQString();
- }
-}
-
-static QString jsStack() {
- QStringList stackFrames;
+static QString jsStack(QV4::ExecutionEngine *engine) {
+ QString stack;
- //The v8 default is currently 10 stack frames.
- v8::Handle<v8::StackTrace> stackTrace =
- v8::StackTrace::CurrentStackTrace(10, v8::StackTrace::kOverview);
- int stackCount = stackTrace->GetFrameCount();
+ QVector<QV4::ExecutionEngine::StackFrame> stackTrace = engine->stackTrace(10);
- for (int i = 0; i < stackCount; i++) {
- v8::Handle<v8::StackFrame> frame = stackTrace->GetFrame(i);
- v8::Handle<v8::String> function(frame->GetFunctionName());
- v8::Handle<v8::String> script(frame->GetScriptName());
- int lineNumber = frame->GetLineNumber();
- int columnNumber = frame->GetColumn();
+ for (int i = 0; i < stackTrace.count(); i++) {
+ const QV4::ExecutionEngine::StackFrame &frame = stackTrace.at(i);
QString stackFrame =
- QString::fromLatin1("%1 (%2:%3:%4)").arg(function->v4Value().asString()->toQString(),
- script->v4Value().asString()->toQString(),
- QString::number(lineNumber),
- QString::number(columnNumber));
- stackFrames.append(stackFrame);
+ QString::fromLatin1("%1 (%2:%3:%4)\n").arg(frame.function,
+ frame.source.url(),
+ QString::number(frame.line),
+ QString::number(frame.column));
+ stack += stackFrame;
}
- return stackFrames.join(QLatin1String("\n"));
+ return stack;
}
QV4::Value console(ConsoleLogTypes logType, const v8::Arguments &args,
@@ -114,6 +97,8 @@ QV4::Value console(ConsoleLogTypes logType, const v8::Arguments &args,
{
QString result;
QV8Engine *engine = V8ENGINE();
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+
for (int i = 0; i < args.Length(); ++i) {
if (i != 0)
result.append(QLatin1Char(' '));
@@ -124,16 +109,11 @@ QV4::Value console(ConsoleLogTypes logType, const v8::Arguments &args,
if (printStack) {
result.append(QLatin1String("\n"));
- result.append(jsStack());
+ result.append(jsStack(v4));
}
- QString file;
- QString function;
- int line;
-
- jsContext(file, &line, function);
-
- QMessageLogger logger(file.toUtf8().constData(), line, function.toUtf8().constData());
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+ QMessageLogger logger(frame.source.url().toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
switch (logType) {
case Log:
logger.debug("%s", qPrintable(result));
@@ -180,15 +160,11 @@ QV4::Value consoleProfile(const v8::Arguments &args)
//we do not allow that. Hence, we pass an empty(default) title
Q_UNUSED(args);
QString title;
+ QV8Engine *engine = V8ENGINE();
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
-
-
- QString file;
- QString function;
- int line;
- jsContext(file, &line, function);
-
- QMessageLogger logger(file.toUtf8().constData(), line, function.toUtf8().constData());
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+ QMessageLogger logger(frame.source.url().toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
if (QQmlProfilerService::startProfiling()) {
QV8ProfilerService::instance()->startProfiling(title);
@@ -208,12 +184,11 @@ QV4::Value consoleProfileEnd(const v8::Arguments &args)
Q_UNUSED(args);
QString title;
- QString file;
- QString function;
- int line;
- jsContext(file, &line, function);
+ QV8Engine *engine = V8ENGINE();
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
- QMessageLogger logger(file.toUtf8().constData(), line, function.toUtf8().constData());
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+ QMessageLogger logger(frame.source.url().toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
if (QQmlProfilerService::stopProfiling()) {
QV8ProfilerService *profiler = QV8ProfilerService::instance();
@@ -258,23 +233,16 @@ QV4::Value consoleCount(const v8::Arguments &args)
if (args.Length() > 0)
name = args[0]->v4Value().toQString();
- v8::Handle<v8::StackTrace> stackTrace =
- v8::StackTrace::CurrentStackTrace(1, v8::StackTrace::kOverview);
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(V8ENGINE());
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
- if (stackTrace->GetFrameCount()) {
- v8::Handle<v8::StackFrame> frame = stackTrace->GetFrame(0);
+ QString scriptName = frame.source.url();
- QString scriptName = frame->GetScriptName()->v4Value().toQString();
- QString functionName = frame->GetFunctionName()->v4Value().toQString();
- int line = frame->GetLineNumber();
- int column = frame->GetColumn();
+ int value = V8ENGINE()->consoleCountHelper(scriptName, frame.line, frame.column);
+ QString message = name + QLatin1String(": ") + QString::number(value);
- int value = V8ENGINE()->consoleCountHelper(scriptName, line, column);
- QString message = name + QLatin1String(": ") + QString::number(value);
-
- QMessageLogger(qPrintable(scriptName), line,
- qPrintable(functionName)).debug("%s", qPrintable(message));
- }
+ QMessageLogger(qPrintable(scriptName), frame.line,
+ qPrintable(frame.function)).debug("%s", qPrintable(message));
return QV4::Value::undefinedValue();
}
@@ -284,14 +252,13 @@ QV4::Value consoleTrace(const v8::Arguments &args)
if (args.Length() != 0)
V4THROW_ERROR("console.trace(): Invalid arguments");
- QString stack = jsStack();
+ QV8Engine *engine = V8ENGINE();
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
- QString file;
- QString function;
- int line;
- jsContext(file, &line, function);
+ QString stack = jsStack(v4);
- QMessageLogger logger(file.toUtf8().constData(), line, function.toUtf8().constData());
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+ QMessageLogger logger(frame.source.url().toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
logger.debug("%s", qPrintable(stack));
return QV4::Value::undefinedValue();
@@ -307,6 +274,9 @@ QV4::Value consoleAssert(const v8::Arguments &args)
if (args.Length() == 0)
V4THROW_ERROR("console.assert(): Missing argument");
+ QV8Engine *engine = V8ENGINE();
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+
if (!args[0]->v4Value().booleanValue()) {
QString message;
for (int i = 1; i < args.Length(); ++i) {
@@ -317,14 +287,10 @@ QV4::Value consoleAssert(const v8::Arguments &args)
message.append(value->v4Value().toQString());
}
- QString stack = jsStack();
-
- QString file;
- QString function;
- int line;
- jsContext(file, &line, function);
+ QString stack = jsStack(v4);
- QMessageLogger logger(file.toUtf8().constData(), line, function.toUtf8().constData());
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+ QMessageLogger logger(frame.source.url().toUtf8().constData(), frame.line, frame.function.toUtf8().constData());
logger.critical("%s\n%s", qPrintable(message), qPrintable(stack));
}
diff --git a/src/qml/qml/v8/qv8qobjectwrapper.cpp b/src/qml/qml/v8/qv8qobjectwrapper.cpp
index 88f41e8c5d..c4e0b0d0e7 100644
--- a/src/qml/qml/v8/qv8qobjectwrapper.cpp
+++ b/src/qml/qml/v8/qv8qobjectwrapper.cpp
@@ -619,15 +619,11 @@ static inline void StoreProperty(QV8Engine *engine, QObject *object, QQmlPropert
QQmlContextData *context = engine->callingContext();
v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
- v8::Handle<v8::StackTrace> trace =
- v8::StackTrace::CurrentStackTrace(1, (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
- v8::StackTrace::kScriptName));
- v8::Handle<v8::StackFrame> frame = trace->GetFrame(0);
- int lineNumber = frame->GetLineNumber();
- int columnNumber = frame->GetColumn();
- QString url = frame->GetScriptName()->v4Value().toQString();
-
- newBinding = new QQmlBinding(&function, object, context, url, qmlSourceCoordinate(lineNumber), qmlSourceCoordinate(columnNumber));
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(engine);
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
+
+ newBinding = new QQmlBinding(&function, object, context, frame.source.url(),
+ qmlSourceCoordinate(frame.line), qmlSourceCoordinate(frame.column));
newBinding->setTarget(object, *property, context);
newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
QQmlBinding::RequiresThisObject);
diff --git a/src/qml/qml/v8/qv8valuetypewrapper.cpp b/src/qml/qml/v8/qv8valuetypewrapper.cpp
index 9bf1169c21..9297df3d17 100644
--- a/src/qml/qml/v8/qv8valuetypewrapper.cpp
+++ b/src/qml/qml/v8/qv8valuetypewrapper.cpp
@@ -392,17 +392,11 @@ v8::Handle<v8::Value> QV8ValueTypeWrapper::Setter(v8::Handle<v8::String> propert
cacheData.valueTypeCoreIndex = index;
cacheData.valueTypePropType = p.userType();
- v8::Handle<v8::StackTrace> trace =
- v8::StackTrace::CurrentStackTrace(1,
- (v8::StackTrace::StackTraceOptions)(v8::StackTrace::kLineNumber |
- v8::StackTrace::kScriptName));
- v8::Handle<v8::StackFrame> frame = trace->GetFrame(0);
- int lineNumber = frame->GetLineNumber();
- int columnNumber = frame->GetColumn();
- QString url = frame->GetScriptName()->v4Value().toQString();
+ QV4::ExecutionEngine *v4 = QV8Engine::getV4(r->engine);
+ QV4::ExecutionEngine::StackFrame frame = v4->currentStackFrame();
newBinding = new QQmlBinding(&function, reference->object, context,
- url, qmlSourceCoordinate(lineNumber), qmlSourceCoordinate(columnNumber));
+ frame.source.url(), qmlSourceCoordinate(frame.line), qmlSourceCoordinate(frame.column));
newBinding->setTarget(reference->object, cacheData, context);
newBinding->setEvaluateFlags(newBinding->evaluateFlags() |
QQmlBinding::RequiresThisObject);