diff options
Diffstat (limited to 'src/plugins/qmltooling/qmldbg_debugger')
7 files changed, 213 insertions, 318 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index 95e6d5704c..8c92b4b170 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp @@ -46,6 +46,7 @@ #include <private/qv4objectiterator_p.h> #include <private/qv4identifier_p.h> #include <private/qv4runtime_p.h> +#include <private/qv4identifiertable_p.h> #include <private/qqmlcontext_p.h> #include <private/qqmlengine_p.h> @@ -96,33 +97,28 @@ int QV4DataCollector::encodeScopeType(QV4::Heap::ExecutionContext::ContextType s { switch (scopeType) { case QV4::Heap::ExecutionContext::Type_GlobalContext: - return 0; - case QV4::Heap::ExecutionContext::Type_CatchContext: - return 4; + break; case QV4::Heap::ExecutionContext::Type_WithContext: return 2; case QV4::Heap::ExecutionContext::Type_CallContext: return 1; case QV4::Heap::ExecutionContext::Type_QmlContext: return 3; - default: - return -1; + case QV4::Heap::ExecutionContext::Type_BlockContext: + return 4; } + return 0; } QV4DataCollector::QV4DataCollector(QV4::ExecutionEngine *engine) - : m_engine(engine), m_namesAsObjects(true), m_redundantRefs(true) + : m_engine(engine) { m_values.set(engine, engine->newArrayObject()); } -// TODO: Directly call addRef() once we don't need to support redundantRefs anymore -QV4DataCollector::Ref QV4DataCollector::collect(const QV4::ScopedValue &value) +QV4DataCollector::Ref QV4DataCollector::addValueRef(const QV4::ScopedValue &value) { - Ref ref = addRef(value); - if (m_redundantRefs) - m_collectedRefs.append(ref); - return ref; + return addRef(value); } const QV4::Object *collectProperty(const QV4::ScopedValue &value, QV4::ExecutionEngine *engine, @@ -158,15 +154,12 @@ const QV4::Object *collectProperty(const QV4::ScopedValue &value, QV4::Execution int numProperties = 0; QV4::ObjectIterator it(scope, o, QV4::ObjectIterator::EnumerableOnly); QV4::PropertyAttributes attrs; - uint index; - QV4::ScopedProperty p(scope); - QV4::ScopedString name(scope); + QV4::ScopedPropertyKey name(scope); while (true) { - it.next(name.getRef(), &index, p, &attrs); - if (attrs.isEmpty()) + name = it.next(nullptr, &attrs); + if (!name->isValid()) break; - else - ++numProperties; + ++numProperties; } dict.insert(valueKey, numProperties); return o; @@ -192,61 +185,21 @@ const QV4::Object *collectProperty(const QV4::ScopedValue &value, QV4::Execution } } -QJsonObject QV4DataCollector::lookupRef(Ref ref, bool deep) +QJsonObject QV4DataCollector::lookupRef(Ref ref) { QJsonObject dict; - if (m_namesAsObjects) { - if (lookupSpecialRef(ref, &dict)) - return dict; - } - - if (m_redundantRefs) - deep = true; - dict.insert(QStringLiteral("handle"), qint64(ref)); QV4::Scope scope(engine()); QV4::ScopedValue value(scope, getValue(ref)); const QV4::Object *object = collectProperty(value, engine(), dict); - if (deep && object) + if (object) dict.insert(QStringLiteral("properties"), collectProperties(object)); return dict; } -// TODO: Drop this method once we don't need to support namesAsObjects anymore -QV4DataCollector::Ref QV4DataCollector::addFunctionRef(const QString &functionName) -{ - Q_ASSERT(m_namesAsObjects); - Ref ref = addRef(QV4::Primitive::emptyValue(), false); - - QJsonObject dict; - dict.insert(QStringLiteral("handle"), qint64(ref)); - dict.insert(QStringLiteral("type"), QStringLiteral("function")); - dict.insert(QStringLiteral("name"), functionName); - m_specialRefs.insert(ref, dict); - m_collectedRefs.append(ref); - - return ref; -} - -// TODO: Drop this method once we don't need to support namesAsObjects anymore -QV4DataCollector::Ref QV4DataCollector::addScriptRef(const QString &scriptName) -{ - Q_ASSERT(m_namesAsObjects); - Ref ref = addRef(QV4::Primitive::emptyValue(), false); - - QJsonObject dict; - dict.insert(QStringLiteral("handle"), qint64(ref)); - dict.insert(QStringLiteral("type"), QStringLiteral("script")); - dict.insert(QStringLiteral("name"), scriptName); - m_specialRefs.insert(ref, dict); - m_collectedRefs.append(ref); - - return ref; -} - bool QV4DataCollector::isValidRef(QV4DataCollector::Ref ref) const { QV4::Scope scope(engine()); @@ -268,12 +221,12 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) Refs collectedRefs; QV4::ScopedValue v(scope); - QV4::InternalClass *ic = ctxt->internalClass(); + QV4::Heap::InternalClass *ic = ctxt->internalClass(); for (uint i = 0; i < ic->size; ++i) { - QString name = ic->nameMap[i]->string; + QString name = ic->keyAt(i); names.append(name); v = static_cast<QV4::Heap::CallContext *>(ctxt->d())->locals[i]; - collectedRefs.append(collect(v)); + collectedRefs.append(addValueRef(v)); } Q_ASSERT(names.size() == collectedRefs.size()); @@ -284,13 +237,7 @@ bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) } } - Ref scopeObjectRef = addRef(scopeObject); - if (m_redundantRefs) { - dict->insert(QStringLiteral("ref"), qint64(scopeObjectRef)); - m_collectedRefs.append(scopeObjectRef); - } else { - *dict = lookupRef(scopeObjectRef, true); - } + *dict = lookupRef(addRef(scopeObject)); return true; } @@ -306,13 +253,8 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int QJsonObject frame; frame[QLatin1String("index")] = frameNr; frame[QLatin1String("debuggerFrame")] = false; - if (m_namesAsObjects) { - frame[QLatin1String("func")] = toRef(addFunctionRef(stackFrame.function)); - frame[QLatin1String("script")] = toRef(addScriptRef(stackFrame.source)); - } else { - frame[QLatin1String("func")] = stackFrame.function; - frame[QLatin1String("script")] = stackFrame.source; - } + frame[QLatin1String("func")] = stackFrame.function; + frame[QLatin1String("script")] = stackFrame.source; frame[QLatin1String("line")] = stackFrame.line - 1; if (stackFrame.column >= 0) frame[QLatin1String("column")] = stackFrame.column; @@ -330,7 +272,7 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int if (ctxt) { QV4::ScopedValue o(scope, ctxt->d()->activation); - frame[QLatin1String("receiver")] = toRef(collect(o)); + frame[QLatin1String("receiver")] = toRef(addValueRef(o)); } // Only type and index are used by Qt Creator, so we keep it easy: @@ -351,30 +293,9 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int return frame; } -// TODO: Drop this method once we don't need to support redundantRefs anymore -QJsonArray QV4DataCollector::flushCollectedRefs() -{ - Q_ASSERT(m_redundantRefs); - 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, true)); - } - - m_collectedRefs.clear(); - return refs; -} - void QV4DataCollector::clear() { m_values.set(engine(), engine()->newArrayObject()); - m_collectedRefs.clear(); - m_specialRefs.clear(); - m_namesAsObjects = true; - m_redundantRefs = true; } QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicate) @@ -394,18 +315,18 @@ QV4DataCollector::Ref QV4DataCollector::addRef(QV4::Value value, bool deduplicat { std::swap(*hasExceptionLoc, hadException); } }; - // if we wouldn't do this, the putIndexed won't work. + // if we wouldn't do this, the put won't work. ExceptionStateSaver resetExceptionState(engine()); QV4::Scope scope(engine()); QV4::ScopedObject array(scope, m_values.value()); if (deduplicate) { for (Ref i = 0; i < array->getLength(); ++i) { - if (array->getIndexed(i) == value.rawValue() && !m_specialRefs.contains(i)) + if (array->get(i) == value.rawValue()) return i; } } Ref ref = array->getLength(); - array->putIndexed(ref, value); + array->put(ref, value); Q_ASSERT(array->getLength() - 1 == ref); return ref; } @@ -415,23 +336,39 @@ QV4::ReturnedValue QV4DataCollector::getValue(Ref ref) QV4::Scope scope(engine()); QV4::ScopedObject array(scope, m_values.value()); Q_ASSERT(ref < array->getLength()); - return array->getIndexed(ref, nullptr); + return array->get(ref, nullptr); } -// TODO: Drop this method once we don't need to support namesAsObjects anymore -bool QV4DataCollector::lookupSpecialRef(Ref ref, QJsonObject *dict) +class CapturePreventer { - Q_ASSERT(m_namesAsObjects); - SpecialRefs::const_iterator it = m_specialRefs.constFind(ref); - if (it == m_specialRefs.cend()) - return false; +public: + CapturePreventer(QV4::ExecutionEngine *engine) + { + if (QQmlEngine *e = engine->qmlEngine()) { + m_engine = QQmlEnginePrivate::get(e); + m_capture = m_engine->propertyCapture; + m_engine->propertyCapture = nullptr; + } + } - *dict = it.value(); - return true; -} + ~CapturePreventer() + { + if (m_engine && m_capture) { + Q_ASSERT(!m_engine->propertyCapture); + m_engine->propertyCapture = m_capture; + } + } + +private: + QQmlEnginePrivate *m_engine = nullptr; + QQmlPropertyCapture *m_capture = nullptr; +}; QJsonArray QV4DataCollector::collectProperties(const QV4::Object *object) { + CapturePreventer capturePreventer(engine()); + Q_UNUSED(capturePreventer); + QJsonArray res; QV4::Scope scope(engine()); @@ -459,8 +396,6 @@ 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_redundantRefs) - m_collectedRefs.append(ref); } collectProperty(value, engine(), dict); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h index 5494e10e9a..bc178fa2db 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -67,42 +67,27 @@ public: QV4DataCollector(QV4::ExecutionEngine *engine); - Ref collect(const QV4::ScopedValue &value); // only for redundantRefs - Ref addFunctionRef(const QString &functionName); // only for namesAsObjects - Ref addScriptRef(const QString &scriptName); // only for namesAsObjects - - void setNamesAsObjects(bool namesAsObjects) { m_namesAsObjects = namesAsObjects; } - bool namesAsObjects() const { return m_namesAsObjects; } - - void setRedundantRefs(bool redundantRefs) { m_redundantRefs = redundantRefs; } - bool redundantRefs() const { return m_redundantRefs; } + Ref addValueRef(const QV4::ScopedValue &value); bool isValidRef(Ref ref) const; - QJsonObject lookupRef(Ref ref, bool deep); + QJsonObject lookupRef(Ref ref); 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(); // only for redundantRefs void clear(); private: Ref addRef(QV4::Value value, bool deduplicate = true); QV4::ReturnedValue getValue(Ref ref); - bool lookupSpecialRef(Ref ref, QJsonObject *dict); // only for namesAsObjects QJsonArray collectProperties(const QV4::Object *object); QJsonObject collectAsJson(const QString &name, const QV4::ScopedValue &value); void collectArgumentsInContext(); QV4::ExecutionEngine *m_engine; - Refs m_collectedRefs; // only for redundantRefs QV4::PersistentValue m_values; - typedef QHash<Ref, QJsonObject> SpecialRefs; // only for namesAsObjects - SpecialRefs m_specialRefs; // only for namesAsObjects - bool m_namesAsObjects; - bool m_redundantRefs; }; QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp index a1ed211a55..5521e7628b 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp @@ -70,7 +70,7 @@ QV4Debugger::QV4Debugger(QV4::ExecutionEngine *engine) , m_pauseRequested(false) , m_haveBreakPoints(false) , m_breakOnThrow(false) - , m_returnedValue(engine, QV4::Primitive::undefinedValue()) + , m_returnedValue(engine, QV4::Value::undefinedValue()) , m_gatherSources(nullptr) , m_runningJob(nullptr) , m_collector(engine) @@ -157,7 +157,7 @@ void QV4Debugger::clearPauseRequest() QV4Debugger::ExecutionState QV4Debugger::currentExecutionState() const { ExecutionState state; - state.fileName = getFunction()->sourceFile(); + state.fileName = QUrl(getFunction()->sourceFile()).fileName(); state.lineNumber = engine()->currentStackFrame->lineNumber(); return state; @@ -288,7 +288,7 @@ void QV4Debugger::pauseAndWait(PauseReason reason) bool QV4Debugger::reallyHitTheBreakPoint(const QString &filename, int linenr) { QHash<BreakPoint, QString>::iterator it = m_breakPoints.find( - BreakPoint(filename.mid(filename.lastIndexOf('/') + 1), linenr)); + BreakPoint(QUrl(filename).fileName(), linenr)); if (it == m_breakPoints.end()) return false; QString condition = it.value(); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp index 7950d21612..b424ef9f6c 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -65,7 +65,7 @@ void JavaScriptJob::run() QV4::Scope scope(engine); QV4::ScopedContext ctx(scope, engine->currentStackFrame ? engine->currentContext() - : engine->rootContext()); + : engine->scriptContext()); QObject scopeObject; QV4::CppStackFrame *frame = engine->currentStackFrame; @@ -103,7 +103,7 @@ void JavaScriptJob::run() } } - QV4::Script script(ctx, QV4::Compiler::EvalCode, this->script); + QV4::Script script(ctx, QV4::Compiler::ContextType::Eval, this->script); if (const QV4::Function *function = frame ? frame->v4Function : engine->globalCode) script.strictMode = function->isStrict(); @@ -150,7 +150,6 @@ void BacktraceJob::run() result.insert(QStringLiteral("toFrame"), fromFrame + frameArray.size()); result.insert(QStringLiteral("frames"), frameArray); } - flushRedundantRefs(); } FrameJob::FrameJob(QV4DataCollector *collector, int frameNr) : @@ -165,7 +164,6 @@ void FrameJob::run() success = false; } else { result = collector->buildFrame(frames[frameNr], frameNr); - flushRedundantRefs(); success = true; } } @@ -195,7 +193,6 @@ void ScopeJob::run() result[QLatin1String("index")] = scopeNr; result[QLatin1String("frameIndex")] = frameNr; result[QLatin1String("object")] = object; - flushRedundantRefs(); } bool ScopeJob::wasSuccessful() const @@ -228,9 +225,8 @@ void ValueLookupJob::run() exception = QString::fromLatin1("Invalid Ref: %1").arg(ref); break; } - result[QString::number(ref)] = collector->lookupRef(ref, true); + result[QString::number(ref)] = collector->lookupRef(ref); } - flushRedundantRefs(); } const QString &ValueLookupJob::exceptionMessage() const @@ -249,9 +245,7 @@ void ExpressionEvalJob::handleResult(QV4::ScopedValue &value) { if (hasExeption()) exception = value->toQStringNoThrow(); - result = collector->lookupRef(collector->collect(value), true); - if (collector->redundantRefs()) - collectedRefs = collector->flushCollectedRefs(); + result = collector->lookupRef(collector->addValueRef(value)); } const QString &ExpressionEvalJob::exceptionMessage() const @@ -264,13 +258,6 @@ const QJsonObject &ExpressionEvalJob::returnValue() const return result; } -// TODO: Drop this method once we don't need to support redundantRefs anymore -const QJsonArray &ExpressionEvalJob::refs() const -{ - Q_ASSERT(collector->redundantRefs()); - return collectedRefs; -} - GatherSourcesJob::GatherSourcesJob(QV4::ExecutionEngine *engine) : engine(engine) {} diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h index eca8710e15..d1c7495863 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.h @@ -78,24 +78,10 @@ class CollectJob : public QV4DebugJob protected: QV4DataCollector *collector; QJsonObject result; - QJsonArray collectedRefs; // only for redundantRefs - - void flushRedundantRefs() - { - if (collector->redundantRefs()) - collectedRefs = collector->flushCollectedRefs(); - } public: CollectJob(QV4DataCollector *collector) : collector(collector) {} const QJsonObject &returnValue() const { return result; } - - // TODO: Drop this method once we don't need to support redundantRefs anymore - const QJsonArray &refs() const - { - Q_ASSERT(collector->redundantRefs()); - return collectedRefs; - } }; class BacktraceJob: public CollectJob @@ -146,7 +132,6 @@ class ExpressionEvalJob: public JavaScriptJob QV4DataCollector *collector; QString exception; QJsonObject result; - QJsonArray collectedRefs; // only for redundantRefs public: ExpressionEvalJob(QV4::ExecutionEngine *engine, int frameNr, int context, @@ -154,7 +139,6 @@ public: void handleResult(QV4::ScopedValue &value) override; const QString &exceptionMessage() const; const QJsonObject &returnValue() const; - const QJsonArray &refs() const; // only for redundantRefs }; class GatherSourcesJob: public QV4DebugJob diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp index 32de8e9027..5866163ca6 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp @@ -67,21 +67,21 @@ const char *const V4_PAUSE = "interrupt"; QT_BEGIN_NAMESPACE -class V8CommandHandler; -class UnknownV8CommandHandler; +class V4CommandHandler; +class UnknownV4CommandHandler; using QQmlDebugPacket = QVersionedPacket<QQmlDebugConnector>; int QV4DebugServiceImpl::sequence = 0; -class V8CommandHandler +class V4CommandHandler { public: - V8CommandHandler(const QString &command) + V4CommandHandler(const QString &command) : cmd(command) {} - virtual ~V8CommandHandler() + virtual ~V4CommandHandler() {} QString command() const { return cmd; } @@ -122,21 +122,6 @@ protected: response.insert(QStringLiteral("running"), debugService->debuggerAgent.isRunning()); } - QV4DataCollector *saneCollector(QV4Debugger *debugger) - { - QV4DataCollector *collector = debugger->collector(); - collector->setNamesAsObjects(debugService->clientRequiresNamesAsObjects()); - collector->setRedundantRefs(debugService->clientRequiresRedundantRefs()); - return collector; - } - - // TODO: drop this method once we don't need to support redundantRefs anymore. - void addRefs(const QJsonArray &refs) - { - Q_ASSERT(debugService->clientRequiresRedundantRefs()); - response.insert(QStringLiteral("refs"), refs); - } - void createErrorResponse(const QString &msg) { QJsonValue command = req.value(QLatin1String("command")); @@ -158,10 +143,10 @@ protected: QJsonObject response; }; -class UnknownV8CommandHandler: public V8CommandHandler +class UnknownV4CommandHandler: public V4CommandHandler { public: - UnknownV8CommandHandler(): V8CommandHandler(QString()) {} + UnknownV4CommandHandler(): V4CommandHandler(QString()) {} void handleRequest() override { @@ -173,10 +158,10 @@ public: }; namespace { -class V8VersionRequest: public V8CommandHandler +class V4VersionRequest: public V4CommandHandler { public: - V8VersionRequest(): V8CommandHandler(QStringLiteral("version")) {} + V4VersionRequest(): V4CommandHandler(QStringLiteral("version")) {} void handleRequest() override { @@ -189,98 +174,137 @@ public: QLatin1String("this is not V8, this is V4 in Qt " QT_VERSION_STR)); body.insert(QStringLiteral("UnpausedEvaluate"), true); body.insert(QStringLiteral("ContextEvaluate"), true); + body.insert(QStringLiteral("ChangeBreakpoint"), true); addBody(body); } }; -class V8SetBreakPointRequest: public V8CommandHandler +class V4BreakPointRequest: public V4CommandHandler { public: - V8SetBreakPointRequest(): V8CommandHandler(QStringLiteral("setbreakpoint")) {} + V4BreakPointRequest(const QString &name): V4CommandHandler(name) {} - void handleRequest() override + void handleRequest() final { + // Other types are currently not supported + m_type = QStringLiteral("scriptRegExp"); + // decypher the payload: - QJsonObject args = req.value(QLatin1String("arguments")).toObject(); - if (args.isEmpty()) + m_args = req.value(QLatin1String("arguments")).toObject(); + if (m_args.isEmpty()) { + createErrorResponse(QStringLiteral("breakpoint request with empty arguments object")); return; + } - QString type = args.value(QLatin1String("type")).toString(); + const int id = handleBreakPointRequest(); + if (id < 0) { + createErrorResponse(m_error); + } else { + // response: + addCommand(); + addRequestSequence(); + addSuccess(true); + addRunning(); + QJsonObject body; + body.insert(QStringLiteral("type"), m_type); + body.insert(QStringLiteral("breakpoint"), id); + addBody(body); + } + } + +protected: + virtual int handleBreakPointRequest() = 0; + + QJsonObject m_args; + QString m_type; + QString m_error; +}; + +class V4SetBreakPointRequest: public V4BreakPointRequest +{ +public: + V4SetBreakPointRequest(): V4BreakPointRequest(QStringLiteral("setbreakpoint")) {} + + int handleBreakPointRequest() final + { + // decypher the payload: + const QString type = m_args.value(QLatin1String("type")).toString(); if (type != QLatin1String("scriptRegExp")) { - createErrorResponse(QStringLiteral("breakpoint type \"%1\" is not implemented").arg(type)); - return; + m_error = QStringLiteral("breakpoint type \"%1\" is not implemented").arg(type); + return -1; } - QString fileName = args.value(QLatin1String("target")).toString(); + const QString fileName = m_args.value(QLatin1String("target")).toString(); if (fileName.isEmpty()) { - createErrorResponse(QStringLiteral("breakpoint has no file name")); - return; + m_error = QStringLiteral("breakpoint has no file name"); + return -1; } - int line = args.value(QLatin1String("line")).toInt(-1); + + const int line = m_args.value(QLatin1String("line")).toInt(-1); if (line < 0) { - createErrorResponse(QStringLiteral("breakpoint has an invalid line number")); - return; + m_error = QStringLiteral("breakpoint has an invalid line number"); + return -1; } - bool enabled = args.value(QStringLiteral("enabled")).toBool(true); - QString condition = args.value(QStringLiteral("condition")).toString(); + const bool enabled = m_args.value(QStringLiteral("enabled")).toBool(true); + const QString condition = m_args.value(QStringLiteral("condition")).toString(); // set the break point: - int id = debugService->debuggerAgent.addBreakPoint(fileName, line + 1, enabled, condition); + return debugService->debuggerAgent.addBreakPoint(fileName, line + 1, enabled, condition); - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - QJsonObject body; - body.insert(QStringLiteral("type"), type); - body.insert(QStringLiteral("breakpoint"), id); // It's undocumented, but V8 sends back an actual_locations array too. However, our // Debugger currently doesn't tell us when it resolved a breakpoint, so we'll leave them // pending until the breakpoint is hit for the first time. - addBody(body); } }; -class V8ClearBreakPointRequest: public V8CommandHandler +class V4ClearBreakPointRequest: public V4BreakPointRequest { public: - V8ClearBreakPointRequest(): V8CommandHandler(QStringLiteral("clearbreakpoint")) {} + V4ClearBreakPointRequest(): V4BreakPointRequest(QStringLiteral("clearbreakpoint")) {} - void handleRequest() override + int handleBreakPointRequest() final { - // decypher the payload: - QJsonObject args = req.value(QLatin1String("arguments")).toObject(); - if (args.isEmpty()) - return; + const int id = m_args.value(QLatin1String("breakpoint")).toInt(-1); + if (id < 0) + m_error = QStringLiteral("breakpoint has an invalid number"); + else // remove the break point: + debugService->debuggerAgent.removeBreakPoint(id); - int id = args.value(QLatin1String("breakpoint")).toInt(-1); + return id; + } +}; + +class V4ChangeBreakPointRequest: public V4BreakPointRequest +{ +public: + V4ChangeBreakPointRequest(): V4BreakPointRequest(QStringLiteral("changebreakpoint")) {} + + int handleBreakPointRequest() final + { + const int id = m_args.value(QLatin1String("breakpoint")).toInt(-1); if (id < 0) { - createErrorResponse(QStringLiteral("breakpoint has an invalid number")); - return; + m_error = QStringLiteral("breakpoint has an invalid number"); + return id; } - // remove the break point: - debugService->debuggerAgent.removeBreakPoint(id); + const QJsonValue enabled = m_args.value(QLatin1String("enabled")); + if (!enabled.isBool()) { + m_error = QStringLiteral("missing bool \"enabled\" in breakpoint change request"); + return -1; + } - // response: - addCommand(); - addRequestSequence(); - addSuccess(true); - addRunning(); - QJsonObject body; - body.insert(QStringLiteral("type"), QStringLiteral("scriptRegExp")); - body.insert(QStringLiteral("breakpoint"), id); - addBody(body); + // enable or disable the break point: + debugService->debuggerAgent.enableBreakPoint(id, enabled.toBool()); + return id; } }; -class V8BacktraceRequest: public V8CommandHandler +class V4BacktraceRequest: public V4CommandHandler { public: - V8BacktraceRequest(): V8CommandHandler(QStringLiteral("backtrace")) {} + V4BacktraceRequest(): V4CommandHandler(QStringLiteral("backtrace")) {} void handleRequest() override { @@ -297,7 +321,7 @@ public: return; } - BacktraceJob job(saneCollector(debugger), fromFrame, toFrame); + BacktraceJob job(debugger->collector(), fromFrame, toFrame); debugger->runInEngine(&job); // response: @@ -306,15 +330,13 @@ public: addSuccess(true); addRunning(); addBody(job.returnValue()); - if (debugService->clientRequiresRedundantRefs()) - addRefs(job.refs()); } }; -class V8FrameRequest: public V8CommandHandler +class V4FrameRequest: public V4CommandHandler { public: - V8FrameRequest(): V8CommandHandler(QStringLiteral("frame")) {} + V4FrameRequest(): V4CommandHandler(QStringLiteral("frame")) {} void handleRequest() override { @@ -334,7 +356,7 @@ public: return; } - FrameJob job(saneCollector(debugger), frameNr); + FrameJob job(debugger->collector(), frameNr); debugger->runInEngine(&job); if (!job.wasSuccessful()) { createErrorResponse(QStringLiteral("frame retrieval failed")); @@ -349,15 +371,13 @@ public: addSuccess(true); addRunning(); addBody(job.returnValue()); - if (debugService->clientRequiresRedundantRefs()) - addRefs(job.refs()); } }; -class V8ScopeRequest: public V8CommandHandler +class V4ScopeRequest: public V4CommandHandler { public: - V8ScopeRequest(): V8CommandHandler(QStringLiteral("scope")) {} + V4ScopeRequest(): V4CommandHandler(QStringLiteral("scope")) {} void handleRequest() override { @@ -382,7 +402,7 @@ public: return; } - ScopeJob job(saneCollector(debugger), frameNr, scopeNr); + ScopeJob job(debugger->collector(), frameNr, scopeNr); debugger->runInEngine(&job); if (!job.wasSuccessful()) { createErrorResponse(QStringLiteral("scope retrieval failed")); @@ -395,15 +415,13 @@ public: addSuccess(true); addRunning(); addBody(job.returnValue()); - if (debugService->clientRequiresRedundantRefs()) - addRefs(job.refs()); } }; -class V8LookupRequest: public V8CommandHandler +class V4LookupRequest: public V4CommandHandler { public: - V8LookupRequest(): V8CommandHandler(QStringLiteral("lookup")) {} + V4LookupRequest(): V4CommandHandler(QStringLiteral("lookup")) {} void handleRequest() override { @@ -424,7 +442,7 @@ public: debugger = debuggers.first(); } - ValueLookupJob job(handles, saneCollector(debugger)); + ValueLookupJob job(handles, debugger->collector()); debugger->runInEngine(&job); if (!job.exceptionMessage().isEmpty()) { createErrorResponse(job.exceptionMessage()); @@ -435,16 +453,14 @@ public: addSuccess(true); addRunning(); addBody(job.returnValue()); - if (debugService->clientRequiresRedundantRefs()) - addRefs(job.refs()); } } }; -class V8ContinueRequest: public V8CommandHandler +class V4ContinueRequest: public V4CommandHandler { public: - V8ContinueRequest(): V8CommandHandler(QStringLiteral("continue")) {} + V4ContinueRequest(): V4CommandHandler(QStringLiteral("continue")) {} void handleRequest() override { @@ -487,10 +503,10 @@ public: } }; -class V8DisconnectRequest: public V8CommandHandler +class V4DisconnectRequest: public V4CommandHandler { public: - V8DisconnectRequest(): V8CommandHandler(QStringLiteral("disconnect")) {} + V4DisconnectRequest(): V4CommandHandler(QStringLiteral("disconnect")) {} void handleRequest() override { @@ -505,10 +521,10 @@ public: } }; -class V8SetExceptionBreakRequest: public V8CommandHandler +class V4SetExceptionBreakRequest: public V4CommandHandler { public: - V8SetExceptionBreakRequest(): V8CommandHandler(QStringLiteral("setexceptionbreak")) {} + V4SetExceptionBreakRequest(): V4CommandHandler(QStringLiteral("setexceptionbreak")) {} void handleRequest() override { @@ -545,10 +561,10 @@ public: } }; -class V8ScriptsRequest: public V8CommandHandler +class V4ScriptsRequest: public V4CommandHandler { public: - V8ScriptsRequest(): V8CommandHandler(QStringLiteral("scripts")) {} + V4ScriptsRequest(): V4CommandHandler(QStringLiteral("scripts")) {} void handleRequest() override { @@ -617,10 +633,10 @@ public: // } // // The "value" key in "body" is the result of evaluating the expression in the request. -class V8EvaluateRequest: public V8CommandHandler +class V4EvaluateRequest: public V4CommandHandler { public: - V8EvaluateRequest(): V8CommandHandler(QStringLiteral("evaluate")) {} + V4EvaluateRequest(): V4CommandHandler(QStringLiteral("evaluate")) {} void handleRequest() override { @@ -645,7 +661,7 @@ public: } ExpressionEvalJob job(debugger->engine(), frame, context, expression, - saneCollector(debugger)); + debugger->collector()); debugger->runInEngine(&job); if (job.hasExeption()) { createErrorResponse(job.exceptionMessage()); @@ -655,44 +671,43 @@ public: addSuccess(true); addRunning(); addBody(job.returnValue()); - if (debugService->clientRequiresRedundantRefs()) - addRefs(job.refs()); } } }; } // anonymous namespace -void QV4DebugServiceImpl::addHandler(V8CommandHandler* handler) +void QV4DebugServiceImpl::addHandler(V4CommandHandler* handler) { handlers[handler->command()] = handler; } -V8CommandHandler *QV4DebugServiceImpl::v8CommandHandler(const QString &command) const +V4CommandHandler *QV4DebugServiceImpl::v4CommandHandler(const QString &command) const { - V8CommandHandler *handler = handlers.value(command, 0); + V4CommandHandler *handler = handlers.value(command, 0); if (handler) return handler; else - return unknownV8CommandHandler.data(); + return unknownV4CommandHandler.data(); } QV4DebugServiceImpl::QV4DebugServiceImpl(QObject *parent) : QQmlConfigurableDebugService<QV4DebugService>(1, parent), - debuggerAgent(this), theSelectedFrame(0), redundantRefs(true), namesAsObjects(true), - unknownV8CommandHandler(new UnknownV8CommandHandler) + debuggerAgent(this), theSelectedFrame(0), + unknownV4CommandHandler(new UnknownV4CommandHandler) { - addHandler(new V8VersionRequest); - addHandler(new V8SetBreakPointRequest); - addHandler(new V8ClearBreakPointRequest); - addHandler(new V8BacktraceRequest); - addHandler(new V8FrameRequest); - addHandler(new V8ScopeRequest); - addHandler(new V8LookupRequest); - addHandler(new V8ContinueRequest); - addHandler(new V8DisconnectRequest); - addHandler(new V8SetExceptionBreakRequest); - addHandler(new V8ScriptsRequest); - addHandler(new V8EvaluateRequest); + addHandler(new V4VersionRequest); + addHandler(new V4SetBreakPointRequest); + addHandler(new V4ClearBreakPointRequest); + addHandler(new V4ChangeBreakPointRequest); + addHandler(new V4BacktraceRequest); + addHandler(new V4FrameRequest); + addHandler(new V4ScopeRequest); + addHandler(new V4LookupRequest); + addHandler(new V4ContinueRequest); + addHandler(new V4DisconnectRequest); + addHandler(new V4SetExceptionBreakRequest); + addHandler(new V4ScriptsRequest); + addHandler(new V4EvaluateRequest); } QV4DebugServiceImpl::~QV4DebugServiceImpl() @@ -782,12 +797,7 @@ void QV4DebugServiceImpl::messageReceived(const QByteArray &message) if (type == V4_CONNECT) { QJsonObject parameters = QJsonDocument::fromJson(payload).object(); - namesAsObjects = true; - redundantRefs = true; - if (parameters.contains("namesAsObjects")) - namesAsObjects = parameters.value("namesAsObjects").toBool(); - if (parameters.contains("redundantRefs")) - redundantRefs = parameters.value("redundantRefs").toBool(); + Q_UNUSED(parameters); // For future protocol changes emit messageToClient(name(), packMessage(type)); stopWaiting(); @@ -805,10 +815,10 @@ void QV4DebugServiceImpl::messageReceived(const QByteArray &message) else breakOnSignals.removeOne(signalName); } else if (type == "v8request") { - handleV8Request(payload); + handleV4Request(payload); } else if (type == V4_DISCONNECT) { TRACE_PROTOCOL(qDebug() << "... payload:" << payload.constData()); - handleV8Request(payload); + handleV4Request(payload); } else { sendSomethingToSomebody(type, 0); } @@ -823,7 +833,7 @@ void QV4DebugServiceImpl::sendSomethingToSomebody(const char *type, int magicNum emit messageToClient(name(), packMessage(type, rs.data())); } -void QV4DebugServiceImpl::handleV8Request(const QByteArray &payload) +void QV4DebugServiceImpl::handleV4Request(const QByteArray &payload) { TRACE_PROTOCOL(qDebug() << "v8request, payload:" << payload.constData()); @@ -832,7 +842,7 @@ void QV4DebugServiceImpl::handleV8Request(const QByteArray &payload) QJsonValue type = o.value(QLatin1String("type")); if (type.toString() == QLatin1String("request")) { QJsonValue command = o.value(QLatin1String("command")); - V8CommandHandler *h = v8CommandHandler(command.toString()); + V4CommandHandler *h = v4CommandHandler(command.toString()); if (h) h->handle(o, this); } @@ -846,11 +856,11 @@ QByteArray QV4DebugServiceImpl::packMessage(const QByteArray &command, const QBy return rs.data(); } -void QV4DebugServiceImpl::send(QJsonObject v8Payload) +void QV4DebugServiceImpl::send(QJsonObject v4Payload) { - v8Payload[QLatin1String("seq")] = sequence++; + v4Payload[QLatin1String("seq")] = sequence++; QJsonDocument doc; - doc.setObject(v8Payload); + doc.setObject(v4Payload); #ifdef NO_PROTOCOL_TRACING QByteArray responseData = doc.toJson(QJsonDocument::Compact); #else diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h index 5401956994..d0b104dfad 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h @@ -64,15 +64,15 @@ QT_BEGIN_NAMESPACE namespace QV4 { struct ExecutionEngine; } class VariableCollector; -class V8CommandHandler; -class UnknownV8CommandHandler; +class V4CommandHandler; +class UnknownV4CommandHandler; class QV4DebugServiceImpl; class QV4DebugServiceImpl : public QQmlConfigurableDebugService<QV4DebugService> { Q_OBJECT public: - explicit QV4DebugServiceImpl(QObject *parent = 0); + explicit QV4DebugServiceImpl(QObject *parent = nullptr); ~QV4DebugServiceImpl() override; void engineAdded(QJSEngine *engine) override; @@ -81,14 +81,11 @@ public: void stateAboutToBeChanged(State state) override; void signalEmitted(const QString &signal) override; - void send(QJsonObject v8Payload); + void send(QJsonObject v4Payload); int selectedFrame() const; void selectFrame(int frameNr); - bool clientRequiresRedundantRefs() const { return redundantRefs; } - bool clientRequiresNamesAsObjects() const { return namesAsObjects; } - QV4DebuggerAgent debuggerAgent; protected: @@ -98,22 +95,19 @@ protected: private: friend class QQmlDebuggerServiceFactory; - void handleV8Request(const QByteArray &payload); + void handleV4Request(const QByteArray &payload); static QByteArray packMessage(const QByteArray &command, const QByteArray &message = QByteArray()); void processCommand(const QByteArray &command, const QByteArray &data); - V8CommandHandler *v8CommandHandler(const QString &command) const; + V4CommandHandler *v4CommandHandler(const QString &command) const; QStringList breakOnSignals; static int sequence; int theSelectedFrame; - bool redundantRefs; - bool namesAsObjects; - - void addHandler(V8CommandHandler* handler); - QHash<QString, V8CommandHandler*> handlers; - QScopedPointer<UnknownV8CommandHandler> unknownV8CommandHandler; + void addHandler(V4CommandHandler* handler); + QHash<QString, V4CommandHandler*> handlers; + QScopedPointer<UnknownV4CommandHandler> unknownV4CommandHandler; }; QT_END_NAMESPACE |