aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp110
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h4
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp177
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h91
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp139
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h6
-rw-r--r--tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp107
7 files changed, 305 insertions, 329 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
index b1d928db52..a3f59870a2 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
@@ -104,6 +104,28 @@ QVector<QV4::Heap::ExecutionContext::ContextType> QV4DataCollector::getScopeType
return types;
}
+int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType)
+{
+ switch (scopeType) {
+ case QV4::Heap::ExecutionContext::Type_GlobalContext:
+ return 0;
+ break;
+ case QV4::Heap::ExecutionContext::Type_CatchContext:
+ return 4;
+ break;
+ case QV4::Heap::ExecutionContext::Type_WithContext:
+ return 2;
+ break;
+ case QV4::Heap::ExecutionContext::Type_SimpleCallContext:
+ case QV4::Heap::ExecutionContext::Type_CallContext:
+ return 1;
+ break;
+ case QV4::Heap::ExecutionContext::Type_QmlContext:
+ default:
+ return -1;
+ }
+}
+
QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine) : m_engine(engine)
{
m_values.set(engine, engine->newArrayObject());
@@ -227,19 +249,35 @@ bool QV4DataCollector::isValidRef(QV4DataCollector::Ref ref) const
return ref < array->getLength();
}
-void QV4DataCollector::collectScope(QJsonObject *dict, QV4Debugger *debugger, int frameNr,
- int scopeNr)
+bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr)
{
QStringList names;
- if (debugger->state() == QV4Debugger::Paused) {
- ArgumentCollectJob argumentsJob(m_engine, this, &names, frameNr, scopeNr);
- debugger->runInEngine(&argumentsJob);
- LocalCollectJob localsJob(m_engine, this, &names, frameNr, scopeNr);
- debugger->runInEngine(&localsJob);
+ QV4::Scope scope(engine());
+ QV4::Scoped<QV4::CallContext> ctxt(scope, findScope(findContext(engine(), frameNr), scopeNr));
+ if (!ctxt)
+ return false;
+
+ QV4::ScopedValue v(scope);
+ int nFormals = ctxt->formalCount();
+ for (unsigned i = 0, ei = nFormals; i != ei; ++i) {
+ QString qName;
+ if (QV4::Identifier *name = ctxt->formals()[nFormals - i - 1])
+ qName = name->string;
+ names.append(qName);
+ v = ctxt->argument(i);
+ collect(v);
+ }
+
+ for (unsigned i = 0, ei = ctxt->variableCount(); i != ei; ++i) {
+ QString qName;
+ if (QV4::Identifier *name = ctxt->variables()[i])
+ qName = name->string;
+ names.append(qName);
+ v = ctxt->d()->locals[i];
+ collect(v);
}
- QV4::Scope scope(engine());
QV4::ScopedObject scopeObject(scope, engine()->newObject());
Q_ASSERT(names.size() == m_collectedRefs.size());
@@ -250,6 +288,62 @@ void QV4DataCollector::collectScope(QJsonObject *dict, QV4Debugger *debugger, in
Ref scopeObjectRef = addRef(scopeObject);
dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef));
m_collectedRefs.append(scopeObjectRef);
+ return true;
+}
+
+QJsonObject toRef(QV4DataCollector::Ref ref) {
+ QJsonObject dict;
+ dict.insert(QStringLiteral("ref"), qint64(ref));
+ return dict;
+}
+
+QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int frameNr)
+{
+ QV4DataCollector::Ref ref;
+
+ QJsonObject frame;
+ frame[QLatin1String("index")] = frameNr;
+ frame[QLatin1String("debuggerFrame")] = false;
+ ref = addFunctionRef(stackFrame.function);
+ frame[QLatin1String("func")] = toRef(ref);
+ ref = addScriptRef(stackFrame.source);
+ frame[QLatin1String("script")] = toRef(ref);
+ frame[QLatin1String("line")] = stackFrame.line - 1;
+ if (stackFrame.column >= 0)
+ frame[QLatin1String("column")] = stackFrame.column;
+
+ QJsonArray scopes;
+ QV4::Scope scope(engine());
+ QV4::ScopedContext ctxt(scope, findContext(engine(), frameNr));
+ while (ctxt) {
+ if (QV4::CallContext *cCtxt = ctxt->asCallContext()) {
+ if (cCtxt->d()->activation)
+ break;
+ }
+ ctxt = ctxt->d()->outer;
+ }
+
+ if (ctxt) {
+ QV4::ScopedValue o(scope, ctxt->asCallContext()->d()->activation);
+ frame[QLatin1String("receiver")] = toRef(collect(o));
+ }
+
+ // Only type and index are used by Qt Creator, so we keep it easy:
+ QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes = getScopeTypes(engine(), frameNr);
+ for (int i = 0, ei = scopeTypes.count(); i != ei; ++i) {
+ int type = encodeScopeType(scopeTypes[i]);
+ if (type == -1)
+ continue;
+
+ QJsonObject scope;
+ scope[QLatin1String("index")] = i;
+ scope[QLatin1String("type")] = type;
+ scopes.push_back(scope);
+ }
+
+ frame[QLatin1String("scopes")] = scopes;
+
+ return frame;
}
QJsonArray QV4DataCollector::flushCollectedRefs()
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
index 1679c2eab7..1c3a05960c 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
@@ -60,6 +60,7 @@ public:
static QV4::Heap::CallContext *findScope(QV4::ExecutionContext *ctxt, int scope);
static QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes(
QV4::ExecutionEngine *engine, int frame);
+ static int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType);
QV4DataCollector(QV4::ExecutionEngine *engine);
@@ -70,7 +71,8 @@ public:
bool isValidRef(Ref ref) const;
QJsonObject lookupRef(Ref ref);
- void collectScope(QJsonObject *dict, QV4Debugger *debugger, int frameNr, int scopeNr);
+ bool collectScope(QJsonObject *dict, int frameNr, int scopeNr);
+ QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr);
QV4::ExecutionEngine *engine() const { return m_engine; }
QJsonArray flushCollectedRefs();
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
index 020be688f3..d60db6cf82 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp
@@ -118,8 +118,79 @@ bool JavaScriptJob::hasExeption() const
return resultIsException;
}
+BacktraceJob::BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame) :
+ CollectJob(collector), fromFrame(fromFrame), toFrame(toFrame)
+{
+}
+
+void BacktraceJob::run()
+{
+ QJsonArray frameArray;
+ QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(toFrame);
+ for (int i = fromFrame; i < toFrame && i < frames.size(); ++i)
+ frameArray.push_back(collector->buildFrame(frames[i], i));
+ if (frameArray.isEmpty()) {
+ result.insert(QStringLiteral("totalFrames"), 0);
+ } else {
+ result.insert(QStringLiteral("fromFrame"), fromFrame);
+ result.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size());
+ result.insert(QStringLiteral("frames"), frameArray);
+ }
+ collectedRefs = collector->flushCollectedRefs();
+}
+
+FrameJob::FrameJob(QV4DataCollector *collector, int frameNr) :
+ CollectJob(collector), frameNr(frameNr), success(false)
+{
+}
+
+void FrameJob::run()
+{
+ QVector<QV4::StackFrame> frames = collector->engine()->stackTrace(frameNr + 1);
+ if (frameNr >= frames.length()) {
+ success = false;
+ } else {
+ result = collector->buildFrame(frames[frameNr], frameNr);
+ collectedRefs = collector->flushCollectedRefs();
+ success = true;
+ }
+}
+
+bool FrameJob::wasSuccessful() const
+{
+ return success;
+}
+
+ScopeJob::ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr) :
+ CollectJob(collector), frameNr(frameNr), scopeNr(scopeNr), success(false)
+{
+}
+
+void ScopeJob::run()
+{
+ QJsonObject object;
+ success = collector->collectScope(&object, frameNr, scopeNr);
+
+ if (success) {
+ QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes =
+ QV4DataCollector::getScopeTypes(collector->engine(), frameNr);
+ result[QLatin1String("type")] = QV4DataCollector::encodeScopeType(scopeTypes[scopeNr]);
+ } else {
+ result[QLatin1String("type")] = -1;
+ }
+ result[QLatin1String("index")] = scopeNr;
+ result[QLatin1String("frameIndex")] = frameNr;
+ result[QLatin1String("object")] = object;
+ collectedRefs = collector->flushCollectedRefs();
+}
+
+bool ScopeJob::wasSuccessful() const
+{
+ return success;
+}
+
ValueLookupJob::ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector) :
- collector(collector), handles(handles) {}
+ CollectJob(collector), handles(handles) {}
void ValueLookupJob::run()
{
@@ -152,16 +223,6 @@ const QString &ValueLookupJob::exceptionMessage() const
return exception;
}
-const QJsonObject &ValueLookupJob::returnValue() const
-{
- return result;
-}
-
-const QJsonArray &ValueLookupJob::refs() const
-{
- return collectedRefs;
-}
-
ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr,
const QString &expression, QV4DataCollector *collector) :
JavaScriptJob(engine, frameNr, expression), collector(collector)
@@ -209,100 +270,6 @@ const QStringList &GatherSourcesJob::result() const
return sources;
}
-ArgumentCollectJob::ArgumentCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector,
- QStringList *names, int frameNr, int scopeNr)
- : engine(engine)
- , collector(collector)
- , names(names)
- , frameNr(frameNr)
- , scopeNr(scopeNr)
-{}
-
-void ArgumentCollectJob::run()
-{
- if (frameNr < 0)
- return;
-
- QV4::Scope scope(engine);
- QV4::Scoped<QV4::CallContext> ctxt(
- scope, QV4DataCollector::findScope(QV4DataCollector::findContext(engine, frameNr), scopeNr));
- if (!ctxt)
- return;
-
- QV4::ScopedValue v(scope);
- int nFormals = ctxt->formalCount();
- for (unsigned i = 0, ei = nFormals; i != ei; ++i) {
- QString qName;
- if (QV4::Identifier *name = ctxt->formals()[nFormals - i - 1])
- qName = name->string;
- names->append(qName);
- v = ctxt->argument(i);
- collector->collect(v);
- }
-}
-
-LocalCollectJob::LocalCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector,
- QStringList *names, int frameNr, int scopeNr)
- : engine(engine)
- , collector(collector)
- , names(names)
- , frameNr(frameNr)
- , scopeNr(scopeNr)
-{}
-
-void LocalCollectJob::run()
-{
- if (frameNr < 0)
- return;
-
- QV4::Scope scope(engine);
- QV4::Scoped<QV4::CallContext> ctxt(
- scope, QV4DataCollector::findScope(QV4DataCollector::findContext(engine, frameNr), scopeNr));
- if (!ctxt)
- return;
-
- QV4::ScopedValue v(scope);
- for (unsigned i = 0, ei = ctxt->variableCount(); i != ei; ++i) {
- QString qName;
- if (QV4::Identifier *name = ctxt->variables()[i])
- qName = name->string;
- names->append(qName);
- v = ctxt->d()->locals[i];
- collector->collect(v);
- }
-}
-
-ThisCollectJob::ThisCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector,
- int frameNr)
- : engine(engine)
- , collector(collector)
- , frameNr(frameNr)
- , thisRef(QV4DataCollector::s_invalidRef)
-{}
-
-void ThisCollectJob::run()
-{
- QV4::Scope scope(engine);
- QV4::ScopedContext ctxt(scope, QV4DataCollector::findContext(engine, frameNr));
- while (ctxt) {
- if (QV4::CallContext *cCtxt = ctxt->asCallContext())
- if (cCtxt->d()->activation)
- break;
- ctxt = ctxt->d()->outer;
- }
-
- if (!ctxt)
- return;
-
- QV4::ScopedValue o(scope, ctxt->asCallContext()->d()->activation);
- thisRef = collector->collect(o);
-}
-
-QV4DataCollector::Ref ThisCollectJob::foundRef() const
-{
- return thisRef;
-}
-
ExceptionCollectJob::ExceptionCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector)
: engine(engine)
, collector(collector)
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h
index e48b5b1e5e..a1adbeff40 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h
@@ -72,88 +72,86 @@ protected:
virtual void handleResult(QV4::ScopedValue &result) = 0;
};
-class ValueLookupJob: public QV4DebugJob
+class CollectJob : public QV4DebugJob
{
+protected:
QV4DataCollector *collector;
- const QJsonArray handles;
QJsonObject result;
QJsonArray collectedRefs;
- QString exception;
+public:
+ CollectJob(QV4DataCollector *collector) : collector(collector) {}
+ const QJsonObject &returnValue() const { return result; }
+ const QJsonArray &refs() const { return collectedRefs; }
+};
+class BacktraceJob: public CollectJob
+{
+ int fromFrame;
+ int toFrame;
public:
- ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector);
+ BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame);
void run();
- const QString &exceptionMessage() const;
- const QJsonObject &returnValue() const;
- const QJsonArray &refs() const;
};
-class ExpressionEvalJob: public JavaScriptJob
+class FrameJob: public CollectJob
{
- QV4DataCollector *collector;
- QString exception;
- QJsonObject result;
- QJsonArray collectedRefs;
+ int frameNr;
+ bool success;
public:
- ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression,
- QV4DataCollector *collector);
- virtual void handleResult(QV4::ScopedValue &value);
- const QString &exceptionMessage() const;
- const QJsonObject &returnValue() const;
- const QJsonArray &refs() const;
+ FrameJob(QV4DataCollector *collector, int frameNr);
+ void run();
+ bool wasSuccessful() const;
};
-class GatherSourcesJob: public QV4DebugJob
+class ScopeJob: public CollectJob
{
- QV4::ExecutionEngine *engine;
- QStringList sources;
+ int frameNr;
+ int scopeNr;
+ bool success;
public:
- GatherSourcesJob(QV4::ExecutionEngine *engine);
+ ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr);
void run();
- const QStringList &result() const;
+ bool wasSuccessful() const;
};
-class ArgumentCollectJob: public QV4DebugJob
+class ValueLookupJob: public CollectJob
{
- QV4::ExecutionEngine *engine;
- QV4DataCollector *collector;
- QStringList *names;
- int frameNr;
- int scopeNr;
+ const QJsonArray handles;
+ QString exception;
public:
- ArgumentCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector,
- QStringList *names, int frameNr, int scopeNr);
+ ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector);
void run();
+ const QString &exceptionMessage() const;
};
-class LocalCollectJob: public QV4DebugJob
+class ExpressionEvalJob: public JavaScriptJob
{
- QV4::ExecutionEngine *engine;
QV4DataCollector *collector;
- QStringList *names;
- int frameNr;
- int scopeNr;
+ QString exception;
+ QJsonObject result;
+ QJsonArray collectedRefs;
public:
- LocalCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, QStringList *names,
- int frameNr, int scopeNr);
- void run();
+ ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression,
+ QV4DataCollector *collector);
+ virtual void handleResult(QV4::ScopedValue &value);
+ const QString &exceptionMessage() const;
+ const QJsonObject &returnValue() const;
+ const QJsonArray &refs() const;
};
-class ThisCollectJob: public QV4DebugJob
+class GatherSourcesJob: public QV4DebugJob
{
QV4::ExecutionEngine *engine;
- QV4DataCollector *collector;
- int frameNr;
- QV4DataCollector::Ref thisRef;
+ QStringList sources;
public:
- ThisCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, int frameNr);
+ GatherSourcesJob(QV4::ExecutionEngine *engine);
void run();
- QV4DataCollector::Ref foundRef() const;
+ const QStringList &result() const;
};
class ExceptionCollectJob: public QV4DebugJob
@@ -176,8 +174,7 @@ public:
EvalJob(QV4::ExecutionEngine *engine, const QString &script);
virtual void handleResult(QV4::ScopedValue &result);
- bool resultAsBoolean() const
-;
+ bool resultAsBoolean() const;
};
QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
index ba953eb21d..5ee9e5e9e9 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
@@ -285,26 +285,16 @@ public:
return;
}
- QJsonArray frameArray;
- QVector<QV4::StackFrame> frames = debugger->stackTrace(toFrame);
- for (int i = fromFrame; i < toFrame && i < frames.size(); ++i)
- frameArray.push_back(debugService->buildFrame(frames[i], i, debugger));
+ BacktraceJob job(debugger->collector(), fromFrame, toFrame);
+ debugger->runInEngine(&job);
// response:
addCommand();
addRequestSequence();
addSuccess(true);
addRunning();
- QJsonObject body;
- if (frameArray.isEmpty()) {
- body.insert(QStringLiteral("totalFrames"), 0);
- } else {
- body.insert(QStringLiteral("fromFrame"), fromFrame);
- body.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size());
- body.insert(QStringLiteral("frames"), frameArray);
- }
- addBody(body);
- addRefs(debugger->collector()->flushCollectedRefs());
+ addBody(job.returnValue());
+ addRefs(job.refs());
}
};
@@ -326,22 +316,27 @@ public:
return;
}
- QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1);
- if (frameNr < 0 || frameNr >= frames.size()) {
+ if (frameNr < 0) {
createErrorResponse(QStringLiteral("frame command has invalid frame number"));
return;
}
+ FrameJob job(debugger->collector(), frameNr);
+ debugger->runInEngine(&job);
+ if (!job.wasSuccessful()) {
+ createErrorResponse(QStringLiteral("frame retrieval failed"));
+ return;
+ }
+
debugService->selectFrame(frameNr);
- QJsonObject frame = debugService->buildFrame(frames[frameNr], frameNr, debugger);
// response:
addCommand();
addRequestSequence();
addSuccess(true);
addRunning();
- addBody(frame);
- addRefs(debugger->collector()->flushCollectedRefs());
+ addBody(job.returnValue());
+ addRefs(job.refs());
}
};
@@ -364,8 +359,7 @@ public:
return;
}
- QVector<QV4::StackFrame> frames = debugger->stackTrace(frameNr + 1);
- if (frameNr < 0 || frameNr >= frames.size()) {
+ if (frameNr < 0) {
createErrorResponse(QStringLiteral("scope command has invalid frame number"));
return;
}
@@ -374,15 +368,20 @@ public:
return;
}
- QJsonObject scope = debugService->buildScope(frameNr, scopeNr, debugger);
+ ScopeJob job(debugger->collector(), frameNr, scopeNr);
+ debugger->runInEngine(&job);
+ if (!job.wasSuccessful()) {
+ createErrorResponse(QStringLiteral("scope retrieval failed"));
+ return;
+ }
// response:
addCommand();
addRequestSequence();
addSuccess(true);
addRunning();
- addBody(scope);
- addRefs(debugger->collector()->flushCollectedRefs());
+ addBody(job.returnValue());
+ addRefs(job.refs());
}
};
@@ -836,98 +835,6 @@ void QV4DebugServiceImpl::send(QJsonObject v8Payload)
emit messageToClient(name(), packMessage("v8message", responseData));
}
-QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
- QV4Debugger *debugger)
-{
- QV4DataCollector::Ref ref;
-
- QJsonObject frame;
- frame[QLatin1String("index")] = frameNr;
- frame[QLatin1String("debuggerFrame")] = false;
- ref = debugger->collector()->addFunctionRef(stackFrame.function);
- frame[QLatin1String("func")] = toRef(ref);
- ref = debugger->collector()->addScriptRef(stackFrame.source);
- frame[QLatin1String("script")] = toRef(ref);
- frame[QLatin1String("line")] = stackFrame.line - 1;
- if (stackFrame.column >= 0)
- frame[QLatin1String("column")] = stackFrame.column;
-
- QJsonArray scopes;
- Q_ASSERT (debugger->state() == QV4Debugger::Paused);
-
- ThisCollectJob job(debugger->engine(), debugger->collector(), frameNr);
- debugger->runInEngine(&job);
- if (job.foundRef() != QV4DataCollector::s_invalidRef)
- frame[QLatin1String("receiver")] = toRef(job.foundRef());
-
- // Only type and index are used by Qt Creator, so we keep it easy:
- QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes =
- QV4DataCollector::getScopeTypes(debugger->engine(), frameNr);
- for (int i = 0, ei = scopeTypes.count(); i != ei; ++i) {
- int type = encodeScopeType(scopeTypes[i]);
- if (type == -1)
- continue;
-
- QJsonObject scope;
- scope[QLatin1String("index")] = i;
- scope[QLatin1String("type")] = type;
- scopes.push_back(scope);
- }
- frame[QLatin1String("scopes")] = scopes;
-
- return frame;
-}
-
-int QV4DebugServiceImpl::encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType)
-{
- switch (scopeType) {
- case QV4::Heap::ExecutionContext::Type_GlobalContext:
- return 0;
- break;
- case QV4::Heap::ExecutionContext::Type_CatchContext:
- return 4;
- break;
- case QV4::Heap::ExecutionContext::Type_WithContext:
- return 2;
- break;
- case QV4::Heap::ExecutionContext::Type_SimpleCallContext:
- case QV4::Heap::ExecutionContext::Type_CallContext:
- return 1;
- break;
- case QV4::Heap::ExecutionContext::Type_QmlContext:
- default:
- return -1;
- }
-}
-
-QJsonObject QV4DebugServiceImpl::buildScope(int frameNr, int scopeNr, QV4Debugger *debugger)
-{
- QJsonObject scope;
-
- QJsonObject object;
- debugger->collector()->collectScope(&object, debugger, frameNr, scopeNr);
-
- if (debugger->state() == QV4Debugger::Paused) {
- QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes =
- QV4DataCollector::getScopeTypes(debugger->engine(), frameNr);
- scope[QLatin1String("type")] = encodeScopeType(scopeTypes[scopeNr]);
- } else {
- scope[QLatin1String("type")] = -1;
- }
- scope[QLatin1String("index")] = scopeNr;
- scope[QLatin1String("frameIndex")] = frameNr;
- scope[QLatin1String("object")] = object;
-
- return scope;
-}
-
-QJsonValue QV4DebugServiceImpl::toRef(QV4DataCollector::Ref ref)
-{
- QJsonObject dict;
- dict.insert(QStringLiteral("ref"), qint64(ref));
- return dict;
-}
-
void QV4DebugServiceImpl::selectFrame(int frameNr)
{
theSelectedFrame = frameNr;
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
index df9da2c07f..69e32189b8 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
@@ -83,10 +83,6 @@ public:
void signalEmitted(const QString &signal) Q_DECL_OVERRIDE;
void send(QJsonObject v8Payload);
- QJsonObject buildScope(int frameNr, int scopeNr, QV4Debugger *debugger);
- QJsonValue toRef(QV4DataCollector::Ref ref);
-
- QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr, QV4Debugger *debugger);
int selectedFrame() const;
void selectFrame(int frameNr);
@@ -104,11 +100,9 @@ private:
const QByteArray &message = QByteArray());
void processCommand(const QByteArray &command, const QByteArray &data);
V8CommandHandler *v8CommandHandler(const QString &command) const;
- int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType);
QStringList breakOnSignals;
static int sequence;
-
int theSelectedFrame;
void addHandler(V8CommandHandler* handler);
diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
index fd504c50d3..7398e97326 100644
--- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
@@ -100,16 +100,24 @@ public:
typedef QV4DataCollector::Refs Refs;
typedef QV4DataCollector::Ref Ref;
struct NamedRefs {
- QStringList names;
QJsonArray refs;
+ QJsonObject scope;
int size() const {
- Q_ASSERT(names.size() == refs.size());
- return names.size();
+ return scope.size();
}
bool contains(const QString &name) const {
- return names.contains(name);
+ return scope.contains(name);
+ }
+
+ QJsonObject resolveRef(int ref) const {
+ foreach (const QJsonValue &val, refs) {
+ QJsonObject obj = val.toObject();
+ if (obj.value(QLatin1String("handle")).toInt() == ref)
+ return obj;
+ }
+ return QJsonObject();
}
#define DUMP_JSON(x) {\
@@ -119,7 +127,7 @@ public:
QJsonObject rawValue(const QString &name) const {
Q_ASSERT(contains(name));
- return refs.at(names.indexOf(name)).toObject();
+ return scope[name].toObject();
}
QJsonValue value(const QString &name) const {
@@ -136,7 +144,7 @@ public:
return;
}
- QJsonObject o = refs.at(names.indexOf(name)).toObject();
+ QJsonObject o = scope[name].toObject();
QJsonDocument d;
d.setObject(o);
qDebug() << name << "=" << d.toJson(QJsonDocument::Indented);
@@ -202,17 +210,30 @@ public:
void captureContextInfo(QV4Debugger *debugger)
{
for (int i = 0, ei = m_stackTrace.size(); i != ei; ++i) {
- m_capturedArguments.append(NamedRefs());
- ArgumentCollectJob argumentsJob(debugger->engine(), &collector,
- &m_capturedArguments.last().names, i, 0);
- debugger->runInEngine(&argumentsJob);
- m_capturedArguments.last().refs = collector.flushCollectedRefs();
-
- m_capturedLocals.append(NamedRefs());
- LocalCollectJob localsJob(debugger->engine(), &collector,
- &m_capturedLocals.last().names, i, 0);
- debugger->runInEngine(&localsJob);
- m_capturedLocals.last().refs = collector.flushCollectedRefs();
+ m_capturedScope.append(NamedRefs());
+ ScopeJob job(&collector, i, 0);
+ debugger->runInEngine(&job);
+ NamedRefs &refs = m_capturedScope.last();
+ refs.refs = job.refs();
+ QJsonObject object = job.returnValue();
+ object = object.value(QLatin1String("object")).toObject();
+ int ref = object.value(QLatin1String("ref")).toInt();
+ object = refs.resolveRef(ref);
+ foreach (const QJsonValue &value, object.value(QLatin1String("properties")).toArray()) {
+ QJsonObject property = value.toObject();
+ QString name = property.value(QLatin1String("name")).toString();
+ property.remove(QLatin1String("name"));
+ if (property.contains(QLatin1String("ref"))) {
+ int childRef = property.value(QLatin1String("ref")).toInt();
+ if (childRef >= 0 && refs.refs.size() > childRef) {
+ property.remove(QLatin1String("ref"));
+ property.insert(QLatin1String("properties"),
+ refs.resolveRef(childRef).value(
+ QLatin1String("properties")).toArray());
+ }
+ }
+ refs.scope.insert(name, property);
+ }
}
}
@@ -229,8 +250,7 @@ public:
QList<QV4Debugger::ExecutionState> m_statesWhenPaused;
QList<TestBreakPoint> m_breakPointsToAddWhenPaused;
QVector<QV4::StackFrame> m_stackTrace;
- QVector<NamedRefs> m_capturedArguments;
- QVector<NamedRefs> m_capturedLocals;
+ QVector<NamedRefs> m_capturedScope;
qint64 m_thrownValue;
QV4DataCollector collector;
@@ -444,8 +464,8 @@ void tst_qv4debugger::conditionalBreakPoint()
QCOMPARE(state.fileName, QString("conditionalBreakPoint"));
QCOMPARE(state.lineNumber, 3);
- QVERIFY(m_debuggerAgent->m_capturedLocals.size() > 1);
- const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedLocals.at(0);
+ QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
+ const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
QCOMPARE(frame0.size(), 2);
QVERIFY(frame0.contains("i"));
QCOMPARE(frame0.value("i").toInt(), 11);
@@ -501,13 +521,13 @@ void tst_qv4debugger::readArguments()
debugger()->addBreakPoint("readArguments", 2);
evaluateJavaScript(script, "readArguments");
QVERIFY(m_debuggerAgent->m_wasPaused);
- QVERIFY(m_debuggerAgent->m_capturedArguments.size() > 1);
- const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedArguments.at(0);
+ QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
+ const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
QCOMPARE(frame0.size(), 4);
QVERIFY(frame0.contains(QStringLiteral("a")));
QCOMPARE(frame0.type(QStringLiteral("a")), QStringLiteral("number"));
QCOMPARE(frame0.value(QStringLiteral("a")).toDouble(), 1.0);
- QVERIFY(frame0.names.contains("b"));
+ QVERIFY(frame0.scope.contains("b"));
QCOMPARE(frame0.type(QStringLiteral("b")), QStringLiteral("string"));
QCOMPARE(frame0.value(QStringLiteral("b")).toString(), QStringLiteral("two"));
}
@@ -525,9 +545,9 @@ void tst_qv4debugger::readLocals()
debugger()->addBreakPoint("readLocals", 3);
evaluateJavaScript(script, "readLocals");
QVERIFY(m_debuggerAgent->m_wasPaused);
- QVERIFY(m_debuggerAgent->m_capturedLocals.size() > 1);
- const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedLocals.at(0);
- QCOMPARE(frame0.size(), 2);
+ QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
+ const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
+ QCOMPARE(frame0.size(), 4); // locals and parameters
QVERIFY(frame0.contains("c"));
QCOMPARE(frame0.type("c"), QStringLiteral("number"));
QCOMPARE(frame0.value("c").toDouble(), 3.0);
@@ -547,9 +567,9 @@ void tst_qv4debugger::readObject()
debugger()->addBreakPoint("readObject", 3);
evaluateJavaScript(script, "readObject");
QVERIFY(m_debuggerAgent->m_wasPaused);
- QVERIFY(m_debuggerAgent->m_capturedLocals.size() > 1);
- const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedLocals.at(0);
- QCOMPARE(frame0.size(), 1);
+ QVERIFY(m_debuggerAgent->m_capturedScope.size() > 1);
+ const TestAgent::NamedRefs &frame0 = m_debuggerAgent->m_capturedScope.at(0);
+ QCOMPARE(frame0.size(), 2);
QVERIFY(frame0.contains("b"));
QCOMPARE(frame0.type("b"), QStringLiteral("object"));
QJsonObject b = frame0.rawValue("b");
@@ -600,28 +620,23 @@ void tst_qv4debugger::readContextInAllFrames()
evaluateJavaScript(script, "readFormalsInAllFrames");
QVERIFY(m_debuggerAgent->m_wasPaused);
QCOMPARE(m_debuggerAgent->m_stackTrace.size(), 13);
- QCOMPARE(m_debuggerAgent->m_capturedArguments.size(), 13);
- QCOMPARE(m_debuggerAgent->m_capturedLocals.size(), 13);
+ QCOMPARE(m_debuggerAgent->m_capturedScope.size(), 13);
for (int i = 0; i < 12; ++i) {
- const TestAgent::NamedRefs &args = m_debuggerAgent->m_capturedArguments.at(i);
- QCOMPARE(args.size(), 1);
- QVERIFY(args.contains("n"));
- QCOMPARE(args.type("n"), QStringLiteral("number"));
- QCOMPARE(args.value("n").toDouble(), i + 1.0);
-
- const TestAgent::NamedRefs &locals = m_debuggerAgent->m_capturedLocals.at(i);
- QCOMPARE(locals.size(), 1);
- QVERIFY(locals.contains("n_1"));
+ const TestAgent::NamedRefs &scope = m_debuggerAgent->m_capturedScope.at(i);
+ QCOMPARE(scope.size(), 2);
+ QVERIFY(scope.contains("n"));
+ QCOMPARE(scope.type("n"), QStringLiteral("number"));
+ QCOMPARE(scope.value("n").toDouble(), i + 1.0);
+ QVERIFY(scope.contains("n_1"));
if (i == 0) {
- QCOMPARE(locals.type("n_1"), QStringLiteral("undefined"));
+ QCOMPARE(scope.type("n_1"), QStringLiteral("undefined"));
} else {
- QCOMPARE(locals.type("n_1"), QStringLiteral("number"));
- QCOMPARE(locals.value("n_1").toInt(), i);
+ QCOMPARE(scope.type("n_1"), QStringLiteral("number"));
+ QCOMPARE(scope.value("n_1").toInt(), i);
}
}
- QCOMPARE(m_debuggerAgent->m_capturedArguments[12].size(), 0);
- QCOMPARE(m_debuggerAgent->m_capturedLocals[12].size(), 0);
+ QCOMPARE(m_debuggerAgent->m_capturedScope[12].size(), 0);
}
void tst_qv4debugger::pauseOnThrow()