aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp46
8 files changed, 276 insertions, 204 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);
diff --git a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
index c5fa6be7a0..70883047c8 100644
--- a/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
+++ b/tests/auto/qml/debugger/qv4debugger/tst_qv4debugger.cpp
@@ -104,11 +104,8 @@ public:
typedef QV4DataCollector::Refs Refs;
typedef QV4DataCollector::Ref Ref;
struct NamedRefs {
- NamedRefs(QV4DataCollector *collector = 0): collector(collector) {}
-
QStringList names;
- Refs refs;
- QV4DataCollector *collector;
+ QJsonArray refs;
int size() const {
Q_ASSERT(names.size() == refs.size());
@@ -126,7 +123,7 @@ public:
QJsonObject rawValue(const QString &name) const {
Q_ASSERT(contains(name));
- return collector->lookupRef(refs.at(names.indexOf(name)));
+ return refs.at(names.indexOf(name)).toObject();
}
QJsonValue value(const QString &name) const {
@@ -143,7 +140,7 @@ public:
return;
}
- QJsonObject o = collector->lookupRef(refs.at(names.indexOf(name)));
+ QJsonObject o = refs.at(names.indexOf(name)).toObject();
QJsonDocument d;
d.setObject(o);
qDebug() << name << "=" << d.toJson(QJsonDocument::Indented);
@@ -168,14 +165,10 @@ public slots:
m_pauseReason = reason;
m_statesWhenPaused << debugger->currentExecutionState();
- if (debugger->state() == QV4Debugger::Paused &&
- debugger->engine()->hasException) {
- Refs refs;
- RefHolder holder(&collector, &refs);
+ if (debugger->state() == QV4Debugger::Paused && debugger->engine()->hasException) {
ExceptionCollectJob job(debugger->engine(), &collector);
debugger->runInEngine(&job);
- Q_ASSERT(refs.size() > 0);
- m_thrownValue = refs.first();
+ m_thrownValue = job.exceptionValue();
}
foreach (const TestBreakPoint &bp, m_breakPointsToAddWhenPaused)
@@ -187,11 +180,11 @@ public slots:
while (!m_expressionRequests.isEmpty()) {
Q_ASSERT(debugger->state() == QV4Debugger::Paused);
ExpressionRequest request = m_expressionRequests.takeFirst();
- m_expressionResults << Refs();
- RefHolder holder(&collector, &m_expressionResults.last());
ExpressionEvalJob job(debugger->engine(), request.frameNr, request.expression,
&collector);
debugger->runInEngine(&job);
+ m_expressionResults << job.returnValue();
+ m_expressionRefs << job.refs();
}
if (m_captureContextInfo)
@@ -213,17 +206,17 @@ public:
void captureContextInfo(QV4Debugger *debugger)
{
for (int i = 0, ei = m_stackTrace.size(); i != ei; ++i) {
- m_capturedArguments.append(NamedRefs(&collector));
- RefHolder argHolder(&collector, &m_capturedArguments.last().refs);
+ 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(&collector));
- RefHolder localHolder(&collector, &m_capturedLocals.last().refs);
+ m_capturedLocals.append(NamedRefs());
LocalCollectJob localsJob(debugger->engine(), &collector,
&m_capturedLocals.last().names, i, 0);
debugger->runInEngine(&localsJob);
+ m_capturedLocals.last().refs = collector.flushCollectedRefs();
}
}
@@ -250,7 +243,8 @@ public:
int frameNr;
};
QVector<ExpressionRequest> m_expressionRequests;
- QVector<Refs> m_expressionResults;
+ QList<QJsonObject> m_expressionResults;
+ QList<QJsonArray> m_expressionRefs;
QV4Debugger *m_debugger;
// Utility methods:
@@ -578,7 +572,7 @@ void tst_qv4debugger::readObject()
QCOMPARE(b_tail.value("name").toString(), QStringLiteral("tail"));
QVERIFY(b_tail.contains("ref"));
- QJsonObject b_tail_value = frame0.collector->lookupRef(b_tail.value("ref").toInt());
+ QJsonObject b_tail_value = m_debuggerAgent->collector.lookupRef(b_tail.value("ref").toInt());
QCOMPARE(b_tail_value.value("type").toString(), QStringLiteral("object"));
QVERIFY(b_tail_value.contains("properties"));
QJsonArray b_tail_props = b_tail_value.value("properties").toArray();
@@ -711,15 +705,13 @@ void tst_qv4debugger::evaluateExpression()
evaluateJavaScript(script, "evaluateExpression");
- QCOMPARE(m_debuggerAgent->m_expressionResults.count(), 2);
- QCOMPARE(m_debuggerAgent->m_expressionResults[0].size(), 1);
- QJsonObject result0 =
- m_debuggerAgent->collector.lookupRef(m_debuggerAgent->m_expressionResults[0].first());
+ QCOMPARE(m_debuggerAgent->m_expressionRefs.count(), 2);
+ QCOMPARE(m_debuggerAgent->m_expressionRefs[0].size(), 1);
+ QJsonObject result0 = m_debuggerAgent->m_expressionRefs[0].first().toObject();
QCOMPARE(result0.value("type").toString(), QStringLiteral("number"));
QCOMPARE(result0.value("value").toInt(), 10);
- QCOMPARE(m_debuggerAgent->m_expressionResults[1].size(), 1);
- QJsonObject result1 =
- m_debuggerAgent->collector.lookupRef(m_debuggerAgent->m_expressionResults[1].first());
+ QCOMPARE(m_debuggerAgent->m_expressionRefs[1].size(), 1);
+ QJsonObject result1 = m_debuggerAgent->m_expressionRefs[1].first().toObject();
QCOMPARE(result1.value("type").toString(), QStringLiteral("number"));
QCOMPARE(result1.value("value").toInt(), 20);
}