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-07 16:25:12 +0000
commiteae5a20b099450985442c70186fd7a7be442f133 (patch)
treee7be003e4ed86ef69ad334eebfd8689cdb1e25b3 /src
parent881bb537c92684d25fae4fec9ac2dd61e1f9723c (diff)
V4 Debugger: Allow expression evaluation without pausing
We can schedule jobs into the GUI thread just fine, even if the debugger is running. They will run in global scope then. The only restriction is that we need exactly one engine to be running in order to do that, as otherwise we cannot decide which engine to use. To avoid interaction with the engine from the debugger thread we move the value lookup functionality into the data collector, and drop the RefHolder. Change-Id: Ifae124d70f42e488ed9a1b6794baef638992ddb1 Reviewed-by: Simon Hausmann <simon.hausmann@theqtcompany.com>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp151
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h67
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp25
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h7
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp2
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp174
-rw-r--r--src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h8
7 files changed, 257 insertions, 177 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
index 0469cd51d6..ac46905f1c 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp
@@ -44,6 +44,9 @@
QT_BEGIN_NAMESPACE
+const QV4DataCollector::Ref QV4DataCollector::s_invalidRef =
+ std::numeric_limits<QV4DataCollector::Ref>::max();
+
QV4::CallContext *QV4DataCollector::findContext(QV4::ExecutionEngine *engine, int frame)
{
QV4::ExecutionContext *ctx = engine->currentContext;
@@ -90,21 +93,16 @@ QVector<QV4::Heap::ExecutionContext::ContextType> QV4DataCollector::getScopeType
return types;
}
-
-QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine)
- : m_engine(engine), m_collectedRefs(Q_NULLPTR)
+QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine) : m_engine(engine)
{
- values.set(engine, engine->newArrayObject());
+ m_values.set(engine, engine->newArrayObject());
}
-QV4DataCollector::~QV4DataCollector()
+QV4DataCollector::Ref QV4DataCollector::collect(const QV4::ScopedValue &value)
{
-}
-
-void QV4DataCollector::collect(const QV4::ScopedValue &value)
-{
- if (m_collectedRefs)
- m_collectedRefs->append(addRef(value));
+ Ref ref = addRef(value);
+ m_collectedRefs.append(ref);
+ return ref;
}
const QV4::Object *collectProperty(const QV4::ScopedValue &value, QV4::ExecutionEngine *engine,
@@ -191,7 +189,8 @@ QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionNa
dict.insert(QStringLiteral("handle"), qint64(ref));
dict.insert(QStringLiteral("type"), QStringLiteral("function"));
dict.insert(QStringLiteral("name"), functionName);
- specialRefs.insert(ref, dict);
+ m_specialRefs.insert(ref, dict);
+ m_collectedRefs.append(ref);
return ref;
}
@@ -204,19 +203,25 @@ QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName)
dict.insert(QStringLiteral("handle"), qint64(ref));
dict.insert(QStringLiteral("type"), QStringLiteral("script"));
dict.insert(QStringLiteral("name"), scriptName);
- specialRefs.insert(ref, dict);
+ m_specialRefs.insert(ref, dict);
+ m_collectedRefs.append(ref);
return ref;
}
+bool QV4DataCollector::isValidRef(QV4DataCollector::Ref ref) const
+{
+ QV4::Scope scope(engine());
+ QV4::ScopedObject array(scope, m_values.value());
+ return ref < array->getLength();
+}
+
void QV4DataCollector::collectScope(QJsonObject *dict, QV4Debugger *debugger, int frameNr,
int scopeNr)
{
QStringList names;
- Refs refs;
if (debugger->state() == QV4Debugger::Paused) {
- RefHolder holder(this, &refs);
ArgumentCollectJob argumentsJob(m_engine, this, &names, frameNr, scopeNr);
debugger->runInEngine(&argumentsJob);
LocalCollectJob localsJob(m_engine, this, &names, frameNr, scopeNr);
@@ -226,15 +231,36 @@ void QV4DataCollector::collectScope(QJsonObject *dict, QV4Debugger *debugger, in
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() == m_collectedRefs.size());
+ for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i)
scopeObject->put(engine(), names.at(i),
- QV4::Value::fromReturnedValue(getValue(refs.at(i))));
+ QV4::Value::fromReturnedValue(getValue(m_collectedRefs.at(i))));
Ref scopeObjectRef = addRef(scopeObject);
dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef));
- if (m_collectedRefs)
- m_collectedRefs->append(scopeObjectRef);
+ m_collectedRefs.append(scopeObjectRef);
+}
+
+QJsonArray QV4DataCollector::flushCollectedRefs()
+{
+ QJsonArray refs;
+ std::sort(m_collectedRefs.begin(), m_collectedRefs.end());
+ for (int i = 0, ei = m_collectedRefs.size(); i != ei; ++i) {
+ QV4DataCollector::Ref ref = m_collectedRefs.at(i);
+ if (i > 0 && ref == m_collectedRefs.at(i - 1))
+ continue;
+ refs.append(lookupRef(ref));
+ }
+
+ m_collectedRefs.clear();
+ return refs;
+}
+
+void QV4DataCollector::clear()
+{
+ m_values.set(engine(), engine()->newArrayObject());
+ m_collectedRefs.clear();
+ m_specialRefs.clear();
}
QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate)
@@ -257,10 +283,10 @@ QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicat
// if we wouldn't do this, the putIndexed won't work.
ExceptionStateSaver resetExceptionState(engine());
QV4::Scope scope(engine());
- QV4::ScopedObject array(scope, values.value());
+ QV4::ScopedObject array(scope, m_values.value());
if (deduplicate) {
for (Ref i = 0; i < array->getLength(); ++i) {
- if (array->getIndexed(i) == value.rawValue() && !specialRefs.contains(i))
+ if (array->getIndexed(i) == value.rawValue() && !m_specialRefs.contains(i))
return i;
}
}
@@ -273,15 +299,15 @@ QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicat
QV4::ReturnedValue QV4DataCollector::getValue(Ref ref)
{
QV4::Scope scope(engine());
- QV4::ScopedObject array(scope, values.value());
+ QV4::ScopedObject array(scope, m_values.value());
Q_ASSERT(ref < array->getLength());
return array->getIndexed(ref, Q_NULLPTR);
}
bool QV4DataCollector::lookupSpecialRef(Ref ref, QJsonObject *dict)
{
- SpecialRefs::const_iterator it = specialRefs.constFind(ref);
- if (it == specialRefs.cend())
+ SpecialRefs::const_iterator it = m_specialRefs.constFind(ref);
+ if (it == m_specialRefs.cend())
return false;
*dict = it.value();
@@ -317,14 +343,41 @@ 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);
+ m_collectedRefs.append(ref);
}
collectProperty(value, engine(), dict);
return dict;
}
+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;
+}
+
+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)
@@ -333,11 +386,12 @@ ExpressionEvalJob::ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr,
{
}
-void ExpressionEvalJob::handleResult(QV4::ScopedValue &result)
+void ExpressionEvalJob::handleResult(QV4::ScopedValue &value)
{
if (hasExeption())
- exception = result->toQStringNoThrow();
- collector->collect(result);
+ exception = value->toQStringNoThrow();
+ result = collector->lookupRef(collector->collect(value));
+ collectedRefs = collector->flushCollectedRefs();
}
const QString &ExpressionEvalJob::exceptionMessage() const
@@ -345,6 +399,16 @@ const QString &ExpressionEvalJob::exceptionMessage() const
return exception;
}
+const QJsonObject &ExpressionEvalJob::returnValue() const
+{
+ return result;
+}
+
+const QJsonArray &ExpressionEvalJob::refs() const
+{
+ return collectedRefs;
+}
+
GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine)
: engine(engine)
{}
@@ -427,20 +491,15 @@ void LocalCollectJob::run()
}
ThisCollectJob::ThisCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector,
- int frameNr, bool *foundThis)
+ int frameNr)
: engine(engine)
, collector(collector)
, frameNr(frameNr)
- , foundThis(foundThis)
+ , thisRef(QV4DataCollector::s_invalidRef)
{}
void ThisCollectJob::run()
{
- *foundThis = myRun();
-}
-
-bool ThisCollectJob::myRun()
-{
QV4::Scope scope(engine);
QV4::ScopedContext ctxt(scope, QV4DataCollector::findContext(engine, frameNr));
while (ctxt) {
@@ -451,23 +510,33 @@ bool ThisCollectJob::myRun()
}
if (!ctxt)
- return false;
+ return;
QV4::ScopedValue o(scope, ctxt->asCallContext()->d()->activation);
- collector->collect(o);
- return true;
+ thisRef = collector->collect(o);
+}
+
+QV4DataCollector::Ref ThisCollectJob::foundRef() const
+{
+ return thisRef;
}
ExceptionCollectJob::ExceptionCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector)
: engine(engine)
, collector(collector)
+ , exception(QV4DataCollector::s_invalidRef)
{}
void ExceptionCollectJob::run()
{
QV4::Scope scope(engine);
QV4::ScopedValue v(scope, *engine->exceptionValue);
- collector->collect(v);
+ exception = collector->collect(v);
+}
+
+QV4DataCollector::Ref ExceptionCollectJob::exceptionValue() const
+{
+ return exception;
}
QT_END_NAMESPACE
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
index bfa3bd2fe1..d1ff98f9b0 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h
@@ -38,6 +38,9 @@
#include <private/qv4engine_p.h>
#include <private/qv4persistent_p.h>
+#include <QtCore/QJsonObject>
+#include <QtCore/QJsonArray>
+
QT_BEGIN_NAMESPACE
class QV4DataCollector
@@ -45,6 +48,7 @@ class QV4DataCollector
public:
typedef uint Ref;
typedef QVector<uint> Refs;
+ static const Ref s_invalidRef;
static QV4::CallContext *findContext(QV4::ExecutionEngine *engine, int frame);
static QV4::Heap::CallContext *findScope(QV4::ExecutionContext *ctxt, int scope);
@@ -52,22 +56,21 @@ public:
QV4::ExecutionEngine *engine, int frame);
QV4DataCollector(QV4::ExecutionEngine *engine);
- ~QV4DataCollector();
-
- void collect(const QV4::ScopedValue &value);
-
- QJsonObject lookupRef(Ref ref);
+ Ref collect(const QV4::ScopedValue &value);
Ref addFunctionRef(const QString &functionName);
Ref addScriptRef(const QString &scriptName);
+ bool isValidRef(Ref ref) const;
+ QJsonObject lookupRef(Ref ref);
+
void collectScope(QJsonObject *dict, QV4Debugger *debugger, int frameNr, int scopeNr);
QV4::ExecutionEngine *engine() const { return m_engine; }
+ QJsonArray flushCollectedRefs();
+ void clear();
private:
- friend class RefHolder;
-
Ref addRef(QV4::Value value, bool deduplicate = true);
QV4::ReturnedValue getValue(Ref ref);
bool lookupSpecialRef(Ref ref, QJsonObject *dict);
@@ -77,40 +80,43 @@ private:
void collectArgumentsInContext();
QV4::ExecutionEngine *m_engine;
- Refs *m_collectedRefs;
- QV4::PersistentValue values;
+ Refs m_collectedRefs;
+ QV4::PersistentValue m_values;
typedef QHash<Ref, QJsonObject> SpecialRefs;
- SpecialRefs specialRefs;
+ SpecialRefs m_specialRefs;
};
-class RefHolder {
-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);
- }
+class ValueLookupJob: public QV4Debugger::Job
+{
+ QV4DataCollector *collector;
+ const QJsonArray handles;
+ QJsonObject result;
+ QJsonArray collectedRefs;
+ QString exception;
-private:
- QV4DataCollector *m_collector;
- QV4DataCollector::Refs *m_previousRefs;
+public:
+ ValueLookupJob(const QJsonArray &handles, QV4DataCollector *collector) :
+ collector(collector), handles(handles) {}
+ void run();
+ const QString &exceptionMessage() const;
+ const QJsonObject &returnValue() const;
+ const QJsonArray &refs() const;
};
class ExpressionEvalJob: public QV4Debugger::JavaScriptJob
{
QV4DataCollector *collector;
QString exception;
+ QJsonObject result;
+ QJsonArray collectedRefs;
public:
ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, const QString &expression,
QV4DataCollector *collector);
- virtual void handleResult(QV4::ScopedValue &result);
+ virtual void handleResult(QV4::ScopedValue &value);
const QString &exceptionMessage() const;
+ const QJsonObject &returnValue() const;
+ const QJsonArray &refs() const;
};
class GatherSourcesJob: public QV4Debugger::Job
@@ -157,23 +163,24 @@ class ThisCollectJob: public QV4Debugger::Job
QV4::ExecutionEngine *engine;
QV4DataCollector *collector;
int frameNr;
- bool *foundThis;
+ QV4DataCollector::Ref thisRef;
public:
- ThisCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, int frameNr,
- bool *foundThis);
+ ThisCollectJob(QV4::ExecutionEngine *engine, QV4DataCollector *collector, int frameNr);
void run();
- bool myRun();
+ QV4DataCollector::Ref foundRef() const;
};
class ExceptionCollectJob: public QV4Debugger::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/qv4debugger.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp
index 014de1f4cb..a7ef1ede6b 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp
@@ -32,6 +32,7 @@
****************************************************************************/
#include "qv4debugger.h"
+#include "qv4datacollector.h"
#include <private/qv4scopedvalue_p.h>
#include <private/qv4script_p.h>
@@ -127,6 +128,7 @@ QV4Debugger::QV4Debugger(QV4::ExecutionEngine *engine)
, m_returnedValue(engine, QV4::Primitive::undefinedValue())
, m_gatherSources(0)
, m_runningJob(0)
+ , m_collector(new QV4DataCollector(engine))
{
static int debuggerId = qRegisterMetaType<QV4Debugger*>();
static int pauseReasonId = qRegisterMetaType<QV4Debugger::PauseReason>();
@@ -134,11 +136,21 @@ QV4Debugger::QV4Debugger(QV4::ExecutionEngine *engine)
Q_UNUSED(pauseReasonId);
}
+QV4Debugger::~QV4Debugger()
+{
+ delete m_collector;
+}
+
QV4::ExecutionEngine *QV4Debugger::engine() const
{
return m_engine;
}
+QV4DataCollector *QV4Debugger::collector() const
+{
+ return m_collector;
+}
+
void QV4Debugger::pause()
{
QMutexLocker locker(&m_lock);
@@ -300,6 +312,14 @@ QV4::Function *QV4Debugger::getFunction() const
return context->d()->engine->globalCode;
}
+void QV4Debugger::runJobUnpaused()
+{
+ QMutexLocker locker(&m_lock);
+ if (m_runningJob)
+ m_runningJob->run();
+ m_jobIsRunning.wakeAll();
+}
+
void QV4Debugger::pauseAndWait(PauseReason reason)
{
if (m_runningJob)
@@ -352,7 +372,10 @@ void QV4Debugger::runInEngine_havingLock(QV4Debugger::Job *job)
Q_ASSERT(m_runningJob == 0);
m_runningJob = job;
- m_runningCondition.wakeAll();
+ if (state() == Paused)
+ m_runningCondition.wakeAll();
+ else
+ QMetaObject::invokeMethod(this, "runJobUnpaused", Qt::QueuedConnection);
m_jobIsRunning.wait(&m_lock);
m_runningJob = 0;
}
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h
index 8662259264..abb43f82f3 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h
@@ -55,6 +55,7 @@
QT_BEGIN_NAMESPACE
+class QV4DataCollector;
class QV4Debugger : public QV4::Debugging::Debugger
{
Q_OBJECT
@@ -110,8 +111,10 @@ public:
};
QV4Debugger(QV4::ExecutionEngine *engine);
+ ~QV4Debugger();
QV4::ExecutionEngine *engine() const;
+ QV4DataCollector *collector() const;
void pause();
void resume(Speed speed);
@@ -153,6 +156,9 @@ public:
signals:
void debuggerPaused(QV4Debugger *self, QV4Debugger::PauseReason reason);
+private slots:
+ void runJobUnpaused();
+
private:
// requires lock to be held
void pauseAndWait(PauseReason reason);
@@ -174,6 +180,7 @@ private:
Job *m_gatherSources;
Job *m_runningJob;
+ QV4DataCollector *m_collector;
QWaitCondition m_jobIsRunning;
};
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
index 8bd9547032..c563a97fe2 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp
@@ -63,7 +63,7 @@ void QV4DebuggerAgent::debuggerPaused(QV4Debugger *debugger, QV4Debugger::PauseR
{
Q_UNUSED(reason);
- m_debugService->clearHandles(debugger->engine());
+ debugger->collector()->clear();
QJsonObject event, body, script;
event.insert(QStringLiteral("type"), QStringLiteral("event"));
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp
index dea1fae779..6524a1ff28 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)
@@ -169,6 +169,7 @@ public:
QJsonObject body;
body.insert(QStringLiteral("V8Version"),
QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR));
+ body.insert(QStringLiteral("UnpausedEvaluate"), true);
addBody(body);
}
};
@@ -296,7 +297,7 @@ public:
body.insert(QStringLiteral("frames"), frameArray);
}
addBody(body);
- addRefs();
+ addRefs(debugger->collector()->flushCollectedRefs());
}
};
@@ -333,7 +334,7 @@ public:
addSuccess(true);
addRunning();
addBody(frame);
- addRefs();
+ addRefs(debugger->collector()->flushCollectedRefs());
}
};
@@ -374,7 +375,7 @@ public:
addSuccess(true);
addRunning();
addBody(scope);
- addRefs();
+ addRefs(debugger->collector()->flushCollectedRefs());
}
};
@@ -389,17 +390,32 @@ 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());
+ QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
+ if (!debugger) {
+ const QList<QV4Debugger *> &debuggers = debugService->debuggerAgent.debuggers();
+ if (debuggers.count() > 1) {
+ createErrorResponse(QStringLiteral("Cannot lookup values if multiple debuggers are running and none is paused"));
+ return;
+ } else if (debuggers.count() == 0) {
+ createErrorResponse(QStringLiteral("No debuggers available to lookup values"));
+ return;
+ }
+ debugger = debuggers.first();
+ }
- // response:
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- addBody(body);
- addRefs();
+ ValueLookupJob job(handles, debugger->collector());
+ debugger->runInEngine(&job);
+ if (!job.exceptionMessage().isEmpty()) {
+ createErrorResponse(job.exceptionMessage());
+ } else {
+ // response:
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ addBody(job.returnValue());
+ addRefs(job.refs());
+ }
}
};
@@ -587,27 +603,34 @@ public:
virtual void handleRequest()
{
QV4Debugger *debugger = debugService->debuggerAgent.pausedDebugger();
- if (debugger) {
- QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
- QString expression = arguments.value(QStringLiteral("expression")).toString();
- 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()) {
- createErrorResponse(job.exceptionMessage());
- } else {
- addCommand();
- addRequestSequence();
- addSuccess(true);
- addRunning();
- addBody(collector->lookupRef(debugService->refs()->last()));
- addRefs();
+
+ if (!debugger) {
+ const QList<QV4Debugger *> &debuggers = debugService->debuggerAgent.debuggers();
+ if (debuggers.count() > 1) {
+ createErrorResponse(QStringLiteral("Cannot evaluate expressions if multiple debuggers are running and none is paused"));
+ return;
+ } else if (debuggers.count() == 0) {
+ createErrorResponse(QStringLiteral("No debuggers available to evaluate expressions"));
+ return;
}
+ debugger = debuggers.first();
+ }
+
+ QJsonObject arguments = req.value(QStringLiteral("arguments")).toObject();
+ QString expression = arguments.value(QStringLiteral("expression")).toString();
+ const int frame = arguments.value(QStringLiteral("frame")).toInt(0);
+
+ ExpressionEvalJob job(debugger->engine(), frame, expression, debugger->collector());
+ debugger->runInEngine(&job);
+ if (job.hasExeption()) {
+ createErrorResponse(job.exceptionMessage());
} else {
- createErrorResponse(QStringLiteral("Debugger has to be paused for evaluate to work."));
+ addCommand();
+ addRequestSequence();
+ addSuccess(true);
+ addRunning();
+ addBody(job.returnValue());
+ addRefs(job.refs());
}
}
};
@@ -805,11 +828,6 @@ void QV4DebugServiceImpl::send(QJsonObject v8Payload)
emit messageToClient(name(), packMessage("v8message", responseData));
}
-void QV4DebugServiceImpl::clearHandles(QV4::ExecutionEngine *engine)
-{
- theCollector.reset(new QV4DataCollector(engine));
-}
-
QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, int frameNr,
QV4Debugger *debugger)
{
@@ -818,38 +836,34 @@ QJsonObject QV4DebugServiceImpl::buildFrame(const QV4::StackFrame &stackFrame, i
QJsonObject frame;
frame[QLatin1String("index")] = frameNr;
frame[QLatin1String("debuggerFrame")] = false;
- ref = theCollector->addFunctionRef(stackFrame.function);
- collectedRefs.append(ref);
+ ref = debugger->collector()->addFunctionRef(stackFrame.function);
frame[QLatin1String("func")] = toRef(ref);
- ref = theCollector->addScriptRef(stackFrame.source);
- collectedRefs.append(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;
- if (debugger->state() == QV4Debugger::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());
+ 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;
- // 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);
- }
+ QJsonObject scope;
+ scope[QLatin1String("index")] = i;
+ scope[QLatin1String("type")] = type;
+ scopes.push_back(scope);
}
frame[QLatin1String("scopes")] = scopes;
@@ -883,8 +897,7 @@ QJsonObject QV4DebugServiceImpl::buildScope(int frameNr, int scopeNr, QV4Debugge
QJsonObject scope;
QJsonObject object;
- RefHolder holder(theCollector.data(), &collectedRefs);
- theCollector->collectScope(&object, debugger, frameNr, scopeNr);
+ debugger->collector()->collectScope(&object, debugger, frameNr, scopeNr);
if (debugger->state() == QV4Debugger::Paused) {
QVector<QV4::Heap::ExecutionContext::ContextType> scopeTypes =
@@ -900,27 +913,6 @@ QJsonObject QV4DebugServiceImpl::buildScope(int frameNr, int scopeNr, QV4Debugge
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;
@@ -928,16 +920,6 @@ QJsonValue QV4DebugServiceImpl::toRef(QV4DataCollector::Ref 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 678ebe43b8..2d9932b838 100644
--- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
+++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h
@@ -78,19 +78,13 @@ public:
void send(QJsonObject v8Payload);
QJsonObject buildScope(int frameNr, int scopeNr, QV4Debugger *debugger);
- QJsonArray buildRefs();
- QJsonValue lookup(QV4DataCollector::Ref refId);
QJsonValue toRef(QV4DataCollector::Ref ref);
QJsonObject buildFrame(const QV4::StackFrame &stackFrame, int frameNr, QV4Debugger *debugger);
int selectedFrame() const;
void selectFrame(int frameNr);
- void clearHandles(QV4::ExecutionEngine *engine);
-
- QV4DataCollector *collector() const;
QV4DebuggerAgent debuggerAgent;
- QV4DataCollector::Refs *refs();
protected:
void messageReceived(const QByteArray &) Q_DECL_OVERRIDE;
@@ -108,9 +102,7 @@ private:
QStringList breakOnSignals;
static int sequence;
- QV4DataCollector::Refs collectedRefs;
- QScopedPointer<QV4DataCollector> theCollector;
int theSelectedFrame;
void addHandler(V8CommandHandler* handler);