diff options
Diffstat (limited to 'src/plugins/qmltooling/qmldbg_debugger')
14 files changed, 440 insertions, 524 deletions
diff --git a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro index f3f8a21ff8..2d8f0ceda2 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro +++ b/src/plugins/qmltooling/qmldbg_debugger/qmldbg_debugger.pro @@ -12,8 +12,6 @@ SOURCES += \ $$PWD/qv4debugjob.cpp HEADERS += \ - $$PWD/../shared/qqmlconfigurabledebugservice.h \ - $$PWD/../shared/qqmldebugpacket.h \ $$PWD/qqmldebuggerservicefactory.h \ $$PWD/qqmlenginedebugservice.h \ $$PWD/qqmlwatcher.h \ @@ -23,9 +21,6 @@ HEADERS += \ $$PWD/qv4datacollector.h \ $$PWD/qv4debugjob.h -INCLUDEPATH += $$PWD \ - $$PWD/../shared - OTHER_FILES += \ $$PWD/qqmldebuggerservice.json diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp index 9315adf4ce..3851cdc71f 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmldebuggerservicefactory.cpp @@ -52,7 +52,7 @@ QQmlDebugService *QQmlDebuggerServiceFactory::create(const QString &key) if (key == QV4DebugServiceImpl::s_key) return new QV4DebugServiceImpl(this); - return 0; + return nullptr; } QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp index f0bb4de016..4c104f01de 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.cpp @@ -39,7 +39,6 @@ #include "qqmlenginedebugservice.h" #include "qqmlwatcher.h" -#include "qqmldebugpacket.h" #include <private/qqmldebugstatesdelegate_p.h> #include <private/qqmlboundsignal_p.h> @@ -56,12 +55,52 @@ #include <QtCore/qdebug.h> #include <QtCore/qmetaobject.h> #include <QtCore/qfileinfo.h> +#include <QtCore/qjsonvalue.h> +#include <QtCore/qjsonobject.h> +#include <QtCore/qjsonarray.h> +#include <QtCore/qjsondocument.h> + #include <private/qmetaobject_p.h> +#include <private/qqmldebugconnector_p.h> +#include <private/qversionedpacket_p.h> QT_BEGIN_NAMESPACE +using QQmlDebugPacket = QVersionedPacket<QQmlDebugConnector>; + +class NullDevice : public QIODevice +{ +public: + NullDevice() { open(QIODevice::ReadWrite); } + +protected: + qint64 readData(char *data, qint64 maxlen) final; + qint64 writeData(const char *data, qint64 len) final; +}; + +qint64 NullDevice::readData(char *data, qint64 maxlen) +{ + Q_UNUSED(data); + return maxlen; +} + +qint64 NullDevice::writeData(const char *data, qint64 len) +{ + Q_UNUSED(data); + return len; +} + +// check whether the data can be saved +// (otherwise we assert in QVariant::operator<< when actually saving it) +static bool isSaveable(const QVariant &value) +{ + NullDevice nullDevice; + QDataStream fakeStream(&nullDevice); + return QMetaType::save(fakeStream, static_cast<int>(value.type()), value.constData()); +} + QQmlEngineDebugServiceImpl::QQmlEngineDebugServiceImpl(QObject *parent) : - QQmlEngineDebugService(2, parent), m_watch(new QQmlWatcher(this)), m_statesDelegate(0) + QQmlEngineDebugService(2, parent), m_watch(new QQmlWatcher(this)), m_statesDelegate(nullptr) { connect(m_watch, &QQmlWatcher::propertyChanged, this, &QQmlEngineDebugServiceImpl::propertyChanged); @@ -98,13 +137,7 @@ QDataStream &operator<<(QDataStream &ds, const QQmlEngineDebugServiceImpl::QQmlObjectProperty &data) { ds << (int)data.type << data.name; - // check first whether the data can be saved - // (otherwise we assert in QVariant::operator<<) - QQmlDebugPacket fakeStream; - if (QMetaType::save(fakeStream, data.value.type(), data.value.constData())) - ds << data.value; - else - ds << QVariant(); + ds << (isSaveable(data.value) ? data.value : QVariant()); ds << data.valueTypeName << data.binding << data.hasNotifySignal; return ds; } @@ -208,21 +241,40 @@ QVariant QQmlEngineDebugServiceImpl::valueContents(QVariant value) const return contents; } - if (QQmlValueTypeFactory::isValueType(userType)) { - const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(userType); - if (mo) { - int toStringIndex = mo->indexOfMethod("toString"); - if (toStringIndex != -1) { - QMetaMethod mm = mo->method(toStringIndex); - QMetaType info(userType); - QString s; - if (info.flags() & QMetaType::IsGadget - && mm.invokeOnGadget(value.data(), Q_RETURN_ARG(QString, s))) - return s; + switch (userType) { + case QMetaType::QRect: + case QMetaType::QRectF: + case QMetaType::QPoint: + case QMetaType::QPointF: + case QMetaType::QSize: + case QMetaType::QSizeF: + case QMetaType::QFont: + // Don't call the toString() method on those. The stream operators are better. + return value; + case QMetaType::QJsonValue: + return value.toJsonValue().toVariant(); + case QMetaType::QJsonObject: + return value.toJsonObject().toVariantMap(); + case QMetaType::QJsonArray: + return value.toJsonArray().toVariantList(); + case QMetaType::QJsonDocument: + return value.toJsonDocument().toVariant(); + default: + if (QQmlValueTypeFactory::isValueType(userType)) { + const QMetaObject *mo = QQmlValueTypeFactory::metaObjectForMetaType(userType); + if (mo) { + int toStringIndex = mo->indexOfMethod("toString()"); + if (toStringIndex != -1) { + QMetaMethod mm = mo->method(toStringIndex); + QString s; + if (mm.invokeOnGadget(value.data(), Q_RETURN_ARG(QString, s))) + return s; + } } - } - return value; + if (isSaveable(value)) + return value; + } } if (QQmlMetaType::isQObject(userType)) { @@ -337,6 +389,9 @@ void QQmlEngineDebugServiceImpl::buildObjectList(QDataStream &message, QQmlContext *ctxt, const QList<QPointer<QObject> > &instances) { + if (!ctxt->isValid()) + return; + QQmlContextData *p = QQmlContextData::get(ctxt); QString ctxtName = ctxt->objectName(); @@ -399,11 +454,8 @@ QQmlEngineDebugServiceImpl::objectData(QObject *object) } QQmlContext *context = qmlContext(object); - if (context) { - QQmlContextData *cdata = QQmlContextData::get(context); - if (cdata) - rv.idString = cdata->findObjectId(object); - } + if (context && context->isValid()) + rv.idString = QQmlContextData::get(context)->findObjectId(object); rv.objectName = object->objectName(); rv.objectId = QQmlDebugService::idForObject(object); @@ -564,14 +616,14 @@ void QQmlEngineDebugServiceImpl::processMessage(const QByteArray &message) QObject *object = QQmlDebugService::objectForId(objectId); QQmlContext *context = qmlContext(object); - if (!context) { + if (!context || !context->isValid()) { QQmlEngine *engine = qobject_cast<QQmlEngine *>( QQmlDebugService::objectForId(engineId)); if (engine && m_engines.contains(engine)) context = engine->rootContext(); } QVariant result; - if (context) { + if (context && context->isValid()) { QQmlExpression exprObj(context, object, expr); bool undefined = false; QVariant value = exprObj.evaluate(&undefined); @@ -632,7 +684,7 @@ bool QQmlEngineDebugServiceImpl::setBinding(int objectId, QObject *object = objectForId(objectId); QQmlContext *context = qmlContext(object); - if (object && context) { + if (object && context && context->isValid()) { QQmlProperty property(object, propertyName, context); if (property.isValid()) { @@ -677,7 +729,7 @@ bool QQmlEngineDebugServiceImpl::resetBinding(int objectId, const QString &prope QObject *object = objectForId(objectId); QQmlContext *context = qmlContext(object); - if (object && context) { + if (object && context && context->isValid()) { QStringRef parentPropertyRef(&propertyName); const int idx = parentPropertyRef.indexOf(QLatin1Char('.')); if (idx != -1) @@ -695,8 +747,9 @@ bool QQmlEngineDebugServiceImpl::resetBinding(int objectId, const QString &prope property.reset(); } else { // overwrite with default value - if (QQmlType *objType = QQmlMetaType::qmlType(object->metaObject())) { - if (QObject *emptyObject = objType->create()) { + QQmlType objType = QQmlMetaType::qmlType(object->metaObject()); + if (objType.isValid()) { + if (QObject *emptyObject = objType.create()) { if (emptyObject->property(parentProperty).isValid()) { QVariant defaultValue = QQmlProperty(emptyObject, propertyName).read(); if (defaultValue.isValid()) { @@ -712,7 +765,7 @@ bool QQmlEngineDebugServiceImpl::resetBinding(int objectId, const QString &prope if (hasValidSignal(object, propertyName)) { QQmlProperty property(object, propertyName, context); - QQmlPropertyPrivate::setSignalExpression(property, 0); + QQmlPropertyPrivate::setSignalExpression(property, nullptr); return true; } @@ -731,11 +784,9 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth { QObject *object = objectForId(objectId); QQmlContext *context = qmlContext(object); - if (!object || !context || !context->engine()) + if (!object || !context || !context->isValid()) return false; QQmlContextData *contextData = QQmlContextData::get(context); - if (!contextData) - return false; QQmlPropertyData dummy; QQmlPropertyData *prop = @@ -759,7 +810,7 @@ bool QQmlEngineDebugServiceImpl::setMethodBody(int objectId, const QString &meth QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(object); Q_ASSERT(vmeMetaObject); // the fact we found the property above should guarentee this - QV4::ExecutionEngine *v4 = QV8Engine::getV4(qmlEngine(object)->handle()); + QV4::ExecutionEngine *v4 = qmlEngine(object)->handle(); QV4::Scope scope(v4); int lineNumber = 0; @@ -800,7 +851,8 @@ void QQmlEngineDebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) void QQmlEngineDebugServiceImpl::objectCreated(QJSEngine *engine, QObject *object) { Q_ASSERT(engine); - Q_ASSERT(m_engines.contains(engine)); + if (!m_engines.contains(engine)) + return; int engineId = QQmlDebugService::idForObject(engine); int objectId = QQmlDebugService::idForObject(object); diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h index 2e40eb4de8..c0c24058eb 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlenginedebugservice.h @@ -95,17 +95,17 @@ public: bool hasNotifySignal; }; - void engineAboutToBeAdded(QJSEngine *) Q_DECL_OVERRIDE; - void engineAboutToBeRemoved(QJSEngine *) Q_DECL_OVERRIDE; - void objectCreated(QJSEngine *, QObject *) Q_DECL_OVERRIDE; + void engineAboutToBeAdded(QJSEngine *) override; + void engineAboutToBeRemoved(QJSEngine *) override; + void objectCreated(QJSEngine *, QObject *) override; - void setStatesDelegate(QQmlDebugStatesDelegate *) Q_DECL_OVERRIDE; + void setStatesDelegate(QQmlDebugStatesDelegate *) override; signals: void scheduleMessage(const QByteArray &); protected: - virtual void messageReceived(const QByteArray &) Q_DECL_OVERRIDE; + void messageReceived(const QByteArray &) override; private: friend class QQmlDebuggerServiceFactory; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp index cbbbb2ceb7..86571e6cbe 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qqmlwatcher.cpp @@ -61,12 +61,12 @@ public: QObject *object, int debugId, const QMetaProperty &prop, - QQmlWatcher *parent = 0); + QQmlWatcher *parent = nullptr); QQmlWatchProxy(int id, QQmlExpression *exp, int debugId, - QQmlWatcher *parent = 0); + QQmlWatcher *parent = nullptr); public slots: void notifyValueChanged(); // Needs to be a slot because of QQmlPropertyPrivate::connect() @@ -86,7 +86,7 @@ QQmlWatchProxy::QQmlWatchProxy(int id, QQmlExpression *exp, int debugId, QQmlWatcher *parent) -: QObject(parent), m_id(id), m_watch(parent), m_object(0), m_debugId(debugId), m_expr(exp) +: QObject(parent), m_id(id), m_watch(parent), m_object(nullptr), m_debugId(debugId), m_expr(exp) { QObject::connect(m_expr, &QQmlExpression::valueChanged, this, &QQmlWatchProxy::notifyValueChanged); @@ -97,7 +97,7 @@ QQmlWatchProxy::QQmlWatchProxy(int id, int debugId, const QMetaProperty &prop, QQmlWatcher *parent) -: QObject(parent), m_id(id), m_watch(parent), m_object(object), m_debugId(debugId), m_property(prop), m_expr(0) +: QObject(parent), m_id(id), m_watch(parent), m_object(object), m_debugId(debugId), m_property(prop), m_expr(nullptr) { static int refreshIdx = -1; if(refreshIdx == -1) diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.cpp index e89b7a63d4..506ecb64bb 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> @@ -55,47 +56,39 @@ QT_BEGIN_NAMESPACE -QV4::SimpleCallContext *QV4DataCollector::findContext(int frame) +QV4::CppStackFrame *QV4DataCollector::findFrame(int frame) { - QV4::ExecutionContext *ctx = engine()->currentContext; - while (ctx) { - QV4::SimpleCallContext *cCtxt = ctx->asSimpleCallContext(); - if (cCtxt && cCtxt->d()->v4Function) { - if (frame < 1) - return cCtxt; - --frame; - } - ctx = engine()->parentContext(ctx); + QV4::CppStackFrame *f = engine()->currentStackFrame; + while (f && frame) { + --frame; + f = f->parent; } - - return 0; + return f; } -QV4::Heap::SimpleCallContext *QV4DataCollector::findScope(QV4::ExecutionContext *ctxt, int scope) +QV4::Heap::ExecutionContext *QV4DataCollector::findContext(int frame) { - if (!ctxt) - return 0; + QV4::CppStackFrame *f = findFrame(frame); - QV4::Scope s(ctxt); - QV4::ScopedContext ctx(s, ctxt); + return f ? f->context()->d() : nullptr; +} + +QV4::Heap::ExecutionContext *QV4DataCollector::findScope(QV4::Heap::ExecutionContext *ctx, int scope) +{ for (; scope > 0 && ctx; --scope) - ctx = ctx->d()->outer; + ctx = ctx->outer; - return (ctx && ctx->d()) ? ctx->asSimpleCallContext()->d() : 0; + return ctx; } QVector<QV4::Heap::ExecutionContext::ContextType> QV4DataCollector::getScopeTypes(int frame) { QVector<QV4::Heap::ExecutionContext::ContextType> types; - QV4::Scope scope(engine()); - QV4::SimpleCallContext *sctxt = findContext(frame); - if (!sctxt || sctxt->d()->type < QV4::Heap::ExecutionContext::Type_QmlContext) - return types; + QV4::Heap::ExecutionContext *it = findFrame(frame)->context()->d(); - QV4::ScopedContext it(scope, sctxt); - for (; it; it = it->d()->outer) - types.append(QV4::Heap::ExecutionContext::ContextType(it->d()->type)); + for (; it; it = it->outer) + types.append(QV4::Heap::ExecutionContext::ContextType(it->type)); return types; } @@ -104,58 +97,51 @@ 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_SimpleCallContext: case QV4::Heap::ExecutionContext::Type_CallContext: return 1; case QV4::Heap::ExecutionContext::Type_QmlContext: - default: - return -1; + return 3; + 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, QJsonObject &dict) { QV4::Scope scope(engine); - QV4::ScopedValue typeString(scope, QV4::Runtime::method_typeofValue(engine, value)); + QV4::ScopedValue typeString(scope, QV4::Runtime::TypeofValue::call(engine, value)); dict.insert(QStringLiteral("type"), typeString->toQStringNoThrow()); const QLatin1String valueKey("value"); switch (value->type()) { case QV4::Value::Empty_Type: Q_ASSERT(!"empty Value encountered"); - return 0; + return nullptr; case QV4::Value::Undefined_Type: dict.insert(valueKey, QJsonValue::Undefined); - return 0; + return nullptr; case QV4::Value::Null_Type: - // "null" is not the correct type, but we leave this in until QtC can deal with "object" - dict.insert(QStringLiteral("type"), QStringLiteral("null")); dict.insert(valueKey, QJsonValue::Null); - return 0; + return nullptr; case QV4::Value::Boolean_Type: dict.insert(valueKey, value->booleanValue()); - return 0; + return nullptr; case QV4::Value::Managed_Type: if (const QV4::String *s = value->as<QV4::String>()) { dict.insert(valueKey, s->toQString()); @@ -168,25 +154,22 @@ 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; } else { Q_UNREACHABLE(); } - return 0; + return nullptr; case QV4::Value::Integer_Type: dict.insert(valueKey, value->integerValue()); - return 0; + return nullptr; default: {// double const double val = value->doubleValue(); if (qIsFinite(val)) @@ -197,66 +180,26 @@ const QV4::Object *collectProperty(const QV4::ScopedValue &value, QV4::Execution dict.insert(valueKey, QStringLiteral("-Infinity")); else dict.insert(valueKey, QStringLiteral("Infinity")); - return 0; + return nullptr; } } } -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()); @@ -266,50 +209,35 @@ bool QV4DataCollector::isValidRef(QV4DataCollector::Ref ref) const bool QV4DataCollector::collectScope(QJsonObject *dict, int frameNr, int scopeNr) { - QStringList names; - QV4::Scope scope(engine()); - QV4::Scoped<QV4::CallContext> ctxt(scope, findScope(findContext(frameNr), scopeNr)); + + QV4::Scoped<QV4::ExecutionContext> ctxt(scope, findScope(findContext(frameNr), scopeNr)); if (!ctxt) return false; - Refs collectedRefs; - QV4::ScopedValue v(scope); - int nFormals = ctxt->formalCount(); - for (unsigned i = 0, ei = nFormals; i != ei; ++i) { - QString qName; - if (QV4::Identifier *name = ctxt->formals()[nFormals - i - 1]) - qName = name->string; - names.append(qName); - v = ctxt->argument(i); - collectedRefs.append(collect(v)); - } - - for (unsigned i = 0, ei = ctxt->variableCount(); i != ei; ++i) { - QString qName; - if (QV4::Identifier *name = ctxt->variables()[i]) - qName = name->string; - names.append(qName); - v = ctxt->d()->locals[i]; - collectedRefs.append(collect(v)); - } - QV4::ScopedObject scopeObject(scope, engine()->newObject()); + if (ctxt->d()->type == QV4::Heap::ExecutionContext::Type_CallContext) { + QStringList names; + Refs collectedRefs; + + QV4::ScopedValue v(scope); + QV4::Heap::InternalClass *ic = ctxt->internalClass(); + for (uint i = 0; i < ic->size; ++i) { + QString name = ic->keyAt(i); + names.append(name); + v = static_cast<QV4::Heap::CallContext *>(ctxt->d())->locals[i]; + collectedRefs.append(addValueRef(v)); + } - Q_ASSERT(names.size() == collectedRefs.size()); - QV4::ScopedString propName(scope); - for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) { - propName = engine()->newString(names.at(i)); - scopeObject->put(propName, QV4::Value::fromReturnedValue(getValue(collectedRefs.at(i)))); + Q_ASSERT(names.size() == collectedRefs.size()); + QV4::ScopedString propName(scope); + for (int i = 0, ei = collectedRefs.size(); i != ei; ++i) { + propName = engine()->newString(names.at(i)); + scopeObject->put(propName, (v = getValue(collectedRefs.at(i)))); + } } - 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; } @@ -325,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; @@ -340,7 +263,7 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int QV4::Scope scope(engine()); QV4::ScopedContext ctxt(scope, findContext(frameNr)); while (ctxt) { - if (QV4::SimpleCallContext *cCtxt = ctxt->asSimpleCallContext()) { + if (QV4::CallContext *cCtxt = ctxt->asCallContext()) { if (cCtxt->d()->activation) break; } @@ -348,8 +271,8 @@ QJsonObject QV4DataCollector::buildFrame(const QV4::StackFrame &stackFrame, int } if (ctxt) { - QV4::ScopedValue o(scope, ctxt->asSimpleCallContext()->d()->activation); - frame[QLatin1String("receiver")] = toRef(collect(o)); + QV4::ScopedValue o(scope, ctxt->d()->activation); + frame[QLatin1String("receiver")] = toRef(addValueRef(o)); } // Only type and index are used by Qt Creator, so we keep it easy: @@ -370,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) @@ -413,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; } @@ -434,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, Q_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()); @@ -478,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 de12e8d527..bc178fa2db 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4datacollector.h @@ -58,50 +58,36 @@ public: typedef uint Ref; typedef QVector<uint> Refs; - static QV4::Heap::SimpleCallContext *findScope(QV4::ExecutionContext *ctxt, int scope); + static QV4::Heap::ExecutionContext *findScope(QV4::Heap::ExecutionContext *ctxt, int scope); static int encodeScopeType(QV4::Heap::ExecutionContext::ContextType scopeType); QVector<QV4::Heap::ExecutionContext::ContextType> getScopeTypes(int frame); - QV4::SimpleCallContext *findContext(int frame); + QV4::Heap::ExecutionContext *findContext(int frame); + QV4::CppStackFrame *findFrame(int frame); 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 b82df9c6a9..5521e7628b 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.cpp @@ -70,9 +70,9 @@ QV4Debugger::QV4Debugger(QV4::ExecutionEngine *engine) , m_pauseRequested(false) , m_haveBreakPoints(false) , m_breakOnThrow(false) - , m_returnedValue(engine, QV4::Primitive::undefinedValue()) - , m_gatherSources(0) - , m_runningJob(0) + , m_returnedValue(engine, QV4::Value::undefinedValue()) + , m_gatherSources(nullptr) + , m_runningJob(nullptr) , m_collector(engine) { static int debuggerId = qRegisterMetaType<QV4Debugger*>(); @@ -115,7 +115,7 @@ void QV4Debugger::resume(Speed speed) if (!m_returnedValue.isUndefined()) m_returnedValue.set(m_engine, QV4::Encode::undefined()); - m_currentContext.set(m_engine, *m_engine->currentContext); + m_currentFrame = m_engine->currentStackFrame; m_stepping = speed; m_runningCondition.wakeAll(); } @@ -157,8 +157,8 @@ void QV4Debugger::clearPauseRequest() QV4Debugger::ExecutionState QV4Debugger::currentExecutionState() const { ExecutionState state; - state.fileName = getFunction()->sourceFile(); - state.lineNumber = engine()->current->lineNumber; + state.fileName = QUrl(getFunction()->sourceFile()).fileName(); + state.lineNumber = engine()->currentStackFrame->lineNumber(); return state; } @@ -182,14 +182,14 @@ void QV4Debugger::maybeBreakAtInstruction() if (m_gatherSources) { m_gatherSources->run(); delete m_gatherSources; - m_gatherSources = 0; + m_gatherSources = nullptr; } switch (m_stepping) { case StepOver: - if (m_currentContext.asManaged()->d() != m_engine->current) + if (m_currentFrame != m_engine->currentStackFrame) break; - // fall through + Q_FALLTHROUGH(); case StepIn: pauseAndWait(Step); return; @@ -203,7 +203,8 @@ void QV4Debugger::maybeBreakAtInstruction() pauseAndWait(PauseRequest); } else if (m_haveBreakPoints) { if (QV4::Function *f = getFunction()) { - const int lineNumber = engine()->current->lineNumber; + // lineNumber will be negative for Ret instructions, so those won't match + const int lineNumber = engine()->currentStackFrame->lineNumber(); if (reallyHitTheBreakPoint(f->sourceFile(), lineNumber)) pauseAndWait(BreakPointHit); } @@ -216,9 +217,8 @@ void QV4Debugger::enteringFunction() return; QMutexLocker locker(&m_lock); - if (m_stepping == StepIn) { - m_currentContext.set(m_engine, *m_engine->currentContext); - } + if (m_stepping == StepIn) + m_currentFrame = m_engine->currentStackFrame; } void QV4Debugger::leavingFunction(const QV4::ReturnedValue &retVal) @@ -229,13 +229,8 @@ void QV4Debugger::leavingFunction(const QV4::ReturnedValue &retVal) QMutexLocker locker(&m_lock); - if (m_stepping != NotStepping && m_currentContext.asManaged()->d() == m_engine->current) { - if (QV4::ExecutionContext *parentContext - = m_engine->parentContext(m_engine->currentContext)) { - m_currentContext.set(m_engine, *parentContext); - } else { - m_currentContext.clear(); - } + if (m_stepping != NotStepping && m_currentFrame == m_engine->currentStackFrame) { + m_currentFrame = m_currentFrame->parent; m_stepping = StepOver; m_returnedValue.set(m_engine, retVal); } @@ -255,10 +250,8 @@ void QV4Debugger::aboutToThrow() QV4::Function *QV4Debugger::getFunction() const { - QV4::Scope scope(m_engine); - QV4::ExecutionContext *context = m_engine->currentContext; - if (QV4::Function *function = context->getFunction()) - return function; + if (m_engine->currentStackFrame) + return m_engine->currentStackFrame->v4Function; else return m_engine->globalCode; } @@ -295,18 +288,18 @@ 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(); if (condition.isEmpty()) return true; - Q_ASSERT(m_runningJob == 0); + Q_ASSERT(m_runningJob == nullptr); EvalJob evilJob(m_engine, condition); m_runningJob = &evilJob; m_runningJob->run(); - m_runningJob = 0; + m_runningJob = nullptr; return evilJob.resultAsBoolean(); } @@ -320,7 +313,7 @@ void QV4Debugger::runInEngine(QV4DebugJob *job) void QV4Debugger::runInEngine_havingLock(QV4DebugJob *job) { Q_ASSERT(job); - Q_ASSERT(m_runningJob == 0); + Q_ASSERT(m_runningJob == nullptr); m_runningJob = job; if (state() == Paused) @@ -328,7 +321,7 @@ void QV4Debugger::runInEngine_havingLock(QV4DebugJob *job) else emit scheduleJob(); m_jobIsRunning.wait(&m_lock); - m_runningJob = 0; + m_runningJob = nullptr; } QT_END_NAMESPACE diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h index cd412e573d..4a755f2b72 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugger.h @@ -129,14 +129,14 @@ public: void runInEngine(QV4DebugJob *job); // compile-time interface - void maybeBreakAtInstruction() Q_DECL_OVERRIDE; + void maybeBreakAtInstruction() override; // execution hooks - void enteringFunction() Q_DECL_OVERRIDE; - void leavingFunction(const QV4::ReturnedValue &retVal) Q_DECL_OVERRIDE; - void aboutToThrow() Q_DECL_OVERRIDE; + void enteringFunction() override; + void leavingFunction(const QV4::ReturnedValue &retVal) override; + void aboutToThrow() override; - bool pauseAtNextOpportunity() const Q_DECL_OVERRIDE; + bool pauseAtNextOpportunity() const override; signals: void debuggerPaused(QV4Debugger *self, QV4Debugger::PauseReason reason); @@ -150,7 +150,7 @@ private: void runJobUnpaused(); QV4::ExecutionEngine *m_engine; - QV4::PersistentValue m_currentContext; + QV4::CppStackFrame *m_currentFrame = 0; QMutex m_lock; QWaitCondition m_runningCondition; State m_state; diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp index 9a34d5770a..71645579c5 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debuggeragent.cpp @@ -56,13 +56,13 @@ QV4Debugger *QV4DebuggerAgent::pausedDebugger() const if (debugger->state() == QV4Debugger::Paused) return debugger; } - return 0; + return nullptr; } bool QV4DebuggerAgent::isRunning() const { // "running" means none of the engines are paused. - return pausedDebugger() == 0; + return pausedDebugger() == nullptr; } void QV4DebuggerAgent::debuggerPaused(QV4Debugger *debugger, QV4Debugger::PauseReason reason) @@ -79,20 +79,19 @@ void QV4DebuggerAgent::debuggerPaused(QV4Debugger *debugger, QV4Debugger::PauseR case QV4Debugger::PauseRequest: case QV4Debugger::BreakPointHit: { event.insert(QStringLiteral("event"), QStringLiteral("break")); - QVector<QV4::StackFrame> frames = debugger->stackTrace(1); - if (frames.isEmpty()) + QV4::CppStackFrame *frame = debugger->engine()->currentStackFrame; + if (!frame) break; - const QV4::StackFrame &topFrame = frames.first(); - body.insert(QStringLiteral("invocationText"), topFrame.function); - body.insert(QStringLiteral("sourceLine"), topFrame.line - 1); - if (topFrame.column > 0) - body.insert(QStringLiteral("sourceColumn"), topFrame.column); + body.insert(QStringLiteral("invocationText"), frame->function()); + body.insert(QStringLiteral("sourceLine"), qAbs(frame->lineNumber()) - 1); +// if (frame->column > 0) +// body.insert(QStringLiteral("sourceColumn"), frame->column); QJsonArray breakPoints; - foreach (int breakPointId, breakPointIds(topFrame.source, topFrame.line)) + foreach (int breakPointId, breakPointIds(frame->source(), frame->lineNumber())) breakPoints.push_back(breakPointId); body.insert(QStringLiteral("breakpoints"), breakPoints); - script.insert(QStringLiteral("name"), topFrame.source); + script.insert(QStringLiteral("name"), frame->source()); } break; case QV4Debugger::Throwing: // TODO: complete this! diff --git a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp index 107ec60943..b424ef9f6c 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugjob.cpp @@ -44,6 +44,7 @@ #include <private/qv4qmlcontext_p.h> #include <private/qv4qobjectwrapper_p.h> #include <private/qqmldebugservice_p.h> +#include <private/qv4jscall_p.h> #include <QtQml/qqmlengine.h> @@ -63,26 +64,21 @@ void JavaScriptJob::run() { QV4::Scope scope(engine); - QV4::ExecutionContextSaver saver(scope); - - QV4::ExecutionContext *ctx = engine->currentContext; + QV4::ScopedContext ctx(scope, engine->currentStackFrame ? engine->currentContext() + : engine->scriptContext()); QObject scopeObject; - if (frameNr > 0) { - for (int i = 0; i < frameNr; ++i) { - ctx = engine->parentContext(ctx); - } - engine->pushContext(ctx); - ctx = engine->currentContext; - } + QV4::CppStackFrame *frame = engine->currentStackFrame; + + for (int i = 0; frame && i < frameNr; ++i) + frame = frame->parent; + if (frameNr > 0 && frame) + ctx = static_cast<QV4::ExecutionContext *>(&frame->jsFrame->context); if (context >= 0) { QQmlContext *extraContext = qmlContext(QQmlDebugService::objectForId(context)); - if (extraContext) { - engine->pushContext(QV4::QmlContext::create(ctx, QQmlContextData::get(extraContext), - &scopeObject)); - ctx = engine->currentContext; - } + if (extraContext) + ctx = QV4::QmlContext::create(ctx, QQmlContextData::get(extraContext), &scopeObject); } else if (frameNr < 0) { // Use QML context if available QQmlEngine *qmlEngine = engine->qmlEngine(); if (qmlEngine) { @@ -102,25 +98,28 @@ void JavaScriptJob::run() } } } - if (!engine->qmlContext()) { - engine->pushContext(QV4::QmlContext::create(ctx, QQmlContextData::get(qmlRootContext), - &scopeObject)); - ctx = engine->currentContext; - } - engine->pushContext(ctx->newWithContext(withContext->toObject(engine))); - ctx = engine->currentContext; + if (!engine->qmlContext()) + ctx = QV4::QmlContext::create(ctx, QQmlContextData::get(qmlRootContext), &scopeObject); } } - QV4::Script script(ctx, this->script); - script.strictMode = ctx->d()->strictMode; + QV4::Script script(ctx, QV4::Compiler::ContextType::Eval, this->script); + if (const QV4::Function *function = frame ? frame->v4Function : engine->globalCode) + script.strictMode = function->isStrict(); + // In order for property lookups in QML to work, we need to disable fast v4 lookups. That // is a side-effect of inheritContext. script.inheritContext = true; script.parse(); QV4::ScopedValue result(scope); - if (!scope.engine->hasException) - result = script.run(); + if (!scope.engine->hasException) { + if (frame) { + QV4::ScopedValue thisObject(scope, frame->thisObject()); + result = script.run(thisObject); + } else { + result = script.run(); + } + } if (scope.engine->hasException) { result = scope.engine->catchException(); resultIsException = true; @@ -151,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) : @@ -166,7 +164,6 @@ void FrameJob::run() success = false; } else { result = collector->buildFrame(frames[frameNr], frameNr); - flushRedundantRefs(); success = true; } } @@ -196,7 +193,6 @@ void ScopeJob::run() result[QLatin1String("index")] = scopeNr; result[QLatin1String("frameIndex")] = frameNr; result[QLatin1String("object")] = object; - flushRedundantRefs(); } bool ScopeJob::wasSuccessful() const @@ -214,23 +210,23 @@ void ValueLookupJob::run() // set if the engine is currently executing QML code. QScopedPointer<QObject> scopeObject; QV4::ExecutionEngine *engine = collector->engine(); + QV4::Scope scope(engine); + QV4::Heap::ExecutionContext *qmlContext = nullptr; if (engine->qmlEngine() && !engine->qmlContext()) { scopeObject.reset(new QObject); - engine->pushContext(QV4::QmlContext::create(engine->currentContext, + qmlContext = QV4::QmlContext::create(engine->currentContext(), QQmlContextData::get(engine->qmlEngine()->rootContext()), - scopeObject.data())); + scopeObject.data()); } + QV4::ScopedStackFrame frame(scope, qmlContext); for (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, true); + result[QString::number(ref)] = collector->lookupRef(ref); } - flushRedundantRefs(); - if (scopeObject) - engine->popContext(); } 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,20 +258,13 @@ 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) {} void GatherSourcesJob::run() { - for (QV4::CompiledData::CompilationUnit *unit : qAsConst(engine->compilationUnits)) { + for (QV4::CompiledData::CompilationUnit *unit : engine->compilationUnits) { QString fileName = unit->fileName(); if (!fileName.isEmpty()) sources.append(fileName); 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 168a08865c..5866163ca6 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.cpp @@ -40,13 +40,12 @@ #include "qv4debugservice.h" #include "qv4debugjob.h" #include "qqmlengine.h" -#include "qqmldebugpacket.h" #include <private/qv4engine_p.h> -#include <private/qv4isel_moth_p.h> #include <private/qv4function_p.h> #include <private/qqmldebugconnector_p.h> #include <private/qv8engine_p.h> +#include <private/qversionedpacket_p.h> #include <QtCore/QJsonArray> #include <QtCore/QJsonDocument> @@ -68,19 +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; } @@ -99,7 +100,7 @@ public: debugService->send(response); } - debugService = 0; + debugService = nullptr; seq = QJsonValue(); req = QJsonObject(); response = QJsonObject(); @@ -121,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")); @@ -157,10 +143,10 @@ protected: QJsonObject response; }; -class UnknownV8CommandHandler: public V8CommandHandler +class UnknownV4CommandHandler: public V4CommandHandler { public: - UnknownV8CommandHandler(): V8CommandHandler(QString()) {} + UnknownV4CommandHandler(): V4CommandHandler(QString()) {} void handleRequest() override { @@ -172,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 { @@ -188,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; + } + + 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; - QString type = args.value(QLatin1String("type")).toString(); + 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 { @@ -296,7 +321,7 @@ public: return; } - BacktraceJob job(saneCollector(debugger), fromFrame, toFrame); + BacktraceJob job(debugger->collector(), fromFrame, toFrame); debugger->runInEngine(&job); // response: @@ -305,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 { @@ -333,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")); @@ -348,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 { @@ -381,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")); @@ -394,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 { @@ -423,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()); @@ -434,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 { @@ -486,10 +503,10 @@ public: } }; -class V8DisconnectRequest: public V8CommandHandler +class V4DisconnectRequest: public V4CommandHandler { public: - V8DisconnectRequest(): V8CommandHandler(QStringLiteral("disconnect")) {} + V4DisconnectRequest(): V4CommandHandler(QStringLiteral("disconnect")) {} void handleRequest() override { @@ -504,10 +521,10 @@ public: } }; -class V8SetExceptionBreakRequest: public V8CommandHandler +class V4SetExceptionBreakRequest: public V4CommandHandler { public: - V8SetExceptionBreakRequest(): V8CommandHandler(QStringLiteral("setexceptionbreak")) {} + V4SetExceptionBreakRequest(): V4CommandHandler(QStringLiteral("setexceptionbreak")) {} void handleRequest() override { @@ -544,10 +561,10 @@ public: } }; -class V8ScriptsRequest: public V8CommandHandler +class V4ScriptsRequest: public V4CommandHandler { public: - V8ScriptsRequest(): V8CommandHandler(QStringLiteral("scripts")) {} + V4ScriptsRequest(): V4CommandHandler(QStringLiteral("scripts")) {} void handleRequest() override { @@ -616,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 { @@ -644,7 +661,7 @@ public: } ExpressionEvalJob job(debugger->engine(), frame, context, expression, - saneCollector(debugger)); + debugger->collector()); debugger->runInEngine(&job); if (job.hasExeption()) { createErrorResponse(job.exceptionMessage()); @@ -654,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() @@ -703,10 +719,9 @@ void QV4DebugServiceImpl::engineAdded(QJSEngine *engine) { QMutexLocker lock(&m_configMutex); if (engine) { - QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle()); + QV4::ExecutionEngine *ee = engine->handle(); if (QQmlDebugConnector *server = QQmlDebugConnector::instance()) { if (ee) { - ee->iselFactory.reset(new QV4::Moth::ISelFactory); QV4Debugger *debugger = new QV4Debugger(ee); if (state() == Enabled) ee->setDebugger(debugger); @@ -722,7 +737,7 @@ void QV4DebugServiceImpl::engineAboutToBeRemoved(QJSEngine *engine) { QMutexLocker lock(&m_configMutex); if (engine){ - const QV4::ExecutionEngine *ee = QV8Engine::getV4(engine->handle()); + const QV4::ExecutionEngine *ee = engine->handle(); if (ee) { QV4Debugger *debugger = qobject_cast<QV4Debugger *>(ee->debugger()); if (debugger) @@ -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 bb13890ae4..d0b104dfad 100644 --- a/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h +++ b/src/plugins/qmltooling/qmldbg_debugger/qv4debugservice.h @@ -51,9 +51,9 @@ // We mean it. // -#include "qqmlconfigurabledebugservice.h" #include "qv4debuggeragent.h" #include "qv4datacollector.h" +#include <private/qqmlconfigurabledebugservice_p.h> #include <private/qqmldebugserviceinterfaces_p.h> #include <private/qv4debugging_p.h> @@ -64,56 +64,50 @@ 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); - ~QV4DebugServiceImpl() Q_DECL_OVERRIDE; + explicit QV4DebugServiceImpl(QObject *parent = nullptr); + ~QV4DebugServiceImpl() override; - void engineAdded(QJSEngine *engine) Q_DECL_OVERRIDE; - void engineAboutToBeRemoved(QJSEngine *engine) Q_DECL_OVERRIDE; + void engineAdded(QJSEngine *engine) override; + void engineAboutToBeRemoved(QJSEngine *engine) override; - void stateAboutToBeChanged(State state) Q_DECL_OVERRIDE; + void stateAboutToBeChanged(State state) override; - void signalEmitted(const QString &signal) Q_DECL_OVERRIDE; - void send(QJsonObject v8Payload); + void signalEmitted(const QString &signal) override; + void send(QJsonObject v4Payload); int selectedFrame() const; void selectFrame(int frameNr); - bool clientRequiresRedundantRefs() const { return redundantRefs; } - bool clientRequiresNamesAsObjects() const { return namesAsObjects; } - QV4DebuggerAgent debuggerAgent; protected: - void messageReceived(const QByteArray &) Q_DECL_OVERRIDE; + void messageReceived(const QByteArray &) override; void sendSomethingToSomebody(const char *type, int magicNumber = 1); 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 |