aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@theqtcompany.com>2015-11-30 12:04:59 +0100
committerUlf Hermann <ulf.hermann@theqtcompany.com>2016-01-22 09:51:37 +0000
commit5537027094d26e517fc4ad3173ea84d254dd3013 (patch)
tree3457ba913c542447d2492ed32049ffb0f63bdf5b /src
parent872a05475721ad771bd347d1526035e6e7479d30 (diff)
V4 Debugger: Avoid looking up values in debugger thread
To avoid interaction with the engine from the debugger thread we move the value lookup functionality into the data collector, and drop the RefHolder. Also, we define some more debugger jobs to move the work the request handlers do into the GUI thread. Task-number: QTBUG-50481 Change-Id: Ia73ebd01e715f13110ef010a766e9b0a1e202df9 Reviewed-by: Nils Jeisecke <jeisecke@saltation.de> Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp378
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h114
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp208
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h10
4 files changed, 361 insertions, 349 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
index 4cca1900de..a86373b627 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
@@ -89,9 +89,30 @@ 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_collectedRefs(Q_NULLPTR)
+ : m_engine(engine)
{
values.set(engine, engine->newArrayObject());
}
@@ -100,10 +121,11 @@ QV4DataCollector::~QV4DataCollector()
{
}
-void QV4DataCollector::collect(const QV4::ScopedValue &value)
+QV4DataCollector::Ref QV4DataCollector::collect(const QV4::ScopedValue &value)
{
- if (m_collectedRefs)
- m_collectedRefs->append(addRef(value));
+ Ref ref = addRef(value);
+ collectedRefs.append(ref);
+ return ref;
}
const QV4::Object *collectProperty(const QV4::ScopedValue &value, QV4::ExecutionEngine *engine,
@@ -191,6 +213,7 @@ QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionNa
dict.insert(QStringLiteral("type"), QStringLiteral("function"));
dict.insert(QStringLiteral("name"), functionName);
specialRefs.insert(ref, dict);
+ collectedRefs.append(ref);
return ref;
}
@@ -204,36 +227,133 @@ QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName)
dict.insert(QStringLiteral("type"), QStringLiteral("script"));
dict.insert(QStringLiteral("name"), scriptName);
specialRefs.insert(ref, dict);
+ collectedRefs.append(ref);
return ref;
}
-void QV4DataCollector::collectScope(QJsonObject *dict, QV4::Debugging::V4Debugger *debugger,
+bool QV4DataCollector::isValidRef(QV4DataCollector::Ref ref) const
+{
+ QV4::Scope scope(engine());
+ QV4::ScopedObject array(scope, values.value());
+ return ref < array->getLength();
+}
+
+bool QV4DataCollector::collectScope(QJsonObject *dict, QV4::Debugging::V4Debugger *debugger,
int frameNr, int scopeNr)
{
QStringList names;
- Refs refs;
+ QV4::Scope scope(engine());
if (debugger->state() == QV4::Debugging::V4Debugger::Paused) {
- RefHolder holder(this, &refs);
- ArgumentCollectJob argumentsJob(m_engine, this, &names, frameNr, scopeNr);
- debugger->runInEngine(&argumentsJob);
- LocalCollectJob localsJob(m_engine, this, &names, frameNr, scopeNr);
- debugger->runInEngine(&localsJob);
+ 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() == refs.size());
- for (int i = 0, ei = refs.size(); i != ei; ++i)
+ Q_ASSERT(names.size() == collectedRefs.size());
+ for (int i = 0, ei = collectedRefs.size(); i != ei; ++i)
scopeObject->put(engine(), names.at(i),
- QV4::Value::fromReturnedValue(getValue(refs.at(i))));
+ QV4::Value::fromReturnedValue(getValue(collectedRefs.at(i))));
Ref scopeObjectRef = addRef(scopeObject);
dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef));
- if (m_collectedRefs)
- m_collectedRefs->append(scopeObjectRef);
+ 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,
+ QV4::Debugging::V4Debugger *debugger)
+{
+ 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;
+ if (debugger->state() == QV4::Debugging::V4Debugger::Paused) {
+ 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()
+{
+ QJsonArray refs;
+ std::sort(collectedRefs.begin(), collectedRefs.end());
+ for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) {
+ QV4DataCollector::Ref ref = collectedRefs.at(i);
+ if (i > 0 && ref == collectedRefs.at(i - 1))
+ continue;
+ refs.append(lookupRef(ref));
+ }
+
+ collectedRefs.clear();
+ return refs;
}
QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate)
@@ -316,14 +436,117 @@ QJsonObject QV4DataCollector::collectAsJson(const QString &name, const QV4::Scop
if (value->isManaged() && !value->isString()) {
Ref ref = addRef(value);
dict.insert(QStringLiteral("ref"), qint64(ref));
- if (m_collectedRefs)
- m_collectedRefs->append(ref);
+ collectedRefs.append(ref);
}
collectProperty(value, engine(), dict);
return dict;
}
+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);
+ QV4::Debugging::V4Debugger *debugger =
+ qobject_cast<QV4::Debugging::V4Debugger *>(collector->engine()->debugger);
+ if (debugger) {
+ for (int i = fromFrame; i < toFrame && i < frames.size(); ++i)
+ frameArray.push_back(collector->buildFrame(frames[i], i, debugger));
+ }
+ 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 {
+ QV4::Debugging::V4Debugger *debugger =
+ qobject_cast<QV4::Debugging::V4Debugger *>(collector->engine()->debugger);
+ if (debugger) {
+ result = collector->buildFrame(frames[frameNr], frameNr, debugger);
+ collectedRefs = collector->flushCollectedRefs();
+ success = true;
+ } else {
+ success = false;
+ }
+ }
+}
+
+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;
+ QV4::Debugging::V4Debugger *debugger =
+ qobject_cast<QV4::Debugging::V4Debugger *>(collector->engine()->debugger);
+ success = (debugger && collector->collectScope(&object, debugger, 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) :
+ CollectJob(collector), handles(handles) {}
+
+void ValueLookupJob::run()
+{
+ foreach (const QJsonValue &handle, handles) {
+ QV4DataCollector::Ref ref = handle.toInt();
+ if (!collector->isValidRef(ref)) {
+ exception = QString::fromLatin1("Invalid Ref: %1").arg(ref);
+ break;
+ }
+ result[QString::number(ref)] = collector->lookupRef(ref);
+ }
+ collectedRefs = collector->flushCollectedRefs();
+}
+
+const QString &ValueLookupJob::exceptionMessage() const
+{
+ return exception;
+}
+
ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr,
const QString &expression,
QV4DataCollector *collector)
@@ -336,7 +559,8 @@ void ExpressionEvalJob::handleResult(QV4::ScopedValue &result)
{
if (hasExeption())
exception = result->toQStringNoThrow();
- collector->collect(result);
+ value = collector->lookupRef(collector->collect(result));
+ collectedRefs = collector->flushCollectedRefs();
}
const QString &ExpressionEvalJob::exceptionMessage() const
@@ -344,6 +568,16 @@ const QString &ExpressionEvalJob::exceptionMessage() const
return exception;
}
+const QJsonObject &ExpressionEvalJob::returnValue() const
+{
+ return value;
+}
+
+const QJsonArray &ExpressionEvalJob::refs() const
+{
+ return collectedRefs;
+}
+
GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine, int seq)
: engine(engine)
, seq(seq)
@@ -364,111 +598,21 @@ void GatherSourcesJob::run()
emit debugger->sourcesCollected(debugger, sources, seq);
}
-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, bool *foundThis)
+ExceptionCollectJob::ExceptionCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector)
: engine(engine)
, collector(collector)
- , frameNr(frameNr)
- , foundThis(foundThis)
+ , exception(-1)
{}
-void ThisCollectJob::run()
-{
- *foundThis = myRun();
-}
-
-bool ThisCollectJob::myRun()
-{
+void ExceptionCollectJob::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 false;
-
- QV4::ScopedValue o(scope, ctxt->asCallContext()->d()->activation);
- collector->collect(o);
- return true;
+ QV4::ScopedValue v(scope, *engine->exceptionValue);
+ exception = collector->collect(v);
}
-ExceptionCollectJob::ExceptionCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector)
- : engine(engine)
- , collector(collector)
-{}
-
-void ExceptionCollectJob::run()
+QV4DataCollector::Ref ExceptionCollectJob::exceptionValue() const
{
- QV4::Scope scope(engine);
- QV4::ScopedValue v(scope, *engine->exceptionValue);
- collector->collect(v);
+ return exception;
}
QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
index d0e4a4ad18..5a2c8ff33b 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
@@ -37,6 +37,9 @@
#include <private/qv4engine_p.h>
#include <private/qv4debugging_p.h>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+
QT_BEGIN_NAMESPACE
class QV4DataCollector
@@ -49,25 +52,27 @@ 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);
~QV4DataCollector();
- void collect(const QV4::ScopedValue &value);
-
+ Ref collect(const QV4::ScopedValue &value);
+ bool isValidRef(Ref ref) const;
QJsonObject lookupRef(Ref ref);
Ref addFunctionRef(const QString &functionName);
Ref addScriptRef(const QString &scriptName);
- void collectScope(QJsonObject *dict, QV4::Debugging::V4Debugger *debugger, int frameNr,
+ bool collectScope(QJsonObject *dict, QV4::Debugging::V4Debugger *debugger, int frameNr,
int scopeNr);
+ QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
+ QV4::Debugging::V4Debugger *debugger);
QV4::ExecutionEngine *engine() const { return m_engine; }
+ QJsonArray flushCollectedRefs();
private:
- friend class RefHolder;
-
Ref addRef(QV4::Value value, bool deduplicate = true);
QV4::ReturnedValue getValue(Ref ref);
bool lookupSpecialRef(Ref ref, QJsonObject *dict);
@@ -77,102 +82,103 @@ private:
void collectArgumentsInContext();
QV4::ExecutionEngine *m_engine;
- Refs *m_collectedRefs;
+ Refs collectedRefs;
QV4::PersistentValue values;
typedef QHash<Ref, QJsonObject> SpecialRefs;
SpecialRefs specialRefs;
};
-class RefHolder {
+class CollectJob : public QV4::Debugging::V4Debugger::Job
+{
+protected:
+ QV4DataCollector *collector;
+ QJsonObject result;
+ QJsonArray collectedRefs;
public:
- RefHolder(QV4DataCollector *collector, QV4DataCollector::Refs *target) :
- m_collector(collector), m_previousRefs(collector->m_collectedRefs)
- {
- m_collector->m_collectedRefs = target;
- }
-
- ~RefHolder()
- {
- std::swap(m_collector->m_collectedRefs, m_previousRefs);
- }
-
-private:
- QV4DataCollector *m_collector;
- QV4DataCollector::Refs *m_previousRefs;
+ CollectJob(QV4DataCollector *collector) : collector(collector) {}
+ const QJsonObject &returnValue() const { return result; }
+ const QJsonArray &refs() const { return collectedRefs; }
};
-class ExpressionEvalJob: public QV4::Debugging::V4Debugger::JavaScriptJob
+class BacktraceJob: public CollectJob
{
- QV4DataCollector *collector;
- QString exception;
-
+ int fromFrame;
+ int toFrame;
public:
- ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression,
- QV4DataCollector *collector);
- virtual void handleResult(QV4::ScopedValue &result);
- const QString &exceptionMessage() const;
+ BacktraceJob(QV4DataCollector *collector, int fromFrame, int toFrame);
+ void run();
};
-class GatherSourcesJob: public QV4::Debugging::V4Debugger::Job
+class FrameJob: public CollectJob
{
- QV4::ExecutionEngine *engine;
- const int seq;
+ int frameNr;
+ bool success;
public:
- GatherSourcesJob(QV4::ExecutionEngine *engine, int seq);
+ FrameJob(QV4DataCollector *collector, int frameNr);
void run();
+ bool wasSuccessful() const;
};
-class ArgumentCollectJob: public QV4::Debugging::V4Debugger::Job
+class ScopeJob: public CollectJob
{
- QV4::ExecutionEngine *engine;
- QV4DataCollector *collector;
- QStringList *names;
int frameNr;
int scopeNr;
+ bool success;
public:
- ArgumentCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector,
- QStringList *names, int frameNr, int scopeNr);
+ ScopeJob(QV4DataCollector *collector, int frameNr, int scopeNr);
void run();
+ bool wasSuccessful() const;
};
-class LocalCollectJob: public QV4::Debugging::V4Debugger::Job
+class ValueLookupJob: public CollectJob
{
- QV4::ExecutionEngine *engine;
- QV4DataCollector *collector;
- QStringList *names;
- int frameNr;
- int scopeNr;
+ const QJsonArray handles;
+ QString exception;
public:
- LocalCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, QStringList *names,
- int frameNr, int scopeNr);
+ ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector);
void run();
+ const QString &exceptionMessage() const;
};
-class ThisCollectJob: public QV4::Debugging::V4Debugger::Job
+class ExpressionEvalJob: public QV4::Debugging::V4Debugger::JavaScriptJob
{
- QV4::ExecutionEngine *engine;
QV4DataCollector *collector;
- int frameNr;
- bool *foundThis;
+ QString exception;
+ QJsonObject value;
+ QJsonArray collectedRefs;
public:
- ThisCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, int frameNr,
- bool *foundThis);
+ ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression,
+ QV4DataCollector *collector);
+ virtual void handleResult(QV4::ScopedValue &result);
+ const QString &exceptionMessage() const;
+ const QJsonObject &returnValue() const;
+ const QJsonArray &refs() const;
+};
+
+class GatherSourcesJob: public QV4::Debugging::V4Debugger::Job
+{
+ QV4::ExecutionEngine *engine;
+ const int seq;
+
+public:
+ GatherSourcesJob(QV4::ExecutionEngine *engine, int seq);
void run();
- bool myRun();
};
class ExceptionCollectJob: public QV4::Debugging::V4Debugger::Job
{
QV4::ExecutionEngine *engine;
QV4DataCollector *collector;
+ QV4DataCollector::Ref exception;
public:
ExceptionCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector);
void run();
+ QV4DataCollector::Ref exceptionValue() const;
};
QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
index 5233a09992..e9bcd772e5 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
@@ -114,9 +114,9 @@ protected:
response.insert(QStringLiteral("running"), debugService->debuggerAgent.isRunning());
}
- void addRefs()
+ void addRefs(const QJsonArray &refs)
{
- response.insert(QStringLiteral("refs"), debugService->buildRefs());
+ response.insert(QStringLiteral("refs"), refs);
}
void createErrorResponse(const QString &msg)
@@ -271,28 +271,16 @@ public:
int toFrame = arguments.value(QStringLiteral("toFrame")).toInt(fromFrame + 10);
// no idea what the bottom property is for, so we'll ignore it.
- QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
-
- 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(debugService->collector(), fromFrame, toFrame);
+ debugService->debuggerAgent.firstDebugger()->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();
+ addBody(job.returnValue());
+ addRefs(job.refs());
}
};
@@ -308,23 +296,27 @@ public:
const int frameNr = arguments.value(QStringLiteral("number")).toInt(
debugService->selectedFrame());
- QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
- 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(debugService->collector(), frameNr);
+ debugService->debuggerAgent.firstDebugger()->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();
+ addBody(job.returnValue());
+ addRefs(job.refs());
}
};
@@ -341,9 +333,7 @@ public:
debugService->selectedFrame());
const int scopeNr = arguments.value(QStringLiteral("number")).toInt(0);
- QV4::Debugging::V4Debugger *debugger = debugService->debuggerAgent.firstDebugger();
- 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;
}
@@ -352,15 +342,20 @@ public:
return;
}
- QJsonObject scope = debugService->buildScope(frameNr, scopeNr, debugger);
+ ScopeJob job(debugService->collector(), frameNr, scopeNr);
+ debugService->debuggerAgent.firstDebugger()->runInEngine(&job);
+ if (!job.wasSuccessful()) {
+ createErrorResponse(QStringLiteral("scope retrieval failed"));
+ return;
+ }
// response:
addCommand();
addRequestSequence();
addSuccess(true);
addRunning();
- addBody(scope);
- addRefs();
+ addBody(job.returnValue());
+ addRefs(job.refs());
}
};
@@ -375,17 +370,19 @@ public:
QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
QJsonArray handles = arguments.value(QStringLiteral("handles")).toArray();
- QJsonObject body;
- foreach (const QJsonValue &handle, handles)
- body[QString::number(handle.toInt())] = debugService->lookup(handle.toInt());
-
- // response:
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- addBody(body);
- addRefs();
+ ValueLookupJob job(handles, debugService->collector());
+ debugService->debuggerAgent.firstDebugger()->runInEngine(&job);
+ if (!job.exceptionMessage().isEmpty()) {
+ createErrorResponse(job.exceptionMessage());
+ } else {
+ // response:
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ addBody(job.returnValue());
+ addRefs(job.refs());
+ }
}
};
@@ -557,7 +554,6 @@ public:
const int frame = arguments.value(QStringLiteral("frame")).toInt(0);
QV4DataCollector *collector = debugService->collector();
- RefHolder holder(collector, debugService->refs());
ExpressionEvalJob job(debugger->engine(), frame, expression, collector);
debugger->runInEngine(&job);
if (job.hasExeption()) {
@@ -567,8 +563,8 @@ public:
addRequestSequence();
addSuccess(true);
addRunning();
- addBody(collector->lookupRef(debugService->refs()->last()));
- addRefs();
+ addBody(job.returnValue());
+ addRefs(job.refs());
}
} else {
createErrorResponse(QStringLiteral("Debugger has to be paused for evaluate to work."));
@@ -789,135 +785,11 @@ void QV4DebugServiceImpl::clearHandles(QV4::ExecutionEngine *engine)
theCollector.reset(new QV4DataCollector(engine));
}
-QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
- QV4::Debugging::V4Debugger *debugger)
-{
- QV4DataCollector::Ref ref;
-
- QJsonObject frame;
- frame[QLatin1String("index")] = frameNr;
- frame[QLatin1String("debuggerFrame")] = false;
- ref = theCollector->addFunctionRef(stackFrame.function);
- collectedRefs.append(ref);
- frame[QLatin1String("func")] = toRef(ref);
- ref = theCollector->addScriptRef(stackFrame.source);
- collectedRefs.append(ref);
- frame[QLatin1String("script")] = toRef(ref);
- frame[QLatin1String("line")] = stackFrame.line - 1;
- if (stackFrame.column >= 0)
- frame[QLatin1String("column")] = stackFrame.column;
-
- QJsonArray scopes;
- if (debugger->state() == QV4::Debugging::V4Debugger::Paused) {
- RefHolder holder(theCollector.data(), &collectedRefs);
- bool foundThis = false;
- ThisCollectJob job(debugger->engine(), theCollector.data(), frameNr, &foundThis);
- debugger->runInEngine(&job);
- if (foundThis)
- frame[QLatin1String("receiver")] = toRef(collectedRefs.last());
-
- // 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,
- QV4::Debugging::V4Debugger *debugger)
-{
- QJsonObject scope;
-
- QJsonObject object;
- RefHolder holder(theCollector.data(), &collectedRefs);
- theCollector->collectScope(&object, debugger, frameNr, scopeNr);
-
- if (debugger->state() == QV4::Debugging::V4Debugger::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::lookup(QV4DataCollector::Ref refId)
-{
- RefHolder holder(theCollector.data(), &collectedRefs);
- return theCollector->lookupRef(refId);
-}
-
-QJsonArray QV4DebugServiceImpl::buildRefs()
-{
- QJsonArray refs;
- std::sort(collectedRefs.begin(), collectedRefs.end());
- for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) {
- QV4DataCollector::Ref ref = collectedRefs.at(i);
- if (i > 0 && ref == collectedRefs.at(i - 1))
- continue;
- refs.append(lookup(ref));
- }
-
- collectedRefs.clear();
- return refs;
-}
-
-QJsonValue QV4DebugServiceImpl::toRef(QV4DataCollector::Ref ref)
-{
- QJsonObject dict;
- dict.insert(QStringLiteral("ref"), qint64(ref));
- return dict;
-}
-
QV4DataCollector *QV4DebugServiceImpl::collector() const
{
return theCollector.data();
}
-QV4DataCollector::Refs *QV4DebugServiceImpl::refs()
-{
- return &collectedRefs;
-}
-
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 273e5ffd62..658b1b3998 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
@@ -78,13 +78,6 @@ public:
void signalEmitted(const QString &signal);
void send(QJsonObject v8Payload);
- QJsonObject buildScope(int frameNr, int scopeNr, QV4::Debugging::V4Debugger *debugger);
- QJsonArray buildRefs();
- QJsonValue lookup(QV4DataCollector::Ref refId);
- QJsonValue toRef(QV4DataCollector::Ref ref);
-
- QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
- QV4::Debugging::V4Debugger *debugger);
int selectedFrame() const;
void selectFrame(int frameNr);
@@ -92,7 +85,6 @@ public:
QV4DataCollector *collector() const;
QV4DebuggerAgent debuggerAgent;
- QV4DataCollector::Refs *refs();
protected:
void messageReceived(const QByteArray &);
@@ -106,14 +98,12 @@ 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;
QMap<int, QV4::Debugging::V4Debugger *> debuggerMap;
static int debuggerIndex;
static int sequence;
const int version;
- QV4DataCollector::Refs collectedRefs;
QScopedPointer<QV4DataCollector> theCollector;
int theSelectedFrame;