From 6a8d4f614171444a77a127dc2e22f295d1ffabe2 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 29 Apr 2019 13:05:03 +0200 Subject: Don't wrap the attachedProperties function into a template Otherwise it gets a separate address for each CU in which the template is instantiated. We want to use the address as key to the attached properties, though. Fixes: QTBUG-75385 Change-Id: Iaec82db116a032f7cb1d40670bb47fdf610664a2 Reviewed-by: Mitch Curtis Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlprivate.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlprivate.h b/src/qml/qml/qqmlprivate.h index fa05b3fe19..ae84803648 100644 --- a/src/qml/qml/qqmlprivate.h +++ b/src/qml/qml/qqmlprivate.h @@ -190,16 +190,13 @@ namespace QQmlPrivate template class AttachedPropertySelector { - static inline QObject *attachedProperties(QObject *obj) { - return T::qmlAttachedProperties(obj); - } template static inline const QMetaObject *attachedPropertiesMetaObject(ReturnType *(*)(QObject *)) { return &ReturnType::staticMetaObject; } public: static inline QQmlAttachedPropertiesFunc func() { - return &attachedProperties; + return QQmlAttachedPropertiesFunc(&T::qmlAttachedProperties); } static inline const QMetaObject *metaObject() { return attachedPropertiesMetaObject(&T::qmlAttachedProperties); -- cgit v1.2.3 From d2c089eb11d3ad6a9917efde8f13b36931b35baf Mon Sep 17 00:00:00 2001 From: Milian Wolff Date: Mon, 29 Apr 2019 10:46:02 +0200 Subject: Add Q_TRACE calls to QtQml for QML profiler trace points This adds tracepoints for LTTng/ETW at the positions that are also used by the QML profiler within QtQml. I.e. with the tracepoints here, you'll see which QML function is being executed which is already quite helpful. This will allow us to bridge the gap between C++ and QML when tracing with LTTng/ETW. Additionally, you'll also be able to see kernel tracepoints which bridges another gap. Combined, this approach can give much deeper insights into what the (embedded) system is doing compared to just looking at the QML profiler alone. Change-Id: Ia8f71bf6d44b7f51c3c5aaa38f032675604aeca6 Reviewed-by: Ulf Hermann Reviewed-by: Rafael Roquetto --- src/qml/jsruntime/qv4vme_moth.cpp | 6 ++++++ src/qml/qml.pro | 3 +++ src/qml/qml/qqmlobjectcreator.cpp | 20 +++++++++++++------- src/qml/qtqml.tracepoints | 14 ++++++++++++++ 4 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 src/qml/qtqml.tracepoints (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index ea2217499f..c69bb67061 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -63,6 +63,8 @@ #include +#include + #undef COUNT_INSTRUCTIONS extern "C" { @@ -418,6 +420,10 @@ ReturnedValue VME::exec(CppStackFrame *frame, ExecutionEngine *engine) CHECK_STACK_LIMITS(engine); Function *function = frame->v4Function; + Q_TRACE_SCOPE(QQmlV4_function_call, engine, function->name()->toQString(), + function->compilationUnit->fileName(), + function->compiledFunction->location.line, + function->compiledFunction->location.column); Profiling::FunctionCallProfiler profiler(engine, function); // start execution profiling QV4::Debugging::Debugger *debugger = engine->debugger(); diff --git a/src/qml/qml.pro b/src/qml/qml.pro index db59140f06..d2170ac40b 100644 --- a/src/qml/qml.pro +++ b/src/qml/qml.pro @@ -4,6 +4,9 @@ QT = core-private qtConfig(qml-network): \ QT += network +TRACEPOINT_PROVIDER = $$PWD/qtqml.tracepoints +CONFIG += qt_tracepoints + DEFINES += QT_NO_URL_CAST_FROM_STRING QT_NO_INTEGER_EVENT_COORDINATES msvc:equals(QT_ARCH, i386): QMAKE_LFLAGS += /BASE:0x66000000 diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index b62b07e39c..d5b15a7a5a 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -57,6 +57,8 @@ #include #include +#include + QT_USE_NAMESPACE namespace { @@ -1130,6 +1132,9 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo { const QV4::CompiledData::Object *obj = compilationUnit->objectAt(index); QQmlObjectCreationProfiler profiler(sharedState->profiler.profiler, obj); + Q_TRACE(QQmlObjectCreator_createInstance_entry, compilationUnit.data(), obj, context->url()); + QString typeName; + Q_TRACE_EXIT(QQmlObjectCreator_createInstance_exit, typeName); ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine)); @@ -1143,8 +1148,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo if (obj->flags & QV4::CompiledData::Object::IsComponent) { isComponent = true; QQmlComponent *component = new QQmlComponent(engine, compilationUnit.data(), index, parent); - Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( - compilationUnit.data(), obj, QStringLiteral(""), context->url())); + typeName = QStringLiteral(""); QQmlComponentPrivate::get(component)->creationContext = context; instance = component; ddata = QQmlData::get(instance, /*create*/true); @@ -1155,8 +1159,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo installPropertyCache = !typeRef->isFullyDynamicType; QQmlType type = typeRef->type; if (type.isValid()) { - Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( - compilationUnit.data(), obj, type.qmlTypeName(), context->url())); + typeName = type.qmlTypeName(); void *ddataMemory = nullptr; type.create(&instance, &ddataMemory, sizeof(QQmlData)); @@ -1188,9 +1191,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo sharedState->allCreatedObjects.push(instance); } else { Q_ASSERT(typeRef->compilationUnit); - Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( - compilationUnit.data(), obj, typeRef->compilationUnit->fileName(), - context->url())); + typeName = typeRef->compilationUnit->fileName(); if (typeRef->compilationUnit->unitData()->isSingleton()) { recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex))); @@ -1217,6 +1218,11 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo ddata = QQmlData::get(instance, /*create*/true); } + + Q_QML_OC_PROFILE(sharedState->profiler, profiler.update( + compilationUnit.data(), obj, typeName, context->url())); + Q_UNUSED(typeName); // only relevant for tracing + ddata->lineNumber = obj->location.line; ddata->columnNumber = obj->location.column; diff --git a/src/qml/qtqml.tracepoints b/src/qml/qtqml.tracepoints new file mode 100644 index 0000000000..841748f201 --- /dev/null +++ b/src/qml/qtqml.tracepoints @@ -0,0 +1,14 @@ +{ +namespace QV4 { +class ExecutionEngine; +namespace CompiledData { +class CompilationUnit; +class Object; +} // CompiledData +} // QV4 +} + +QQmlObjectCreator_createInstance_entry(const QV4::CompiledData::CompilationUnit *compilationUnit, const QV4::CompiledData::Object *object, const QUrl &url) +QQmlObjectCreator_createInstance_exit(const QString &typeName) +QQmlV4_function_call_entry(const QV4::ExecutionEngine *engine, const QString &function, const QString &fileName, int line, int column) +QQmlV4_function_call_exit() -- cgit v1.2.3 From 5032ff5c2b48d53e4580bb7d50b1f6de081263b0 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 4 Apr 2019 15:41:18 +0200 Subject: Move workerscript to its own module Change-Id: I778cfe842ddf1c600a837d8f2061a338887eed95 Reviewed-by: Lars Knoll --- src/qml/jsruntime/jsruntime.pri | 2 - src/qml/jsruntime/qv4objectproto_p.h | 2 +- src/qml/jsruntime/qv4regexpobject.cpp | 7 - src/qml/jsruntime/qv4regexpobject_p.h | 9 +- src/qml/jsruntime/qv4sequenceobject_p.h | 2 +- src/qml/jsruntime/qv4serialize.cpp | 447 --------------------- src/qml/jsruntime/qv4serialize_p.h | 76 ---- src/qml/qml/qqmlengine.cpp | 16 - src/qml/qml/qqmlengine_p.h | 4 +- src/qml/types/qquickworkerscript.cpp | 669 -------------------------------- src/qml/types/qquickworkerscript_p.h | 123 ------ src/qml/types/types.pri | 7 - 12 files changed, 10 insertions(+), 1354 deletions(-) delete mode 100644 src/qml/jsruntime/qv4serialize.cpp delete mode 100644 src/qml/jsruntime/qv4serialize_p.h delete mode 100644 src/qml/types/qquickworkerscript.cpp delete mode 100644 src/qml/types/qquickworkerscript_p.h (limited to 'src/qml') diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index a24ee0a188..ae9a36ca22 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -42,7 +42,6 @@ SOURCES += \ $$PWD/qv4objectiterator.cpp \ $$PWD/qv4regexp.cpp \ $$PWD/qv4runtimecodegen.cpp \ - $$PWD/qv4serialize.cpp \ $$PWD/qv4script.cpp \ $$PWD/qv4symbol.cpp \ $$PWD/qv4setobject.cpp \ @@ -109,7 +108,6 @@ HEADERS += \ $$PWD/qv4property_p.h \ $$PWD/qv4objectiterator_p.h \ $$PWD/qv4regexp_p.h \ - $$PWD/qv4serialize_p.h \ $$PWD/qv4script_p.h \ $$PWD/qv4symbol_p.h \ $$PWD/qv4setobject_p.h \ diff --git a/src/qml/jsruntime/qv4objectproto_p.h b/src/qml/jsruntime/qv4objectproto_p.h index e9515b5b68..8707305dc2 100644 --- a/src/qml/jsruntime/qv4objectproto_p.h +++ b/src/qml/jsruntime/qv4objectproto_p.h @@ -74,7 +74,7 @@ struct ObjectCtor: FunctionObject static ReturnedValue virtualCall(const FunctionObject *m, const Value *thisObject, const Value *argv, int argc); }; -struct ObjectPrototype: Object +struct Q_QML_PRIVATE_EXPORT ObjectPrototype: Object { void init(ExecutionEngine *engine, Object *ctor); diff --git a/src/qml/jsruntime/qv4regexpobject.cpp b/src/qml/jsruntime/qv4regexpobject.cpp index 5bd25dcbec..64aba1d85c 100644 --- a/src/qml/jsruntime/qv4regexpobject.cpp +++ b/src/qml/jsruntime/qv4regexpobject.cpp @@ -198,13 +198,6 @@ QString RegExpObject::toString() const return p; } -QString RegExpObject::source() const -{ - Scope scope(engine()); - ScopedValue s(scope, get(scope.engine->id_source())); - return s->toQString(); -} - ReturnedValue RegExpObject::builtinExec(ExecutionEngine *engine, const String *str) { QString s = str->toQString(); diff --git a/src/qml/jsruntime/qv4regexpobject_p.h b/src/qml/jsruntime/qv4regexpobject_p.h index 04b533e49d..b94889e9f0 100644 --- a/src/qml/jsruntime/qv4regexpobject_p.h +++ b/src/qml/jsruntime/qv4regexpobject_p.h @@ -101,7 +101,7 @@ DECLARE_HEAP_OBJECT(RegExpCtor, FunctionObject) { } -struct RegExpObject: Object { +struct Q_QML_PRIVATE_EXPORT RegExpObject: Object { V4_OBJECT2(RegExpObject, Object) Q_MANAGED_TYPE(RegExpObject) V4_INTERNALCLASS(RegExpObject) @@ -145,7 +145,12 @@ struct RegExpObject: Object { QRegularExpression toQRegularExpression() const; #endif QString toString() const; - QString source() const; + QString source() const + { + Scope scope(engine()); + ScopedValue s(scope, get(scope.engine->id_source())); + return s->toQString(); + } Heap::RegExp *value() const { return d()->value; } uint flags() const { return d()->value->flags; } diff --git a/src/qml/jsruntime/qv4sequenceobject_p.h b/src/qml/jsruntime/qv4sequenceobject_p.h index da71215bed..886dfaa521 100644 --- a/src/qml/jsruntime/qv4sequenceobject_p.h +++ b/src/qml/jsruntime/qv4sequenceobject_p.h @@ -65,7 +65,7 @@ QT_BEGIN_NAMESPACE namespace QV4 { -struct SequencePrototype : public QV4::Object +struct Q_QML_PRIVATE_EXPORT SequencePrototype : public QV4::Object { V4_PROTOTYPE(arrayPrototype) void init(); diff --git a/src/qml/jsruntime/qv4serialize.cpp b/src/qml/jsruntime/qv4serialize.cpp deleted file mode 100644 index a5e62d3e35..0000000000 --- a/src/qml/jsruntime/qv4serialize.cpp +++ /dev/null @@ -1,447 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qv4serialize_p.h" - -#include -#include -#include -#if QT_CONFIG(qml_sequence_object) -#include -#endif -#include -#include - -QT_BEGIN_NAMESPACE - -using namespace QV4; - -// We allow the following JavaScript types to be passed between the main and -// the secondary thread: -// + undefined -// + null -// + Boolean -// + String -// + Function -// + Array -// + "Simple" Objects -// + Number -// + Date -// + RegExp -// - -enum Type { - WorkerUndefined, - WorkerNull, - WorkerTrue, - WorkerFalse, - WorkerString, - WorkerFunction, - WorkerArray, - WorkerObject, - WorkerInt32, - WorkerUint32, - WorkerNumber, - WorkerDate, - WorkerRegexp, - WorkerListModel, -#if QT_CONFIG(qml_sequence_object) - WorkerSequence -#endif -}; - -static inline quint32 valueheader(Type type, quint32 size = 0) -{ - return quint8(type) << 24 | (size & 0xFFFFFF); -} - -static inline Type headertype(quint32 header) -{ - return (Type)(header >> 24); -} - -static inline quint32 headersize(quint32 header) -{ - return header & 0xFFFFFF; -} - -static inline void push(QByteArray &data, quint32 value) -{ - data.append((const char *)&value, sizeof(quint32)); -} - -static inline void push(QByteArray &data, double value) -{ - data.append((const char *)&value, sizeof(double)); -} - -static inline void push(QByteArray &data, void *ptr) -{ - data.append((const char *)&ptr, sizeof(void *)); -} - -static inline void reserve(QByteArray &data, int extra) -{ - data.reserve(data.size() + extra); -} - -static inline quint32 popUint32(const char *&data) -{ - quint32 rv = *((const quint32 *)data); - data += sizeof(quint32); - return rv; -} - -static inline double popDouble(const char *&data) -{ - double rv = *((const double *)data); - data += sizeof(double); - return rv; -} - -static inline void *popPtr(const char *&data) -{ - void *rv = *((void *const *)data); - data += sizeof(void *); - return rv; -} - -// XXX TODO: Check that worker script is exception safe in the case of -// serialization/deserialization failures - -#define ALIGN(size) (((size) + 3) & ~3) -void Serialize::serialize(QByteArray &data, const QV4::Value &v, ExecutionEngine *engine) -{ - QV4::Scope scope(engine); - - if (v.isEmpty()) { - Q_ASSERT(!"Serialize: got empty value"); - } else if (v.isUndefined()) { - push(data, valueheader(WorkerUndefined)); - } else if (v.isNull()) { - push(data, valueheader(WorkerNull)); - } else if (v.isBoolean()) { - push(data, valueheader(v.booleanValue() == true ? WorkerTrue : WorkerFalse)); - } else if (v.isString()) { - const QString &qstr = v.toQString(); - int length = qstr.length(); - if (length > 0xFFFFFF) { - push(data, valueheader(WorkerUndefined)); - return; - } - int utf16size = ALIGN(length * sizeof(quint16)); - - reserve(data, utf16size + sizeof(quint32)); - push(data, valueheader(WorkerString, length)); - - int offset = data.size(); - data.resize(data.size() + utf16size); - char *buffer = data.data() + offset; - - memcpy(buffer, qstr.constData(), length*sizeof(QChar)); - } else if (v.as()) { - // XXX TODO: Implement passing function objects between the main and - // worker scripts - push(data, valueheader(WorkerUndefined)); - } else if (const QV4::ArrayObject *array = v.as()) { - uint length = array->getLength(); - if (length > 0xFFFFFF) { - push(data, valueheader(WorkerUndefined)); - return; - } - reserve(data, sizeof(quint32) + length * sizeof(quint32)); - push(data, valueheader(WorkerArray, length)); - ScopedValue val(scope); - for (uint ii = 0; ii < length; ++ii) - serialize(data, (val = array->get(ii)), engine); - } else if (v.isInteger()) { - reserve(data, 2 * sizeof(quint32)); - push(data, valueheader(WorkerInt32)); - push(data, (quint32)v.integerValue()); -// } else if (v.IsUint32()) { -// reserve(data, 2 * sizeof(quint32)); -// push(data, valueheader(WorkerUint32)); -// push(data, v.Uint32Value()); - } else if (v.isNumber()) { - reserve(data, sizeof(quint32) + sizeof(double)); - push(data, valueheader(WorkerNumber)); - push(data, v.asDouble()); - } else if (const QV4::DateObject *d = v.as()) { - reserve(data, sizeof(quint32) + sizeof(double)); - push(data, valueheader(WorkerDate)); - push(data, d->date()); - } else if (const RegExpObject *re = v.as()) { - quint32 flags = re->flags(); - QString pattern = re->source(); - int length = pattern.length() + 1; - if (length > 0xFFFFFF) { - push(data, valueheader(WorkerUndefined)); - return; - } - int utf16size = ALIGN(length * sizeof(quint16)); - - reserve(data, sizeof(quint32) + utf16size); - push(data, valueheader(WorkerRegexp, flags)); - push(data, (quint32)length); - - int offset = data.size(); - data.resize(data.size() + utf16size); - char *buffer = data.data() + offset; - - memcpy(buffer, pattern.constData(), length*sizeof(QChar)); - } else if (const QObjectWrapper *qobjectWrapper = v.as()) { - // XXX TODO: Generalize passing objects between the main thread and worker scripts so - // that others can trivially plug in their elements. - if (QObject *lm = qobjectWrapper->object()) { - if (QObject *agent = qvariant_cast(lm->property("agent"))) { - if (QMetaObject::invokeMethod(agent, "addref")) { - push(data, valueheader(WorkerListModel)); - push(data, (void *)agent); - return; - } - } - } - // No other QObject's are allowed to be sent - push(data, valueheader(WorkerUndefined)); - } else if (const Object *o = v.as()) { -#if QT_CONFIG(qml_sequence_object) - if (o->isListType()) { - // valid sequence. we generate a length (sequence length + 1 for the sequence type) - uint seqLength = ScopedValue(scope, o->get(engine->id_length()))->toUInt32(); - uint length = seqLength + 1; - if (length > 0xFFFFFF) { - push(data, valueheader(WorkerUndefined)); - return; - } - reserve(data, sizeof(quint32) + length * sizeof(quint32)); - push(data, valueheader(WorkerSequence, length)); - serialize(data, QV4::Value::fromInt32(QV4::SequencePrototype::metaTypeForSequence(o)), engine); // sequence type - ScopedValue val(scope); - for (uint ii = 0; ii < seqLength; ++ii) - serialize(data, (val = o->get(ii)), engine); // sequence elements - - return; - } -#endif - - // regular object - QV4::ScopedValue val(scope, v); - QV4::ScopedArrayObject properties(scope, QV4::ObjectPrototype::getOwnPropertyNames(engine, val)); - quint32 length = properties->getLength(); - if (length > 0xFFFFFF) { - push(data, valueheader(WorkerUndefined)); - return; - } - push(data, valueheader(WorkerObject, length)); - - QV4::ScopedValue s(scope); - for (quint32 ii = 0; ii < length; ++ii) { - s = properties->get(ii); - serialize(data, s, engine); - - QV4::String *str = s->as(); - val = o->get(str); - if (scope.hasException()) - scope.engine->catchException(); - - serialize(data, val, engine); - } - return; - } else { - push(data, valueheader(WorkerUndefined)); - } -} - -struct VariantRef -{ - VariantRef() : obj(nullptr) {} - VariantRef(const VariantRef &r) : obj(r.obj) { addref(); } - VariantRef(QObject *a) : obj(a) { addref(); } - ~VariantRef() { release(); } - - VariantRef &operator=(const VariantRef &o) { - o.addref(); - release(); - obj = o.obj; - return *this; - } - - void addref() const - { - if (obj) - QMetaObject::invokeMethod(obj, "addref"); - } - - void release() const - { - if (obj) - QMetaObject::invokeMethod(obj, "release"); - - } - - QObject *obj; -}; - -QT_END_NAMESPACE -Q_DECLARE_METATYPE(VariantRef) -Q_DECLARE_METATYPE(QV4::ExecutionEngine *) -QT_BEGIN_NAMESPACE - -ReturnedValue Serialize::deserialize(const char *&data, ExecutionEngine *engine) -{ - quint32 header = popUint32(data); - Type type = headertype(header); - - Scope scope(engine); - - switch (type) { - case WorkerUndefined: - return QV4::Encode::undefined(); - case WorkerNull: - return QV4::Encode::null(); - case WorkerTrue: - return QV4::Encode(true); - case WorkerFalse: - return QV4::Encode(false); - case WorkerString: - { - quint32 size = headersize(header); - QString qstr((const QChar *)data, size); - data += ALIGN(size * sizeof(quint16)); - return QV4::Encode(engine->newString(qstr)); - } - case WorkerFunction: - Q_ASSERT(!"Unreachable"); - break; - case WorkerArray: - { - quint32 size = headersize(header); - ScopedArrayObject a(scope, engine->newArrayObject()); - ScopedValue v(scope); - for (quint32 ii = 0; ii < size; ++ii) { - v = deserialize(data, engine); - a->put(ii, v); - } - return a.asReturnedValue(); - } - case WorkerObject: - { - quint32 size = headersize(header); - ScopedObject o(scope, engine->newObject()); - ScopedValue name(scope); - ScopedString n(scope); - ScopedValue value(scope); - for (quint32 ii = 0; ii < size; ++ii) { - name = deserialize(data, engine); - value = deserialize(data, engine); - n = name->asReturnedValue(); - o->put(n, value); - } - return o.asReturnedValue(); - } - case WorkerInt32: - return QV4::Encode((qint32)popUint32(data)); - case WorkerUint32: - return QV4::Encode(popUint32(data)); - case WorkerNumber: - return QV4::Encode(popDouble(data)); - case WorkerDate: - return QV4::Encode(engine->newDateObject(QV4::Value::fromDouble(popDouble(data)))); - case WorkerRegexp: - { - quint32 flags = headersize(header); - quint32 length = popUint32(data); - QString pattern = QString((const QChar *)data, length - 1); - data += ALIGN(length * sizeof(quint16)); - return Encode(engine->newRegExpObject(pattern, flags)); - } - case WorkerListModel: - { - QObject *agent = reinterpret_cast(popPtr(data)); - QV4::ScopedValue rv(scope, QV4::QObjectWrapper::wrap(engine, agent)); - // ### Find a better solution then the ugly property - VariantRef ref(agent); - QVariant var = QVariant::fromValue(ref); - QV4::ScopedValue v(scope, scope.engine->fromVariant(var)); - QV4::ScopedString s(scope, engine->newString(QStringLiteral("__qml:hidden:ref"))); - rv->as()->defineReadonlyProperty(s, v); - - QMetaObject::invokeMethod(agent, "release"); - agent->setProperty("engine", QVariant::fromValue(engine)); - return rv->asReturnedValue(); - } -#if QT_CONFIG(qml_sequence_object) - case WorkerSequence: - { - ScopedValue value(scope); - bool succeeded = false; - quint32 length = headersize(header); - quint32 seqLength = length - 1; - value = deserialize(data, engine); - int sequenceType = value->integerValue(); - ScopedArrayObject array(scope, engine->newArrayObject()); - array->arrayReserve(seqLength); - for (quint32 ii = 0; ii < seqLength; ++ii) { - value = deserialize(data, engine); - array->arrayPut(ii, value); - } - array->setArrayLengthUnchecked(seqLength); - QVariant seqVariant = QV4::SequencePrototype::toVariant(array, sequenceType, &succeeded); - return QV4::SequencePrototype::fromVariant(engine, seqVariant, &succeeded); - } -#endif - } - Q_ASSERT(!"Unreachable"); - return QV4::Encode::undefined(); -} - -QByteArray Serialize::serialize(const QV4::Value &value, ExecutionEngine *engine) -{ - QByteArray rv; - serialize(rv, value, engine); - return rv; -} - -ReturnedValue Serialize::deserialize(const QByteArray &data, ExecutionEngine *engine) -{ - const char *stream = data.constData(); - return deserialize(stream, engine); -} - -QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4serialize_p.h b/src/qml/jsruntime/qv4serialize_p.h deleted file mode 100644 index c8700c3ca5..0000000000 --- a/src/qml/jsruntime/qv4serialize_p.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QV4SERIALIZE_P_H -#define QV4SERIALIZE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -namespace QV4 { - -class Serialize { -public: - - static QByteArray serialize(const Value &, ExecutionEngine *); - static ReturnedValue deserialize(const QByteArray &, ExecutionEngine *); - -private: - static void serialize(QByteArray &, const Value &, ExecutionEngine *); - static ReturnedValue deserialize(const char *&, ExecutionEngine *); -}; - -} - -QT_END_NAMESPACE - -#endif // QV8WORKER_P_H diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index bb2b3e462c..cb94ae379e 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -87,9 +87,6 @@ #include #endif #include -#if QT_CONFIG(qml_worker_script) -#include -#endif #include #ifdef Q_OS_WIN // for %APPDATA% @@ -239,9 +236,6 @@ void QQmlEnginePrivate::registerQuickTypes() #endif qmlRegisterType(uri, 2, 8, "LoggingCategory"); qmlRegisterType(uri, 2, 12, "LoggingCategory"); -#if QT_CONFIG(qml_worker_script) - qmlRegisterType(uri, 2, 0, "WorkerScript"); -#endif #if QT_CONFIG(qml_locale) qmlRegisterUncreatableType(uri, 2, 0, "Locale", QQmlEngine::tr("Locale cannot be instantiated. Use Qt.locale()")); #endif @@ -968,16 +962,6 @@ void QQmlEnginePrivate::init() rootContext = new QQmlContext(q,true); } -#if QT_CONFIG(qml_worker_script) -QQuickWorkerScriptEngine *QQmlEnginePrivate::getWorkerScriptEngine() -{ - Q_Q(QQmlEngine); - if (!workerScriptEngine) - workerScriptEngine = new QQuickWorkerScriptEngine(q); - return workerScriptEngine; -} -#endif - /*! \class QQmlEngine \since 5.0 diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 4f7fb79593..6ef88404fd 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -94,7 +94,6 @@ class QQmlTypeNameCache; class QQmlComponentAttached; class QQmlCleanup; class QQmlDelayedError; -class QQuickWorkerScriptEngine; class QQmlObjectCreator; class QDir; class QQmlIncubator; @@ -154,8 +153,7 @@ public: QV4::ExecutionEngine *v4engine() const { return q_func()->handle(); } #if QT_CONFIG(qml_worker_script) - QQuickWorkerScriptEngine *getWorkerScriptEngine(); - QQuickWorkerScriptEngine *workerScriptEngine; + QThread *workerScriptEngine; #endif QUrl baseUrl; diff --git a/src/qml/types/qquickworkerscript.cpp b/src/qml/types/qquickworkerscript.cpp deleted file mode 100644 index c081c9e7fc..0000000000 --- a/src/qml/types/qquickworkerscript.cpp +++ /dev/null @@ -1,669 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qtqmlglobal_p.h" -#include "qquickworkerscript_p.h" -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if QT_CONFIG(qml_network) -#include -#include "qqmlnetworkaccessmanagerfactory.h" -#endif - -#include -#include - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class WorkerDataEvent : public QEvent -{ -public: - enum Type { WorkerData = QEvent::User }; - - WorkerDataEvent(int workerId, const QByteArray &data); - virtual ~WorkerDataEvent(); - - int workerId() const; - QByteArray data() const; - -private: - int m_id; - QByteArray m_data; -}; - -class WorkerLoadEvent : public QEvent -{ -public: - enum Type { WorkerLoad = WorkerDataEvent::WorkerData + 1 }; - - WorkerLoadEvent(int workerId, const QUrl &url); - - int workerId() const; - QUrl url() const; - -private: - int m_id; - QUrl m_url; -}; - -class WorkerRemoveEvent : public QEvent -{ -public: - enum Type { WorkerRemove = WorkerLoadEvent::WorkerLoad + 1 }; - - WorkerRemoveEvent(int workerId); - - int workerId() const; - -private: - int m_id; -}; - -class WorkerErrorEvent : public QEvent -{ -public: - enum Type { WorkerError = WorkerRemoveEvent::WorkerRemove + 1 }; - - WorkerErrorEvent(const QQmlError &error); - - QQmlError error() const; - -private: - QQmlError m_error; -}; - -class QQuickWorkerScriptEnginePrivate : public QObject -{ - Q_OBJECT -public: - enum WorkerEventTypes { - WorkerDestroyEvent = QEvent::User + 100 - }; - - QQuickWorkerScriptEnginePrivate(QQmlEngine *eng); - - QQmlEngine *qmlengine; - - QMutex m_lock; - QWaitCondition m_wait; - - struct WorkerScript : public QV8Engine { - WorkerScript(int id, QQuickWorkerScriptEnginePrivate *parent); - ~WorkerScript() override; - -#if QT_CONFIG(qml_network) - QNetworkAccessManager *networkAccessManager() override; -#endif - - QQuickWorkerScriptEnginePrivate *p = nullptr; - QUrl source; - QQuickWorkerScript *owner = nullptr; -#if QT_CONFIG(qml_network) - QScopedPointer accessManager; -#endif - int id = -1; - }; - - QHash workers; - QV4::ReturnedValue getWorker(WorkerScript *); - - int m_nextId; - - static QV4::ReturnedValue method_sendMessage(const QV4::FunctionObject *, const QV4::Value *thisObject, const QV4::Value *argv, int argc); - -signals: - void stopThread(); - -protected: - bool event(QEvent *) override; - -private: - void processMessage(int, const QByteArray &); - void processLoad(int, const QUrl &); - void reportScriptException(WorkerScript *, const QQmlError &error); -}; - -QQuickWorkerScriptEnginePrivate::QQuickWorkerScriptEnginePrivate(QQmlEngine *engine) -: qmlengine(engine), m_nextId(0) -{ -} - -QV4::ReturnedValue QQuickWorkerScriptEnginePrivate::method_sendMessage(const QV4::FunctionObject *b, - const QV4::Value *, const QV4::Value *argv, int argc) -{ - QV4::Scope scope(b); - WorkerScript *script = static_cast(scope.engine->v8Engine); - - QV4::ScopedValue v(scope, argc > 0 ? argv[0] : QV4::Value::undefinedValue()); - QByteArray data = QV4::Serialize::serialize(v, scope.engine); - - QMutexLocker locker(&script->p->m_lock); - if (script && script->owner) - QCoreApplication::postEvent(script->owner, new WorkerDataEvent(0, data)); - - return QV4::Encode::undefined(); -} - -bool QQuickWorkerScriptEnginePrivate::event(QEvent *event) -{ - if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) { - WorkerDataEvent *workerEvent = static_cast(event); - processMessage(workerEvent->workerId(), workerEvent->data()); - return true; - } else if (event->type() == (QEvent::Type)WorkerLoadEvent::WorkerLoad) { - WorkerLoadEvent *workerEvent = static_cast(event); - processLoad(workerEvent->workerId(), workerEvent->url()); - return true; - } else if (event->type() == (QEvent::Type)WorkerDestroyEvent) { - emit stopThread(); - return true; - } else if (event->type() == (QEvent::Type)WorkerRemoveEvent::WorkerRemove) { - QMutexLocker locker(&m_lock); - WorkerRemoveEvent *workerEvent = static_cast(event); - QHash::iterator itr = workers.find(workerEvent->workerId()); - if (itr != workers.end()) { - delete itr.value(); - workers.erase(itr); - } - return true; - } else { - return QObject::event(event); - } -} - -void QQuickWorkerScriptEnginePrivate::processMessage(int id, const QByteArray &data) -{ - WorkerScript *script = workers.value(id); - if (!script) - return; - - QV4::ExecutionEngine *v4 = QV8Engine::getV4(script); - QV4::Scope scope(v4); - QV4::ScopedString v(scope); - QV4::ScopedObject worker(scope, v4->globalObject->get((v = v4->newString(QStringLiteral("WorkerScript"))))); - QV4::ScopedFunctionObject onmessage(scope); - if (worker) - onmessage = worker->get((v = v4->newString(QStringLiteral("onMessage")))); - - if (!onmessage) - return; - - QV4::ScopedValue value(scope, QV4::Serialize::deserialize(data, v4)); - - QV4::JSCallData jsCallData(scope, 1); - *jsCallData->thisObject = v4->global(); - jsCallData->args[0] = value; - onmessage->call(jsCallData); - if (scope.hasException()) { - QQmlError error = scope.engine->catchExceptionAsQmlError(); - reportScriptException(script, error); - } -} - -void QQuickWorkerScriptEnginePrivate::processLoad(int id, const QUrl &url) -{ - if (url.isRelative()) - return; - - QString fileName = QQmlFile::urlToLocalFileOrQrc(url); - - WorkerScript *script = workers.value(id); - if (!script) - return; - - QV4::ExecutionEngine *v4 = QV8Engine::getV4(script); - - script->source = url; - - if (fileName.endsWith(QLatin1String(".mjs"))) { - auto moduleUnit = v4->loadModule(url); - if (moduleUnit) { - if (moduleUnit->instantiate(v4)) - moduleUnit->evaluate(); - } else { - v4->throwError(QStringLiteral("Could not load module file")); - } - } else { - QString error; - QV4::Scope scope(v4); - QScopedPointer program; - program.reset(QV4::Script::createFromFileOrCache(v4, /*qmlContext*/nullptr, fileName, url, &error)); - if (program.isNull()) { - if (!error.isEmpty()) - qWarning().nospace() << error; - return; - } - - if (!v4->hasException) - program->run(); - } - - if (v4->hasException) { - QQmlError error = v4->catchExceptionAsQmlError(); - reportScriptException(script, error); - } -} - -void QQuickWorkerScriptEnginePrivate::reportScriptException(WorkerScript *script, - const QQmlError &error) -{ - QMutexLocker locker(&script->p->m_lock); - if (script->owner) - QCoreApplication::postEvent(script->owner, new WorkerErrorEvent(error)); -} - -WorkerDataEvent::WorkerDataEvent(int workerId, const QByteArray &data) -: QEvent((QEvent::Type)WorkerData), m_id(workerId), m_data(data) -{ -} - -WorkerDataEvent::~WorkerDataEvent() -{ -} - -int WorkerDataEvent::workerId() const -{ - return m_id; -} - -QByteArray WorkerDataEvent::data() const -{ - return m_data; -} - -WorkerLoadEvent::WorkerLoadEvent(int workerId, const QUrl &url) -: QEvent((QEvent::Type)WorkerLoad), m_id(workerId), m_url(url) -{ -} - -int WorkerLoadEvent::workerId() const -{ - return m_id; -} - -QUrl WorkerLoadEvent::url() const -{ - return m_url; -} - -WorkerRemoveEvent::WorkerRemoveEvent(int workerId) -: QEvent((QEvent::Type)WorkerRemove), m_id(workerId) -{ -} - -int WorkerRemoveEvent::workerId() const -{ - return m_id; -} - -WorkerErrorEvent::WorkerErrorEvent(const QQmlError &error) -: QEvent((QEvent::Type)WorkerError), m_error(error) -{ -} - -QQmlError WorkerErrorEvent::error() const -{ - return m_error; -} - -QQuickWorkerScriptEngine::QQuickWorkerScriptEngine(QQmlEngine *parent) -: QThread(parent), d(new QQuickWorkerScriptEnginePrivate(parent)) -{ - d->m_lock.lock(); - connect(d, SIGNAL(stopThread()), this, SLOT(quit()), Qt::DirectConnection); - start(QThread::LowestPriority); - d->m_wait.wait(&d->m_lock); - d->moveToThread(this); - d->m_lock.unlock(); -} - -QQuickWorkerScriptEngine::~QQuickWorkerScriptEngine() -{ - d->m_lock.lock(); - QCoreApplication::postEvent(d, new QEvent((QEvent::Type)QQuickWorkerScriptEnginePrivate::WorkerDestroyEvent)); - d->m_lock.unlock(); - - //We have to force to cleanup the main thread's event queue here - //to make sure the main GUI release all pending locks/wait conditions which - //some worker script/agent are waiting for (QQmlListModelWorkerAgent::sync() for example). - while (!isFinished()) { - // We can't simply wait here, because the worker thread will not terminate - // until the main thread processes the last data event it generates - QCoreApplication::processEvents(); - yieldCurrentThread(); - } - - d->deleteLater(); -} - -QQuickWorkerScriptEnginePrivate::WorkerScript::WorkerScript(int id, QQuickWorkerScriptEnginePrivate *parent) - : QV8Engine(new QV4::ExecutionEngine) - , p(parent) - , id(id) -{ - m_v4Engine->v8Engine = this; - - initQmlGlobalObject(); - - QV4::Scope scope(m_v4Engine); - QV4::ScopedObject api(scope, scope.engine->newObject()); - QV4::ScopedString name(scope, m_v4Engine->newString(QStringLiteral("sendMessage"))); - QV4::ScopedValue sendMessage(scope, QV4::FunctionObject::createBuiltinFunction(m_v4Engine, name, method_sendMessage, 1)); - api->put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("sendMessage"))), sendMessage); - m_v4Engine->globalObject->put(QV4::ScopedString(scope, scope.engine->newString(QStringLiteral("WorkerScript"))), api); -} - -QQuickWorkerScriptEnginePrivate::WorkerScript::~WorkerScript() -{ - delete m_v4Engine; -} - -#if QT_CONFIG(qml_network) -QNetworkAccessManager *QQuickWorkerScriptEnginePrivate::WorkerScript::networkAccessManager() -{ - if (!accessManager) { - if (p->qmlengine && p->qmlengine->networkAccessManagerFactory()) { - accessManager.reset(p->qmlengine->networkAccessManagerFactory()->create(p)); - } else { - accessManager.reset(new QNetworkAccessManager(p)); - } - } - return accessManager.data(); -} -#endif - -int QQuickWorkerScriptEngine::registerWorkerScript(QQuickWorkerScript *owner) -{ - typedef QQuickWorkerScriptEnginePrivate::WorkerScript WorkerScript; - WorkerScript *script = new WorkerScript(d->m_nextId++, d); - - script->owner = owner; - - d->m_lock.lock(); - d->workers.insert(script->id, script); - d->m_lock.unlock(); - - return script->id; -} - -void QQuickWorkerScriptEngine::removeWorkerScript(int id) -{ - QQuickWorkerScriptEnginePrivate::WorkerScript* script = d->workers.value(id); - if (script) { - script->owner = nullptr; - QCoreApplication::postEvent(d, new WorkerRemoveEvent(id)); - } -} - -void QQuickWorkerScriptEngine::executeUrl(int id, const QUrl &url) -{ - QCoreApplication::postEvent(d, new WorkerLoadEvent(id, url)); -} - -void QQuickWorkerScriptEngine::sendMessage(int id, const QByteArray &data) -{ - QCoreApplication::postEvent(d, new WorkerDataEvent(id, data)); -} - -void QQuickWorkerScriptEngine::run() -{ - d->m_lock.lock(); - - d->m_wait.wakeAll(); - - d->m_lock.unlock(); - - exec(); - - qDeleteAll(d->workers); - d->workers.clear(); -} - - -/*! - \qmltype WorkerScript - \instantiates QQuickWorkerScript - \ingroup qtquick-threading - \inqmlmodule QtQml - \brief Enables the use of threads in a Qt Quick application. - - Use WorkerScript to run operations in a new thread. - This is useful for running operations in the background so - that the main GUI thread is not blocked. - - Messages can be passed between the new thread and the parent thread - using \l sendMessage() and the \c onMessage() handler. - - An example: - - \snippet qml/workerscript/workerscript.qml 0 - - The above worker script specifies a JavaScript file, "script.mjs", that handles - the operations to be performed in the new thread. Here is \c script.mjs: - - \quotefile qml/workerscript/script.mjs - - When the user clicks anywhere within the rectangle, \c sendMessage() is - called, triggering the \tt WorkerScript.onMessage() handler in - \tt script.mjs. This in turn sends a reply message that is then received - by the \tt onMessage() handler of \tt myWorker. - - The example uses a script that is an ECMAScript module, because it has the ".mjs" extension. - It can use import statements to access functionality from other modules and it is run in JavaScript - strict mode. - - If a worker script has the extension ".js" instead, then it is considered to contain plain JavaScript - statements and it is run in non-strict mode. - - \note Each WorkerScript element will instantiate a separate JavaScript engine to ensure perfect - isolation and thread-safety. If the impact of that results in a memory consumption that is too - high for your environment, then consider sharing a WorkerScript element. - - \section3 Restrictions - - Since the \c WorkerScript.onMessage() function is run in a separate thread, the - JavaScript file is evaluated in a context separate from the main QML engine. This means - that unlike an ordinary JavaScript file that is imported into QML, the \c script.mjs - in the above example cannot access the properties, methods or other attributes - of the QML item, nor can it access any context properties set on the QML object - through QQmlContext. - - Additionally, there are restrictions on the types of values that can be passed to and - from the worker script. See the sendMessage() documentation for details. - - Worker scripts that are plain JavaScript sources can not use \l {qtqml-javascript-imports.html}{.import} syntax. - Scripts that are ECMAScript modules can freely use import and export statements. - - \sa {Qt Quick Examples - Threading}, - {Threaded ListModel Example} -*/ -QQuickWorkerScript::QQuickWorkerScript(QObject *parent) -: QObject(parent), m_engine(nullptr), m_scriptId(-1), m_componentComplete(true) -{ -} - -QQuickWorkerScript::~QQuickWorkerScript() -{ - if (m_scriptId != -1) m_engine->removeWorkerScript(m_scriptId); -} - -/*! - \qmlproperty url WorkerScript::source - - This holds the url of the JavaScript file that implements the - \tt WorkerScript.onMessage() handler for threaded operations. - - If the file name component of the url ends with ".mjs", then the script - is parsed as an ECMAScript module and run in strict mode. Otherwise it is considered to be - plain script. -*/ -QUrl QQuickWorkerScript::source() const -{ - return m_source; -} - -void QQuickWorkerScript::setSource(const QUrl &source) -{ - if (m_source == source) - return; - - m_source = source; - - if (engine()) - m_engine->executeUrl(m_scriptId, m_source); - - emit sourceChanged(); -} - -/*! - \qmlmethod WorkerScript::sendMessage(jsobject message) - - Sends the given \a message to a worker script handler in another - thread. The other worker script handler can receive this message - through the onMessage() handler. - - The \c message object may only contain values of the following - types: - - \list - \li boolean, number, string - \li JavaScript objects and arrays - \li ListModel objects (any other type of QObject* is not allowed) - \endlist - - All objects and arrays are copied to the \c message. With the exception - of ListModel objects, any modifications by the other thread to an object - passed in \c message will not be reflected in the original object. -*/ -void QQuickWorkerScript::sendMessage(QQmlV4Function *args) -{ - if (!engine()) { - qWarning("QQuickWorkerScript: Attempt to send message before WorkerScript establishment"); - return; - } - - QV4::Scope scope(args->v4engine()); - QV4::ScopedValue argument(scope, QV4::Value::undefinedValue()); - if (args->length() != 0) - argument = (*args)[0]; - - m_engine->sendMessage(m_scriptId, QV4::Serialize::serialize(argument, scope.engine)); -} - -void QQuickWorkerScript::classBegin() -{ - m_componentComplete = false; -} - -QQuickWorkerScriptEngine *QQuickWorkerScript::engine() -{ - if (m_engine) return m_engine; - if (m_componentComplete) { - QQmlEngine *engine = qmlEngine(this); - if (!engine) { - qWarning("QQuickWorkerScript: engine() called without qmlEngine() set"); - return nullptr; - } - - m_engine = QQmlEnginePrivate::get(engine)->getWorkerScriptEngine(); - m_scriptId = m_engine->registerWorkerScript(this); - - if (m_source.isValid()) - m_engine->executeUrl(m_scriptId, m_source); - - return m_engine; - } - return nullptr; -} - -void QQuickWorkerScript::componentComplete() -{ - m_componentComplete = true; - engine(); // Get it started now. -} - -/*! - \qmlsignal WorkerScript::message(jsobject msg) - - This signal is emitted when a message \a msg is received from a worker - script in another thread through a call to sendMessage(). - - The corresponding handler is \c onMessage. -*/ - -bool QQuickWorkerScript::event(QEvent *event) -{ - if (event->type() == (QEvent::Type)WorkerDataEvent::WorkerData) { - if (QQmlEngine *engine = qmlEngine(this)) { - QV4::ExecutionEngine *v4 = engine->handle(); - WorkerDataEvent *workerEvent = static_cast(event); - emit message(QJSValue(v4, QV4::Serialize::deserialize(workerEvent->data(), v4))); - } - return true; - } else if (event->type() == (QEvent::Type)WorkerErrorEvent::WorkerError) { - WorkerErrorEvent *workerEvent = static_cast(event); - QQmlEnginePrivate::warning(qmlEngine(this), workerEvent->error()); - return true; - } else { - return QObject::event(event); - } -} - -QT_END_NAMESPACE - -#include - -#include "moc_qquickworkerscript_p.cpp" diff --git a/src/qml/types/qquickworkerscript_p.h b/src/qml/types/qquickworkerscript_p.h deleted file mode 100644 index 87cf2e9754..0000000000 --- a/src/qml/types/qquickworkerscript_p.h +++ /dev/null @@ -1,123 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQUICKWORKERSCRIPT_P_H -#define QQUICKWORKERSCRIPT_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include - -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - - -class QQuickWorkerScript; -class QQuickWorkerScriptEnginePrivate; -class QQuickWorkerScriptEngine : public QThread -{ -Q_OBJECT -public: - QQuickWorkerScriptEngine(QQmlEngine *parent = nullptr); - ~QQuickWorkerScriptEngine(); - - int registerWorkerScript(QQuickWorkerScript *); - void removeWorkerScript(int); - void executeUrl(int, const QUrl &); - void sendMessage(int, const QByteArray &); - -protected: - void run() override; - -private: - QQuickWorkerScriptEnginePrivate *d; -}; - -class QQmlV4Function; -class Q_AUTOTEST_EXPORT QQuickWorkerScript : public QObject, public QQmlParserStatus -{ - Q_OBJECT - Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) - - Q_INTERFACES(QQmlParserStatus) -public: - QQuickWorkerScript(QObject *parent = nullptr); - ~QQuickWorkerScript(); - - QUrl source() const; - void setSource(const QUrl &); - -public Q_SLOTS: - void sendMessage(QQmlV4Function*); - -Q_SIGNALS: - void sourceChanged(); - void message(const QJSValue &messageObject); - -protected: - void classBegin() override; - void componentComplete() override; - bool event(QEvent *) override; - -private: - QQuickWorkerScriptEngine *engine(); - QQuickWorkerScriptEngine *m_engine; - int m_scriptId; - QUrl m_source; - bool m_componentComplete; -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QQuickWorkerScript) - -#endif // QQUICKWORKERSCRIPT_P_H diff --git a/src/qml/types/types.pri b/src/qml/types/types.pri index ba11271d66..c50273071b 100644 --- a/src/qml/types/types.pri +++ b/src/qml/types/types.pri @@ -8,13 +8,6 @@ HEADERS += \ $$PWD/qqmlconnections_p.h \ $$PWD/qqmlmodelindexvaluetype_p.h -qtConfig(qml-worker-script) { - SOURCES += \ - $$PWD/qquickworkerscript.cpp - HEADERS += \ - $$PWD/qquickworkerscript_p.h -} - qtConfig(qml-animation) { SOURCES += \ $$PWD/qqmltimer.cpp -- cgit v1.2.3 From 803e1d2dc77522665fbfd4ddaa911825bcd50892 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 6 May 2019 12:41:55 +0200 Subject: Move PropertyResolver out of qqmlirbuilder* The "early" compilation doesn't use it and we can get rid of a few V4_BOOTSTRAP checks this way. Change-Id: I1c4845aba445b105ddace0b6810e0e5c28a25b29 Reviewed-by: Simon Hausmann --- src/qml/compiler/compiler.pri | 2 + src/qml/compiler/qqmlirbuilder.cpp | 47 -------------- src/qml/compiler/qqmlirbuilder_p.h | 26 -------- src/qml/compiler/qqmlpropertycachecreator.cpp | 4 +- src/qml/compiler/qqmlpropertycachecreator_p.h | 3 +- src/qml/compiler/qqmlpropertyresolver.cpp | 92 +++++++++++++++++++++++++++ src/qml/compiler/qqmlpropertyresolver_p.h | 87 +++++++++++++++++++++++++ src/qml/compiler/qqmlpropertyvalidator.cpp | 5 +- src/qml/compiler/qqmltypecompiler.cpp | 18 +++--- 9 files changed, 199 insertions(+), 85 deletions(-) create mode 100644 src/qml/compiler/qqmlpropertyresolver.cpp create mode 100644 src/qml/compiler/qqmlpropertyresolver_p.h (limited to 'src/qml') diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri index da3c173545..0767c4fedf 100644 --- a/src/qml/compiler/compiler.pri +++ b/src/qml/compiler/compiler.pri @@ -28,6 +28,7 @@ SOURCES += \ !qmldevtools_build { HEADERS += \ + $$PWD/qqmlpropertyresolver_p.h \ $$PWD/qqmltypecompiler_p.h \ $$PWD/qqmlpropertycachecreator_p.h \ $$PWD/qqmlpropertyvalidator_p.h \ @@ -35,6 +36,7 @@ HEADERS += \ SOURCES += \ + $$PWD/qqmlpropertyresolver.cpp \ $$PWD/qqmltypecompiler.cpp \ $$PWD/qqmlpropertycachecreator.cpp \ $$PWD/qqmlpropertyvalidator.cpp \ diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 6e077ec44c..04d116ddee 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1914,53 +1914,6 @@ QVector JSCodeGen::generateJSCodeForFunctionsAndBindings(const QListproperty(name, nullptr, nullptr); - - // Find the first property - while (d && d->isFunction()) - d = cache->overrideData(d); - - if (check != IgnoreRevision && d && !cache->isAllowedInRevision(d)) { - if (notInRevision) *notInRevision = true; - return nullptr; - } else { - return d; - } -} - - -QQmlPropertyData *PropertyResolver::signal(const QString &name, bool *notInRevision) const -{ - if (notInRevision) *notInRevision = false; - - QQmlPropertyData *d = cache->property(name, nullptr, nullptr); - if (notInRevision) *notInRevision = false; - - while (d && !(d->isFunction())) - d = cache->overrideData(d); - - if (d && !cache->isAllowedInRevision(d)) { - if (notInRevision) *notInRevision = true; - return nullptr; - } else if (d && d->isSignal()) { - return d; - } - - if (name.endsWith(QLatin1String("Changed"))) { - QString propName = name.mid(0, name.length() - static_cast(strlen("Changed"))); - - d = property(propName, notInRevision); - if (d) - return cache->signal(d->notifyIndex()); - } - - return nullptr; -} - IRLoader::IRLoader(const QV4::CompiledData::Unit *qmlData, QmlIR::Document *output) : unit(qmlData) , output(output) diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 298fe7dd92..0b462cf4bb 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -508,32 +508,6 @@ private: char *writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const; }; -#ifndef V4_BOOTSTRAP -struct Q_QML_EXPORT PropertyResolver -{ - PropertyResolver(const QQmlRefPointer &cache) - : cache(cache) - {} - - QQmlPropertyData *property(int index) const - { - return cache->property(index); - } - - enum RevisionCheck { - CheckRevision, - IgnoreRevision - }; - - QQmlPropertyData *property(const QString &name, bool *notInRevision = nullptr, RevisionCheck check = CheckRevision) const; - - // This code must match the semantics of QQmlPropertyPrivate::findSignalByName - QQmlPropertyData *signal(const QString &name, bool *notInRevision) const; - - QQmlRefPointer cache; -}; -#endif - struct Q_QML_PRIVATE_EXPORT JSCodeGen : public QV4::Compiler::Codegen { JSCodeGen(const QString &sourceCode, QV4::Compiler::JSUnitGenerator *jsUnitGenerator, QV4::Compiler::Module *jsModule, diff --git a/src/qml/compiler/qqmlpropertycachecreator.cpp b/src/qml/compiler/qqmlpropertycachecreator.cpp index fb54da5b73..bd4f2a0612 100644 --- a/src/qml/compiler/qqmlpropertycachecreator.cpp +++ b/src/qml/compiler/qqmlpropertycachecreator.cpp @@ -64,7 +64,9 @@ bool QQmlBindingInstantiationContext::resolveInstantiatingProperty() Q_ASSERT(instantiatingBinding->propertyNameIndex != 0); bool notInRevision = false; - instantiatingProperty = QmlIR::PropertyResolver(referencingObjectPropertyCache).property(instantiatingPropertyName, ¬InRevision, QmlIR::PropertyResolver::IgnoreRevision); + instantiatingProperty = QQmlPropertyResolver(referencingObjectPropertyCache) + .property(instantiatingPropertyName, ¬InRevision, + QQmlPropertyResolver::IgnoreRevision); return instantiatingProperty != nullptr; } diff --git a/src/qml/compiler/qqmlpropertycachecreator_p.h b/src/qml/compiler/qqmlpropertycachecreator_p.h index 346cfb5803..28eea27675 100644 --- a/src/qml/compiler/qqmlpropertycachecreator_p.h +++ b/src/qml/compiler/qqmlpropertycachecreator_p.h @@ -53,6 +53,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -323,7 +324,7 @@ inline QQmlCompileError QQmlPropertyCacheCreator::createMetaObj int varPropCount = 0; - QmlIR::PropertyResolver resolver(baseTypeCache); + QQmlPropertyResolver resolver(baseTypeCache); auto p = obj->propertiesBegin(); auto pend = obj->propertiesEnd(); diff --git a/src/qml/compiler/qqmlpropertyresolver.cpp b/src/qml/compiler/qqmlpropertyresolver.cpp new file mode 100644 index 0000000000..90eaca0b90 --- /dev/null +++ b/src/qml/compiler/qqmlpropertyresolver.cpp @@ -0,0 +1,92 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlpropertyresolver_p.h" + +QT_BEGIN_NAMESPACE + +QQmlPropertyData *QQmlPropertyResolver::property(const QString &name, bool *notInRevision, + RevisionCheck check) const +{ + if (notInRevision) *notInRevision = false; + + QQmlPropertyData *d = cache->property(name, nullptr, nullptr); + + // Find the first property + while (d && d->isFunction()) + d = cache->overrideData(d); + + if (check != IgnoreRevision && d && !cache->isAllowedInRevision(d)) { + if (notInRevision) *notInRevision = true; + return nullptr; + } else { + return d; + } +} + + +QQmlPropertyData *QQmlPropertyResolver::signal(const QString &name, bool *notInRevision) const +{ + if (notInRevision) *notInRevision = false; + + QQmlPropertyData *d = cache->property(name, nullptr, nullptr); + if (notInRevision) *notInRevision = false; + + while (d && !(d->isFunction())) + d = cache->overrideData(d); + + if (d && !cache->isAllowedInRevision(d)) { + if (notInRevision) *notInRevision = true; + return nullptr; + } else if (d && d->isSignal()) { + return d; + } + + if (name.endsWith(QLatin1String("Changed"))) { + QString propName = name.mid(0, name.length() - static_cast(strlen("Changed"))); + + d = property(propName, notInRevision); + if (d) + return cache->signal(d->notifyIndex()); + } + + return nullptr; +} + +QT_END_NAMESPACE diff --git a/src/qml/compiler/qqmlpropertyresolver_p.h b/src/qml/compiler/qqmlpropertyresolver_p.h new file mode 100644 index 0000000000..df857f242e --- /dev/null +++ b/src/qml/compiler/qqmlpropertyresolver_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLPROPERTYRESOLVER_P_H +#define QQMLPROPERTYRESOLVER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +struct Q_QML_EXPORT QQmlPropertyResolver +{ + QQmlPropertyResolver(const QQmlRefPointer &cache) + : cache(cache) + {} + + QQmlPropertyData *property(int index) const + { + return cache->property(index); + } + + enum RevisionCheck { + CheckRevision, + IgnoreRevision + }; + + QQmlPropertyData *property(const QString &name, bool *notInRevision = nullptr, + RevisionCheck check = CheckRevision) const; + + // This code must match the semantics of QQmlPropertyPrivate::findSignalByName + QQmlPropertyData *signal(const QString &name, bool *notInRevision) const; + + QQmlRefPointer cache; +}; + +QT_END_NAMESPACE + +#endif // QQMLPROPERTYRESOLVER_P_H diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp index 8c06760d42..1812ad6546 100644 --- a/src/qml/compiler/qqmlpropertyvalidator.cpp +++ b/src/qml/compiler/qqmlpropertyvalidator.cpp @@ -41,6 +41,7 @@ #include #include +#include #include QT_BEGIN_NAMESPACE @@ -121,7 +122,7 @@ QVector QQmlPropertyValidator::validateObject(int objectIndex, groupProperties.insert(pos, binding); } - QmlIR::PropertyResolver propertyResolver(propertyCache); + QQmlPropertyResolver propertyResolver(propertyCache); QString defaultPropertyName; QQmlPropertyData *defaultProperty = nullptr; @@ -164,7 +165,7 @@ QVector QQmlPropertyValidator::validateObject(int objectIndex, pd = propertyResolver.signal(name, ¬InRevision); } else { pd = propertyResolver.property(name, ¬InRevision, - QmlIR::PropertyResolver::CheckRevision); + QQmlPropertyResolver::CheckRevision); } if (notInRevision) { diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 239f04a58f..db57d38c24 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -44,6 +44,7 @@ #include #include #include +#include #define COMPILE_EXCEPTION(token, desc) \ { \ @@ -357,7 +358,7 @@ bool SignalHandlerConverter::convertSignalHandlerExpressionsToFunctionDeclaratio if (!QmlIR::IRBuilder::isSignalPropertyName(propertyName)) continue; - QmlIR::PropertyResolver resolver(propertyCache); + QQmlPropertyResolver resolver(propertyCache); Q_ASSERT(propertyName.startsWith(QLatin1String("on"))); propertyName.remove(0, 2); @@ -513,7 +514,7 @@ bool QQmlEnumTypeResolver::resolveEnumBindings() continue; const QmlIR::Object *obj = qmlObjects.at(i); - QmlIR::PropertyResolver resolver(propertyCache); + QQmlPropertyResolver resolver(propertyCache); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { if (binding->flags & QV4::CompiledData::Binding::IsSignalHandlerExpression @@ -722,7 +723,7 @@ void QQmlAliasAnnotator::annotateBindingsToAliases() const QmlIR::Object *obj = qmlObjects.at(i); - QmlIR::PropertyResolver resolver(propertyCache); + QQmlPropertyResolver resolver(propertyCache); QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { @@ -754,7 +755,7 @@ void QQmlScriptStringScanner::scan() const QmlIR::Object *obj = qmlObjects.at(i); - QmlIR::PropertyResolver resolver(propertyCache); + QQmlPropertyResolver resolver(propertyCache); QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); for (QmlIR::Binding *binding = obj->firstBinding(); binding; binding = binding->next) { @@ -799,7 +800,7 @@ static bool isUsableComponent(const QMetaObject *metaObject) void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlIR::Object *obj, QQmlPropertyCache *propertyCache) { - QmlIR::PropertyResolver propertyResolver(propertyCache); + QQmlPropertyResolver propertyResolver(propertyCache); QQmlPropertyData *defaultProperty = obj->indexOfDefaultPropertyOrAlias != -1 ? propertyCache->parent()->defaultProperty() : propertyCache->defaultProperty(); @@ -1110,7 +1111,7 @@ QQmlComponentAndAliasResolver::AliasResolutionResult QQmlComponentAndAliasResolv break; } - QmlIR::PropertyResolver resolver(targetCache); + QQmlPropertyResolver resolver(targetCache); QQmlPropertyData *targetProperty = resolver.property(property.toString()); @@ -1224,7 +1225,7 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex) QQmlCustomParser *customParser = customParsers.value(obj->inheritedTypeNameIndex); - QmlIR::PropertyResolver propertyResolver(propertyCache); + QQmlPropertyResolver propertyResolver(propertyCache); QStringList deferredPropertyNames; { @@ -1263,7 +1264,8 @@ bool QQmlDeferredAndCustomParserBindingScanner::scanObject(int objectIndex) continue; bool notInRevision = false; - pd = propertyResolver.property(name, ¬InRevision, QmlIR::PropertyResolver::CheckRevision); + pd = propertyResolver.property(name, ¬InRevision, + QQmlPropertyResolver::CheckRevision); } bool seenSubObjectWithId = false; -- cgit v1.2.3 From 791e63021e1e1333ff3c678674df8f4f18212e43 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 6 May 2019 13:06:15 +0200 Subject: Move QQmlIR::IRLoader out of qqmlirbuilder* We don't need it to build the IR and we can drop a few checks for V4_BOOTSTRAP this way. Change-Id: I9464e65528c70c42ebc8ddad576eaab001dc9d2f Reviewed-by: Simon Hausmann --- src/qml/compiler/compiler.pri | 2 + src/qml/compiler/qqmlirbuilder.cpp | 164 ----------------------------- src/qml/compiler/qqmlirbuilder_p.h | 19 +--- src/qml/compiler/qqmlirloader.cpp | 205 +++++++++++++++++++++++++++++++++++++ src/qml/compiler/qqmlirloader_p.h | 80 +++++++++++++++ src/qml/qml/qqmltypeloader.cpp | 5 +- 6 files changed, 292 insertions(+), 183 deletions(-) create mode 100644 src/qml/compiler/qqmlirloader.cpp create mode 100644 src/qml/compiler/qqmlirloader_p.h (limited to 'src/qml') diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri index 0767c4fedf..c15c45a1cb 100644 --- a/src/qml/compiler/compiler.pri +++ b/src/qml/compiler/compiler.pri @@ -28,6 +28,7 @@ SOURCES += \ !qmldevtools_build { HEADERS += \ + $$PWD/qqmlirloader_p.h \ $$PWD/qqmlpropertyresolver_p.h \ $$PWD/qqmltypecompiler_p.h \ $$PWD/qqmlpropertycachecreator_p.h \ @@ -36,6 +37,7 @@ HEADERS += \ SOURCES += \ + $$PWD/qqmlirloader.cpp \ $$PWD/qqmlpropertyresolver.cpp \ $$PWD/qqmltypecompiler.cpp \ $$PWD/qqmlpropertycachecreator.cpp \ diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 04d116ddee..28e7daecd5 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1911,167 +1911,3 @@ QVector JSCodeGen::generateJSCodeForFunctionsAndBindings(const QListjsParserEngine.pool(); -} - -void IRLoader::load() -{ - output->jsGenerator.stringTable.initializeFromBackingUnit(unit); - - const QV4::CompiledData::QmlUnit *qmlUnit = unit->qmlUnit(); - - for (quint32 i = 0; i < qmlUnit->nImports; ++i) - output->imports << qmlUnit->importAt(i); - - if (unit->flags & QV4::CompiledData::Unit::IsSingleton) { - QmlIR::Pragma *p = New(); - p->location = QV4::CompiledData::Location(); - p->type = QmlIR::Pragma::PragmaSingleton; - output->pragmas << p; - } - - for (uint i = 0; i < qmlUnit->nObjects; ++i) { - const QV4::CompiledData::Object *serializedObject = qmlUnit->objectAt(i); - QmlIR::Object *object = loadObject(serializedObject); - output->objects.append(object); - } -} - -struct FakeExpression : public QQmlJS::AST::NullExpression -{ - FakeExpression(int start, int length) - : location(start, length) - {} - - virtual QQmlJS::AST::SourceLocation firstSourceLocation() const - { return location; } - - virtual QQmlJS::AST::SourceLocation lastSourceLocation() const - { return location; } - -private: - QQmlJS::AST::SourceLocation location; -}; - -QmlIR::Object *IRLoader::loadObject(const QV4::CompiledData::Object *serializedObject) -{ - QmlIR::Object *object = pool->New(); - object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex); - - object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias; - object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias; - object->flags = serializedObject->flags; - object->id = serializedObject->id; - object->location = serializedObject->location; - object->locationOfIdProperty = serializedObject->locationOfIdProperty; - - QVector functionIndices; - functionIndices.reserve(serializedObject->nFunctions + serializedObject->nBindings / 2); - - for (uint i = 0; i < serializedObject->nBindings; ++i) { - QmlIR::Binding *b = pool->New(); - *static_cast(b) = serializedObject->bindingTable()[i]; - object->bindings->append(b); - if (b->type == QV4::CompiledData::Binding::Type_Script) { - functionIndices.append(b->value.compiledScriptIndex); - b->value.compiledScriptIndex = functionIndices.count() - 1; - - QmlIR::CompiledFunctionOrExpression *foe = pool->New(); - foe->nameIndex = 0; - - QQmlJS::AST::ExpressionNode *expr; - - if (b->stringIndex != quint32(0)) { - const int start = output->code.length(); - const QString script = output->stringAt(b->stringIndex); - const int length = script.length(); - output->code.append(script); - expr = new (pool) FakeExpression(start, length); - } else - expr = new (pool) QQmlJS::AST::NullExpression(); - foe->node = new (pool) QQmlJS::AST::ExpressionStatement(expr); // dummy - object->functionsAndExpressions->append(foe); - } - } - - Q_ASSERT(object->functionsAndExpressions->count == functionIndices.count()); - - for (uint i = 0; i < serializedObject->nSignals; ++i) { - const QV4::CompiledData::Signal *serializedSignal = serializedObject->signalAt(i); - QmlIR::Signal *s = pool->New(); - s->nameIndex = serializedSignal->nameIndex; - s->location = serializedSignal->location; - s->parameters = pool->New >(); - - for (uint i = 0; i < serializedSignal->nParameters; ++i) { - QmlIR::SignalParameter *p = pool->New(); - *static_cast(p) = *serializedSignal->parameterAt(i); - s->parameters->append(p); - } - - object->qmlSignals->append(s); - } - - for (uint i = 0; i < serializedObject->nEnums; ++i) { - const QV4::CompiledData::Enum *serializedEnum = serializedObject->enumAt(i); - QmlIR::Enum *e = pool->New(); - e->nameIndex = serializedEnum->nameIndex; - e->location = serializedEnum->location; - e->enumValues = pool->New >(); - - for (uint i = 0; i < serializedEnum->nEnumValues; ++i) { - QmlIR::EnumValue *v = pool->New(); - *static_cast(v) = *serializedEnum->enumValueAt(i); - e->enumValues->append(v); - } - - object->qmlEnums->append(e); - } - - const QV4::CompiledData::Property *serializedProperty = serializedObject->propertyTable(); - for (uint i = 0; i < serializedObject->nProperties; ++i, ++serializedProperty) { - QmlIR::Property *p = pool->New(); - *static_cast(p) = *serializedProperty; - object->properties->append(p); - } - - { - const QV4::CompiledData::Alias *serializedAlias = serializedObject->aliasTable(); - for (uint i = 0; i < serializedObject->nAliases; ++i, ++serializedAlias) { - QmlIR::Alias *a = pool->New(); - *static_cast(a) = *serializedAlias; - object->aliases->append(a); - } - } - - const quint32_le *functionIdx = serializedObject->functionOffsetTable(); - for (uint i = 0; i < serializedObject->nFunctions; ++i, ++functionIdx) { - QmlIR::Function *f = pool->New(); - const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx); - - functionIndices.append(*functionIdx); - f->index = functionIndices.count() - 1; - f->location = compiledFunction->location; - f->nameIndex = compiledFunction->nameIndex; - - f->formals.allocate(pool, int(compiledFunction->nFormals)); - const quint32_le *formalNameIdx = compiledFunction->formalsTable(); - for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx) - f->formals[i] = *formalNameIdx; - - object->functions->append(f); - } - - object->runtimeFunctionIndices.allocate(pool, functionIndices); - - return object; -} - -#endif // V4_BOOTSTRAP diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index 0b462cf4bb..c937158a33 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -65,11 +65,11 @@ QT_BEGIN_NAMESPACE class QQmlPropertyCache; class QQmlContextData; class QQmlTypeNameCache; +struct QQmlIRLoader; namespace QmlIR { struct Document; -struct IRLoader; template struct PoolList @@ -347,7 +347,7 @@ public: const quint32 *namedObjectsInComponentTable() const { return namedObjectsInComponent.begin(); } private: - friend struct IRLoader; + friend struct ::QQmlIRLoader; PoolList *properties; PoolList *aliases; @@ -524,21 +524,6 @@ private: const QV4::Compiler::StringTableGenerator *stringPool; }; -struct Q_QML_PRIVATE_EXPORT IRLoader { - IRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output); - - void load(); - -private: - QmlIR::Object *loadObject(const QV4::CompiledData::Object *serializedObject); - - template _Tp *New() { return pool->New<_Tp>(); } - - const QV4::CompiledData::Unit *unit; - QmlIR::Document *output; - QQmlJS::MemoryPool *pool; -}; - } // namespace QmlIR struct QQmlCompileError diff --git a/src/qml/compiler/qqmlirloader.cpp b/src/qml/compiler/qqmlirloader.cpp new file mode 100644 index 0000000000..c2eb6da2fa --- /dev/null +++ b/src/qml/compiler/qqmlirloader.cpp @@ -0,0 +1,205 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qqmlirloader_p.h" +#include + +QT_BEGIN_NAMESPACE + +QQmlIRLoader::QQmlIRLoader(const QV4::CompiledData::Unit *qmlData, QmlIR::Document *output) + : unit(qmlData) + , output(output) +{ + pool = output->jsParserEngine.pool(); +} + +void QQmlIRLoader::load() +{ + output->jsGenerator.stringTable.initializeFromBackingUnit(unit); + + const QV4::CompiledData::QmlUnit *qmlUnit = unit->qmlUnit(); + + for (quint32 i = 0; i < qmlUnit->nImports; ++i) + output->imports << qmlUnit->importAt(i); + + if (unit->flags & QV4::CompiledData::Unit::IsSingleton) { + QmlIR::Pragma *p = New(); + p->location = QV4::CompiledData::Location(); + p->type = QmlIR::Pragma::PragmaSingleton; + output->pragmas << p; + } + + for (uint i = 0; i < qmlUnit->nObjects; ++i) { + const QV4::CompiledData::Object *serializedObject = qmlUnit->objectAt(i); + QmlIR::Object *object = loadObject(serializedObject); + output->objects.append(object); + } +} + +struct FakeExpression : public QQmlJS::AST::NullExpression +{ + FakeExpression(int start, int length) + : location(start, length) + {} + + virtual QQmlJS::AST::SourceLocation firstSourceLocation() const + { return location; } + + virtual QQmlJS::AST::SourceLocation lastSourceLocation() const + { return location; } + +private: + QQmlJS::AST::SourceLocation location; +}; + +QmlIR::Object *QQmlIRLoader::loadObject(const QV4::CompiledData::Object *serializedObject) +{ + QmlIR::Object *object = pool->New(); + object->init(pool, serializedObject->inheritedTypeNameIndex, serializedObject->idNameIndex); + + object->indexOfDefaultPropertyOrAlias = serializedObject->indexOfDefaultPropertyOrAlias; + object->defaultPropertyIsAlias = serializedObject->defaultPropertyIsAlias; + object->flags = serializedObject->flags; + object->id = serializedObject->id; + object->location = serializedObject->location; + object->locationOfIdProperty = serializedObject->locationOfIdProperty; + + QVector functionIndices; + functionIndices.reserve(serializedObject->nFunctions + serializedObject->nBindings / 2); + + for (uint i = 0; i < serializedObject->nBindings; ++i) { + QmlIR::Binding *b = pool->New(); + *static_cast(b) = serializedObject->bindingTable()[i]; + object->bindings->append(b); + if (b->type == QV4::CompiledData::Binding::Type_Script) { + functionIndices.append(b->value.compiledScriptIndex); + b->value.compiledScriptIndex = functionIndices.count() - 1; + + QmlIR::CompiledFunctionOrExpression *foe = pool->New(); + foe->nameIndex = 0; + + QQmlJS::AST::ExpressionNode *expr; + + if (b->stringIndex != quint32(0)) { + const int start = output->code.length(); + const QString script = output->stringAt(b->stringIndex); + const int length = script.length(); + output->code.append(script); + expr = new (pool) FakeExpression(start, length); + } else + expr = new (pool) QQmlJS::AST::NullExpression(); + foe->node = new (pool) QQmlJS::AST::ExpressionStatement(expr); // dummy + object->functionsAndExpressions->append(foe); + } + } + + Q_ASSERT(object->functionsAndExpressions->count == functionIndices.count()); + + for (uint i = 0; i < serializedObject->nSignals; ++i) { + const QV4::CompiledData::Signal *serializedSignal = serializedObject->signalAt(i); + QmlIR::Signal *s = pool->New(); + s->nameIndex = serializedSignal->nameIndex; + s->location = serializedSignal->location; + s->parameters = pool->New >(); + + for (uint i = 0; i < serializedSignal->nParameters; ++i) { + QmlIR::SignalParameter *p = pool->New(); + *static_cast(p) = *serializedSignal->parameterAt(i); + s->parameters->append(p); + } + + object->qmlSignals->append(s); + } + + for (uint i = 0; i < serializedObject->nEnums; ++i) { + const QV4::CompiledData::Enum *serializedEnum = serializedObject->enumAt(i); + QmlIR::Enum *e = pool->New(); + e->nameIndex = serializedEnum->nameIndex; + e->location = serializedEnum->location; + e->enumValues = pool->New >(); + + for (uint i = 0; i < serializedEnum->nEnumValues; ++i) { + QmlIR::EnumValue *v = pool->New(); + *static_cast(v) = *serializedEnum->enumValueAt(i); + e->enumValues->append(v); + } + + object->qmlEnums->append(e); + } + + const QV4::CompiledData::Property *serializedProperty = serializedObject->propertyTable(); + for (uint i = 0; i < serializedObject->nProperties; ++i, ++serializedProperty) { + QmlIR::Property *p = pool->New(); + *static_cast(p) = *serializedProperty; + object->properties->append(p); + } + + { + const QV4::CompiledData::Alias *serializedAlias = serializedObject->aliasTable(); + for (uint i = 0; i < serializedObject->nAliases; ++i, ++serializedAlias) { + QmlIR::Alias *a = pool->New(); + *static_cast(a) = *serializedAlias; + object->aliases->append(a); + } + } + + const quint32_le *functionIdx = serializedObject->functionOffsetTable(); + for (uint i = 0; i < serializedObject->nFunctions; ++i, ++functionIdx) { + QmlIR::Function *f = pool->New(); + const QV4::CompiledData::Function *compiledFunction = unit->functionAt(*functionIdx); + + functionIndices.append(*functionIdx); + f->index = functionIndices.count() - 1; + f->location = compiledFunction->location; + f->nameIndex = compiledFunction->nameIndex; + + f->formals.allocate(pool, int(compiledFunction->nFormals)); + const quint32_le *formalNameIdx = compiledFunction->formalsTable(); + for (uint i = 0; i < compiledFunction->nFormals; ++i, ++formalNameIdx) + f->formals[i] = *formalNameIdx; + + object->functions->append(f); + } + + object->runtimeFunctionIndices.allocate(pool, functionIndices); + + return object; +} + +QT_END_NAMESPACE diff --git a/src/qml/compiler/qqmlirloader_p.h b/src/qml/compiler/qqmlirloader_p.h new file mode 100644 index 0000000000..cf46ca3cb0 --- /dev/null +++ b/src/qml/compiler/qqmlirloader_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQMLIRLOADER_P_H +#define QQMLIRLOADER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace QmlIR { +struct Document; +struct Object; +} + +struct Q_QML_PRIVATE_EXPORT QQmlIRLoader { + QQmlIRLoader(const QV4::CompiledData::Unit *unit, QmlIR::Document *output); + + void load(); + +private: + QmlIR::Object *loadObject(const QV4::CompiledData::Object *serializedObject); + + template _Tp *New() { return pool->New<_Tp>(); } + + const QV4::CompiledData::Unit *unit; + QmlIR::Document *output; + QQmlJS::MemoryPool *pool; +}; + +QT_END_NAMESPACE + +#endif // QQMLIRLOADER_P_H diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 457558fb56..1f80e1905e 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -2502,7 +2503,7 @@ void QQmlTypeData::dataReceived(const SourceCodeData &data) void QQmlTypeData::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) { m_document.reset(new QmlIR::Document(isDebugging())); - QmlIR::IRLoader loader(unit, m_document.data()); + QQmlIRLoader loader(unit, m_document.data()); loader.load(); m_document->jsModule.fileName = urlString(); m_document->jsModule.finalUrl = finalUrlString(); @@ -2544,7 +2545,7 @@ bool QQmlTypeData::loadFromSource() void QQmlTypeData::restoreIR(QQmlRefPointer unit) { m_document.reset(new QmlIR::Document(isDebugging())); - QmlIR::IRLoader loader(unit->unitData(), m_document.data()); + QQmlIRLoader loader(unit->unitData(), m_document.data()); loader.load(); m_document->jsModule.fileName = urlString(); m_document->jsModule.finalUrl = finalUrlString(); -- cgit v1.2.3 From 3df85008591dffc64427095b022421469cb9a866 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 30 Apr 2019 11:22:23 +0200 Subject: Avoid std::function in qqmlirbuilder.cpp Some compilers seem to miscompile this construction. Furthermore, it doesn't really add to the readability of the code. Inline the code in question at the only place it's used and avoid most of the const_cast by adding a non-const accessor to CompiledData::Unit. Fixes: QTBUG-75392 Change-Id: I015317f28a92817d08d616cc35956745758d7847 Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlirbuilder.cpp | 36 ++++++++++++++---------------------- src/qml/compiler/qv4compileddata_p.h | 4 ++++ 2 files changed, 18 insertions(+), 22 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 868f600a10..558399ad6c 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1558,15 +1558,12 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen QQmlRefPointer compilationUnit = output.javaScriptCompilationUnit; - const QV4::CompiledData::Unit *jsUnit = nullptr; - std::function unitFinalizer - = [](QV4::CompiledData::QmlUnit *unit, uint) { - return unit; - }; + QV4::CompiledData::Unit *jsUnit = nullptr; + const bool finalize = !compilationUnit->data; // We may already have unit data if we're loading an ahead-of-time generated cache file. - if (compilationUnit->data) { - jsUnit = compilationUnit->data; + if (!finalize) { + jsUnit = const_cast(compilationUnit->data); #ifndef V4_BOOTSTRAP output.javaScriptCompilationUnit->dynamicStrings = output.jsGenerator.stringTable.allStrings(); #endif @@ -1599,20 +1596,6 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen #endif createdUnit->sourceFileIndex = output.jsGenerator.stringTable.getStringId(output.jsModule.fileName); createdUnit->finalUrlIndex = output.jsGenerator.stringTable.getStringId(output.jsModule.finalUrl); - - // Combine the qml data into the general unit data. - unitFinalizer = [&jsUnit](QV4::CompiledData::QmlUnit *qmlUnit, uint qmlDataSize) { - void *ptr = const_cast(jsUnit); - QV4::CompiledData::Unit *newUnit = (QV4::CompiledData::Unit *)realloc(ptr, jsUnit->unitSize + qmlDataSize); - jsUnit = newUnit; - newUnit->offsetToQmlUnit = newUnit->unitSize; - newUnit->unitSize += qmlDataSize; - memcpy(const_cast(newUnit->qmlUnit()), qmlUnit, qmlDataSize); - free(const_cast(qmlUnit)); - qmlUnit = nullptr; - newUnit->generateChecksum(); - return const_cast(newUnit->qmlUnit()); - }; } // No more new strings after this point, we're calculating offsets. @@ -1779,7 +1762,16 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen } } - qmlUnit = unitFinalizer(qmlUnit, totalSize); + if (finalize) { + // Combine the qml data into the general unit data. + jsUnit = static_cast(realloc(jsUnit, jsUnit->unitSize + totalSize)); + jsUnit->offsetToQmlUnit = jsUnit->unitSize; + jsUnit->unitSize += totalSize; + memcpy(jsUnit->qmlUnit(), qmlUnit, totalSize); + free(qmlUnit); + jsUnit->generateChecksum(); + qmlUnit = jsUnit->qmlUnit(); + } static const bool showStats = qEnvironmentVariableIsSet("QML_SHOW_UNIT_STATS"); if (showStats) { diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 3fd9fdf74b..76795f7aa3 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -891,6 +891,10 @@ struct Unit return reinterpret_cast(reinterpret_cast(this) + offsetToQmlUnit); } + QmlUnit *qmlUnit() { + return reinterpret_cast(reinterpret_cast(this) + offsetToQmlUnit); + } + bool isSingleton() const { return flags & Unit::IsSingleton; } -- cgit v1.2.3 From cf4a7fa44403bb3bae9c98afb80222d5e03798c5 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 6 May 2019 12:19:07 +0200 Subject: Remove the bootstrap code from assembler and JIT We don't build the assembler or the JIT in bootstrap mode. Change-Id: Idc3a56cc1e9cfba415bef9cba221c8a60ee75010 Reviewed-by: Simon Hausmann --- src/qml/jit/qv4assemblercommon_p.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/jit/qv4assemblercommon_p.h b/src/qml/jit/qv4assemblercommon_p.h index f305213ce2..b9f71b7bd9 100644 --- a/src/qml/jit/qv4assemblercommon_p.h +++ b/src/qml/jit/qv4assemblercommon_p.h @@ -449,7 +449,7 @@ public: // r6 is used by MacroAssemblerARMv7 static const RegisterID JSStackFrameRegister = JSC::ARMRegisters::r8; static const RegisterID CppStackFrameRegister = JSC::ARMRegisters::r10; -#if CPU(ARM_THUMB2) || defined(V4_BOOTSTRAP) +#if CPU(ARM_THUMB2) static const RegisterID FramePointerRegister = JSC::ARMRegisters::r7; static const RegisterID EngineRegister = JSC::ARMRegisters::r11; #else // Thumbs down -- cgit v1.2.3 From 6376014ab61c45d6570ec226fc4eee6906dd32f9 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 7 May 2019 15:12:14 +0200 Subject: Move the check for SSE2 into the configure system The JIT requires SSE2. Without it we can still use the interpreter. If you compile with SSE2 enabled and then run on a machine without SSE2 you will get a more interesting crash now. However, in this day and age we don't have to expect random pre-Pentium4 CPUs out in the wild anymore. If you want to use such a thing, you will probably build a special version of Qt for it. Change-Id: I14a71cb83876d2ce7fdad012c385d0d4389e7ddf Reviewed-by: Simon Hausmann --- src/qml/configure.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/qml') diff --git a/src/qml/configure.json b/src/qml/configure.json index 2f88aef1fb..9313e4594b 100644 --- a/src/qml/configure.json +++ b/src/qml/configure.json @@ -90,8 +90,8 @@ "purpose": "Provides a JIT for QML and JavaScript", "section": "QML", "condition": [ - " (arch.i386 && tests.pointer_32bit) - || (arch.x86_64 && tests.pointer_64bit) + " (arch.i386 && tests.pointer_32bit && features.sse2) + || (arch.x86_64 && tests.pointer_64bit && features.sse2) || (arch.arm && tests.pointer_32bit && tests.arm_fp && tests.arm_thumb && (config.linux || config.ios || config.tvos || config.qnx)) || (arch.arm64 && tests.pointer_64bit && tests.arm_fp -- cgit v1.2.3 From 9de487fbd33531c65cffd5cfc27f34c4bcff4573 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 6 May 2019 13:36:52 +0200 Subject: Move dynamicStrings into the bootstrapped part of QV4::CompiledData We don't really need the dynamic strings at compile time, but having them defined simplifies some code. Change-Id: Ibcfaae7834f8aa63918da6787d222fe71657c4ee Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlirbuilder.cpp | 2 -- src/qml/compiler/qv4compileddata_p.h | 20 +++++++++----------- 2 files changed, 9 insertions(+), 13 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 28e7daecd5..9ac1a8b5ac 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1570,9 +1570,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen // We may already have unit data if we're loading an ahead-of-time generated cache file. if (compilationUnit->data) { jsUnit = compilationUnit->data; -#ifndef V4_BOOTSTRAP output.javaScriptCompilationUnit->dynamicStrings = output.jsGenerator.stringTable.allStrings(); -#endif } else { QV4::CompiledData::Unit *createdUnit; jsUnit = createdUnit = output.jsGenerator.generateUnit(); diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index dd7ba471c3..f604cc0d46 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -1089,6 +1089,7 @@ struct Q_QML_PRIVATE_EXPORT CompilationUnit final : public CompilationUnitBase { const Unit *data = nullptr; const QmlUnit *qmlData = nullptr; + QStringList dynamicStrings; public: CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), const QString &finalUrlString = QString()); ~CompilationUnit(); @@ -1114,6 +1115,13 @@ public: void setUnitData(const Unit *unitData, const QmlUnit *qmlUnit = nullptr, const QString &fileName = QString(), const QString &finalUrlString = QString()); + QString stringAt(int index) const + { + if (uint(index) >= data->stringTableSize) + return dynamicStrings.at(index - data->stringTableSize); + return data->stringAtInternal(index); + } + #ifndef V4_BOOTSTRAP QIntrusiveListNode nextCompilationUnit; ExecutionEngine *engine = nullptr; @@ -1176,7 +1184,6 @@ public: bool isRegisteredWithEngine = false; QScopedPointer backingFile; - QStringList dynamicStrings; // --- interface for QQmlPropertyCacheCreator typedef Object CompiledObject; @@ -1184,12 +1191,6 @@ public: const Object *objectAt(int index) const { return qmlData->objectAt(index); } int importCount() const { return qmlData->nImports; } const Import *importAt(int index) const { return qmlData->importAt(index); } - QString stringAt(int index) const - { - if (uint(index) >= data->stringTableSize) - return dynamicStrings.at(index - data->stringTableSize); - return data->stringAtInternal(index); - } Heap::Object *templateObjectAt(int index) const; @@ -1230,10 +1231,7 @@ public: protected: quint32 totalStringCount() const { return data->stringTableSize; } - -#else // V4_BOOTSTRAP - QString stringAt(int index) const { return data->stringAtInternal(index); } -#endif // V4_BOOTSTRAP +#endif private: void destroy(); -- cgit v1.2.3 From 92fa6adcc5b85f8601a5648d4f8879f3a0c6675f Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Fri, 26 Apr 2019 14:30:42 +0200 Subject: Filter out duplicate entries in Object.keys This can happen due to overloaded methods on the C++ side. Fixes: QTBUG-73786 Change-Id: I757cfda65a773687cea451ab83eb41b976a9fb60 Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4qobjectwrapper.cpp | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp index e81c90dd1a..095f27279f 100644 --- a/src/qml/jsruntime/qv4qobjectwrapper.cpp +++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp @@ -763,6 +763,8 @@ struct QObjectWrapperOwnPropertyKeyIterator : ObjectOwnPropertyKeyIterator ~QObjectWrapperOwnPropertyKeyIterator() override = default; PropertyKey next(const QV4::Object *o, Property *pd = nullptr, PropertyAttributes *attrs = nullptr) override; +private: + QSet m_alreadySeen; }; PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const QV4::Object *o, Property *pd, PropertyAttributes *attrs) @@ -803,6 +805,11 @@ PropertyKey QObjectWrapperOwnPropertyKeyIterator::next(const QV4::Object *o, Pro ++propertyIndex; if (method.access() == QMetaMethod::Private || (preventDestruction && (index == deleteLaterIdx || index == destroyedIdx1 || index == destroyedIdx2))) continue; + // filter out duplicates due to overloads: + if (m_alreadySeen.contains(method.name())) + continue; + else + m_alreadySeen.insert(method.name()); ExecutionEngine *thatEngine = that->engine(); Scope scope(thatEngine); ScopedString methodName(scope, thatEngine->newString(QString::fromUtf8(method.name()))); -- cgit v1.2.3 From a8b3536d6e5e7eb1c51fb20df071185dbce317a2 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 8 May 2019 13:29:50 +0200 Subject: Move compileModule() into qv4codegen.cpp This is a better fit for the method. In turn, remove all the V4_BOOTSTRAP conditions from qv4engine_p.h and make sure we don't include or compile it in bootstrap mode. Change-Id: I5933b0724e561313ca20c420b83e4d70e63bddf5 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4codegen.cpp | 45 +++++++++++++++++++++++++ src/qml/compiler/qv4codegen_p.h | 6 ++++ src/qml/jsruntime/jsruntime.pri | 2 +- src/qml/jsruntime/qv4engine.cpp | 60 ++------------------------------- src/qml/jsruntime/qv4engine_p.h | 18 ++-------- src/qml/jsruntime/qv4runtime.cpp | 4 ++- src/qml/jsruntime/qv4runtime_p.h | 1 - src/qml/jsruntime/qv4runtimecodegen.cpp | 1 + src/qml/jsruntime/qv4value.cpp | 2 +- src/qml/qml/qqmltypeloader.cpp | 3 +- 10 files changed, 64 insertions(+), 78 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 1bf0e7147d..3c669c9b1a 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -45,6 +45,8 @@ #include #include #include +#include +#include #include #include #include @@ -3800,6 +3802,49 @@ QQmlRefPointer Codegen::createUnitForLoading() return result; } +QQmlRefPointer Codegen::compileModule( + bool debugMode, const QString &url, const QString &sourceCode, + const QDateTime &sourceTimeStamp, QList *diagnostics) +{ + QQmlJS::Engine ee; + QQmlJS::Lexer lexer(&ee); + lexer.setCode(sourceCode, /*line*/1, /*qml mode*/false); + QQmlJS::Parser parser(&ee); + + const bool parsed = parser.parseModule(); + + if (diagnostics) + *diagnostics = parser.diagnosticMessages(); + + if (!parsed) + return nullptr; + + QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast(parser.rootNode()); + if (!moduleNode) { + // if parsing was successful, and we have no module, then + // the file was empty. + if (diagnostics) + diagnostics->clear(); + return nullptr; + } + + using namespace QV4::Compiler; + Compiler::Module compilerModule(debugMode); + compilerModule.unitFlags |= CompiledData::Unit::IsESModule; + compilerModule.sourceTimeStamp = sourceTimeStamp; + JSUnitGenerator jsGenerator(&compilerModule); + Codegen cg(&jsGenerator, /*strictMode*/true); + cg.generateFromModule(url, url, sourceCode, moduleNode, &compilerModule); + auto errors = cg.errors(); + if (diagnostics) + *diagnostics << errors; + + if (!errors.isEmpty()) + return nullptr; + + return cg.generateCompilationUnit(); +} + class Codegen::VolatileMemoryLocationScanner: protected QQmlJS::AST::Visitor { VolatileMemoryLocations locs; diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index ad86483132..ece76e4406 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -52,6 +52,7 @@ #include "private/qv4global_p.h" #include +#include #include #include #include @@ -59,6 +60,8 @@ #include #include +#include + QT_BEGIN_NAMESPACE using namespace QQmlJS; @@ -683,6 +686,9 @@ public: QQmlRefPointer generateCompilationUnit(bool generateUnitData = true); static QQmlRefPointer createUnitForLoading(); + static QQmlRefPointer compileModule( + bool debugMode, const QString &url, const QString &sourceCode, + const QDateTime &sourceTimeStamp, QList *diagnostics); Context *currentContext() const { return _context; } BytecodeGenerator *generator() const { return bytecodeGenerator; } diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index ae9a36ca22..de2e0603e8 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -3,6 +3,7 @@ INCLUDEPATH += $$OUT_PWD !qmldevtools_build { SOURCES += \ + $$PWD/qv4engine.cpp \ $$PWD/qv4context.cpp \ $$PWD/qv4persistent.cpp \ $$PWD/qv4lookup.cpp \ @@ -149,7 +150,6 @@ HEADERS += \ $$PWD/qv4functiontable_p.h SOURCES += \ - $$PWD/qv4engine.cpp \ $$PWD/qv4runtime.cpp \ $$PWD/qv4string.cpp \ $$PWD/qv4value.cpp \ diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index e10bf3cf79..b65a2f2dad 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -38,9 +38,6 @@ ****************************************************************************/ #include -#include -#include -#include #include #include #include @@ -55,8 +52,6 @@ #include #endif -#ifndef V4_BOOTSTRAP - #include #include #include @@ -134,14 +129,10 @@ #include #endif -#endif // #ifndef V4_BOOTSTRAP - QT_BEGIN_NAMESPACE using namespace QV4; -#ifndef V4_BOOTSTRAP - static QBasicAtomicInt engineSerial = Q_BASIC_ATOMIC_INITIALIZER(1); ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const QV4::Value *, int) @@ -1702,7 +1693,8 @@ QQmlRefPointer ExecutionEngine::compileModule(con QQmlRefPointer ExecutionEngine::compileModule(const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp) { QList diagnostics; - auto unit = compileModule(/*debugMode*/debugger() != nullptr, url.toString(), sourceCode, sourceTimeStamp, &diagnostics); + auto unit = Compiler::Codegen::compileModule(/*debugMode*/debugger() != nullptr, url.toString(), + sourceCode, sourceTimeStamp, &diagnostics); for (const QQmlJS::DiagnosticMessage &m : diagnostics) { if (m.isError()) { throwSyntaxError(m.message, url.toString(), m.loc.startLine, m.loc.startColumn); @@ -1715,52 +1707,6 @@ QQmlRefPointer ExecutionEngine::compileModule(con return unit; } -#endif // ifndef V4_BOOTSTRAP - -QQmlRefPointer ExecutionEngine::compileModule(bool debugMode, const QString &url, const QString &sourceCode, - const QDateTime &sourceTimeStamp, QList *diagnostics) -{ - QQmlJS::Engine ee; - QQmlJS::Lexer lexer(&ee); - lexer.setCode(sourceCode, /*line*/1, /*qml mode*/false); - QQmlJS::Parser parser(&ee); - - const bool parsed = parser.parseModule(); - - if (diagnostics) - *diagnostics = parser.diagnosticMessages(); - - if (!parsed) - return nullptr; - - QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast(parser.rootNode()); - if (!moduleNode) { - // if parsing was successful, and we have no module, then - // the file was empty. - if (diagnostics) - diagnostics->clear(); - return nullptr; - } - - using namespace QV4::Compiler; - Compiler::Module compilerModule(debugMode); - compilerModule.unitFlags |= CompiledData::Unit::IsESModule; - compilerModule.sourceTimeStamp = sourceTimeStamp; - JSUnitGenerator jsGenerator(&compilerModule); - Codegen cg(&jsGenerator, /*strictMode*/true); - cg.generateFromModule(url, url, sourceCode, moduleNode, &compilerModule); - auto errors = cg.errors(); - if (diagnostics) - *diagnostics << errors; - - if (!errors.isEmpty()) - return nullptr; - - return cg.generateCompilationUnit(); -} - -#ifndef V4_BOOTSTRAP - void ExecutionEngine::injectModule(const QQmlRefPointer &moduleUnit) { // Injection can happen from the QML type loader thread for example, but instantiation and @@ -2050,6 +1996,4 @@ static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &v return wrapper->object(); } -#endif // ifndef V4_BOOTSTRAP - QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index d0c58eee8f..4ce854bc52 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -58,11 +58,9 @@ #include #include -#ifndef V4_BOOTSTRAP -# include "qv4function_p.h" -# include -# include -#endif +#include "qv4function_p.h" +#include +#include namespace WTF { class BumpPointerAllocator; @@ -128,13 +126,8 @@ public: Function *globalCode; -#ifdef V4_BOOTSTRAP - QJSEngine *jsEngine() const; - QQmlEngine *qmlEngine() const; -#else // !V4_BOOTSTRAP QJSEngine *jsEngine() const { return publicEngine; } QQmlEngine *qmlEngine() const { return v8Engine ? v8Engine->engine() : nullptr; } -#endif // V4_BOOTSTRAP QV8Engine *v8Engine; QJSEngine *publicEngine; @@ -438,9 +431,7 @@ public: Symbol *symbol_unscopables() const { return reinterpret_cast(jsSymbols + Symbol_unscopables); } Symbol *symbol_revokableProxy() const { return reinterpret_cast(jsSymbols + Symbol_revokableProxy); } -#ifndef V4_BOOTSTRAP QIntrusiveList compilationUnits; -#endif quint32 m_engineId; @@ -611,8 +602,6 @@ public: double localTZA = 0.0; // local timezone, initialized at startup - static QQmlRefPointer compileModule(bool debugMode, const QString &url, const QString &sourceCode, const QDateTime &sourceTimeStamp, QList *diagnostics); -#ifndef V4_BOOTSTRAP QQmlRefPointer compileModule(const QUrl &url); QQmlRefPointer compileModule(const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp); @@ -621,7 +610,6 @@ public: void injectModule(const QQmlRefPointer &moduleUnit); QQmlRefPointer moduleForUrl(const QUrl &_url, const CompiledData::CompilationUnit *referrer = nullptr) const; QQmlRefPointer loadModule(const QUrl &_url, const CompiledData::CompilationUnit *referrer = nullptr); -#endif private: #if QT_CONFIG(qml_debug) diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index e95dfa775f..f404aac580 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -38,9 +38,9 @@ ****************************************************************************/ #include "qv4global_p.h" -#include "qv4engine_p.h" #include "qv4runtime_p.h" #ifndef V4_BOOTSTRAP +#include "qv4engine_p.h" #include "qv4object_p.h" #include "qv4objectproto_p.h" #include "qv4globalobject_p.h" @@ -2170,6 +2170,7 @@ ReturnedValue Runtime::LessEqual::call(const Value &left, const Value &right) return Encode(r); } +#ifndef V4_BOOTSTRAP struct LazyScope { ExecutionEngine *engine = nullptr; @@ -2189,6 +2190,7 @@ struct LazyScope **scopedValue = value; } }; +#endif Bool Runtime::CompareEqual::call(const Value &left, const Value &right) { diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 72af90d1dc..78ab6a1822 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -53,7 +53,6 @@ #include "qv4global_p.h" #include "qv4value_p.h" #include "qv4context_p.h" -#include "qv4engine_p.h" #include "qv4math_p.h" #include "qv4runtimeapi_p.h" #include diff --git a/src/qml/jsruntime/qv4runtimecodegen.cpp b/src/qml/jsruntime/qv4runtimecodegen.cpp index 9866966936..99d0de5ec6 100644 --- a/src/qml/jsruntime/qv4runtimecodegen.cpp +++ b/src/qml/jsruntime/qv4runtimecodegen.cpp @@ -37,6 +37,7 @@ ** ****************************************************************************/ +#include "qv4engine_p.h" #include "qv4runtimecodegen_p.h" #include "qv4compilerscanfunctions_p.h" diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index cbc153bb86..9b50938ccb 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -36,7 +36,7 @@ ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include + #include #include #include diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 1f80e1905e..a953e677fa 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -3049,7 +3049,8 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) if (m_isModule) { QList diagnostics; - unit = QV4::ExecutionEngine::compileModule(isDebugging(), urlString(), source, data.sourceTimeStamp(), &diagnostics); + unit = QV4::Compiler::Codegen::compileModule(isDebugging(), urlString(), source, + data.sourceTimeStamp(), &diagnostics); QList errors = QQmlEnginePrivate::qmlErrorFromDiagnostics(urlString(), diagnostics); if (!errors.isEmpty()) { setError(errors); -- cgit v1.2.3 From fd6321c03e2d63997078bfa41332dbddefbb86b0 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 5 Apr 2019 09:59:10 +0200 Subject: Remove last traces of QV8Engine Change-Id: I59f738402d51e39188bbbca2ef1fbc8a61612372 Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmltypecompiler.cpp | 4 +- src/qml/jsapi/qjsengine.cpp | 4 - src/qml/jsruntime/qv4engine.cpp | 220 ++++++++++++++++++++- src/qml/jsruntime/qv4engine_p.h | 120 +++++++++++- src/qml/jsruntime/qv4include.cpp | 16 +- src/qml/qml/qqmlcomponent.cpp | 2 +- src/qml/qml/qqmlengine.cpp | 2 +- src/qml/qml/qqmlengine_p.h | 10 - src/qml/qml/qqmlglobal_p.h | 1 - src/qml/qml/qqmllocale.cpp | 2 +- src/qml/qml/qqmlpropertycache.cpp | 2 +- src/qml/qml/qqmltypeloader.cpp | 2 +- src/qml/qml/qqmlvaluetype.cpp | 1 + src/qml/qml/qqmlxmlhttprequest.cpp | 18 +- src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 15 +- src/qml/qml/v8/qv8engine.cpp | 331 -------------------------------- src/qml/qml/v8/qv8engine_p.h | 228 ---------------------- src/qml/qml/v8/v8.pri | 2 - src/qml/qtqmlglobal.h | 2 + 19 files changed, 367 insertions(+), 615 deletions(-) delete mode 100644 src/qml/qml/v8/qv8engine.cpp delete mode 100644 src/qml/qml/v8/qv8engine_p.h (limited to 'src/qml') diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index db57d38c24..996b2f16ae 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -146,7 +146,7 @@ QQmlRefPointer QQmlTypeCompiler::compile() document->jsModule.fileName = typeData->urlString(); document->jsModule.finalUrl = typeData->finalUrlString(); QmlIR::JSCodeGen v4CodeGenerator(document->code, &document->jsGenerator, &document->jsModule, &document->jsParserEngine, - document->program, &document->jsGenerator.stringTable, engine->v8engine()->illegalNames()); + document->program, &document->jsGenerator.stringTable, engine->v4engine()->illegalNames()); QQmlJSCodeGenerator jsCodeGen(this, &v4CodeGenerator); if (!jsCodeGen.generateCodeForComponents()) return nullptr; @@ -298,7 +298,7 @@ SignalHandlerConverter::SignalHandlerConverter(QQmlTypeCompiler *typeCompiler) , qmlObjects(*typeCompiler->qmlObjects()) , imports(typeCompiler->imports()) , customParsers(typeCompiler->customParserCache()) - , illegalNames(typeCompiler->enginePrivate()->v8engine()->illegalNames()) + , illegalNames(typeCompiler->enginePrivate()->v4engine()->illegalNames()) , propertyCaches(typeCompiler->propertyCaches()) { } diff --git a/src/qml/jsapi/qjsengine.cpp b/src/qml/jsapi/qjsengine.cpp index 45ea79d31a..7bf2a4d004 100644 --- a/src/qml/jsapi/qjsengine.cpp +++ b/src/qml/jsapi/qjsengine.cpp @@ -41,7 +41,6 @@ #include "qjsengine_p.h" #include "qjsvalue.h" #include "qjsvalue_p.h" -#include "private/qv8engine_p.h" #include "private/qv4engine_p.h" #include "private/qv4mm_p.h" @@ -348,7 +347,6 @@ QJSEngine::QJSEngine(QObject *parent) : QObject(*new QJSEnginePrivate, parent) , m_v4Engine(new QV4::ExecutionEngine(this)) { - m_v4Engine->v8Engine = new QV8Engine(m_v4Engine); checkForApplicationInstance(); QJSEnginePrivate::addToDebugServer(this); @@ -361,7 +359,6 @@ QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent) : QObject(dd, parent) , m_v4Engine(new QV4::ExecutionEngine(this)) { - m_v4Engine->v8Engine = new QV8Engine(m_v4Engine); checkForApplicationInstance(); } @@ -375,7 +372,6 @@ QJSEngine::QJSEngine(QJSEnginePrivate &dd, QObject *parent) QJSEngine::~QJSEngine() { QJSEnginePrivate::removeFromDebugServer(this); - delete m_v4Engine->v8Engine; delete m_v4Engine; } diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index b65a2f2dad..b04a879c7f 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -102,7 +102,6 @@ #include "qv4dataview_p.h" #include "qv4promiseobject_p.h" #include "qv4typedarray_p.h" -#include #include #include #include @@ -110,9 +109,16 @@ #include #include #include +#include +#include #if QT_CONFIG(qml_locale) #include #endif +#if QT_CONFIG(qml_xml_http_request) +#include +#include +#endif +#include #include #if USE(PTHREADS) @@ -129,6 +135,8 @@ #include #endif +Q_DECLARE_METATYPE(QList) + QT_BEGIN_NAMESPACE using namespace QV4; @@ -142,6 +150,43 @@ ReturnedValue throwTypeError(const FunctionObject *b, const QV4::Value *, const qint32 ExecutionEngine::maxCallDepth = -1; +template +ReturnType convertJSValueToVariantType(const QJSValue &value) +{ + return value.toVariant().value(); +} + +static void saveJSValue(QDataStream &stream, const void *data) +{ + const QJSValue *jsv = reinterpret_cast(data); + quint32 isNullOrUndefined = 0; + if (jsv->isNull()) + isNullOrUndefined |= 0x1; + if (jsv->isUndefined()) + isNullOrUndefined |= 0x2; + stream << isNullOrUndefined; + if (!isNullOrUndefined) + reinterpret_cast(data)->toVariant().save(stream); +} + +static void restoreJSValue(QDataStream &stream, void *data) +{ + QJSValue *jsv = reinterpret_cast(data); + + quint32 isNullOrUndefined; + stream >> isNullOrUndefined; + + if (isNullOrUndefined & 0x1) { + *jsv = QJSValue(QJSValue::NullValue); + } else if (isNullOrUndefined & 0x2) { + *jsv = QJSValue(); + } else { + QVariant v; + v.load(stream); + QJSValuePrivate::setVariant(jsv, v); + } +} + ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) : executableAllocator(new QV4::ExecutableAllocator) , regExpAllocator(new QV4::ExecutableAllocator) @@ -149,7 +194,6 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) , jsStack(new WTF::PageAllocation) , gcStack(new WTF::PageAllocation) , globalCode(nullptr) - , v8Engine(nullptr) , publicEngine(jsEngine) , m_engineId(engineSerial.fetchAndAddOrdered(1)) , regExpCache(nullptr) @@ -157,6 +201,10 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) #if QT_CONFIG(qml_jit) , m_canAllocateExecutableMemory(OSAllocator::canAllocateExecutableMemory()) #endif +#if QT_CONFIG(qml_xml_http_request) + , m_xmlHttpRequestData(nullptr) +#endif + , m_qmlEngine(nullptr) { memoryManager = new QV4::MemoryManager(this); @@ -643,11 +691,28 @@ ExecutionEngine::ExecutionEngine(QJSEngine *jsEngine) pd->set = thrower(); functionPrototype()->insertMember(id_caller(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable); functionPrototype()->insertMember(id_arguments(), pd, Attr_Accessor|Attr_ReadOnly_ButConfigurable); + + QML_MEMORY_SCOPE_STRING("QV4Engine::QV4Engine"); + qMetaTypeId(); + qMetaTypeId >(); + + if (!QMetaType::hasRegisteredConverterFunction()) + QMetaType::registerConverter(convertJSValueToVariantType); + if (!QMetaType::hasRegisteredConverterFunction()) + QMetaType::registerConverter(convertJSValueToVariantType); + if (!QMetaType::hasRegisteredConverterFunction()) + QMetaType::registerConverter(convertJSValueToVariantType); + QMetaType::registerStreamOperators(qMetaTypeId(), saveJSValue, restoreJSValue); + + QV4::QObjectWrapper::initializeBindings(this); + + m_delayedCallQueue.init(this); } ExecutionEngine::~ExecutionEngine() { modules.clear(); + qDeleteAll(m_extensionData); delete m_multiplyWrappedQObjects; m_multiplyWrappedQObjects = nullptr; delete identifierTable; @@ -664,6 +729,11 @@ ExecutionEngine::~ExecutionEngine() delete jsStack; gcStack->deallocate(); delete gcStack; + +#if QT_CONFIG(qml_xml_http_request) + qt_rem_qmlxmlhttprequest(this, m_xmlHttpRequestData); + m_xmlHttpRequestData = nullptr; +#endif } ExecutionContext *ExecutionEngine::currentContext() const @@ -1750,6 +1820,133 @@ QQmlRefPointer ExecutionEngine::loadModule(const return newModule; } +void ExecutionEngine::initQmlGlobalObject() +{ + initializeGlobal(); + freezeObject(*globalObject); +} + +void ExecutionEngine::initializeGlobal() +{ + QV4::Scope scope(this); + QV4::GlobalExtensions::init(globalObject, QJSEngine::AllExtensions); + + QV4::ScopedObject qt(scope, memoryManager->allocate(qmlEngine())); + globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt); + +#if QT_CONFIG(qml_locale) + QQmlLocale::registerStringLocaleCompare(this); + QQmlDateExtension::registerExtension(this); + QQmlNumberExtension::registerExtension(this); +#endif + +#if QT_CONFIG(qml_xml_http_request) + qt_add_domexceptions(this); + m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(this); +#endif + + qt_add_sqlexceptions(this); + + { + for (uint i = 0; i < globalObject->internalClass()->size; ++i) { + if (globalObject->internalClass()->nameMap.at(i).isString()) { + QV4::PropertyKey id = globalObject->internalClass()->nameMap.at(i); + m_illegalNames.insert(id.toQString()); + } + } + } +} + +const QSet &ExecutionEngine::illegalNames() const +{ + return m_illegalNames; +} + +void ExecutionEngine::setQmlEngine(QQmlEngine *engine) +{ + m_qmlEngine = engine; + initQmlGlobalObject(); +} + +static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object) +{ + if (object->as()) + return; + + QV4::Scope scope(v4); + + bool instanceOfObject = false; + QV4::ScopedObject p(scope, object->getPrototypeOf()); + while (p) { + if (p->d() == v4->objectPrototype()->d()) { + instanceOfObject = true; + break; + } + p = p->getPrototypeOf(); + } + if (!instanceOfObject) + return; + + QV4::Heap::InternalClass *frozen = object->internalClass()->propertiesFrozen(); + if (object->internalClass() == frozen) + return; + object->setInternalClass(frozen); + + QV4::ScopedObject o(scope); + for (uint i = 0; i < frozen->size; ++i) { + if (!frozen->nameMap.at(i).isStringOrSymbol()) + continue; + o = *object->propertyData(i); + if (o) + freeze_recursive(v4, o); + } +} + +void ExecutionEngine::freezeObject(const QV4::Value &value) +{ + QV4::Scope scope(this); + QV4::ScopedObject o(scope, value); + freeze_recursive(this, o); +} + +void ExecutionEngine::startTimer(const QString &timerName) +{ + if (!m_time.isValid()) + m_time.start(); + m_startedTimers[timerName] = m_time.elapsed(); +} + +qint64 ExecutionEngine::stopTimer(const QString &timerName, bool *wasRunning) +{ + if (!m_startedTimers.contains(timerName)) { + *wasRunning = false; + return 0; + } + *wasRunning = true; + qint64 startedAt = m_startedTimers.take(timerName); + return m_time.elapsed() - startedAt; +} + +int ExecutionEngine::consoleCountHelper(const QString &file, quint16 line, quint16 column) +{ + const QString key = file + QString::number(line) + QString::number(column); + int number = m_consoleCount.value(key, 0); + number++; + m_consoleCount.insert(key, number); + return number; +} + +void ExecutionEngine::setExtensionData(int index, Deletable *data) +{ + if (m_extensionData.count() <= index) + m_extensionData.resize(index + 1); + + if (m_extensionData.at(index)) + delete m_extensionData.at(index); + + m_extensionData[index] = data; +} + // Converts a JS value to a meta-type. // data must point to a place that can store a value of the given type. // Returns true if conversion succeeded, false otherwise. @@ -1996,4 +2193,23 @@ static QObject *qtObjectFromJS(QV4::ExecutionEngine *engine, const QV4::Value &v return wrapper->object(); } +struct QV4EngineRegistrationData +{ + QV4EngineRegistrationData() : extensionCount(0) {} + + QMutex mutex; + int extensionCount; +}; +Q_GLOBAL_STATIC(QV4EngineRegistrationData, registrationData); + +QMutex *ExecutionEngine::registrationMutex() +{ + return ®istrationData()->mutex; +} + +int ExecutionEngine::registerExtension() +{ + return registrationData()->extensionCount++; +} + QT_END_NAMESPACE diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 4ce854bc52..0d113754c0 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -53,13 +53,16 @@ #include "qv4global_p.h" #include "qv4managed_p.h" #include "qv4context_p.h" +#include "qv4stackframe_p.h" #include #include "qv4enginebase_p.h" #include #include +#include +#include +#include #include "qv4function_p.h" -#include #include namespace WTF { @@ -67,9 +70,65 @@ class BumpPointerAllocator; class PageAllocation; } +#define V4_DEFINE_EXTENSION(dataclass, datafunction) \ + static inline dataclass *datafunction(QV4::ExecutionEngine *engine) \ + { \ + static int extensionId = -1; \ + if (extensionId == -1) { \ + QV4::ExecutionEngine::registrationMutex()->lock(); \ + if (extensionId == -1) \ + extensionId = QV4::ExecutionEngine::registerExtension(); \ + QV4::ExecutionEngine::registrationMutex()->unlock(); \ + } \ + dataclass *rv = (dataclass *)engine->extensionData(extensionId); \ + if (!rv) { \ + rv = new dataclass(engine); \ + engine->setExtensionData(extensionId, rv); \ + } \ + return rv; \ + } \ + + QT_BEGIN_NAMESPACE -class QV8Engine; +namespace QV4 { struct QObjectMethod; } + +// Used to allow a QObject method take and return raw V4 handles without having to expose +// 48 in the public API. +// Use like this: +// class MyClass : public QObject { +// Q_OBJECT +// ... +// Q_INVOKABLE void myMethod(QQmlV4Function*); +// }; +// The QQmlV8Function - and consequently the arguments and return value - only remains +// valid during the call. If the return value isn't set within myMethod(), the will return +// undefined. + +class QQmlV4Function +{ +public: + int length() const { return callData->argc(); } + QV4::ReturnedValue operator[](int idx) const { return (idx < callData->argc() ? callData->args[idx].asReturnedValue() : QV4::Encode::undefined()); } + void setReturnValue(QV4::ReturnedValue rv) { *retVal = rv; } + QV4::ExecutionEngine *v4engine() const { return e; } +private: + friend struct QV4::QObjectMethod; + QQmlV4Function(); + QQmlV4Function(const QQmlV4Function &); + QQmlV4Function &operator=(const QQmlV4Function &); + + QQmlV4Function(QV4::CallData *callData, QV4::Value *retVal, QV4::ExecutionEngine *e) + : callData(callData), retVal(retVal), e(e) + { + callData->thisObject = QV4::Encode::undefined(); + } + + QV4::CallData *callData; + QV4::Value *retVal; + QV4::ExecutionEngine *e; +}; + class QQmlError; class QJSEngine; class QQmlEngine; @@ -127,8 +186,7 @@ public: Function *globalCode; QJSEngine *jsEngine() const { return publicEngine; } - QQmlEngine *qmlEngine() const { return v8Engine ? v8Engine->engine() : nullptr; } - QV8Engine *v8Engine; + QQmlEngine *qmlEngine() const { return m_qmlEngine; } QJSEngine *publicEngine; enum JSObjects { @@ -599,6 +657,44 @@ public: } QV4::ReturnedValue global(); + void initQmlGlobalObject(); + void initializeGlobal(); + + void freezeObject(const QV4::Value &value); + + // Return the list of illegal id names (the names of the properties on the global object) + const QSet &illegalNames() const; + +#if QT_CONFIG(qml_xml_http_request) + void *xmlHttpRequestData() const { return m_xmlHttpRequestData; } +#endif + + void setQmlEngine(QQmlEngine *engine); + + QQmlDelayedCallQueue *delayedCallQueue() { return &m_delayedCallQueue; } + + // used for console.time(), console.timeEnd() + void startTimer(const QString &timerName); + qint64 stopTimer(const QString &timerName, bool *wasRunning); + + // used for console.count() + int consoleCountHelper(const QString &file, quint16 line, quint16 column); + + struct Deletable { + virtual ~Deletable() {} + }; + + static QMutex *registrationMutex(); + static int registerExtension(); + + void setExtensionData(int, Deletable *); + Deletable *extensionData(int index) const + { + if (index < m_extensionData.count()) + return m_extensionData[index]; + else + return nullptr; + } double localTZA = 0.0; // local timezone, initialized at startup @@ -616,10 +712,26 @@ private: QScopedPointer m_debugger; QScopedPointer m_profiler; #endif + QSet m_illegalNames; int jitCallCountThreshold; // used by generated Promise objects to handle 'then' events QScopedPointer m_reactionHandler; + +#if QT_CONFIG(qml_xml_http_request) + void *m_xmlHttpRequestData; +#endif + + QQmlEngine *m_qmlEngine; + + QQmlDelayedCallQueue m_delayedCallQueue; + + QElapsedTimer m_time; + QHash m_startedTimers; + + QHash m_consoleCount; + + QVector m_extensionData; }; #define CHECK_STACK_LIMITS(v4) if ((v4)->checkStackLimits()) return Encode::undefined(); \ diff --git a/src/qml/jsruntime/qv4include.cpp b/src/qml/jsruntime/qv4include.cpp index 3c732bc555..c0885a418c 100644 --- a/src/qml/jsruntime/qv4include.cpp +++ b/src/qml/jsruntime/qv4include.cpp @@ -72,13 +72,17 @@ QV4Include::QV4Include(const QUrl &url, QV4::ExecutionEngine *engine, m_resultObject.set(v4, resultValue(v4)); #if QT_CONFIG(qml_network) - m_network = engine->v8Engine->networkAccessManager(); + if (QQmlEngine *qmlEngine = engine->qmlEngine()) { + m_network = qmlEngine->networkAccessManager(); - QNetworkRequest request; - request.setUrl(url); + QNetworkRequest request; + request.setUrl(url); - m_reply = m_network->get(request); - QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished())); + m_reply = m_network->get(request); + QObject::connect(m_reply, SIGNAL(finished()), this, SLOT(finished())); + } else { + finished(); + } #else finished(); #endif @@ -197,7 +201,7 @@ void QV4Include::finished() } /* - Documented in qv8engine.cpp + Documented in qv4engine.cpp */ QV4::ReturnedValue QV4Include::method_include(const QV4::FunctionObject *b, const QV4::Value *, const QV4::Value *argv, int argc) { diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index 64d2a064df..f9f26b6b1e 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -72,7 +72,7 @@ namespace { QT_BEGIN_NAMESPACE -class QQmlComponentExtension : public QV8Engine::Deletable +class QQmlComponentExtension : public QV4::ExecutionEngine::Deletable { public: QQmlComponentExtension(QV4::ExecutionEngine *v4); diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index cb94ae379e..8bdbe0fc47 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -957,7 +957,7 @@ void QQmlEnginePrivate::init() qRegisterMetaType >(); qRegisterMetaType(); - v8engine()->setEngine(q); + q->handle()->setQmlEngine(q); rootContext = new QQmlContext(q,true); } diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index 6ef88404fd..668dfed91e 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -76,7 +76,6 @@ #include -#include #include #include @@ -149,7 +148,6 @@ public: QQmlDelayedError *erroredBindings; int inProgressCreations; - QV8Engine *v8engine() const { return q_func()->handle()->v8Engine; } QV4::ExecutionEngine *v4engine() const { return q_func()->handle(); } #if QT_CONFIG(qml_worker_script) @@ -240,7 +238,6 @@ public: static void warning(QQmlEnginePrivate *, const QQmlError &); static void warning(QQmlEnginePrivate *, const QList &); - inline static QV8Engine *getV8Engine(QQmlEngine *e); inline static QV4::ExecutionEngine *getV4Engine(QQmlEngine *e); inline static QQmlEnginePrivate *get(QQmlEngine *e); inline static const QQmlEnginePrivate *get(const QQmlEngine *e); @@ -388,13 +385,6 @@ QQmlPropertyCache *QQmlEnginePrivate::cache(const QQmlType &type, int minorVersi return QQmlMetaType::propertyCache(type, minorVersion); } -QV8Engine *QQmlEnginePrivate::getV8Engine(QQmlEngine *e) -{ - Q_ASSERT(e); - - return e->handle()->v8Engine; -} - QV4::ExecutionEngine *QQmlEnginePrivate::getV4Engine(QQmlEngine *e) { Q_ASSERT(e); diff --git a/src/qml/qml/qqmlglobal_p.h b/src/qml/qml/qqmlglobal_p.h index 53caffe040..136159993a 100644 --- a/src/qml/qml/qqmlglobal_p.h +++ b/src/qml/qml/qqmlglobal_p.h @@ -55,7 +55,6 @@ #include #include #include -#include QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmllocale.cpp b/src/qml/qml/qqmllocale.cpp index 2b17037df0..dca13ac8d4 100644 --- a/src/qml/qml/qqmllocale.cpp +++ b/src/qml/qml/qqmllocale.cpp @@ -662,7 +662,7 @@ LOCALE_STRING_PROPERTY(exponential) LOCALE_STRING_PROPERTY(amText) LOCALE_STRING_PROPERTY(pmText) -class QV4LocaleDataDeletable : public QV8Engine::Deletable +class QV4LocaleDataDeletable : public QV4::ExecutionEngine::Deletable { public: QV4LocaleDataDeletable(QV4::ExecutionEngine *engine); diff --git a/src/qml/qml/qqmlpropertycache.cpp b/src/qml/qml/qqmlpropertycache.cpp index a6546ae330..48c4216d54 100644 --- a/src/qml/qml/qqmlpropertycache.cpp +++ b/src/qml/qml/qqmlpropertycache.cpp @@ -868,7 +868,7 @@ QQmlPropertyCacheMethodArguments *QQmlPropertyCache::createArgumentsObject(int a QString QQmlPropertyCache::signalParameterStringForJS(QV4::ExecutionEngine *engine, const QList ¶meterNameList, QString *errorString) { bool unnamedParameter = false; - const QSet &illegalNames = engine->v8Engine->illegalNames(); + const QSet &illegalNames = engine->illegalNames(); QString parameters; for (int i = 0; i < parameterNameList.count(); ++i) { diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index a953e677fa..d694909c7c 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2516,7 +2516,7 @@ bool QQmlTypeData::loadFromSource() m_document.reset(new QmlIR::Document(isDebugging())); m_document->jsModule.sourceTimeStamp = m_backupSourceCode.sourceTimeStamp(); QQmlEngine *qmlEngine = typeLoader()->engine(); - QmlIR::IRBuilder compiler(qmlEngine->handle()->v8Engine->illegalNames()); + QmlIR::IRBuilder compiler(qmlEngine->handle()->illegalNames()); QString sourceError; const QString source = m_backupSourceCode.readAll(&sourceError); diff --git a/src/qml/qml/qqmlvaluetype.cpp b/src/qml/qml/qqmlvaluetype.cpp index f08005fd20..fce753cd26 100644 --- a/src/qml/qml/qqmlvaluetype.cpp +++ b/src/qml/qml/qqmlvaluetype.cpp @@ -39,6 +39,7 @@ #include "qqmlvaluetype_p.h" +#include #include #include #include diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp index c6b7f2ab3f..b435f8ef66 100644 --- a/src/qml/qml/qqmlxmlhttprequest.cpp +++ b/src/qml/qml/qqmlxmlhttprequest.cpp @@ -95,7 +95,7 @@ struct QQmlXMLHttpRequestData { static inline QQmlXMLHttpRequestData *xhrdata(ExecutionEngine *v4) { - return (QQmlXMLHttpRequestData *)v4->v8Engine->xmlHttpRequestData(); + return (QQmlXMLHttpRequestData *)v4->xmlHttpRequestData(); } QQmlXMLHttpRequestData::QQmlXMLHttpRequestData() @@ -591,7 +591,7 @@ ReturnedValue NodePrototype::getProto(ExecutionEngine *v4) if (d->nodePrototype.isUndefined()) { ScopedObject p(scope, v4->memoryManager->allocate()); d->nodePrototype.set(v4, p); - v4->v8Engine->freezeObject(p); + v4->freezeObject(p); } return d->nodePrototype.value(); } @@ -640,7 +640,7 @@ ReturnedValue Element::prototype(ExecutionEngine *engine) p->setPrototypeUnchecked((pp = NodePrototype::getProto(engine))); p->defineAccessorProperty(QStringLiteral("tagName"), NodePrototype::method_get_nodeName, nullptr); d->elementPrototype.set(engine, p); - engine->v8Engine->freezeObject(p); + engine->freezeObject(p); } return d->elementPrototype.value(); } @@ -657,7 +657,7 @@ ReturnedValue Attr::prototype(ExecutionEngine *engine) p->defineAccessorProperty(QStringLiteral("value"), method_value, nullptr); p->defineAccessorProperty(QStringLiteral("ownerElement"), method_ownerElement, nullptr); d->attrPrototype.set(engine, p); - engine->v8Engine->freezeObject(p); + engine->freezeObject(p); } return d->attrPrototype.value(); } @@ -713,7 +713,7 @@ ReturnedValue CharacterData::prototype(ExecutionEngine *v4) p->defineAccessorProperty(QStringLiteral("data"), NodePrototype::method_get_nodeValue, nullptr); p->defineAccessorProperty(QStringLiteral("length"), method_length, nullptr); d->characterDataPrototype.set(v4, p); - v4->v8Engine->freezeObject(p); + v4->freezeObject(p); } return d->characterDataPrototype.value(); } @@ -749,7 +749,7 @@ ReturnedValue Text::prototype(ExecutionEngine *v4) p->defineAccessorProperty(QStringLiteral("isElementContentWhitespace"), method_isElementContentWhitespace, nullptr); p->defineAccessorProperty(QStringLiteral("wholeText"), method_wholeText, nullptr); d->textPrototype.set(v4, p); - v4->v8Engine->freezeObject(p); + v4->freezeObject(p); } return d->textPrototype.value(); } @@ -764,7 +764,7 @@ ReturnedValue CDATA::prototype(ExecutionEngine *v4) ScopedObject pp(scope); p->setPrototypeUnchecked((pp = Text::prototype(v4))); d->cdataPrototype.set(v4, p); - v4->v8Engine->freezeObject(p); + v4->freezeObject(p); } return d->cdataPrototype.value(); } @@ -782,7 +782,7 @@ ReturnedValue Document::prototype(ExecutionEngine *v4) p->defineAccessorProperty(QStringLiteral("xmlStandalone"), method_xmlStandalone, nullptr); p->defineAccessorProperty(QStringLiteral("documentElement"), method_documentElement, nullptr); d->documentPrototype.set(v4, p); - v4->v8Engine->freezeObject(p); + v4->freezeObject(p); } return d->documentPrototype.value(); } @@ -1646,7 +1646,7 @@ struct QQmlXMLHttpRequestCtor : public FunctionObject Scope scope(f->engine()); const QQmlXMLHttpRequestCtor *ctor = static_cast(f); - QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->v8Engine->networkAccessManager(), scope.engine); + QQmlXMLHttpRequest *r = new QQmlXMLHttpRequest(scope.engine->qmlEngine()->networkAccessManager(), scope.engine); Scoped w(scope, scope.engine->memoryManager->allocate(r)); ScopedObject proto(scope, ctor->d()->proto); w->setPrototypeUnchecked(proto); diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 3bc588b50e..532bfa8754 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -47,7 +47,6 @@ #if QT_CONFIG(qml_locale) #include #endif -#include #include #include @@ -1684,10 +1683,8 @@ ReturnedValue ConsoleObject::method_time(const FunctionObject *b, const Value *, if (argc != 1) THROW_GENERIC_ERROR("console.time(): Invalid arguments"); - QV8Engine *v8engine = scope.engine->v8Engine; - QString name = argv[0].toQStringNoThrow(); - v8engine->startTimer(name); + scope.engine->startTimer(name); return QV4::Encode::undefined(); } @@ -1697,11 +1694,9 @@ ReturnedValue ConsoleObject::method_timeEnd(const FunctionObject *b, const Value if (argc != 1) THROW_GENERIC_ERROR("console.timeEnd(): Invalid arguments"); - QV8Engine *v8engine = scope.engine->v8Engine; - QString name = argv[0].toQStringNoThrow(); bool wasRunning; - qint64 elapsed = v8engine->stopTimer(name, &wasRunning); + qint64 elapsed = scope.engine->stopTimer(name, &wasRunning); if (wasRunning) { qDebug("%s: %llims", qPrintable(name), elapsed); } @@ -1717,13 +1712,12 @@ ReturnedValue ConsoleObject::method_count(const FunctionObject *b, const Value * Scope scope(b); QV4::ExecutionEngine *v4 = scope.engine; - QV8Engine *v8engine = scope.engine->v8Engine; QV4::CppStackFrame *frame = v4->currentStackFrame; QString scriptName = frame->source(); - int value = v8engine->consoleCountHelper(scriptName, frame->lineNumber(), 0); + int value = v4->consoleCountHelper(scriptName, frame->lineNumber(), 0); QString message = name + QLatin1String(": ") + QString::number(value); QMessageLogger(qPrintable(scriptName), frame->lineNumber(), @@ -2147,8 +2141,7 @@ function. */ ReturnedValue QtObject::method_callLater(const FunctionObject *b, const Value *thisObject, const Value *argv, int argc) { - QV8Engine *v8engine = b->engine()->v8Engine; - return v8engine->delayedCallQueue()->addUniquelyAndExecuteLater(b, thisObject, argv, argc); + return b->engine()->delayedCallQueue()->addUniquelyAndExecuteLater(b, thisObject, argv, argc); } QT_END_NAMESPACE diff --git a/src/qml/qml/v8/qv8engine.cpp b/src/qml/qml/v8/qv8engine.cpp deleted file mode 100644 index d76344b613..0000000000 --- a/src/qml/qml/v8/qv8engine.cpp +++ /dev/null @@ -1,331 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qv8engine_p.h" - -#if QT_CONFIG(qml_sequence_object) -#include "qv4sequenceobject_p.h" -#endif - -#include "private/qjsengine_p.h" - -#include -#include -#include -#if QT_CONFIG(qml_xml_http_request) -#include -#endif -#if QT_CONFIG(qml_locale) -#include -#endif -#include -#include -#include -#include -#include -#include -#include -#include - -#include "qv4domerrors_p.h" -#include "qv4sqlerrors_p.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -Q_DECLARE_METATYPE(QList) - - -// XXX TODO: Need to check all the global functions will also work in a worker script where the -// QQmlEngine is not available -QT_BEGIN_NAMESPACE - -template -ReturnType convertJSValueToVariantType(const QJSValue &value) -{ - return value.toVariant().value(); -} - -static void saveJSValue(QDataStream &stream, const void *data) -{ - const QJSValue *jsv = reinterpret_cast(data); - quint32 isNullOrUndefined = 0; - if (jsv->isNull()) - isNullOrUndefined |= 0x1; - if (jsv->isUndefined()) - isNullOrUndefined |= 0x2; - stream << isNullOrUndefined; - if (!isNullOrUndefined) - reinterpret_cast(data)->toVariant().save(stream); -} - -static void restoreJSValue(QDataStream &stream, void *data) -{ - QJSValue *jsv = reinterpret_cast(data); - - quint32 isNullOrUndefined; - stream >> isNullOrUndefined; - - if (isNullOrUndefined & 0x1) { - *jsv = QJSValue(QJSValue::NullValue); - } else if (isNullOrUndefined & 0x2) { - *jsv = QJSValue(); - } else { - QVariant v; - v.load(stream); - QJSValuePrivate::setVariant(jsv, v); - } -} - -QV8Engine::QV8Engine(QV4::ExecutionEngine *v4) - : m_engine(nullptr) - , m_v4Engine(v4) -#if QT_CONFIG(qml_xml_http_request) - , m_xmlHttpRequestData(nullptr) -#endif -{ -#ifndef Q_OS_WASM // wasm does not have working simd QTBUG-63924 -#ifdef Q_PROCESSOR_X86_32 - if (!qCpuHasFeature(SSE2)) { - qFatal("This program requires an X86 processor that supports SSE2 extension, at least a Pentium 4 or newer"); - } -#endif -#endif - - QML_MEMORY_SCOPE_STRING("QV8Engine::QV8Engine"); - qMetaTypeId(); - qMetaTypeId >(); - - if (!QMetaType::hasRegisteredConverterFunction()) - QMetaType::registerConverter(convertJSValueToVariantType); - if (!QMetaType::hasRegisteredConverterFunction()) - QMetaType::registerConverter(convertJSValueToVariantType); - if (!QMetaType::hasRegisteredConverterFunction()) - QMetaType::registerConverter(convertJSValueToVariantType); - QMetaType::registerStreamOperators(qMetaTypeId(), saveJSValue, restoreJSValue); - - m_delayedCallQueue.init(m_v4Engine); - - QV4::QObjectWrapper::initializeBindings(m_v4Engine); -} - -QV8Engine::~QV8Engine() -{ - qDeleteAll(m_extensionData); - m_extensionData.clear(); - -#if QT_CONFIG(qml_xml_http_request) - qt_rem_qmlxmlhttprequest(m_v4Engine, m_xmlHttpRequestData); - m_xmlHttpRequestData = nullptr; -#endif -} - -#if QT_CONFIG(qml_network) -QNetworkAccessManager *QV8Engine::networkAccessManager() -{ - return QQmlEnginePrivate::get(m_engine)->getNetworkAccessManager(); -} -#endif - -const QSet &QV8Engine::illegalNames() const -{ - return m_illegalNames; -} - -void QV8Engine::initializeGlobal() -{ - QV4::Scope scope(m_v4Engine); - QV4::GlobalExtensions::init(m_v4Engine->globalObject, QJSEngine::AllExtensions); - - QV4::ScopedObject qt(scope, m_v4Engine->memoryManager->allocate(m_engine)); - m_v4Engine->globalObject->defineDefaultProperty(QStringLiteral("Qt"), qt); - -#if QT_CONFIG(qml_locale) - QQmlLocale::registerStringLocaleCompare(m_v4Engine); - QQmlDateExtension::registerExtension(m_v4Engine); - QQmlNumberExtension::registerExtension(m_v4Engine); -#endif - -#if QT_CONFIG(qml_xml_http_request) - qt_add_domexceptions(m_v4Engine); - m_xmlHttpRequestData = qt_add_qmlxmlhttprequest(m_v4Engine); -#endif - - qt_add_sqlexceptions(m_v4Engine); - - { - for (uint i = 0; i < m_v4Engine->globalObject->internalClass()->size; ++i) { - if (m_v4Engine->globalObject->internalClass()->nameMap.at(i).isString()) { - QV4::PropertyKey id = m_v4Engine->globalObject->internalClass()->nameMap.at(i); - m_illegalNames.insert(id.toQString()); - } - } - } -} - -static void freeze_recursive(QV4::ExecutionEngine *v4, QV4::Object *object) -{ - if (object->as()) - return; - - QV4::Scope scope(v4); - - bool instanceOfObject = false; - QV4::ScopedObject p(scope, object->getPrototypeOf()); - while (p) { - if (p->d() == v4->objectPrototype()->d()) { - instanceOfObject = true; - break; - } - p = p->getPrototypeOf(); - } - if (!instanceOfObject) - return; - - QV4::Heap::InternalClass *frozen = object->internalClass()->propertiesFrozen(); - if (object->internalClass() == frozen) - return; - object->setInternalClass(frozen); - - QV4::ScopedObject o(scope); - for (uint i = 0; i < frozen->size; ++i) { - if (!frozen->nameMap.at(i).isStringOrSymbol()) - continue; - o = *object->propertyData(i); - if (o) - freeze_recursive(v4, o); - } -} - -void QV8Engine::freezeObject(const QV4::Value &value) -{ - QV4::Scope scope(m_v4Engine); - QV4::ScopedObject o(scope, value); - freeze_recursive(m_v4Engine, o); -} - -struct QV8EngineRegistrationData -{ - QV8EngineRegistrationData() : extensionCount(0) {} - - QMutex mutex; - int extensionCount; -}; -Q_GLOBAL_STATIC(QV8EngineRegistrationData, registrationData); - -QMutex *QV8Engine::registrationMutex() -{ - return ®istrationData()->mutex; -} - -int QV8Engine::registerExtension() -{ - return registrationData()->extensionCount++; -} - -void QV8Engine::setExtensionData(int index, Deletable *data) -{ - if (m_extensionData.count() <= index) - m_extensionData.resize(index + 1); - - if (m_extensionData.at(index)) - delete m_extensionData.at(index); - - m_extensionData[index] = data; -} - -void QV8Engine::initQmlGlobalObject() -{ - initializeGlobal(); - freezeObject(*m_v4Engine->globalObject); -} - -void QV8Engine::setEngine(QQmlEngine *engine) -{ - m_engine = engine; - initQmlGlobalObject(); -} - -void QV8Engine::startTimer(const QString &timerName) -{ - if (!m_time.isValid()) - m_time.start(); - m_startedTimers[timerName] = m_time.elapsed(); -} - -qint64 QV8Engine::stopTimer(const QString &timerName, bool *wasRunning) -{ - if (!m_startedTimers.contains(timerName)) { - *wasRunning = false; - return 0; - } - *wasRunning = true; - qint64 startedAt = m_startedTimers.take(timerName); - return m_time.elapsed() - startedAt; -} - -int QV8Engine::consoleCountHelper(const QString &file, quint16 line, quint16 column) -{ - const QString key = file + QString::number(line) + QString::number(column); - int number = m_consoleCount.value(key, 0); - number++; - m_consoleCount.insert(key, number); - return number; -} - -QT_END_NAMESPACE - diff --git a/src/qml/qml/v8/qv8engine_p.h b/src/qml/qml/v8/qv8engine_p.h deleted file mode 100644 index f9b69cfacc..0000000000 --- a/src/qml/qml/v8/qv8engine_p.h +++ /dev/null @@ -1,228 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQml module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QQMLV8ENGINE_P_H -#define QQMLV8ENGINE_P_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include "private/qintrusivelist_p.h" - - -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -namespace QV4 { - struct ArrayObject; - struct ExecutionEngine; - struct QObjectMethod; -} - -#define V4_DEFINE_EXTENSION(dataclass, datafunction) \ - static inline dataclass *datafunction(QV4::ExecutionEngine *engine) \ - { \ - static int extensionId = -1; \ - if (extensionId == -1) { \ - QV8Engine::registrationMutex()->lock(); \ - if (extensionId == -1) \ - extensionId = QV8Engine::registerExtension(); \ - QV8Engine::registrationMutex()->unlock(); \ - } \ - dataclass *rv = (dataclass *)engine->v8Engine->extensionData(extensionId); \ - if (!rv) { \ - rv = new dataclass(engine); \ - engine->v8Engine->setExtensionData(extensionId, rv); \ - } \ - return rv; \ - } \ - -// Used to allow a QObject method take and return raw V4 handles without having to expose -// 48 in the public API. -// Use like this: -// class MyClass : public QObject { -// Q_OBJECT -// ... -// Q_INVOKABLE void myMethod(QQmlV4Function*); -// }; -// The QQmlV8Function - and consequently the arguments and return value - only remains -// valid during the call. If the return value isn't set within myMethod(), the will return -// undefined. - -class QQmlV4Function -{ -public: - int length() const { return callData->argc(); } - QV4::ReturnedValue operator[](int idx) const { return (idx < callData->argc() ? callData->args[idx].asReturnedValue() : QV4::Encode::undefined()); } - void setReturnValue(QV4::ReturnedValue rv) { *retVal = rv; } - QV4::ExecutionEngine *v4engine() const { return e; } -private: - friend struct QV4::QObjectMethod; - QQmlV4Function(); - QQmlV4Function(const QQmlV4Function &); - QQmlV4Function &operator=(const QQmlV4Function &); - - QQmlV4Function(QV4::CallData *callData, QV4::Value *retVal, QV4::ExecutionEngine *e) - : callData(callData), retVal(retVal), e(e) - { - callData->thisObject = QV4::Encode::undefined(); - } - - QV4::CallData *callData; - QV4::Value *retVal; - QV4::ExecutionEngine *e; -}; - -class QObject; -class QQmlEngine; -class QNetworkAccessManager; -class QQmlContextData; - -class Q_QML_PRIVATE_EXPORT QV8Engine -{ - friend class QJSEngine; -public: -// static QJSEngine* get(QV8Engine* d) { Q_ASSERT(d); return d->q; } - static QV4::ExecutionEngine *getV4(QV8Engine *d) { return d->m_v4Engine; } - - QV8Engine(QV4::ExecutionEngine *v4); - virtual ~QV8Engine(); - - // This enum should be in sync with QQmlEngine::ObjectOwnership - enum ObjectOwnership { CppOwnership, JavaScriptOwnership }; - - struct Deletable { - virtual ~Deletable() {} - }; - - void initQmlGlobalObject(); - void setEngine(QQmlEngine *engine); - QQmlEngine *engine() { return m_engine; } - QQmlDelayedCallQueue *delayedCallQueue() { return &m_delayedCallQueue; } - -#if QT_CONFIG(qml_xml_http_request) - void *xmlHttpRequestData() const { return m_xmlHttpRequestData; } -#endif - - void freezeObject(const QV4::Value &value); - -#if QT_CONFIG(qml_network) - // Return the network access manager for this engine. By default this returns the network - // access manager of the QQmlEngine. It is overridden in the case of a threaded v8 - // instance (like in WorkerScript). - virtual QNetworkAccessManager *networkAccessManager(); -#endif - - // Return the list of illegal id names (the names of the properties on the global object) - const QSet &illegalNames() const; - - static QMutex *registrationMutex(); - static int registerExtension(); - - inline Deletable *extensionData(int) const; - void setExtensionData(int, Deletable *); - -public: - // used for console.time(), console.timeEnd() - void startTimer(const QString &timerName); - qint64 stopTimer(const QString &timerName, bool *wasRunning); - - // used for console.count() - int consoleCountHelper(const QString &file, quint16 line, quint16 column); - -protected: - QQmlEngine *m_engine; - QQmlDelayedCallQueue m_delayedCallQueue; - - QV4::ExecutionEngine *m_v4Engine; - -#if QT_CONFIG(qml_xml_http_request) - void *m_xmlHttpRequestData; -#endif - - QVector m_extensionData; - - QSet m_illegalNames; - - QElapsedTimer m_time; - QHash m_startedTimers; - - QHash m_consoleCount; - - void initializeGlobal(); - -private: - Q_DISABLE_COPY(QV8Engine) -}; - -inline QV8Engine::Deletable *QV8Engine::extensionData(int index) const -{ - if (index < m_extensionData.count()) - return m_extensionData[index]; - else - return nullptr; -} - - -QT_END_NAMESPACE - -#endif // QQMLV8ENGINE_P_H diff --git a/src/qml/qml/v8/v8.pri b/src/qml/qml/v8/v8.pri index 4592022939..fbcc47de0c 100644 --- a/src/qml/qml/v8/v8.pri +++ b/src/qml/qml/v8/v8.pri @@ -1,11 +1,9 @@ HEADERS += \ - $$PWD/qv8engine_p.h \ $$PWD/qv4domerrors_p.h \ $$PWD/qv4sqlerrors_p.h \ $$PWD/qqmlbuiltinfunctions_p.h SOURCES += \ - $$PWD/qv8engine.cpp \ $$PWD/qv4domerrors.cpp \ $$PWD/qv4sqlerrors.cpp \ $$PWD/qqmlbuiltinfunctions.cpp diff --git a/src/qml/qtqmlglobal.h b/src/qml/qtqmlglobal.h index a111f72e81..3e275c6359 100644 --- a/src/qml/qtqmlglobal.h +++ b/src/qml/qtqmlglobal.h @@ -54,6 +54,8 @@ # define QT_FEATURE_qml_debug -1 # define QT_FEATURE_qml_sequence_object 1 # define QT_FEATURE_qml_jit -1 +# define QT_FEATURE_qml_worker_script -1 +# define QT_FEATURE_qml_xml_http_request -1 #endif QT_BEGIN_NAMESPACE -- cgit v1.2.3 From 12829b50fc85587c9c08c834efd63ebe8ccbbcd2 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Wed, 8 May 2019 11:05:39 +0200 Subject: Register QObject along with QQmlComponent as basic type of the language Apparently we need it somewhere. Before the restructuring of imports all QtQml types were automatically registered on QQmlEnginePrivate::init(). We don't do this anymore, so we need to register the basic building blocks of the language separately now. Fixes: QTBUG-75645 Change-Id: I77fe23f709304586cd16986650b0056ea87bcd45 Reviewed-by: Liang Qi Reviewed-by: Mitch Curtis Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlengine.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 8bdbe0fc47..ea639d870b 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -944,7 +944,11 @@ void QQmlEnginePrivate::init() Q_Q(QQmlEngine); if (baseModulesUninitialized) { - qmlRegisterType("QML", 1, 0, "Component"); // required for the Compiler. + + // required for the Compiler. + qmlRegisterType("QML", 1, 0, "QtObject"); + qmlRegisterType("QML", 1, 0, "Component"); + QQmlData::init(); baseModulesUninitialized = false; } -- cgit v1.2.3 From ae8c798a0a01334d1af33a59acdaeda8898a9f5c Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 6 May 2019 13:21:17 +0200 Subject: Drop some dead bootstrap code The dependencies are only hashed if a dependencyHasher is given. This is generally not the case when compiling ahead of time. There is also no need to hide the declaration of DependentTypesHasher from the bootstrap code. Change-Id: I0ea74c3079656ce1fe353956999820916c8ff626 Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlirbuilder.cpp | 25 +++++-------------------- src/qml/compiler/qv4compileddata.cpp | 11 ++++------- src/qml/compiler/qv4compileddata_p.h | 7 +++---- src/qml/qml/qqmltypeloader.cpp | 10 ++++++---- 4 files changed, 18 insertions(+), 35 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 9ac1a8b5ac..cd3953044b 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -48,12 +48,6 @@ #include #include -#ifndef V4_BOOTSTRAP -#include -#include -#include -#endif - #ifdef CONST #undef CONST #endif @@ -61,11 +55,6 @@ QT_USE_NAMESPACE static const quint32 emptyStringIndex = 0; - -#if 0 //ndef V4_BOOTSTRAP -DEFINE_BOOL_CONFIG_OPTION(lookupHints, QML_LOOKUP_HINTS); -#endif // V4_BOOTSTRAP - using namespace QmlIR; #define COMPILE_EXCEPTION(location, desc) \ @@ -1586,18 +1575,14 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen // definitely not suitable for StaticData access. createdUnit->flags &= ~QV4::CompiledData::Unit::StaticData; -#ifndef V4_BOOTSTRAP if (dependencyHasher) { - QCryptographicHash hash(QCryptographicHash::Md5); - if (dependencyHasher(&hash)) { - QByteArray checksum = hash.result(); - Q_ASSERT(checksum.size() == sizeof(createdUnit->dependencyMD5Checksum)); - memcpy(createdUnit->dependencyMD5Checksum, checksum.constData(), sizeof(createdUnit->dependencyMD5Checksum)); + const QByteArray checksum = dependencyHasher(); + if (checksum.size() == sizeof(createdUnit->dependencyMD5Checksum)) { + memcpy(createdUnit->dependencyMD5Checksum, checksum.constData(), + sizeof(createdUnit->dependencyMD5Checksum)); } } -#else - Q_UNUSED(dependencyHasher); -#endif + createdUnit->sourceFileIndex = output.jsGenerator.stringTable.getStringId(output.jsModule.fileName); createdUnit->finalUrlIndex = output.jsGenerator.stringTable.getStringId(output.jsModule.finalUrl); diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index a78094f17c..5f2993c364 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -425,13 +425,10 @@ bool CompilationUnit::verifyChecksum(const DependentTypesHasher &dependencyHashe } return true; } - QCryptographicHash hash(QCryptographicHash::Md5); - if (!dependencyHasher(&hash)) - return false; - QByteArray checksum = hash.result(); - Q_ASSERT(checksum.size() == sizeof(data->dependencyMD5Checksum)); - return memcmp(data->dependencyMD5Checksum, checksum.constData(), - sizeof(data->dependencyMD5Checksum)) == 0; + const QByteArray checksum = dependencyHasher(); + return checksum.size() == sizeof(data->dependencyMD5Checksum) + && memcmp(data->dependencyMD5Checksum, checksum.constData(), + sizeof(data->dependencyMD5Checksum)) == 0; } QStringList CompilationUnit::moduleRequests() const diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index f604cc0d46..3e89c25c7d 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -51,6 +51,7 @@ // #include +#include #include #include #include @@ -1057,12 +1058,10 @@ struct ResolvedTypeReferenceMap: public QMap { bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const; }; - -using DependentTypesHasher = std::function; -#else -struct DependentTypesHasher {}; #endif +using DependentTypesHasher = std::function; + // index is per-object binding index typedef QVector BindingPropertyData; diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index d694909c7c..2233af6cd8 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2357,10 +2357,12 @@ void QQmlTypeData::done() QQmlEngine *const engine = typeLoader()->engine(); - const auto dependencyHasher = [engine, &resolvedTypeCache, this](QCryptographicHash *hash) { - if (!resolvedTypeCache.addToHash(hash, engine)) - return false; - return ::addTypeReferenceChecksumsToHash(m_compositeSingletons, hash, engine); + const auto dependencyHasher = [engine, &resolvedTypeCache, this]() { + QCryptographicHash hash(QCryptographicHash::Md5); + return (resolvedTypeCache.addToHash(&hash, engine) + && ::addTypeReferenceChecksumsToHash(m_compositeSingletons, &hash, engine)) + ? hash.result() + : QByteArray(); }; // verify if any dependencies changed if we're using a cache -- cgit v1.2.3 From 005edd128aa5acc3321e32e714954a17dd9451b2 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 9 May 2019 11:51:00 +0200 Subject: Generate the compilation unit checksum whenever we have MD5 This is actually not dependent on V4_BOOTSTRAP. There are various conditions that might influence QCryptographicHash. Change-Id: Iad0384a2cf8360e6db8ef398bd45f63161c0b70f Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4compileddata.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 5f2993c364..6e09eac977 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -949,7 +949,7 @@ void CompilationUnit::destroy() void Unit::generateChecksum() { -#ifndef V4_BOOTSTRAP +#ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 QCryptographicHash hash(QCryptographicHash::Md5); const int checksummableDataOffset = offsetof(QV4::CompiledData::Unit, md5Checksum) + sizeof(md5Checksum); -- cgit v1.2.3 From 74f0d35c2329c0f2566fea44097ecea614906567 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 9 May 2019 15:45:19 +0200 Subject: Move qv4string{_p.h|.cpp} out of the devtools The only thing we actually need is toArrayIndex() and that is a static method. We provide it in a separate file. Change-Id: I86b11e3d81a319202a0babacd17d87e7816ac88a Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4codegen.cpp | 6 +- src/qml/compiler/qv4compiler.cpp | 1 - src/qml/compiler/qv4compilerscanfunctions.cpp | 1 - src/qml/jsruntime/jsruntime.pri | 5 +- src/qml/jsruntime/qv4string.cpp | 5 -- src/qml/jsruntime/qv4string_p.h | 36 ++-------- src/qml/jsruntime/qv4stringtoarrayindex_p.h | 96 +++++++++++++++++++++++++++ src/qml/jsruntime/qv4value.cpp | 4 +- 8 files changed, 107 insertions(+), 47 deletions(-) create mode 100644 src/qml/jsruntime/qv4stringtoarrayindex_p.h (limited to 'src/qml') diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 3c669c9b1a..edd479a0bd 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include #include @@ -1245,7 +1245,7 @@ bool Codegen::visit(ArrayMemberExpression *ast) return false; if (AST::StringLiteral *str = AST::cast(ast->expression)) { QString s = str->value.toString(); - uint arrayIndex = QV4::String::toArrayIndex(s); + uint arrayIndex = stringToArrayIndex(s); if (arrayIndex == UINT_MAX) { setExprResult(Reference::fromMember(base, str->value.toString())); return false; @@ -2515,7 +2515,7 @@ bool Codegen::visit(ObjectPattern *ast) if (cname || p->type != PatternProperty::Literal) break; QString name = p->name->asString(); - uint arrayIndex = QV4::String::toArrayIndex(name); + uint arrayIndex = stringToArrayIndex(name); if (arrayIndex != UINT_MAX) break; if (members.contains(name)) diff --git a/src/qml/compiler/qv4compiler.cpp b/src/qml/compiler/qv4compiler.cpp index 123d77f788..4a54e5a44b 100644 --- a/src/qml/compiler/qv4compiler.cpp +++ b/src/qml/compiler/qv4compiler.cpp @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include diff --git a/src/qml/compiler/qv4compilerscanfunctions.cpp b/src/qml/compiler/qv4compilerscanfunctions.cpp index 8984b6931e..ef67a11a70 100644 --- a/src/qml/compiler/qv4compilerscanfunctions.cpp +++ b/src/qml/compiler/qv4compilerscanfunctions.cpp @@ -49,7 +49,6 @@ #include #include #include -#include QT_USE_NAMESPACE using namespace QV4; diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index de2e0603e8..fe9e4932c2 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -37,6 +37,7 @@ SOURCES += \ $$PWD/qv4reflect.cpp \ $$PWD/qv4regexpobject.cpp \ $$PWD/qv4stackframe.cpp \ + $$PWD/qv4string.cpp \ $$PWD/qv4stringiterator.cpp \ $$PWD/qv4stringobject.cpp \ $$PWD/qv4variantobject.cpp \ @@ -103,6 +104,7 @@ HEADERS += \ $$PWD/qv4regexpobject_p.h \ $$PWD/qv4runtimecodegen_p.h \ $$PWD/qv4stackframe_p.h \ + $$PWD/qv4string_p.h \ $$PWD/qv4stringiterator_p.h \ $$PWD/qv4stringobject_p.h \ $$PWD/qv4variantobject_p.h \ @@ -144,14 +146,13 @@ HEADERS += \ $$PWD/qv4runtime_p.h \ $$PWD/qv4runtimeapi_p.h \ $$PWD/qv4value_p.h \ - $$PWD/qv4string_p.h \ + $$PWD/qv4stringtoarrayindex_p.h \ $$PWD/qv4util_p.h \ $$PWD/qv4value_p.h \ $$PWD/qv4functiontable_p.h SOURCES += \ $$PWD/qv4runtime.cpp \ - $$PWD/qv4string.cpp \ $$PWD/qv4value.cpp \ $$PWD/qv4executableallocator.cpp diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 68d65f2e24..24a17bf5d5 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -256,8 +256,3 @@ qint64 String::virtualGetLength(const Managed *m) } #endif // V4_BOOTSTRAP - -uint String::toArrayIndex(const QString &str) -{ - return QV4::String::toArrayIndex(str.constData(), str.constData() + str.length()); -} diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index fbd4f5f550..a986fe185e 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -54,6 +54,7 @@ #include "qv4managed_p.h" #include #include "qv4enginebase_p.h" +#include "qv4stringtoarrayindex_p.h" QT_BEGIN_NAMESPACE @@ -241,41 +242,12 @@ protected: static qint64 virtualGetLength(const Managed *m); #endif -public: - static uint toArrayIndex(const QString &str); - -private: - static inline uint toUInt(const QChar *ch) { return ch->unicode(); } - static inline uint toUInt(const char *ch) { return static_cast(*ch); } - - template - static inline uint toArrayIndex(const T *ch, const T *end) - { - uint i = toUInt(ch) - '0'; - if (i > 9) - return UINT_MAX; - ++ch; - // reject "01", "001", ... - if (i == 0 && ch != end) - return UINT_MAX; - - while (ch < end) { - uint x = toUInt(ch) - '0'; - if (x > 9) - return UINT_MAX; - if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i)) // i = i * 10 + x - return UINT_MAX; - ++ch; - } - return i; - } - public: template static inline uint calculateHashValue(const T *ch, const T* end, uint *subtype) { // array indices get their number as hash value - uint h = toArrayIndex(ch, end); + uint h = stringToArrayIndex(ch, end); if (h != UINT_MAX) { if (subtype) *subtype = Heap::StringOrSymbol::StringType_ArrayIndex; @@ -283,12 +255,12 @@ public: } while (ch < end) { - h = 31 * h + toUInt(ch); + h = 31 * h + charToUInt(ch); ++ch; } if (subtype) - *subtype = (toUInt(ch) == '@') ? Heap::StringOrSymbol::StringType_Symbol : Heap::StringOrSymbol::StringType_Regular; + *subtype = (charToUInt(ch) == '@') ? Heap::StringOrSymbol::StringType_Symbol : Heap::StringOrSymbol::StringType_Regular; return h; } }; diff --git a/src/qml/jsruntime/qv4stringtoarrayindex_p.h b/src/qml/jsruntime/qv4stringtoarrayindex_p.h new file mode 100644 index 0000000000..61bd988d1e --- /dev/null +++ b/src/qml/jsruntime/qv4stringtoarrayindex_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV4STRINGTOARRAYINDEX_P_H +#define QV4STRINGTOARRAYINDEX_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +inline uint charToUInt(const QChar *ch) { return ch->unicode(); } +inline uint charToUInt(const char *ch) { return static_cast(*ch); } + +template +uint stringToArrayIndex(const T *ch, const T *end) +{ + uint i = charToUInt(ch) - '0'; + if (i > 9) + return std::numeric_limits::max(); + ++ch; + // reject "01", "001", ... + if (i == 0 && ch != end) + return std::numeric_limits::max(); + + while (ch < end) { + uint x = charToUInt(ch) - '0'; + if (x > 9) + return std::numeric_limits::max(); + if (mul_overflow(i, uint(10), &i) || add_overflow(i, x, &i)) // i = i * 10 + x + return std::numeric_limits::max(); + ++ch; + } + return i; +} + +inline uint stringToArrayIndex(const QString &str) +{ + return stringToArrayIndex(str.constData(), str.constData() + str.length()); +} + +} // namespace QV4 + +QT_END_NAMESPACE + +#endif // QV4STRINGTOARRAYINDEX_P_H diff --git a/src/qml/jsruntime/qv4value.cpp b/src/qml/jsruntime/qv4value.cpp index 9b50938ccb..82cf11f148 100644 --- a/src/qml/jsruntime/qv4value.cpp +++ b/src/qml/jsruntime/qv4value.cpp @@ -38,9 +38,9 @@ ****************************************************************************/ #include -#include #include #ifndef V4_BOOTSTRAP +#include #include #include #include @@ -248,7 +248,6 @@ QV4::PropertyKey Value::toPropertyKey(ExecutionEngine *e) const ScopedStringOrSymbol s(scope, v); return s->toPropertyKey(); } -#endif // V4_BOOTSTRAP bool Value::sameValue(Value other) const { if (_val == other._val) @@ -285,7 +284,6 @@ bool Value::sameValueZero(Value other) const { return false; } -#ifndef V4_BOOTSTRAP Heap::String *Value::toString(ExecutionEngine *e, Value val) { return RuntimeHelpers::convertToString(e, val); -- cgit v1.2.3 From 6ac109398d954d12e14067f5ba30bb6576863121 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 9 May 2019 15:48:09 +0200 Subject: Make sure we don't include qv4stackframe_p.h in qmldevtools The only thing we need is CallData, which is now provided as separate file. Change-Id: Iccbab67ac30d09077075b200f18d1d694f3ecb2a Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4codegen_p.h | 2 +- src/qml/compiler/qv4instr_moth.cpp | 2 +- src/qml/jsruntime/jsruntime.pri | 1 + src/qml/jsruntime/qv4calldata_p.h | 113 ++++++++++++++++++++++++++++++++++++ src/qml/jsruntime/qv4stackframe_p.h | 50 +--------------- 5 files changed, 117 insertions(+), 51 deletions(-) create mode 100644 src/qml/jsruntime/qv4calldata_p.h (limited to 'src/qml') diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index ece76e4406..962ccc8562 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -58,7 +58,7 @@ #include #include #include -#include +#include #include diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index 5148154a6a..5b637ea567 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -39,7 +39,7 @@ #include "qv4instr_moth_p.h" #include -#include +#include using namespace QV4; using namespace QV4::Moth; diff --git a/src/qml/jsruntime/jsruntime.pri b/src/qml/jsruntime/jsruntime.pri index fe9e4932c2..e6f1079aa7 100644 --- a/src/qml/jsruntime/jsruntime.pri +++ b/src/qml/jsruntime/jsruntime.pri @@ -143,6 +143,7 @@ qtConfig(qml-sequence-object) { HEADERS += \ + $$PWD/qv4calldata_p.h \ $$PWD/qv4runtime_p.h \ $$PWD/qv4runtimeapi_p.h \ $$PWD/qv4value_p.h \ diff --git a/src/qml/jsruntime/qv4calldata_p.h b/src/qml/jsruntime/qv4calldata_p.h new file mode 100644 index 0000000000..8487872bf5 --- /dev/null +++ b/src/qml/jsruntime/qv4calldata_p.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQml module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV4CALLDATA_P_H +#define QV4CALLDATA_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +struct CallData +{ + enum Offsets { + Function = 0, + Context = 1, + Accumulator = 2, + This = 3, + NewTarget = 4, + Argc = 5, + + LastOffset = Argc, + OffsetCount = LastOffset + 1 + }; + + Value function; + Value context; + Value accumulator; + Value thisObject; + Value newTarget; + Value _argc; + + int argc() const { + Q_ASSERT(_argc.isInteger()); + return _argc.int_32(); + } + + void setArgc(int argc) { + Q_ASSERT(argc >= 0); + _argc.setInt_32(argc); + } + + inline ReturnedValue argument(int i) const { + return i < argc() ? args[i].asReturnedValue() : Value::undefinedValue().asReturnedValue(); + } + + Value args[1]; + + static Q_DECL_CONSTEXPR int HeaderSize() { return offsetof(CallData, args) / sizeof(QV4::Value); } +}; + +Q_STATIC_ASSERT(std::is_standard_layout::value); +Q_STATIC_ASSERT(offsetof(CallData, function ) == CallData::Function * sizeof(Value)); +Q_STATIC_ASSERT(offsetof(CallData, context ) == CallData::Context * sizeof(Value)); +Q_STATIC_ASSERT(offsetof(CallData, accumulator) == CallData::Accumulator * sizeof(Value)); +Q_STATIC_ASSERT(offsetof(CallData, thisObject ) == CallData::This * sizeof(Value)); +Q_STATIC_ASSERT(offsetof(CallData, newTarget ) == CallData::NewTarget * sizeof(Value)); +Q_STATIC_ASSERT(offsetof(CallData, _argc ) == CallData::Argc * sizeof(Value)); +Q_STATIC_ASSERT(offsetof(CallData, args ) == 6 * sizeof(Value)); + +} // namespace QV4 + +QT_END_NAMESPACE + +#endif // QV4CALLDATA_P_H diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h index 44cfef9173..51a6acf43c 100644 --- a/src/qml/jsruntime/qv4stackframe_p.h +++ b/src/qml/jsruntime/qv4stackframe_p.h @@ -52,6 +52,7 @@ #include #include +#include #ifndef V4_BOOTSTRAP #include #endif @@ -60,55 +61,6 @@ QT_BEGIN_NAMESPACE namespace QV4 { -struct CallData -{ - enum Offsets { - Function = 0, - Context = 1, - Accumulator = 2, - This = 3, - NewTarget = 4, - Argc = 5, - - LastOffset = Argc, - OffsetCount = LastOffset + 1 - }; - - Value function; - Value context; - Value accumulator; - Value thisObject; - Value newTarget; - Value _argc; - - int argc() const { - Q_ASSERT(_argc.isInteger()); - return _argc.int_32(); - } - - void setArgc(int argc) { - Q_ASSERT(argc >= 0); - _argc.setInt_32(argc); - } - - inline ReturnedValue argument(int i) const { - return i < argc() ? args[i].asReturnedValue() : Value::undefinedValue().asReturnedValue(); - } - - Value args[1]; - - static Q_DECL_CONSTEXPR int HeaderSize() { return offsetof(CallData, args) / sizeof(QV4::Value); } -}; - -Q_STATIC_ASSERT(std::is_standard_layout::value); -Q_STATIC_ASSERT(offsetof(CallData, function ) == CallData::Function * sizeof(Value)); -Q_STATIC_ASSERT(offsetof(CallData, context ) == CallData::Context * sizeof(Value)); -Q_STATIC_ASSERT(offsetof(CallData, accumulator) == CallData::Accumulator * sizeof(Value)); -Q_STATIC_ASSERT(offsetof(CallData, thisObject ) == CallData::This * sizeof(Value)); -Q_STATIC_ASSERT(offsetof(CallData, newTarget ) == CallData::NewTarget * sizeof(Value)); -Q_STATIC_ASSERT(offsetof(CallData, _argc ) == CallData::Argc * sizeof(Value)); -Q_STATIC_ASSERT(offsetof(CallData, args ) == 6 * sizeof(Value)); - struct Q_QML_EXPORT CppStackFrame { EngineBase *engine; Value *savedStackTop; -- cgit v1.2.3 From e5255809b5adbe3c837cc1ece18f63054e0d53b5 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 9 May 2019 15:50:40 +0200 Subject: Don't include qv4enginebase_p.h in qmldevtools We don't need it and we don't need to check for V4_BOOTSTRAP in there. Shuffle some includes around to provide everything we do need. Change-Id: I3e75f1c6f9dc518006aabc9dcee21e5153899ac5 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4enginebase_p.h | 3 --- src/qml/jsruntime/qv4managed_p.h | 1 - src/qml/jsruntime/qv4runtime.cpp | 8 +++++++- src/qml/jsruntime/qv4runtime_p.h | 1 - src/qml/memory/qv4mm.cpp | 1 + src/qml/memory/qv4writebarrier_p.h | 2 +- 6 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index 82eccd9f3c..00876c71a2 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -79,9 +79,6 @@ struct Q_QML_EXPORT EngineBase { #elif defined(Q_ATOMIC_INT16_IS_SUPPORTED) quint8 unused = 0; QAtomicInteger isInterrupted = false; -#elif defined(V4_BOOTSTRAP) - // We don't need the isInterrupted flag when bootstrapping. - quint8 unused[3]; #else # error V4 needs either 8bit or 16bit atomics. #endif diff --git a/src/qml/jsruntime/qv4managed_p.h b/src/qml/jsruntime/qv4managed_p.h index d85b30a056..4f22dc7330 100644 --- a/src/qml/jsruntime/qv4managed_p.h +++ b/src/qml/jsruntime/qv4managed_p.h @@ -54,7 +54,6 @@ #include "qv4value_p.h" #include "qv4enginebase_p.h" #include -#include #include QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index f404aac580..107dfbda6f 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -1175,8 +1175,14 @@ Bool RuntimeHelpers::strictEqual(const Value &x, const Value &y) if (x.isNumber()) return y.isNumber() && x.asDouble() == y.asDouble(); - if (x.isManaged()) + if (x.isManaged()) { +#ifdef V4_BOOTSTRAP + Q_UNIMPLEMENTED(); + return false; +#else return y.isManaged() && x.cast()->isEqualTo(y.cast()); +#endif + } return false; } diff --git a/src/qml/jsruntime/qv4runtime_p.h b/src/qml/jsruntime/qv4runtime_p.h index 78ab6a1822..349099f8d5 100644 --- a/src/qml/jsruntime/qv4runtime_p.h +++ b/src/qml/jsruntime/qv4runtime_p.h @@ -52,7 +52,6 @@ #include "qv4global_p.h" #include "qv4value_p.h" -#include "qv4context_p.h" #include "qv4math_p.h" #include "qv4runtimeapi_p.h" #include diff --git a/src/qml/memory/qv4mm.cpp b/src/qml/memory/qv4mm.cpp index 34d334a24d..9288d3e3b6 100644 --- a/src/qml/memory/qv4mm.cpp +++ b/src/qml/memory/qv4mm.cpp @@ -63,6 +63,7 @@ #include "qv4profiling_p.h" #include "qv4mapobject_p.h" #include "qv4setobject_p.h" +#include "qv4writebarrier_p.h" //#define MM_STATS diff --git a/src/qml/memory/qv4writebarrier_p.h b/src/qml/memory/qv4writebarrier_p.h index 8b04aa6cb1..c65cfc0269 100644 --- a/src/qml/memory/qv4writebarrier_p.h +++ b/src/qml/memory/qv4writebarrier_p.h @@ -51,7 +51,6 @@ // #include -#include QT_BEGIN_NAMESPACE @@ -60,6 +59,7 @@ QT_BEGIN_NAMESPACE #define WRITEBARRIER(x) (1/WRITEBARRIER_##x == 1) namespace QV4 { +struct EngineBase; namespace WriteBarrier { -- cgit v1.2.3 From 24b286773ae5d47ad43f5e1810ebe6c5093a49da Mon Sep 17 00:00:00 2001 From: Simon Hausmann Date: Mon, 13 May 2019 12:41:50 +0200 Subject: Elaborate on the meaning of values held by basic types Explicitly mention the copying semantics as well as how they are called in the JavaScript language. Task-number: QTBUG-75308 Change-Id: I82b8c6324133d3265b66325c6f67b19b344e0470 Reviewed-by: Kavindra Palaraja Reviewed-by: Paul Wicking --- src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/qml') diff --git a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc index c4c1b61693..5144fe219e 100644 --- a/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc +++ b/src/qml/doc/src/qmllanguageref/typesystem/basictypes.qdoc @@ -44,6 +44,10 @@ Basic types can be used to refer to: \li A value that contains a simple set of property-value pairs (e.g. \l size refers to a value with \c width and \c height attributes) \endlist +When a variable or property holds a basic type and it is assigned to another +variable or property, then a copy of the value is made. In JavaScript, this +value is called a primitive value. + \sa {qtqml-typesystem-topic.html}{The QML Type System} -- cgit v1.2.3 From c1829ea50bf5c99428f0a19887c503b4c7bd4b9a Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 13 May 2019 15:49:42 +0200 Subject: Fix illegal downcast on QQmlEngine destruction Make QQmlEnginePrivate::isEngineThread() legal to call during QQmlEngine destruction. Change-Id: I2bae9d70883cf8013f39f2046ebe83bb8dbcd46b Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlengine_p.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index d05c945ae4..92e56cd957 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -309,8 +309,8 @@ Returns true if the calling thread is the QQmlEngine thread. */ bool QQmlEnginePrivate::isEngineThread() const { - Q_Q(const QQmlEngine); - return QThread::currentThread() == q->thread(); + + return QThread::currentThread() == q_ptr->thread(); } /*! @@ -335,8 +335,6 @@ the instance directly if not. template void QQmlEnginePrivate::deleteInEngineThread(T *value) { - Q_Q(QQmlEngine); - Q_ASSERT(value); if (isEngineThread()) { delete value; @@ -352,7 +350,7 @@ void QQmlEnginePrivate::deleteInEngineThread(T *value) toDeleteInEngineThread.append(i); mutex.unlock(); if (wasEmpty) - QCoreApplication::postEvent(q, new QEvent(QEvent::User)); + QCoreApplication::postEvent(q_ptr, new QEvent(QEvent::User)); } } -- cgit v1.2.3 From 078eb28e0c657b8107c5e8be873b3503fdea7ed2 Mon Sep 17 00:00:00 2001 From: Allan Sandfeld Jensen Date: Mon, 13 May 2019 17:53:06 +0200 Subject: Do not take a reference of nullptr References are not allowed to be null, but we pass a nullptr as receiver in QQmlContextWrapper::resolveQmlContextPropertyLookupGetter. Detected with UBSAN. Change-Id: Iaa7945fb17e4b0e549e541e47589b2f47d32ea4e Reviewed-by: Simon Hausmann Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4object.cpp | 9 +++++---- src/qml/jsruntime/qv4object_p.h | 8 ++++---- 2 files changed, 9 insertions(+), 8 deletions(-) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4object.cpp b/src/qml/jsruntime/qv4object.cpp index 7dd0a247d6..02524b7da6 100644 --- a/src/qml/jsruntime/qv4object.cpp +++ b/src/qml/jsruntime/qv4object.cpp @@ -93,7 +93,7 @@ void Heap::Object::setUsedAsProto() internalClass.set(internalClass->engine, internalClass->asProtoClass()); } -ReturnedValue Object::getValueAccessor(const Value &thisObject, const Value &v, PropertyAttributes attrs) +ReturnedValue Object::getValueAccessor(const Value *thisObject, const Value &v, PropertyAttributes attrs) { if (!attrs.isAccessor()) return v.asReturnedValue(); @@ -103,7 +103,8 @@ ReturnedValue Object::getValueAccessor(const Value &thisObject, const Value &v, Scope scope(f->engine()); JSCallData jsCallData(scope); - *jsCallData->thisObject = thisObject; + if (thisObject) + *jsCallData->thisObject = *thisObject; return f->call(jsCallData); } @@ -415,7 +416,7 @@ ReturnedValue Object::internalGet(PropertyKey id, const Value *receiver, bool *h if (o->arrayData && o->arrayData->getProperty(index, pd, &attrs)) { if (hasProperty) *hasProperty = true; - return Object::getValue(*receiver, pd->value, attrs); + return Object::getValue(receiver, pd->value, attrs); } if (o->internalClass->vtable->type == Type_StringObject) { ScopedString str(scope, static_cast(o)->getIndex(index)); @@ -438,7 +439,7 @@ ReturnedValue Object::internalGet(PropertyKey id, const Value *receiver, bool *h if (idx.isValid()) { if (hasProperty) *hasProperty = true; - return Object::getValue(*receiver, *o->propertyData(idx.index), idx.attrs); + return Object::getValue(receiver, *o->propertyData(idx.index), idx.attrs); } o = o->prototype(); if (!o || o->internalClass->vtable->get != Object::virtualGet) diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index c3f1cb2c35..bee4aadafe 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -185,22 +185,22 @@ struct Q_QML_EXPORT Object: Managed { // // helpers // - static ReturnedValue getValue(const Value &thisObject, const Value &v, PropertyAttributes attrs) { + static ReturnedValue getValue(const Value *thisObject, const Value &v, PropertyAttributes attrs) { if (attrs.isData()) return v.asReturnedValue(); return getValueAccessor(thisObject, v, attrs); } ReturnedValue getValue(const Value &v, PropertyAttributes attrs) const { - return getValue(*this, v, attrs); + return getValue(this, v, attrs); } ReturnedValue getValueByIndex(uint propertyIndex) const { PropertyAttributes attrs = internalClass()->propertyData.at(propertyIndex); const Value *v = propertyData(propertyIndex); if (!attrs.isAccessor()) return v->asReturnedValue(); - return getValueAccessor(*this, *v, attrs); + return getValueAccessor(this, *v, attrs); } - static ReturnedValue getValueAccessor(const Value &thisObject, const Value &v, PropertyAttributes attrs); + static ReturnedValue getValueAccessor(const Value *thisObject, const Value &v, PropertyAttributes attrs); bool putValue(uint memberIndex, PropertyAttributes attrs, const Value &value); -- cgit v1.2.3 From 733adcf32c1cce288435940c66846a51ad29a464 Mon Sep 17 00:00:00 2001 From: Jarek Kobus Date: Mon, 13 May 2019 11:18:28 +0200 Subject: Compile fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It fixes the following issue: error: comparison of integer expressions of different signedness: ‘size_t’ {aka ‘long unsigned int’} and ‘int’ [-Werror=sign-compare] Change-Id: I4b896f49ff753a5cf79cd1e40e76815f712eec89 Reviewed-by: Ulf Hermann --- src/qml/jsruntime/qv4memberdata.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4memberdata.cpp b/src/qml/jsruntime/qv4memberdata.cpp index f327c85001..ffebe1b5da 100644 --- a/src/qml/jsruntime/qv4memberdata.cpp +++ b/src/qml/jsruntime/qv4memberdata.cpp @@ -72,8 +72,8 @@ Heap::MemberData *MemberData::allocate(ExecutionEngine *e, uint n, Heap::MemberD // The above code can overflow in a number of interesting ways. All of those are unsigned, // and therefore defined behavior. Still, apply some sane bounds. - if (alloc > std::numeric_limits::max()) - alloc = std::numeric_limits::max(); + if (alloc > size_t(std::numeric_limits::max())) + alloc = size_t(std::numeric_limits::max()); Heap::MemberData *m; if (old) { -- cgit v1.2.3 From 7f7d87c68da4cb29b2b2b9c324c6863228da0c26 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Tue, 7 May 2019 12:47:33 +0200 Subject: Split CompiledData::CompilationUnit in two We need a CompilationUnit that only holds the data needed for compilation and another one that is executable by the runtime. Change-Id: I704d859ba028576a18460f5e3a59f210f64535d3 Reviewed-by: Simon Hausmann --- src/qml/compiler/compiler.pri | 8 +- src/qml/compiler/qqmlirbuilder.cpp | 14 +- src/qml/compiler/qqmlirbuilder_p.h | 2 +- src/qml/compiler/qqmlirloader_p.h | 1 + src/qml/compiler/qqmlpropertyvalidator.cpp | 32 +- src/qml/compiler/qqmlpropertyvalidator_p.h | 6 +- src/qml/compiler/qqmltypecompiler.cpp | 19 +- src/qml/compiler/qqmltypecompiler_p.h | 15 +- src/qml/compiler/qv4codegen.cpp | 26 +- src/qml/compiler/qv4codegen_p.h | 5 +- src/qml/compiler/qv4compileddata.cpp | 742 +------------------- src/qml/compiler/qv4compileddata_p.h | 248 ++----- src/qml/compiler/qv4executablecompilationunit.cpp | 784 ++++++++++++++++++++++ src/qml/compiler/qv4executablecompilationunit_p.h | 318 +++++++++ src/qml/debugger/qqmlprofiler_p.h | 15 +- src/qml/jsruntime/qv4context.cpp | 4 +- src/qml/jsruntime/qv4engine.cpp | 14 +- src/qml/jsruntime/qv4engine_p.h | 16 +- src/qml/jsruntime/qv4function.cpp | 13 +- src/qml/jsruntime/qv4function_p.h | 33 +- src/qml/jsruntime/qv4functionobject.cpp | 11 +- src/qml/jsruntime/qv4functionobject_p.h | 2 +- src/qml/jsruntime/qv4generatorobject.cpp | 2 +- src/qml/jsruntime/qv4module.cpp | 4 +- src/qml/jsruntime/qv4module_p.h | 4 +- src/qml/jsruntime/qv4profiling.cpp | 2 +- src/qml/jsruntime/qv4profiling_p.h | 20 +- src/qml/jsruntime/qv4runtime.cpp | 50 +- src/qml/jsruntime/qv4script.cpp | 18 +- src/qml/jsruntime/qv4script_p.h | 10 +- src/qml/jsruntime/qv4vme_moth.cpp | 10 +- src/qml/qml/qqmlbinding.cpp | 6 +- src/qml/qml/qqmlbinding_p.h | 2 +- src/qml/qml/qqmlcomponent.cpp | 3 +- src/qml/qml/qqmlcomponent.h | 7 +- src/qml/qml/qqmlcomponent_p.h | 2 +- src/qml/qml/qqmlcontext.cpp | 2 +- src/qml/qml/qqmlcontext_p.h | 6 +- src/qml/qml/qqmlcustomparser_p.h | 4 +- src/qml/qml/qqmldata_p.h | 8 +- src/qml/qml/qqmlengine.cpp | 6 +- src/qml/qml/qqmlengine_p.h | 6 +- src/qml/qml/qqmlincubator_p.h | 2 +- src/qml/qml/qqmljavascriptexpression.cpp | 4 +- src/qml/qml/qqmljavascriptexpression_p.h | 4 +- src/qml/qml/qqmlmetatype.cpp | 4 +- src/qml/qml/qqmlmetatype_p.h | 6 +- src/qml/qml/qqmlobjectcreator.cpp | 60 +- src/qml/qml/qqmlobjectcreator_p.h | 8 +- src/qml/qml/qqmlproperty_p.h | 1 + src/qml/qml/qqmltype.cpp | 4 +- src/qml/qml/qqmltypeloader.cpp | 77 ++- src/qml/qml/qqmltypeloader_p.h | 19 +- src/qml/qml/qqmltypewrapper.cpp | 2 +- src/qml/qml/qqmlvmemetaobject.cpp | 2 +- src/qml/qml/qqmlvmemetaobject_p.h | 4 +- src/qml/qml/v8/qqmlbuiltinfunctions.cpp | 3 +- src/qml/types/qqmlconnections.cpp | 6 +- src/qml/types/qqmlconnections_p.h | 4 +- 59 files changed, 1489 insertions(+), 1221 deletions(-) create mode 100644 src/qml/compiler/qv4executablecompilationunit.cpp create mode 100644 src/qml/compiler/qv4executablecompilationunit_p.h (limited to 'src/qml') diff --git a/src/qml/compiler/compiler.pri b/src/qml/compiler/compiler.pri index c15c45a1cb..3291d6e1f5 100644 --- a/src/qml/compiler/compiler.pri +++ b/src/qml/compiler/compiler.pri @@ -10,7 +10,6 @@ HEADERS += \ $$PWD/qv4compilerscanfunctions_p.h \ $$PWD/qv4codegen_p.h \ $$PWD/qqmlirbuilder_p.h \ - $$PWD/qqmltypecompiler_p.h \ $$PWD/qv4instr_moth_p.h \ $$PWD/qv4bytecodehandler_p.h @@ -33,8 +32,8 @@ HEADERS += \ $$PWD/qqmltypecompiler_p.h \ $$PWD/qqmlpropertycachecreator_p.h \ $$PWD/qqmlpropertyvalidator_p.h \ - $$PWD/qv4compilationunitmapper_p.h - + $$PWD/qv4compilationunitmapper_p.h \ + $$PWD/qv4executablecompilationunit_p.h SOURCES += \ $$PWD/qqmlirloader.cpp \ @@ -42,7 +41,8 @@ SOURCES += \ $$PWD/qqmltypecompiler.cpp \ $$PWD/qqmlpropertycachecreator.cpp \ $$PWD/qqmlpropertyvalidator.cpp \ - $$PWD/qv4compilationunitmapper.cpp + $$PWD/qv4compilationunitmapper.cpp \ + $$PWD/qv4executablecompilationunit.cpp unix: SOURCES += $$PWD/qv4compilationunitmapper_unix.cpp else: SOURCES += $$PWD/qv4compilationunitmapper_win.cpp diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 41bdc3ae92..e63aa3b66d 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1548,15 +1548,12 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen output.jsGenerator.stringTable.registerString(output.jsModule.fileName); output.jsGenerator.stringTable.registerString(output.jsModule.finalUrl); - QQmlRefPointer compilationUnit = output.javaScriptCompilationUnit; - QV4::CompiledData::Unit *jsUnit = nullptr; - const bool finalize = !compilationUnit->data; // We may already have unit data if we're loading an ahead-of-time generated cache file. - if (!finalize) { - jsUnit = const_cast(compilationUnit->data); - output.javaScriptCompilationUnit->dynamicStrings = output.jsGenerator.stringTable.allStrings(); + if (output.javaScriptCompilationUnit.data) { + jsUnit = const_cast(output.javaScriptCompilationUnit.data); + output.javaScriptCompilationUnit.dynamicStrings = output.jsGenerator.stringTable.allStrings(); } else { QV4::CompiledData::Unit *createdUnit; jsUnit = createdUnit = output.jsGenerator.generateUnit(); @@ -1748,7 +1745,7 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen } } - if (finalize) { + if (!output.javaScriptCompilationUnit.data) { // Combine the qml data into the general unit data. jsUnit = static_cast(realloc(jsUnit, jsUnit->unitSize + totalSize)); jsUnit->offsetToQmlUnit = jsUnit->unitSize; @@ -1781,7 +1778,8 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen qDebug() << " " << totalStringSize << "bytes total strings"; } - compilationUnit->setUnitData(jsUnit, qmlUnit, output.jsModule.fileName, output.jsModule.finalUrl); + output.javaScriptCompilationUnit.setUnitData(jsUnit, qmlUnit, output.jsModule.fileName, + output.jsModule.finalUrl); } char *QmlUnitGenerator::writeBindings(char *bindingPtr, const Object *o, BindingFilter filter) const diff --git a/src/qml/compiler/qqmlirbuilder_p.h b/src/qml/compiler/qqmlirbuilder_p.h index c937158a33..b49eaee420 100644 --- a/src/qml/compiler/qqmlirbuilder_p.h +++ b/src/qml/compiler/qqmlirbuilder_p.h @@ -379,7 +379,7 @@ struct Q_QML_PRIVATE_EXPORT Document QVector objects; QV4::Compiler::JSUnitGenerator jsGenerator; - QQmlRefPointer javaScriptCompilationUnit; + QV4::CompiledData::CompilationUnit javaScriptCompilationUnit; int registerString(const QString &str) { return jsGenerator.registerString(str); } QString stringAt(int index) const { return jsGenerator.stringForIndex(index); } diff --git a/src/qml/compiler/qqmlirloader_p.h b/src/qml/compiler/qqmlirloader_p.h index cf46ca3cb0..aa303c923f 100644 --- a/src/qml/compiler/qqmlirloader_p.h +++ b/src/qml/compiler/qqmlirloader_p.h @@ -52,6 +52,7 @@ // #include +#include QT_BEGIN_NAMESPACE diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp index 1812ad6546..5b0bd8858a 100644 --- a/src/qml/compiler/qqmlpropertyvalidator.cpp +++ b/src/qml/compiler/qqmlpropertyvalidator.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE -QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer &compilationUnit) +QQmlPropertyValidator::QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer &compilationUnit) : enginePrivate(enginePrivate) , compilationUnit(compilationUnit) , imports(imports) @@ -339,7 +339,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache if (binding->flags & QV4::CompiledData::Binding::IsResolvedEnum) return noError; - QString value = binding->valueAsString(compilationUnit.data()); + QString value = compilationUnit->bindingValueAsString(binding); QMetaProperty p = propertyCache->firstCppMetaObject()->property(property->coreIndex()); bool ok; if (p.isFlagType()) { @@ -427,7 +427,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache break; case QVariant::Color: { bool ok = false; - QQmlStringConverters::rgbaFromString(binding->valueAsString(compilationUnit.data()), &ok); + QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok); if (!ok) { return warnOrError(tr("Invalid property assignment: color expected")); } @@ -436,7 +436,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache #if QT_CONFIG(datestring) case QVariant::Date: { bool ok = false; - QQmlStringConverters::dateFromString(binding->valueAsString(compilationUnit.data()), &ok); + QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok); if (!ok) { return warnOrError(tr("Invalid property assignment: date expected")); } @@ -444,7 +444,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache break; case QVariant::Time: { bool ok = false; - QQmlStringConverters::timeFromString(binding->valueAsString(compilationUnit.data()), &ok); + QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok); if (!ok) { return warnOrError(tr("Invalid property assignment: time expected")); } @@ -452,7 +452,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache break; case QVariant::DateTime: { bool ok = false; - QQmlStringConverters::dateTimeFromString(binding->valueAsString(compilationUnit.data()), &ok); + QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok); if (!ok) { return warnOrError(tr("Invalid property assignment: datetime expected")); } @@ -461,7 +461,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache #endif // datestring case QVariant::Point: { bool ok = false; - QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok); + QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok); if (!ok) { return warnOrError(tr("Invalid property assignment: point expected")); } @@ -469,7 +469,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache break; case QVariant::PointF: { bool ok = false; - QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok); + QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok); if (!ok) { return warnOrError(tr("Invalid property assignment: point expected")); } @@ -477,7 +477,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache break; case QVariant::Size: { bool ok = false; - QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok); + QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok); if (!ok) { return warnOrError(tr("Invalid property assignment: size expected")); } @@ -485,7 +485,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache break; case QVariant::SizeF: { bool ok = false; - QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok); + QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok); if (!ok) { return warnOrError(tr("Invalid property assignment: size expected")); } @@ -493,7 +493,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache break; case QVariant::Rect: { bool ok = false; - QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok); + QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok); if (!ok) { return warnOrError(tr("Invalid property assignment: rect expected")); } @@ -501,7 +501,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache break; case QVariant::RectF: { bool ok = false; - QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok); + QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok); if (!ok) { return warnOrError(tr("Invalid property assignment: point expected")); } @@ -518,7 +518,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache float xp; float yp; } vec; - if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) { + if (!QQmlStringConverters::createFromString(QMetaType::QVector2D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) { return warnOrError(tr("Invalid property assignment: 2D vector expected")); } } @@ -529,7 +529,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache float yp; float zy; } vec; - if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) { + if (!QQmlStringConverters::createFromString(QMetaType::QVector3D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) { return warnOrError(tr("Invalid property assignment: 3D vector expected")); } } @@ -541,7 +541,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache float zy; float wp; } vec; - if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) { + if (!QQmlStringConverters::createFromString(QMetaType::QVector4D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) { return warnOrError(tr("Invalid property assignment: 4D vector expected")); } } @@ -553,7 +553,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache float yp; float zp; } vec; - if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec))) { + if (!QQmlStringConverters::createFromString(QMetaType::QQuaternion, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec))) { return warnOrError(tr("Invalid property assignment: quaternion expected")); } } diff --git a/src/qml/compiler/qqmlpropertyvalidator_p.h b/src/qml/compiler/qqmlpropertyvalidator_p.h index e9ae844ccb..8244b2df21 100644 --- a/src/qml/compiler/qqmlpropertyvalidator_p.h +++ b/src/qml/compiler/qqmlpropertyvalidator_p.h @@ -58,7 +58,7 @@ class QQmlPropertyValidator { Q_DECLARE_TR_FUNCTIONS(QQmlPropertyValidator) public: - QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer &compilationUnit); + QQmlPropertyValidator(QQmlEnginePrivate *enginePrivate, const QQmlImports &imports, const QQmlRefPointer &compilationUnit); QVector validate(); @@ -72,13 +72,13 @@ private: Q_REQUIRED_RESULT QVector recordError(const QV4::CompiledData::Location &location, const QString &description) const; Q_REQUIRED_RESULT QVector recordError(const QQmlCompileError &error) const; QString stringAt(int index) const { return compilationUnit->stringAt(index); } - QV4::CompiledData::ResolvedTypeReference *resolvedType(int id) const + QV4::ResolvedTypeReference *resolvedType(int id) const { return compilationUnit->resolvedType(id); } QQmlEnginePrivate *enginePrivate; - QQmlRefPointer compilationUnit; + QQmlRefPointer compilationUnit; const QQmlImports &imports; const QV4::CompiledData::Unit *qmlUnit; const QQmlPropertyCacheVector &propertyCaches; diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp index 996b2f16ae..66320b8db9 100644 --- a/src/qml/compiler/qqmltypecompiler.cpp +++ b/src/qml/compiler/qqmltypecompiler.cpp @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *parsedQML, const QQmlRefPointer &typeNameCache, - QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher) + QV4::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher) : resolvedTypes(resolvedTypeCache) , engine(engine) , typeData(typeData) @@ -66,7 +66,7 @@ QQmlTypeCompiler::QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *type { } -QQmlRefPointer QQmlTypeCompiler::compile() +QQmlRefPointer QQmlTypeCompiler::compile() { // Build property caches and VME meta object data @@ -134,7 +134,7 @@ QQmlRefPointer QQmlTypeCompiler::compile() return nullptr; } - if (!document->javaScriptCompilationUnit) { + if (!document->javaScriptCompilationUnit.unitData()) { // Compile JS binding expressions and signal handlers if necessary { // We can compile script strings ahead of time, but they must be compiled @@ -159,7 +159,9 @@ QQmlRefPointer QQmlTypeCompiler::compile() QmlIR::QmlUnitGenerator qmlGenerator; qmlGenerator.generate(*document, dependencyHasher); - QQmlRefPointer compilationUnit = document->javaScriptCompilationUnit; + QQmlRefPointer compilationUnit + = QV4::ExecutableCompilationUnit::create(std::move( + document->javaScriptCompilationUnit)); compilationUnit->typeNameCache = typeNameCache; compilationUnit->resolvedTypes = *resolvedTypes; compilationUnit->propertyCaches = std::move(m_propertyCaches); @@ -209,7 +211,7 @@ int QQmlTypeCompiler::registerConstant(QV4::ReturnedValue v) const QV4::CompiledData::Unit *QQmlTypeCompiler::qmlUnit() const { - return document->javaScriptCompilationUnit->unitData(); + return document->javaScriptCompilationUnit.unitData(); } const QQmlImports *QQmlTypeCompiler::imports() const @@ -253,11 +255,6 @@ const QV4::Compiler::StringTableGenerator *QQmlTypeCompiler::stringPool() const return &document->jsGenerator.stringTable; } -void QQmlTypeCompiler::setBindingPropertyDataPerObject(const QVector &propertyData) -{ - document->javaScriptCompilationUnit->bindingPropertyDataPerObject = propertyData; -} - QString QQmlTypeCompiler::bindingAsString(const QmlIR::Object *object, int scriptIndex) const { return object->bindingAsString(document, scriptIndex); @@ -857,7 +854,7 @@ void QQmlComponentAndAliasResolver::findAndRegisterImplicitComponents(const QmlI syntheticComponent->flags |= QV4::CompiledData::Object::IsComponent; if (!containsResolvedType(syntheticComponent->inheritedTypeNameIndex)) { - auto typeRef = new QV4::CompiledData::ResolvedTypeReference; + auto typeRef = new QV4::ResolvedTypeReference; typeRef->type = componentType; typeRef->majorVersion = componentType.majorVersion(); typeRef->minorVersion = componentType.minorVersion(); diff --git a/src/qml/compiler/qqmltypecompiler_p.h b/src/qml/compiler/qqmltypecompiler_p.h index a49b97453f..f588909c42 100644 --- a/src/qml/compiler/qqmltypecompiler_p.h +++ b/src/qml/compiler/qqmltypecompiler_p.h @@ -81,7 +81,7 @@ struct QQmlTypeCompiler public: QQmlTypeCompiler(QQmlEnginePrivate *engine, QQmlTypeData *typeData, QmlIR::Document *document, const QQmlRefPointer &typeNameCache, - QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache, + QV4::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher); // --- interface used by QQmlPropertyCacheCreator @@ -91,10 +91,10 @@ public: QString stringAt(int idx) const; QmlIR::PoolList::Iterator objectFunctionsBegin(const QmlIR::Object *object) const { return object->functionsBegin(); } QmlIR::PoolList::Iterator objectFunctionsEnd(const QmlIR::Object *object) const { return object->functionsEnd(); } - QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypes = nullptr; + QV4::ResolvedTypeReferenceMap *resolvedTypes = nullptr; // --- - QQmlRefPointer compile(); + QQmlRefPointer compile(); QList compilationErrors() const { return errors; } void recordError(QQmlError error); @@ -118,7 +118,6 @@ public: QQmlJS::MemoryPool *memoryPool(); QStringRef newStringRef(const QString &string); const QV4::Compiler::StringTableGenerator *stringPool() const; - void setBindingPropertyDataPerObject(const QVector &propertyData); const QHash &customParserCache() const { return customParsers; } @@ -126,7 +125,7 @@ public: void addImport(const QString &module, const QString &qualifier, int majorVersion, int minorVersion); - QV4::CompiledData::ResolvedTypeReference *resolvedType(int id) const + QV4::ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes->value(id); } @@ -157,12 +156,12 @@ protected: void recordError(const QQmlCompileError &error) { compiler->recordError(error); } - QV4::CompiledData::ResolvedTypeReference *resolvedType(int id) const + QV4::ResolvedTypeReference *resolvedType(int id) const { return compiler->resolvedType(id); } bool containsResolvedType(int id) const { return compiler->resolvedTypes->contains(id); } - QV4::CompiledData::ResolvedTypeReferenceMap::iterator insertResolvedType( - int id, QV4::CompiledData::ResolvedTypeReference *value) + QV4::ResolvedTypeReferenceMap::iterator insertResolvedType( + int id, QV4::ResolvedTypeReference *value) { return compiler->resolvedTypes->insert(id, value); } QQmlTypeCompiler *compiler; diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index edd479a0bd..d17d58588c 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -3783,26 +3783,14 @@ QList Codegen::errors() const return _errors; } -QQmlRefPointer Codegen::generateCompilationUnit(bool generateUnitData) +QV4::CompiledData::CompilationUnit Codegen::generateCompilationUnit( + bool generateUnitData) { - CompiledData::Unit *unitData = nullptr; - if (generateUnitData) - unitData = jsUnitGenerator->generateUnit(); - CompiledData::CompilationUnit *compilationUnit = new CompiledData::CompilationUnit(unitData); - - QQmlRefPointer unit; - unit.adopt(compilationUnit); - return unit; -} - -QQmlRefPointer Codegen::createUnitForLoading() -{ - QQmlRefPointer result; - result.adopt(new CompiledData::CompilationUnit); - return result; + return QV4::CompiledData::CompilationUnit( + generateUnitData ? jsUnitGenerator->generateUnit() : nullptr); } -QQmlRefPointer Codegen::compileModule( +CompiledData::CompilationUnit Codegen::compileModule( bool debugMode, const QString &url, const QString &sourceCode, const QDateTime &sourceTimeStamp, QList *diagnostics) { @@ -3817,7 +3805,7 @@ QQmlRefPointer Codegen::compileModule( *diagnostics = parser.diagnosticMessages(); if (!parsed) - return nullptr; + return CompiledData::CompilationUnit(); QQmlJS::AST::ESModule *moduleNode = QQmlJS::AST::cast(parser.rootNode()); if (!moduleNode) { @@ -3840,7 +3828,7 @@ QQmlRefPointer Codegen::compileModule( *diagnostics << errors; if (!errors.isEmpty()) - return nullptr; + return CompiledData::CompilationUnit(); return cg.generateCompilationUnit(); } diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 962ccc8562..8cf56b6cb7 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -684,9 +684,8 @@ public: Reference referenceForName(const QString &name, bool lhs, const QQmlJS::AST::SourceLocation &accessLocation = QQmlJS::AST::SourceLocation()); - QQmlRefPointer generateCompilationUnit(bool generateUnitData = true); - static QQmlRefPointer createUnitForLoading(); - static QQmlRefPointer compileModule( + QV4::CompiledData::CompilationUnit generateCompilationUnit(bool generateUnitData = true); + static QV4::CompiledData::CompilationUnit compileModule( bool debugMode, const QString &url, const QString &sourceCode, const QDateTime &sourceTimeStamp, QList *diagnostics); diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 6e09eac977..091c29c8c7 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -39,34 +39,12 @@ #include "qv4compileddata_p.h" #include -#ifndef V4_BOOTSTRAP -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "qv4compilationunitmapper_p.h" -#include -#include -#include -#include -#include -#include -#include -#include -#endif #include #include #include #include #include +#include // generated by qmake: #include "qml_compile_hash_p.h" @@ -99,10 +77,6 @@ CompilationUnit::CompilationUnit(const Unit *unitData, const QString &fileName, CompilationUnit::~CompilationUnit() { -#ifndef V4_BOOTSTRAP - unlink(); -#endif - if (data) { if (data->qmlUnit() != qmlData) free(const_cast(qmlData)); @@ -126,582 +100,11 @@ CompilationUnit::~CompilationUnit() delete [] imports; imports = nullptr; } -#ifndef V4_BOOTSTRAP - -QString CompilationUnit::localCacheFilePath(const QUrl &url) -{ - const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url); - const QString cacheFileSuffix = QFileInfo(localSourcePath + QLatin1Char('c')).completeSuffix(); - QCryptographicHash fileNameHash(QCryptographicHash::Sha1); - fileNameHash.addData(localSourcePath.toUtf8()); - QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/"); - QDir::root().mkpath(directory); - return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + cacheFileSuffix; -} - -QV4::Function *CompilationUnit::linkToEngine(ExecutionEngine *engine) -{ - this->engine = engine; - engine->compilationUnits.insert(this); - - Q_ASSERT(!runtimeStrings); - Q_ASSERT(data); - const quint32 stringCount = totalStringCount(); - runtimeStrings = (QV4::Heap::String **)malloc(stringCount * sizeof(QV4::Heap::String*)); - // memset the strings to 0 in case a GC run happens while we're within the loop below - memset(runtimeStrings, 0, stringCount * sizeof(QV4::Heap::String*)); - for (uint i = 0; i < stringCount; ++i) - runtimeStrings[i] = engine->newString(stringAt(i)); - - runtimeRegularExpressions = new QV4::Value[data->regexpTableSize]; - // memset the regexps to 0 in case a GC run happens while we're within the loop below - memset(runtimeRegularExpressions, 0, data->regexpTableSize * sizeof(QV4::Value)); - for (uint i = 0; i < data->regexpTableSize; ++i) { - const CompiledData::RegExp *re = data->regexpAt(i); - uint f = re->flags; - const CompiledData::RegExp::Flags flags = static_cast(f); - runtimeRegularExpressions[i] = QV4::RegExp::create(engine, stringAt(re->stringIndex), flags); - } - - if (data->lookupTableSize) { - runtimeLookups = new QV4::Lookup[data->lookupTableSize]; - memset(runtimeLookups, 0, data->lookupTableSize * sizeof(QV4::Lookup)); - const CompiledData::Lookup *compiledLookups = data->lookupTable(); - for (uint i = 0; i < data->lookupTableSize; ++i) { - QV4::Lookup *l = runtimeLookups + i; - - Lookup::Type type = Lookup::Type(uint(compiledLookups[i].type_and_flags)); - if (type == CompiledData::Lookup::Type_Getter) - l->getter = QV4::Lookup::getterGeneric; - else if (type == CompiledData::Lookup::Type_Setter) - l->setter = QV4::Lookup::setterGeneric; - else if (type == CompiledData::Lookup::Type_GlobalGetter) - l->globalGetter = QV4::Lookup::globalGetterGeneric; - else if (type == CompiledData::Lookup::Type_QmlContextPropertyGetter) - l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter; - l->nameIndex = compiledLookups[i].nameIndex; - } - } - - if (data->jsClassTableSize) { - runtimeClasses = (QV4::Heap::InternalClass **)malloc(data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *)); - // memset the regexps to 0 in case a GC run happens while we're within the loop below - memset(runtimeClasses, 0, data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *)); - for (uint i = 0; i < data->jsClassTableSize; ++i) { - int memberCount = 0; - const CompiledData::JSClassMember *member = data->jsClassAt(i, &memberCount); - runtimeClasses[i] = engine->internalClasses(QV4::ExecutionEngine::Class_Object); - for (int j = 0; j < memberCount; ++j, ++member) - runtimeClasses[i] = runtimeClasses[i]->addMember(engine->identifierTable->asPropertyKey(runtimeStrings[member->nameOffset]), member->isAccessor ? QV4::Attr_Accessor : QV4::Attr_Data); - } - } - - runtimeFunctions.resize(data->functionTableSize); - for (int i = 0 ;i < runtimeFunctions.size(); ++i) { - const QV4::CompiledData::Function *compiledFunction = data->functionAt(i); - runtimeFunctions[i] = QV4::Function::create(engine, this, compiledFunction); - } - - Scope scope(engine); - Scoped ic(scope); - - runtimeBlocks.resize(data->blockTableSize); - for (int i = 0 ;i < runtimeBlocks.size(); ++i) { - const QV4::CompiledData::Block *compiledBlock = data->blockAt(i); - ic = engine->internalClasses(EngineBase::Class_CallContext); - - // first locals - const quint32_le *localsIndices = compiledBlock->localsTable(); - for (quint32 j = 0; j < compiledBlock->nLocals; ++j) - ic = ic->addMember(engine->identifierTable->asPropertyKey(runtimeStrings[localsIndices[j]]), Attr_NotConfigurable); - runtimeBlocks[i] = ic->d(); - } - - static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE"); - if (showCode) { - qDebug() << "=== Constant table"; - Moth::dumpConstantTable(constants, data->constantTableSize); - qDebug() << "=== String table"; - for (uint i = 0, end = totalStringCount(); i < end; ++i) - qDebug() << " " << i << ":" << runtimeStrings[i]->toQString(); - qDebug() << "=== Closure table"; - for (uint i = 0; i < data->functionTableSize; ++i) - qDebug() << " " << i << ":" << runtimeFunctions[i]->name()->toQString(); - qDebug() << "root function at index " << (data->indexOfRootFunction != -1 ? data->indexOfRootFunction : 0); - } - - if (data->indexOfRootFunction != -1) - return runtimeFunctions[data->indexOfRootFunction]; - else - return nullptr; -} - -Heap::Object *CompilationUnit::templateObjectAt(int index) const -{ - Q_ASSERT(index < int(data->templateObjectTableSize)); - if (!templateObjects.size()) - templateObjects.resize(data->templateObjectTableSize); - Heap::Object *o = templateObjects.at(index); - if (o) - return o; - - // create the template object - Scope scope(engine); - const CompiledData::TemplateObject *t = data->templateObjectAt(index); - Scoped a(scope, engine->newArrayObject(t->size)); - Scoped raw(scope, engine->newArrayObject(t->size)); - ScopedValue s(scope); - for (uint i = 0; i < t->size; ++i) { - s = runtimeStrings[t->stringIndexAt(i)]; - a->arraySet(i, s); - s = runtimeStrings[t->rawStringIndexAt(i)]; - raw->arraySet(i, s); - } - - ObjectPrototype::method_freeze(engine->functionCtor(), nullptr, raw, 1); - a->defineReadonlyProperty(QStringLiteral("raw"), raw); - ObjectPrototype::method_freeze(engine->functionCtor(), nullptr, a, 1); - - templateObjects[index] = a->objectValue()->d(); - return templateObjects.at(index); -} - -void CompilationUnit::unlink() -{ - if (engine) - nextCompilationUnit.remove(); - - if (isRegisteredWithEngine) { - Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0)); - if (qmlEngine) - qmlEngine->unregisterInternalCompositeType(this); - QQmlMetaType::unregisterInternalCompositeType(this); - isRegisteredWithEngine = false; - } - - propertyCaches.clear(); - - if (runtimeLookups) { - for (uint i = 0; i < data->lookupTableSize; ++i) { - QV4::Lookup &l = runtimeLookups[i]; - if (l.getter == QV4::QObjectWrapper::lookupGetter) { - if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache) - pc->release(); - } else if (l.getter == QQmlValueTypeWrapper::lookupGetter) { - if (QQmlPropertyCache *pc = l.qgadgetLookup.propertyCache) - pc->release(); - } - - if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty) { - if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache) - pc->release(); - } - } - } - - dependentScripts.clear(); - - typeNameCache = nullptr; - - qDeleteAll(resolvedTypes); - resolvedTypes.clear(); - - engine = nullptr; - qmlEngine = nullptr; - free(runtimeStrings); - runtimeStrings = nullptr; - delete [] runtimeLookups; - runtimeLookups = nullptr; - delete [] runtimeRegularExpressions; - runtimeRegularExpressions = nullptr; - free(runtimeClasses); - runtimeClasses = nullptr; - for (QV4::Function *f : qAsConst(runtimeFunctions)) - f->destroy(); - runtimeFunctions.clear(); -} - -void CompilationUnit::markObjects(QV4::MarkStack *markStack) -{ - if (runtimeStrings) { - for (uint i = 0, end = totalStringCount(); i < end; ++i) - if (runtimeStrings[i]) - runtimeStrings[i]->mark(markStack); - } - if (runtimeRegularExpressions) { - for (uint i = 0; i < data->regexpTableSize; ++i) - runtimeRegularExpressions[i].mark(markStack); - } - if (runtimeClasses) { - for (uint i = 0; i < data->jsClassTableSize; ++i) - if (runtimeClasses[i]) - runtimeClasses[i]->mark(markStack); - } - for (QV4::Function *f : qAsConst(runtimeFunctions)) - if (f && f->internalClass) - f->internalClass->mark(markStack); - for (QV4::Heap::InternalClass *c : qAsConst(runtimeBlocks)) - if (c) - c->mark(markStack); - - for (QV4::Heap::Object *o : qAsConst(templateObjects)) - if (o) - o->mark(markStack); - - if (runtimeLookups) { - for (uint i = 0; i < data->lookupTableSize; ++i) - runtimeLookups[i].markObjects(markStack); - } - - if (m_module) - m_module->mark(markStack); -} - -IdentifierHash CompilationUnit::createNamedObjectsPerComponent(int componentObjectIndex) -{ - IdentifierHash namedObjectCache(engine); - const CompiledData::Object *component = objectAt(componentObjectIndex); - const quint32_le *namedObjectIndexPtr = component->namedObjectsInComponentTable(); - for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) { - const CompiledData::Object *namedObject = objectAt(*namedObjectIndexPtr); - namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id); - } - return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache); -} - -void CompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine) -{ - this->qmlEngine = qmlEngine; - - // Add to type registry of composites - if (propertyCaches.needsVMEMetaObject(/*root object*/0)) { - QQmlMetaType::registerInternalCompositeType(this); - qmlEngine->registerInternalCompositeType(this); - } else { - const QV4::CompiledData::Object *obj = objectAt(/*root object*/0); - auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); - Q_ASSERT(typeRef); - if (typeRef->compilationUnit) { - metaTypeId = typeRef->compilationUnit->metaTypeId; - listMetaTypeId = typeRef->compilationUnit->listMetaTypeId; - } else { - metaTypeId = typeRef->type.typeId(); - listMetaTypeId = typeRef->type.qListTypeId(); - } - } - - // Collect some data for instantiation later. - int bindingCount = 0; - int parserStatusCount = 0; - int objectCount = 0; - for (quint32 i = 0, count = this->objectCount(); i < count; ++i) { - const QV4::CompiledData::Object *obj = objectAt(i); - bindingCount += obj->nBindings; - if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) { - if (typeRef->type.isValid()) { - if (typeRef->type.parserStatusCast() != -1) - ++parserStatusCount; - } - ++objectCount; - if (typeRef->compilationUnit) { - bindingCount += typeRef->compilationUnit->totalBindingsCount; - parserStatusCount += typeRef->compilationUnit->totalParserStatusCount; - objectCount += typeRef->compilationUnit->totalObjectCount; - } - } - } - - totalBindingsCount = bindingCount; - totalParserStatusCount = parserStatusCount; - totalObjectCount = objectCount; -} - -bool CompilationUnit::verifyChecksum(const DependentTypesHasher &dependencyHasher) const -{ - if (!dependencyHasher) { - for (size_t i = 0; i < sizeof(data->dependencyMD5Checksum); ++i) { - if (data->dependencyMD5Checksum[i] != 0) - return false; - } - return true; - } - const QByteArray checksum = dependencyHasher(); - return checksum.size() == sizeof(data->dependencyMD5Checksum) - && memcmp(data->dependencyMD5Checksum, checksum.constData(), - sizeof(data->dependencyMD5Checksum)) == 0; -} - -QStringList CompilationUnit::moduleRequests() const -{ - QStringList requests; - requests.reserve(data->moduleRequestTableSize); - for (uint i = 0; i < data->moduleRequestTableSize; ++i) - requests << stringAt(data->moduleRequestTable()[i]); - return requests; -} - -Heap::Module *CompilationUnit::instantiate(ExecutionEngine *engine) -{ - if (isESModule() && m_module) - return m_module; - - if (data->indexOfRootFunction < 0) - return nullptr; - - if (!this->engine) - linkToEngine(engine); - - Scope scope(engine); - Scoped module(scope, engine->memoryManager->allocate(engine, this)); - - if (isESModule()) - m_module = module->d(); - - for (const QString &request: moduleRequests()) { - auto dependentModuleUnit = engine->loadModule(QUrl(request), this); - if (engine->hasException) - return nullptr; - dependentModuleUnit->instantiate(engine); - } - - ScopedString importName(scope); - - const uint importCount = data->importEntryTableSize; - if (importCount > 0) { - imports = new const Value *[importCount]; - memset(imports, 0, importCount * sizeof(Value *)); - } - for (uint i = 0; i < importCount; ++i) { - const CompiledData::ImportEntry &entry = data->importEntryTable()[i]; - auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this); - importName = runtimeStrings[entry.importName]; - const Value *valuePtr = dependentModuleUnit->resolveExport(importName); - if (!valuePtr) { - QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference "); - referenceErrorMessage += importName->toQString(); - engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column); - return nullptr; - } - imports[i] = valuePtr; - } - - for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) { - const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i]; - auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this); - if (!dependentModuleUnit) - return nullptr; - - ScopedString importName(scope, runtimeStrings[entry.importName]); - if (!dependentModuleUnit->resolveExport(importName)) { - QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference "); - referenceErrorMessage += importName->toQString(); - engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column); - return nullptr; - } - } - - return module->d(); -} - -const Value *CompilationUnit::resolveExport(QV4::String *exportName) -{ - QVector resolveSet; - return resolveExportRecursively(exportName, &resolveSet); -} - -QStringList CompilationUnit::exportedNames() const -{ - QStringList names; - QVector exportNameSet; - getExportedNamesRecursively(&names, &exportNameSet); - names.sort(); - auto last = std::unique(names.begin(), names.end()); - names.erase(last, names.end()); - return names; -} - -const Value *CompilationUnit::resolveExportRecursively(QV4::String *exportName, QVector *resolveSet) -{ - if (!m_module) - return nullptr; - - for (const auto &entry: *resolveSet) - if (entry.module == this && entry.exportName->isEqualTo(exportName)) - return nullptr; - - (*resolveSet) << ResolveSetEntry(this, exportName); - - if (exportName->toQString() == QLatin1String("*")) - return &m_module->self; - - Scope scope(engine); - - if (auto localExport = lookupNameInExportTable(data->localExportEntryTable(), data->localExportEntryTableSize, exportName)) { - ScopedString localName(scope, runtimeStrings[localExport->localName]); - uint index = m_module->scope->internalClass->indexOfValueOrGetter(localName->toPropertyKey()); - if (index == UINT_MAX) - return nullptr; - if (index >= m_module->scope->locals.size) - return imports[index - m_module->scope->locals.size]; - return &m_module->scope->locals[index]; - } - - if (auto indirectExport = lookupNameInExportTable(data->indirectExportEntryTable(), data->indirectExportEntryTableSize, exportName)) { - auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(indirectExport->moduleRequest)), this); - if (!dependentModuleUnit) - return nullptr; - ScopedString importName(scope, runtimeStrings[indirectExport->importName]); - return dependentModuleUnit->resolveExportRecursively(importName, resolveSet); - } - - - if (exportName->toQString() == QLatin1String("default")) - return nullptr; - - const Value *starResolution = nullptr; - - for (uint i = 0; i < data->starExportEntryTableSize; ++i) { - const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i]; - auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this); - if (!dependentModuleUnit) - return nullptr; - - const Value *resolution = dependentModuleUnit->resolveExportRecursively(exportName, resolveSet); - // ### handle ambiguous - if (resolution) { - if (!starResolution) { - starResolution = resolution; - continue; - } - if (resolution != starResolution) - return nullptr; - } - } - - return starResolution; -} - -const ExportEntry *CompilationUnit::lookupNameInExportTable(const ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const -{ - const CompiledData::ExportEntry *lastExportEntry = firstExportEntry + tableSize; - auto matchingExport = std::lower_bound(firstExportEntry, lastExportEntry, name, [this](const CompiledData::ExportEntry &lhs, QV4::String *name) { - return stringAt(lhs.exportName) < name->toQString(); - }); - if (matchingExport == lastExportEntry || stringAt(matchingExport->exportName) != name->toQString()) - return nullptr; - return matchingExport; -} - -void CompilationUnit::getExportedNamesRecursively(QStringList *names, QVector *exportNameSet, bool includeDefaultExport) const -{ - if (exportNameSet->contains(this)) - return; - exportNameSet->append(this); - - const auto append = [names, includeDefaultExport](const QString &name) { - if (!includeDefaultExport && name == QLatin1String("default")) - return; - names->append(name); - }; - - for (uint i = 0; i < data->localExportEntryTableSize; ++i) { - const CompiledData::ExportEntry &entry = data->localExportEntryTable()[i]; - append(stringAt(entry.exportName)); - } - - for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) { - const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i]; - append(stringAt(entry.exportName)); - } - - for (uint i = 0; i < data->starExportEntryTableSize; ++i) { - const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i]; - auto dependentModuleUnit = engine->loadModule(QUrl(stringAt(entry.moduleRequest)), this); - if (!dependentModuleUnit) - return; - dependentModuleUnit->getExportedNamesRecursively(names, exportNameSet, /*includeDefaultExport*/false); - } -} -void CompilationUnit::evaluate() -{ - QV4::Scope scope(engine); - QV4::Scoped module(scope, m_module); - module->evaluate(); -} - -void CompilationUnit::evaluateModuleRequests() -{ - for (const QString &request: moduleRequests()) { - auto dependentModuleUnit = engine->loadModule(QUrl(request), this); - if (engine->hasException) - return; - dependentModuleUnit->evaluate(); - if (engine->hasException) - return; - } -} - -bool CompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString) -{ - if (!QQmlFile::isLocalFile(url)) { - *errorString = QStringLiteral("File has to be a local file."); - return false; - } - - const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url); - QScopedPointer cacheFile(new CompilationUnitMapper()); - - const QStringList cachePaths = { sourcePath + QLatin1Char('c'), localCacheFilePath(url) }; - for (const QString &cachePath : cachePaths) { - CompiledData::Unit *mappedUnit = cacheFile->open(cachePath, sourceTimeStamp, errorString); - if (!mappedUnit) - continue; - - const Unit * const oldDataPtr = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data : nullptr; - const Unit *oldData = data; - auto dataPtrRevert = qScopeGuard([this, oldData](){ - setUnitData(oldData); - }); - setUnitData(mappedUnit); - - if (data->sourceFileIndex != 0 && sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) { - *errorString = QStringLiteral("QML source file has moved to a different location."); - continue; - } - - dataPtrRevert.dismiss(); - free(const_cast(oldDataPtr)); - backingFile.reset(cacheFile.take()); - return true; - } - - return false; -} - -#endif // V4_BOOTSTRAP - -#if defined(V4_BOOTSTRAP) -bool CompilationUnit::saveToDisk(const QString &outputFileName, QString *errorString) -#else -bool CompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString) -#endif +bool CompilationUnit::saveToDisk(const QString &outputFileName, QString *errorString) const { errorString->clear(); -#if !defined(V4_BOOTSTRAP) - if (data->sourceTimeStamp == 0) { - *errorString = QStringLiteral("Missing time stamp for source file"); - return false; - } - - if (!QQmlFile::isLocalFile(unitUrl)) { - *errorString = QStringLiteral("File has to be a local file."); - return false; - } - const QString outputFileName = localCacheFilePath(unitUrl); -#endif - #if QT_CONFIG(temporaryfile) // Foo.qml -> Foo.qmlc QSaveFile cacheFile(outputFileName); @@ -767,51 +170,6 @@ void CompilationUnit::setUnitData(const Unit *unitData, const QmlUnit *qmlUnit, m_finalUrlString = !finalUrlString.isEmpty() ? finalUrlString : stringAt(data->finalUrlIndex); } -#ifndef V4_BOOTSTRAP -QString Binding::valueAsString(const CompilationUnit *unit) const -{ - switch (type) { - case Type_Script: - case Type_String: - return unit->stringAt(stringIndex); - case Type_Null: - return QStringLiteral("null"); - case Type_Boolean: - return value.b ? QStringLiteral("true") : QStringLiteral("false"); - case Type_Number: - return QString::number(valueAsNumber(unit->constants)); - case Type_Invalid: - return QString(); -#if !QT_CONFIG(translation) - case Type_TranslationById: - case Type_Translation: - return unit->stringAt(unit->unitData()->translations()[value.translationDataIndex].stringIndex); -#else - case Type_TranslationById: { - const TranslationData &translation = unit->unitData()->translations()[value.translationDataIndex]; - QByteArray id = unit->stringAt(translation.stringIndex).toUtf8(); - return qtTrId(id.constData(), translation.number); - } - case Type_Translation: { - const TranslationData &translation = unit->unitData()->translations()[value.translationDataIndex]; - // This code must match that in the qsTr() implementation - const QString &path = unit->fileName(); - int lastSlash = path.lastIndexOf(QLatin1Char('/')); - QStringRef context = (lastSlash > -1) ? path.midRef(lastSlash + 1, path.length() - lastSlash - 5) - : QStringRef(); - QByteArray contextUtf8 = context.toUtf8(); - QByteArray comment = unit->stringAt(translation.commentIndex).toUtf8(); - QByteArray text = unit->stringAt(translation.stringIndex).toUtf8(); - return QCoreApplication::translate(contextUtf8.constData(), text.constData(), - comment.constData(), translation.number); - } -#endif - default: - break; - } - return QString(); -} - //reverse of Lexer::singleEscape() QString Binding::escapedString(const QString &string) { @@ -855,98 +213,16 @@ QString Binding::escapedString(const QString &string) return tmp; } -QString Binding::valueAsScriptString(const CompilationUnit *unit) const -{ - if (type == Type_String) - return escapedString(unit->stringAt(stringIndex)); - else - return valueAsString(unit); -} - -/*! -Returns the property cache, if one alread exists. The cache is not referenced. -*/ -QQmlRefPointer ResolvedTypeReference::propertyCache() const -{ - if (type.isValid()) - return typePropertyCache; - else - return compilationUnit->rootPropertyCache(); -} - -/*! -Returns the property cache, creating one if it doesn't already exist. The cache is not referenced. -*/ -QQmlRefPointer ResolvedTypeReference::createPropertyCache(QQmlEngine *engine) -{ - if (typePropertyCache) { - return typePropertyCache; - } else if (type.isValid()) { - typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject(), minorVersion); - return typePropertyCache; - } else { - return compilationUnit->rootPropertyCache(); - } -} - -bool ResolvedTypeReference::addToHash(QCryptographicHash *hash, QQmlEngine *engine) -{ - if (type.isValid()) { - bool ok = false; - hash->addData(createPropertyCache(engine)->checksum(&ok)); - return ok; - } - if (!compilationUnit) - return false; - hash->addData(compilationUnit->unitData()->md5Checksum, sizeof(compilationUnit->unitData()->md5Checksum)); - return true; -} - -template -bool qtTypeInherits(const QMetaObject *mo) { - while (mo) { - if (mo == &T::staticMetaObject) - return true; - mo = mo->superClass(); - } - return false; -} - -void ResolvedTypeReference::doDynamicTypeCheck() -{ - const QMetaObject *mo = nullptr; - if (typePropertyCache) - mo = typePropertyCache->firstCppMetaObject(); - else if (type.isValid()) - mo = type.metaObject(); - else if (compilationUnit) - mo = compilationUnit->rootPropertyCache()->firstCppMetaObject(); - isFullyDynamicType = qtTypeInherits(mo); -} - -bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *engine) const -{ - for (auto it = constBegin(), end = constEnd(); it != end; ++it) { - if (!it.value()->addToHash(hash, engine)) - return false; - } - - return true; -} - -#endif - -void CompilationUnit::destroy() +void CompilationUnit::unlink() { -#if !defined(V4_BOOTSTRAP) - if (qmlEngine) - QQmlEnginePrivate::deleteInEngineThread(qmlEngine, this); - else -#endif - delete this; + free(runtimeStrings); + runtimeStrings = nullptr; + delete [] runtimeRegularExpressions; + runtimeRegularExpressions = nullptr; + free(runtimeClasses); + runtimeClasses = nullptr; } - void Unit::generateChecksum() { #ifndef QT_CRYPTOGRAPHICHASH_ONLY_SHA1 diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 4a90c841bb..9301939bff 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -65,11 +65,6 @@ #include #include #include -#ifndef V4_BOOTSTRAP -#include -#include -#include "private/qintrusivelist_p.h" -#endif QT_BEGIN_NAMESPACE @@ -101,7 +96,6 @@ struct Module; struct Function; class EvalISelFactory; -class CompilationUnitMapper; namespace CompiledData { @@ -528,10 +522,6 @@ struct Q_QML_PRIVATE_EXPORT Binding bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; } bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); } -#ifndef V4_BOOTSTRAP - QString valueAsString(const CompilationUnit *unit) const; - QString valueAsScriptString(const CompilationUnit *unit) const; -#endif double valueAsNumber(const Value *constantTable) const { if (type != Type_Number) @@ -1053,17 +1043,6 @@ struct TypeReferenceMap : QHash } }; -#ifndef V4_BOOTSTRAP -struct ResolvedTypeReference; -// map from name index -// While this could be a hash, a map is chosen here to provide a stable -// order, which is used to calculating a check-sum on dependent meta-objects. -struct ResolvedTypeReferenceMap: public QMap -{ - bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const; -}; -#endif - using DependentTypesHasher = std::function; // index is per-object binding index @@ -1073,6 +1052,30 @@ typedef QVector BindingPropertyData; struct Q_QML_PRIVATE_EXPORT CompilationUnitBase { + Q_DISABLE_COPY(CompilationUnitBase) + + CompilationUnitBase() = default; + ~CompilationUnitBase() = default; + + CompilationUnitBase(CompilationUnitBase &&other) noexcept { *this = std::move(other); } + + CompilationUnitBase &operator=(CompilationUnitBase &&other) noexcept + { + if (this != &other) { + runtimeStrings = other.runtimeStrings; + other.runtimeStrings = nullptr; + constants = other.constants; + other.constants = nullptr; + runtimeRegularExpressions = other.runtimeRegularExpressions; + other.runtimeRegularExpressions = nullptr; + runtimeClasses = other.runtimeClasses; + other.runtimeClasses = nullptr; + imports = other.imports; + other.imports = nullptr; + } + return *this; + } + // pointers either to data->constants() or little-endian memory copy. QV4::Heap::String **runtimeStrings = nullptr; // Array const Value* constants = nullptr; @@ -1088,30 +1091,42 @@ Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeRegularExpressions) == offs Q_STATIC_ASSERT(offsetof(CompilationUnitBase, runtimeClasses) == offsetof(CompilationUnitBase, runtimeRegularExpressions) + sizeof(const Value *)); Q_STATIC_ASSERT(offsetof(CompilationUnitBase, imports) == offsetof(CompilationUnitBase, runtimeClasses) + sizeof(const Value *)); -struct Q_QML_PRIVATE_EXPORT CompilationUnit final : public CompilationUnitBase +struct Q_QML_PRIVATE_EXPORT CompilationUnit : public CompilationUnitBase { + Q_DISABLE_COPY(CompilationUnit) + const Unit *data = nullptr; const QmlUnit *qmlData = nullptr; QStringList dynamicStrings; public: + using CompiledObject = CompiledData::Object; + CompilationUnit(const Unit *unitData = nullptr, const QString &fileName = QString(), const QString &finalUrlString = QString()); ~CompilationUnit(); - void addref() + CompilationUnit(CompilationUnit &&other) noexcept { - Q_ASSERT(refCount.load() > 0); - refCount.ref(); + *this = std::move(other); } - void release() - { - Q_ASSERT(refCount.load() > 0); - if (!refCount.deref()) - destroy(); - } - int count() const + CompilationUnit &operator=(CompilationUnit &&other) noexcept { - return refCount.load(); + if (this != &other) { + data = other.data; + other.data = nullptr; + qmlData = other.qmlData; + other.qmlData = nullptr; + dynamicStrings = std::move(other.dynamicStrings); + other.dynamicStrings.clear(); + m_fileName = std::move(other.m_fileName); + other.m_fileName.clear(); + m_finalUrlString = std::move(other.m_finalUrlString); + other.m_finalUrlString.clear(); + m_module = other.m_module; + other.m_module = nullptr; + CompilationUnitBase::operator=(std::move(other)); + } + return *this; } const Unit *unitData() const { return data; } @@ -1125,185 +1140,24 @@ public: return data->stringAtInternal(index); } -#ifndef V4_BOOTSTRAP - QIntrusiveListNode nextCompilationUnit; - ExecutionEngine *engine = nullptr; - QQmlEnginePrivate *qmlEngine = nullptr; // only used in QML environment for composite types, not in plain QJSEngine case. - - // url() and fileName() shall be used to load the actual QML/JS code or to show errors or - // warnings about that code. They include any potential URL interceptions and thus represent the - // "physical" location of the code. - // - // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code - // They are _not_ intercepted and thus represent the "logical" name for the code. - QString fileName() const { return m_fileName; } QString finalUrlString() const { return m_finalUrlString; } - QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; } - QUrl finalUrl() const - { - if (m_finalUrl.isNull) - m_finalUrl = QUrl(finalUrlString()); - return m_finalUrl; - } - - QV4::Lookup *runtimeLookups = nullptr; - QVector runtimeFunctions; - QVector runtimeBlocks; - mutable QVector templateObjects; - mutable QQmlNullableValue m_url; - mutable QQmlNullableValue m_finalUrl; - - // QML specific fields - QQmlPropertyCacheVector propertyCaches; - QQmlRefPointer rootPropertyCache() const { return propertyCaches.at(/*root object*/0); } - - QQmlRefPointer typeNameCache; - - // index is object index. This allows fast access to the - // property data when initializing bindings, avoiding expensive - // lookups by string (property name). - QVector bindingPropertyDataPerObject; - - // mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects - // this is initialized on-demand by QQmlContextData - QHash namedObjectsPerComponentCache; - inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex); - - void finalizeCompositeType(QQmlEnginePrivate *qmlEngine); - - int totalBindingsCount = 0; // Number of bindings used in this type - int totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses - int totalObjectCount = 0; // Number of objects explicitly instantiated - - QVector> dependentScripts; - ResolvedTypeReferenceMap resolvedTypes; - ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); } - - bool verifyChecksum(const DependentTypesHasher &dependencyHasher) const; - - int metaTypeId = -1; - int listMetaTypeId = -1; - bool isRegisteredWithEngine = false; - QScopedPointer backingFile; + Heap::Module *module() const { return m_module; } + void setModule(Heap::Module *module) { m_module = module; } - // --- interface for QQmlPropertyCacheCreator - typedef Object CompiledObject; - int objectCount() const { return qmlData->nObjects; } - const Object *objectAt(int index) const { return qmlData->objectAt(index); } - int importCount() const { return qmlData->nImports; } - const Import *importAt(int index) const { return qmlData->importAt(index); } - - Heap::Object *templateObjectAt(int index) const; - - struct FunctionIterator - { - FunctionIterator(const Unit *unit, const Object *object, int index) : unit(unit), object(object), index(index) {} - const Unit *unit; - const Object *object; - int index; - - const Function *operator->() const { return unit->functionAt(object->functionOffsetTable()[index]); } - void operator++() { ++index; } - bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; } - bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; } - }; - FunctionIterator objectFunctionsBegin(const Object *object) const { return FunctionIterator(data, object, 0); } - FunctionIterator objectFunctionsEnd(const Object *object) const { return FunctionIterator(data, object, object->nFunctions); } - // --- - - bool isESModule() const { return data->flags & Unit::IsESModule; } - bool isSharedLibrary() const { return data->flags & Unit::IsSharedLibrary; } - QStringList moduleRequests() const; - Heap::Module *instantiate(ExecutionEngine *engine); - const Value *resolveExport(QV4::String *exportName); - QStringList exportedNames() const; - void evaluate(); - void evaluateModuleRequests(); - - QV4::Function *linkToEngine(QV4::ExecutionEngine *engine); void unlink(); - void markObjects(MarkStack *markStack); - - bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString); - - static QString localCacheFilePath(const QUrl &url); - -protected: - quint32 totalStringCount() const - { return data->stringTableSize; } -#endif - private: - void destroy(); - - struct ResolveSetEntry - { - ResolveSetEntry() {} - ResolveSetEntry(CompilationUnit *module, QV4::String *exportName) - : module(module), exportName(exportName) {} - CompilationUnit *module = nullptr; - QV4::String *exportName = nullptr; - }; - - const Value *resolveExportRecursively(QV4::String *exportName, QVector *resolveSet); - const ExportEntry *lookupNameInExportTable(const ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const; - void getExportedNamesRecursively(QStringList *names, QVector *exportNameSet, bool includeDefaultExport = true) const; - QString m_fileName; // initialized from data->sourceFileIndex QString m_finalUrlString; // initialized from data->finalUrlIndex - QAtomicInt refCount = 1; - - Q_NEVER_INLINE IdentifierHash createNamedObjectsPerComponent(int componentObjectIndex); - Heap::Module *m_module = nullptr; public: -#if defined(V4_BOOTSTRAP) - bool saveToDisk(const QString &outputFileName, QString *errorString); -#else - bool saveToDisk(const QUrl &unitUrl, QString *errorString); -#endif -}; - -#ifndef V4_BOOTSTRAP -struct ResolvedTypeReference -{ - ResolvedTypeReference() - : majorVersion(0) - , minorVersion(0) - , isFullyDynamicType(false) - {} - - QQmlType type; - QQmlRefPointer typePropertyCache; - QQmlRefPointer compilationUnit; - - int majorVersion; - int minorVersion; - // Types such as QQmlPropertyMap can add properties dynamically at run-time and - // therefore cannot have a property cache installed when instantiated. - bool isFullyDynamicType; - - QQmlRefPointer propertyCache() const; - QQmlRefPointer createPropertyCache(QQmlEngine *); - bool addToHash(QCryptographicHash *hash, QQmlEngine *engine); - - void doDynamicTypeCheck(); + bool saveToDisk(const QString &outputFileName, QString *errorString) const; }; -IdentifierHash CompilationUnit::namedObjectsPerComponent(int componentObjectIndex) -{ - auto it = namedObjectsPerComponentCache.find(componentObjectIndex); - if (Q_UNLIKELY(it == namedObjectsPerComponentCache.end())) - return createNamedObjectsPerComponent(componentObjectIndex); - return *it; -} -#endif // V4_BOOTSTRAP - } // CompiledData namespace } // QV4 namespace diff --git a/src/qml/compiler/qv4executablecompilationunit.cpp b/src/qml/compiler/qv4executablecompilationunit.cpp new file mode 100644 index 0000000000..432e0c5e37 --- /dev/null +++ b/src/qml/compiler/qv4executablecompilationunit.cpp @@ -0,0 +1,784 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qv4executablecompilationunit_p.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QV4 { + +ExecutableCompilationUnit::ExecutableCompilationUnit() = default; + +ExecutableCompilationUnit::ExecutableCompilationUnit( + CompiledData::CompilationUnit &&compilationUnit) + : CompiledData::CompilationUnit(std::move(compilationUnit)) +{} + +ExecutableCompilationUnit::~ExecutableCompilationUnit() +{ + unlink(); +} + +QString ExecutableCompilationUnit::localCacheFilePath(const QUrl &url) +{ + const QString localSourcePath = QQmlFile::urlToLocalFileOrQrc(url); + const QString cacheFileSuffix = QFileInfo(localSourcePath + QLatin1Char('c')).completeSuffix(); + QCryptographicHash fileNameHash(QCryptographicHash::Sha1); + fileNameHash.addData(localSourcePath.toUtf8()); + QString directory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + QLatin1String("/qmlcache/"); + QDir::root().mkpath(directory); + return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + cacheFileSuffix; +} + +QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine) +{ + this->engine = engine; + engine->compilationUnits.insert(this); + + Q_ASSERT(!runtimeStrings); + Q_ASSERT(data); + const quint32 stringCount = totalStringCount(); + runtimeStrings = (QV4::Heap::String **)malloc(stringCount * sizeof(QV4::Heap::String*)); + // memset the strings to 0 in case a GC run happens while we're within the loop below + memset(runtimeStrings, 0, stringCount * sizeof(QV4::Heap::String*)); + for (uint i = 0; i < stringCount; ++i) + runtimeStrings[i] = engine->newString(stringAt(i)); + + runtimeRegularExpressions + = new QV4::Value[data->regexpTableSize]; + // memset the regexps to 0 in case a GC run happens while we're within the loop below + memset(runtimeRegularExpressions, 0, + data->regexpTableSize * sizeof(QV4::Value)); + for (uint i = 0; i < data->regexpTableSize; ++i) { + const CompiledData::RegExp *re = data->regexpAt(i); + uint f = re->flags; + const CompiledData::RegExp::Flags flags = static_cast(f); + runtimeRegularExpressions[i] = QV4::RegExp::create( + engine, stringAt(re->stringIndex), flags); + } + + if (data->lookupTableSize) { + runtimeLookups = new QV4::Lookup[data->lookupTableSize]; + memset(runtimeLookups, 0, data->lookupTableSize * sizeof(QV4::Lookup)); + const CompiledData::Lookup *compiledLookups = data->lookupTable(); + for (uint i = 0; i < data->lookupTableSize; ++i) { + QV4::Lookup *l = runtimeLookups + i; + + CompiledData::Lookup::Type type + = CompiledData::Lookup::Type(uint(compiledLookups[i].type_and_flags)); + if (type == CompiledData::Lookup::Type_Getter) + l->getter = QV4::Lookup::getterGeneric; + else if (type == CompiledData::Lookup::Type_Setter) + l->setter = QV4::Lookup::setterGeneric; + else if (type == CompiledData::Lookup::Type_GlobalGetter) + l->globalGetter = QV4::Lookup::globalGetterGeneric; + else if (type == CompiledData::Lookup::Type_QmlContextPropertyGetter) + l->qmlContextPropertyGetter = QQmlContextWrapper::resolveQmlContextPropertyLookupGetter; + l->nameIndex = compiledLookups[i].nameIndex; + } + } + + if (data->jsClassTableSize) { + runtimeClasses + = (QV4::Heap::InternalClass **)malloc(data->jsClassTableSize + * sizeof(QV4::Heap::InternalClass *)); + // memset the regexps to 0 in case a GC run happens while we're within the loop below + memset(runtimeClasses, 0, + data->jsClassTableSize * sizeof(QV4::Heap::InternalClass *)); + for (uint i = 0; i < data->jsClassTableSize; ++i) { + int memberCount = 0; + const CompiledData::JSClassMember *member + = data->jsClassAt(i, &memberCount); + runtimeClasses[i] + = engine->internalClasses(QV4::ExecutionEngine::Class_Object); + for (int j = 0; j < memberCount; ++j, ++member) + runtimeClasses[i] + = runtimeClasses[i]->addMember( + engine->identifierTable->asPropertyKey( + runtimeStrings[member->nameOffset]), + member->isAccessor + ? QV4::Attr_Accessor + : QV4::Attr_Data); + } + } + + runtimeFunctions.resize(data->functionTableSize); + for (int i = 0 ;i < runtimeFunctions.size(); ++i) { + const QV4::CompiledData::Function *compiledFunction = data->functionAt(i); + runtimeFunctions[i] = QV4::Function::create(engine, this, compiledFunction); + } + + Scope scope(engine); + Scoped ic(scope); + + runtimeBlocks.resize(data->blockTableSize); + for (int i = 0 ;i < runtimeBlocks.size(); ++i) { + const QV4::CompiledData::Block *compiledBlock = data->blockAt(i); + ic = engine->internalClasses(EngineBase::Class_CallContext); + + // first locals + const quint32_le *localsIndices = compiledBlock->localsTable(); + for (quint32 j = 0; j < compiledBlock->nLocals; ++j) + ic = ic->addMember( + engine->identifierTable->asPropertyKey(runtimeStrings[localsIndices[j]]), + Attr_NotConfigurable); + runtimeBlocks[i] = ic->d(); + } + + static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE"); + if (showCode) { + qDebug() << "=== Constant table"; + Moth::dumpConstantTable(constants, data->constantTableSize); + qDebug() << "=== String table"; + for (uint i = 0, end = totalStringCount(); i < end; ++i) + qDebug() << " " << i << ":" << runtimeStrings[i]->toQString(); + qDebug() << "=== Closure table"; + for (uint i = 0; i < data->functionTableSize; ++i) + qDebug() << " " << i << ":" << runtimeFunctions[i]->name()->toQString(); + qDebug() << "root function at index " + << (data->indexOfRootFunction != -1 + ? data->indexOfRootFunction : 0); + } + + if (data->indexOfRootFunction != -1) + return runtimeFunctions[data->indexOfRootFunction]; + else + return nullptr; +} + +Heap::Object *ExecutableCompilationUnit::templateObjectAt(int index) const +{ + Q_ASSERT(index < int(data->templateObjectTableSize)); + if (!templateObjects.size()) + templateObjects.resize(data->templateObjectTableSize); + Heap::Object *o = templateObjects.at(index); + if (o) + return o; + + // create the template object + Scope scope(engine); + const CompiledData::TemplateObject *t = data->templateObjectAt(index); + Scoped a(scope, engine->newArrayObject(t->size)); + Scoped raw(scope, engine->newArrayObject(t->size)); + ScopedValue s(scope); + for (uint i = 0; i < t->size; ++i) { + s = runtimeStrings[t->stringIndexAt(i)]; + a->arraySet(i, s); + s = runtimeStrings[t->rawStringIndexAt(i)]; + raw->arraySet(i, s); + } + + ObjectPrototype::method_freeze(engine->functionCtor(), nullptr, raw, 1); + a->defineReadonlyProperty(QStringLiteral("raw"), raw); + ObjectPrototype::method_freeze(engine->functionCtor(), nullptr, a, 1); + + templateObjects[index] = a->objectValue()->d(); + return templateObjects.at(index); +} + +void ExecutableCompilationUnit::unlink() +{ + if (engine) + nextCompilationUnit.remove(); + + if (isRegisteredWithEngine) { + Q_ASSERT(data && propertyCaches.count() > 0 && propertyCaches.at(/*root object*/0)); + if (qmlEngine) + qmlEngine->unregisterInternalCompositeType(this); + QQmlMetaType::unregisterInternalCompositeType(this); + isRegisteredWithEngine = false; + } + + propertyCaches.clear(); + + if (runtimeLookups) { + for (uint i = 0; i < data->lookupTableSize; ++i) { + QV4::Lookup &l = runtimeLookups[i]; + if (l.getter == QV4::QObjectWrapper::lookupGetter) { + if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache) + pc->release(); + } else if (l.getter == QQmlValueTypeWrapper::lookupGetter) { + if (QQmlPropertyCache *pc = l.qgadgetLookup.propertyCache) + pc->release(); + } + + if (l.qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty) { + if (QQmlPropertyCache *pc = l.qobjectLookup.propertyCache) + pc->release(); + } + } + } + + dependentScripts.clear(); + + typeNameCache = nullptr; + + qDeleteAll(resolvedTypes); + resolvedTypes.clear(); + + engine = nullptr; + qmlEngine = nullptr; + + delete [] runtimeLookups; + runtimeLookups = nullptr; + + for (QV4::Function *f : qAsConst(runtimeFunctions)) + f->destroy(); + runtimeFunctions.clear(); + + CompiledData::CompilationUnit::unlink(); +} + +void ExecutableCompilationUnit::markObjects(QV4::MarkStack *markStack) +{ + if (runtimeStrings) { + for (uint i = 0, end = totalStringCount(); i < end; ++i) + if (runtimeStrings[i]) + runtimeStrings[i]->mark(markStack); + } + if (runtimeRegularExpressions) { + for (uint i = 0; i < data->regexpTableSize; ++i) + runtimeRegularExpressions[i].mark(markStack); + } + if (runtimeClasses) { + for (uint i = 0; i < data->jsClassTableSize; ++i) + if (runtimeClasses[i]) + runtimeClasses[i]->mark(markStack); + } + for (QV4::Function *f : qAsConst(runtimeFunctions)) + if (f && f->internalClass) + f->internalClass->mark(markStack); + for (QV4::Heap::InternalClass *c : qAsConst(runtimeBlocks)) + if (c) + c->mark(markStack); + + for (QV4::Heap::Object *o : qAsConst(templateObjects)) + if (o) + o->mark(markStack); + + if (runtimeLookups) { + for (uint i = 0; i < data->lookupTableSize; ++i) + runtimeLookups[i].markObjects(markStack); + } + + if (auto mod = module()) + mod->mark(markStack); +} + +IdentifierHash ExecutableCompilationUnit::createNamedObjectsPerComponent(int componentObjectIndex) +{ + IdentifierHash namedObjectCache(engine); + const CompiledData::Object *component = objectAt(componentObjectIndex); + const quint32_le *namedObjectIndexPtr = component->namedObjectsInComponentTable(); + for (quint32 i = 0; i < component->nNamedObjectsInComponent; ++i, ++namedObjectIndexPtr) { + const CompiledData::Object *namedObject = objectAt(*namedObjectIndexPtr); + namedObjectCache.add(runtimeStrings[namedObject->idNameIndex], namedObject->id); + } + return *namedObjectsPerComponentCache.insert(componentObjectIndex, namedObjectCache); +} + +void ExecutableCompilationUnit::finalizeCompositeType(QQmlEnginePrivate *qmlEngine) +{ + this->qmlEngine = qmlEngine; + + // Add to type registry of composites + if (propertyCaches.needsVMEMetaObject(/*root object*/0)) { + QQmlMetaType::registerInternalCompositeType(this); + qmlEngine->registerInternalCompositeType(this); + } else { + const QV4::CompiledData::Object *obj = objectAt(/*root object*/0); + auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex); + Q_ASSERT(typeRef); + if (typeRef->compilationUnit) { + metaTypeId = typeRef->compilationUnit->metaTypeId; + listMetaTypeId = typeRef->compilationUnit->listMetaTypeId; + } else { + metaTypeId = typeRef->type.typeId(); + listMetaTypeId = typeRef->type.qListTypeId(); + } + } + + // Collect some data for instantiation later. + int bindingCount = 0; + int parserStatusCount = 0; + int objectCount = 0; + for (quint32 i = 0, count = this->objectCount(); i < count; ++i) { + const QV4::CompiledData::Object *obj = objectAt(i); + bindingCount += obj->nBindings; + if (auto *typeRef = resolvedTypes.value(obj->inheritedTypeNameIndex)) { + if (typeRef->type.isValid()) { + if (typeRef->type.parserStatusCast() != -1) + ++parserStatusCount; + } + ++objectCount; + if (typeRef->compilationUnit) { + bindingCount += typeRef->compilationUnit->totalBindingsCount; + parserStatusCount += typeRef->compilationUnit->totalParserStatusCount; + objectCount += typeRef->compilationUnit->totalObjectCount; + } + } + } + + totalBindingsCount = bindingCount; + totalParserStatusCount = parserStatusCount; + totalObjectCount = objectCount; +} + +bool ExecutableCompilationUnit::verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const +{ + if (!dependencyHasher) { + for (size_t i = 0; i < sizeof(data->dependencyMD5Checksum); ++i) { + if (data->dependencyMD5Checksum[i] != 0) + return false; + } + return true; + } + const QByteArray checksum = dependencyHasher(); + return checksum.size() == sizeof(data->dependencyMD5Checksum) + && memcmp(data->dependencyMD5Checksum, checksum.constData(), + sizeof(data->dependencyMD5Checksum)) == 0; +} + +QStringList ExecutableCompilationUnit::moduleRequests() const +{ + QStringList requests; + requests.reserve(data->moduleRequestTableSize); + for (uint i = 0; i < data->moduleRequestTableSize; ++i) + requests << stringAt(data->moduleRequestTable()[i]); + return requests; +} + +Heap::Module *ExecutableCompilationUnit::instantiate(ExecutionEngine *engine) +{ + if (isESModule() && module()) + return module(); + + if (data->indexOfRootFunction < 0) + return nullptr; + + if (!this->engine) + linkToEngine(engine); + + Scope scope(engine); + Scoped module(scope, engine->memoryManager->allocate(engine, this)); + + if (isESModule()) + setModule(module->d()); + + for (const QString &request: moduleRequests()) { + auto dependentModuleUnit = engine->loadModule(QUrl(request), this); + if (engine->hasException) + return nullptr; + dependentModuleUnit->instantiate(engine); + } + + ScopedString importName(scope); + + const uint importCount = data->importEntryTableSize; + if (importCount > 0) { + imports = new const Value *[importCount]; + memset(imports, 0, importCount * sizeof(Value *)); + } + for (uint i = 0; i < importCount; ++i) { + const CompiledData::ImportEntry &entry = data->importEntryTable()[i]; + auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this); + importName = runtimeStrings[entry.importName]; + const Value *valuePtr = dependentModuleUnit->resolveExport(importName); + if (!valuePtr) { + QString referenceErrorMessage = QStringLiteral("Unable to resolve import reference "); + referenceErrorMessage += importName->toQString(); + engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column); + return nullptr; + } + imports[i] = valuePtr; + } + + for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) { + const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i]; + auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this); + if (!dependentModuleUnit) + return nullptr; + + ScopedString importName(scope, runtimeStrings[entry.importName]); + if (!dependentModuleUnit->resolveExport(importName)) { + QString referenceErrorMessage = QStringLiteral("Unable to resolve re-export reference "); + referenceErrorMessage += importName->toQString(); + engine->throwReferenceError(referenceErrorMessage, fileName(), entry.location.line, entry.location.column); + return nullptr; + } + } + + return module->d(); +} + +const Value *ExecutableCompilationUnit::resolveExportRecursively( + QV4::String *exportName, QVector *resolveSet) +{ + if (!module()) + return nullptr; + + for (const auto &entry: *resolveSet) + if (entry.module == this && entry.exportName->isEqualTo(exportName)) + return nullptr; + + (*resolveSet) << ResolveSetEntry(this, exportName); + + if (exportName->toQString() == QLatin1String("*")) + return &module()->self; + + Scope scope(engine); + + if (auto localExport = lookupNameInExportTable( + data->localExportEntryTable(), data->localExportEntryTableSize, exportName)) { + ScopedString localName(scope, runtimeStrings[localExport->localName]); + uint index = module()->scope->internalClass->indexOfValueOrGetter(localName->toPropertyKey()); + if (index == UINT_MAX) + return nullptr; + if (index >= module()->scope->locals.size) + return imports[index - module()->scope->locals.size]; + return &module()->scope->locals[index]; + } + + if (auto indirectExport = lookupNameInExportTable( + data->indirectExportEntryTable(), data->indirectExportEntryTableSize, exportName)) { + auto dependentModuleUnit = engine->loadModule(urlAt(indirectExport->moduleRequest), this); + if (!dependentModuleUnit) + return nullptr; + ScopedString importName(scope, runtimeStrings[indirectExport->importName]); + return dependentModuleUnit->resolveExportRecursively(importName, resolveSet); + } + + + if (exportName->toQString() == QLatin1String("default")) + return nullptr; + + const Value *starResolution = nullptr; + + for (uint i = 0; i < data->starExportEntryTableSize; ++i) { + const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i]; + auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this); + if (!dependentModuleUnit) + return nullptr; + + const Value *resolution = dependentModuleUnit->resolveExportRecursively(exportName, resolveSet); + // ### handle ambiguous + if (resolution) { + if (!starResolution) { + starResolution = resolution; + continue; + } + if (resolution != starResolution) + return nullptr; + } + } + + return starResolution; +} + +const CompiledData::ExportEntry *ExecutableCompilationUnit::lookupNameInExportTable( + const CompiledData::ExportEntry *firstExportEntry, int tableSize, QV4::String *name) const +{ + const CompiledData::ExportEntry *lastExportEntry = firstExportEntry + tableSize; + auto matchingExport = std::lower_bound(firstExportEntry, lastExportEntry, name, [this](const CompiledData::ExportEntry &lhs, QV4::String *name) { + return stringAt(lhs.exportName) < name->toQString(); + }); + if (matchingExport == lastExportEntry || stringAt(matchingExport->exportName) != name->toQString()) + return nullptr; + return matchingExport; +} + +void ExecutableCompilationUnit::getExportedNamesRecursively( + QStringList *names, QVector *exportNameSet, + bool includeDefaultExport) const +{ + if (exportNameSet->contains(this)) + return; + exportNameSet->append(this); + + const auto append = [names, includeDefaultExport](const QString &name) { + if (!includeDefaultExport && name == QLatin1String("default")) + return; + names->append(name); + }; + + for (uint i = 0; i < data->localExportEntryTableSize; ++i) { + const CompiledData::ExportEntry &entry = data->localExportEntryTable()[i]; + append(stringAt(entry.exportName)); + } + + for (uint i = 0; i < data->indirectExportEntryTableSize; ++i) { + const CompiledData::ExportEntry &entry = data->indirectExportEntryTable()[i]; + append(stringAt(entry.exportName)); + } + + for (uint i = 0; i < data->starExportEntryTableSize; ++i) { + const CompiledData::ExportEntry &entry = data->starExportEntryTable()[i]; + auto dependentModuleUnit = engine->loadModule(urlAt(entry.moduleRequest), this); + if (!dependentModuleUnit) + return; + dependentModuleUnit->getExportedNamesRecursively(names, exportNameSet, /*includeDefaultExport*/false); + } +} + +void ExecutableCompilationUnit::evaluate() +{ + QV4::Scope scope(engine); + QV4::Scoped mod(scope, module()); + mod->evaluate(); +} + +void ExecutableCompilationUnit::evaluateModuleRequests() +{ + for (const QString &request: moduleRequests()) { + auto dependentModuleUnit = engine->loadModule(QUrl(request), this); + if (engine->hasException) + return; + dependentModuleUnit->evaluate(); + if (engine->hasException) + return; + } +} + +bool ExecutableCompilationUnit::loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString) +{ + if (!QQmlFile::isLocalFile(url)) { + *errorString = QStringLiteral("File has to be a local file."); + return false; + } + + const QString sourcePath = QQmlFile::urlToLocalFileOrQrc(url); + QScopedPointer cacheFile(new CompilationUnitMapper()); + + const QStringList cachePaths = { sourcePath + QLatin1Char('c'), localCacheFilePath(url) }; + for (const QString &cachePath : cachePaths) { + CompiledData::Unit *mappedUnit = cacheFile->open(cachePath, sourceTimeStamp, errorString); + if (!mappedUnit) + continue; + + const CompiledData::Unit * const oldDataPtr + = (data && !(data->flags & QV4::CompiledData::Unit::StaticData)) ? data + : nullptr; + const CompiledData::Unit *oldData = data; + auto dataPtrRevert = qScopeGuard([this, oldData](){ + setUnitData(oldData); + }); + setUnitData(mappedUnit); + + if (data->sourceFileIndex != 0 + && sourcePath != QQmlFile::urlToLocalFileOrQrc(stringAt(data->sourceFileIndex))) { + *errorString = QStringLiteral("QML source file has moved to a different location."); + continue; + } + + dataPtrRevert.dismiss(); + free(const_cast(oldDataPtr)); + backingFile.reset(cacheFile.take()); + return true; + } + + return false; +} + +bool ExecutableCompilationUnit::saveToDisk(const QUrl &unitUrl, QString *errorString) +{ + if (data->sourceTimeStamp == 0) { + *errorString = QStringLiteral("Missing time stamp for source file"); + return false; + } + + if (!QQmlFile::isLocalFile(unitUrl)) { + *errorString = QStringLiteral("File has to be a local file."); + return false; + } + + return CompilationUnit::saveToDisk(localCacheFilePath(unitUrl), errorString); +} + +/*! +Returns the property cache, if one alread exists. The cache is not referenced. +*/ +QQmlRefPointer ResolvedTypeReference::propertyCache() const +{ + if (type.isValid()) + return typePropertyCache; + else + return compilationUnit->rootPropertyCache(); +} + +/*! +Returns the property cache, creating one if it doesn't already exist. The cache is not referenced. +*/ +QQmlRefPointer ResolvedTypeReference::createPropertyCache(QQmlEngine *engine) +{ + if (typePropertyCache) { + return typePropertyCache; + } else if (type.isValid()) { + typePropertyCache = QQmlEnginePrivate::get(engine)->cache(type.metaObject(), minorVersion); + return typePropertyCache; + } else { + return compilationUnit->rootPropertyCache(); + } +} + +bool ResolvedTypeReference::addToHash(QCryptographicHash *hash, QQmlEngine *engine) +{ + if (type.isValid()) { + bool ok = false; + hash->addData(createPropertyCache(engine)->checksum(&ok)); + return ok; + } + if (!compilationUnit) + return false; + hash->addData(compilationUnit->data->md5Checksum, + sizeof(compilationUnit->data->md5Checksum)); + return true; +} + +template +bool qtTypeInherits(const QMetaObject *mo) { + while (mo) { + if (mo == &T::staticMetaObject) + return true; + mo = mo->superClass(); + } + return false; +} + +void ResolvedTypeReference::doDynamicTypeCheck() +{ + const QMetaObject *mo = nullptr; + if (typePropertyCache) + mo = typePropertyCache->firstCppMetaObject(); + else if (type.isValid()) + mo = type.metaObject(); + else if (compilationUnit) + mo = compilationUnit->rootPropertyCache()->firstCppMetaObject(); + isFullyDynamicType = qtTypeInherits(mo); +} + +bool ResolvedTypeReferenceMap::addToHash(QCryptographicHash *hash, QQmlEngine *engine) const +{ + for (auto it = constBegin(), end = constEnd(); it != end; ++it) { + if (!it.value()->addToHash(hash, engine)) + return false; + } + + return true; +} + +QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Binding *binding) const +{ + using namespace CompiledData; + switch (binding->type) { + case Binding::Type_Script: + case Binding::Type_String: + return stringAt(binding->stringIndex); + case Binding::Type_Null: + return QStringLiteral("null"); + case Binding::Type_Boolean: + return binding->value.b ? QStringLiteral("true") : QStringLiteral("false"); + case Binding::Type_Number: + return QString::number(binding->valueAsNumber(constants)); + case Binding::Type_Invalid: + return QString(); +#if !QT_CONFIG(translation) + case Binding::Type_TranslationById: + case Binding::Type_Translation: + return unit->stringAt( + unit->data->translations()[binding->value.translationDataIndex].stringIndex); +#else + case Binding::Type_TranslationById: { + const TranslationData &translation + = data->translations()[binding->value.translationDataIndex]; + QByteArray id = stringAt(translation.stringIndex).toUtf8(); + return qtTrId(id.constData(), translation.number); + } + case Binding::Type_Translation: { + const TranslationData &translation + = data->translations()[binding->value.translationDataIndex]; + // This code must match that in the qsTr() implementation + const QString &path = fileName(); + int lastSlash = path.lastIndexOf(QLatin1Char('/')); + QStringRef context = (lastSlash > -1) ? path.midRef(lastSlash + 1, path.length() - lastSlash - 5) + : QStringRef(); + QByteArray contextUtf8 = context.toUtf8(); + QByteArray comment = stringAt(translation.commentIndex).toUtf8(); + QByteArray text = stringAt(translation.stringIndex).toUtf8(); + return QCoreApplication::translate(contextUtf8.constData(), text.constData(), + comment.constData(), translation.number); + } +#endif + default: + break; + } + return QString(); +} + +QString ExecutableCompilationUnit::bindingValueAsScriptString( + const CompiledData::Binding *binding) const +{ + return (binding->type == CompiledData::Binding::Type_String) + ? CompiledData::Binding::escapedString(stringAt(binding->stringIndex)) + : bindingValueAsString(binding); +} + +} // namespace QV4 + +QT_END_NAMESPACE diff --git a/src/qml/compiler/qv4executablecompilationunit_p.h b/src/qml/compiler/qv4executablecompilationunit_p.h new file mode 100644 index 0000000000..dd3918cc84 --- /dev/null +++ b/src/qml/compiler/qv4executablecompilationunit_p.h @@ -0,0 +1,318 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the tools applications of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QV4EXECUTABLECOMPILATIONUNIT_P_H +#define QV4EXECUTABLECOMPILATIONUNIT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQmlEnginePrivate; +namespace QV4 { + +class CompilationUnitMapper; +struct ResolvedTypeReference; +// map from name index +// While this could be a hash, a map is chosen here to provide a stable +// order, which is used to calculating a check-sum on dependent meta-objects. +struct ResolvedTypeReferenceMap: public QMap +{ + bool addToHash(QCryptographicHash *hash, QQmlEngine *engine) const; +}; + +class Q_QML_PRIVATE_EXPORT ExecutableCompilationUnit final: public CompiledData::CompilationUnit, + public QQmlRefCount +{ + Q_DISABLE_COPY_MOVE(ExecutableCompilationUnit) +public: + friend class QQmlRefPointer; + + static QQmlRefPointer create( + CompiledData::CompilationUnit &&compilationUnit) + { + return QQmlRefPointer( + new ExecutableCompilationUnit(std::move(compilationUnit)), + QQmlRefPointer::Adopt); + } + + static QQmlRefPointer create() + { + return QQmlRefPointer( + new ExecutableCompilationUnit, + QQmlRefPointer::Adopt); + } + + QIntrusiveListNode nextCompilationUnit; + ExecutionEngine *engine = nullptr; + QQmlEnginePrivate *qmlEngine = nullptr; // only used in QML environment for composite types, not in plain QJSEngine case. + + // url() and fileName() shall be used to load the actual QML/JS code or to show errors or + // warnings about that code. They include any potential URL interceptions and thus represent the + // "physical" location of the code. + // + // finalUrl() and finalUrlString() shall be used to resolve further URLs referred to in the code + // They are _not_ intercepted and thus represent the "logical" name for the code. + + QUrl url() const { if (m_url.isNull) m_url = QUrl(fileName()); return m_url; } + QUrl finalUrl() const + { + if (m_finalUrl.isNull) + m_finalUrl = QUrl(finalUrlString()); + return m_finalUrl; + } + + QV4::Lookup *runtimeLookups = nullptr; + QVector runtimeFunctions; + QVector runtimeBlocks; + mutable QVector templateObjects; + mutable QQmlNullableValue m_url; + mutable QQmlNullableValue m_finalUrl; + + // QML specific fields + QQmlPropertyCacheVector propertyCaches; + QQmlRefPointer rootPropertyCache() const { return propertyCaches.at(/*root object*/0); } + + QQmlRefPointer typeNameCache; + + // index is object index. This allows fast access to the + // property data when initializing bindings, avoiding expensive + // lookups by string (property name). + QVector bindingPropertyDataPerObject; + + // mapping from component object index (CompiledData::Unit object index that points to component) to identifier hash of named objects + // this is initialized on-demand by QQmlContextData + QHash namedObjectsPerComponentCache; + inline IdentifierHash namedObjectsPerComponent(int componentObjectIndex); + + void finalizeCompositeType(QQmlEnginePrivate *qmlEngine); + + int totalBindingsCount = 0; // Number of bindings used in this type + int totalParserStatusCount = 0; // Number of instantiated types that are QQmlParserStatus subclasses + int totalObjectCount = 0; // Number of objects explicitly instantiated + + QVector> dependentScripts; + ResolvedTypeReferenceMap resolvedTypes; + ResolvedTypeReference *resolvedType(int id) const { return resolvedTypes.value(id); } + + bool verifyChecksum(const CompiledData::DependentTypesHasher &dependencyHasher) const; + + int metaTypeId = -1; + int listMetaTypeId = -1; + bool isRegisteredWithEngine = false; + + QScopedPointer backingFile; + + // --- interface for QQmlPropertyCacheCreator + using CompiledObject = CompiledData::Object; + using CompiledFunction = CompiledData::Function; + + int objectCount() const { return qmlData->nObjects; } + const CompiledObject *objectAt(int index) const + { + return qmlData->objectAt(index); + } + + int importCount() const { return qmlData->nImports; } + const CompiledData::Import *importAt(int index) const + { + return qmlData->importAt(index); + } + + Heap::Object *templateObjectAt(int index) const; + + struct FunctionIterator + { + FunctionIterator(const CompiledData::Unit *unit, const CompiledObject *object, int index) + : unit(unit), object(object), index(index) {} + const CompiledData::Unit *unit; + const CompiledObject *object; + int index; + + const CompiledFunction *operator->() const + { + return unit->functionAt(object->functionOffsetTable()[index]); + } + + void operator++() { ++index; } + bool operator==(const FunctionIterator &rhs) const { return index == rhs.index; } + bool operator!=(const FunctionIterator &rhs) const { return index != rhs.index; } + }; + + FunctionIterator objectFunctionsBegin(const CompiledObject *object) const + { + return FunctionIterator(data, object, 0); + } + + FunctionIterator objectFunctionsEnd(const CompiledObject *object) const + { + return FunctionIterator(data, object, object->nFunctions); + } + + bool isESModule() const + { + return data->flags & CompiledData::Unit::IsESModule; + } + + bool isSharedLibrary() const + { + return data->flags & CompiledData::Unit::IsSharedLibrary; + } + + QStringList moduleRequests() const; + Heap::Module *instantiate(ExecutionEngine *engine); + const Value *resolveExport(QV4::String *exportName) + { + QVector resolveSet; + return resolveExportRecursively(exportName, &resolveSet); + } + + QStringList exportedNames() const + { + QStringList names; + QVector exportNameSet; + getExportedNamesRecursively(&names, &exportNameSet); + names.sort(); + auto last = std::unique(names.begin(), names.end()); + names.erase(last, names.end()); + return names; + } + + void evaluate(); + void evaluateModuleRequests(); + + QV4::Function *linkToEngine(QV4::ExecutionEngine *engine); + void unlink(); + + void markObjects(MarkStack *markStack); + + bool loadFromDisk(const QUrl &url, const QDateTime &sourceTimeStamp, QString *errorString); + + static QString localCacheFilePath(const QUrl &url); + bool saveToDisk(const QUrl &unitUrl, QString *errorString); + + QString bindingValueAsString(const CompiledData::Binding *binding) const; + QString bindingValueAsScriptString(const CompiledData::Binding *binding) const; + +protected: + quint32 totalStringCount() const + { return data->stringTableSize; } + +private: + struct ResolveSetEntry + { + ResolveSetEntry() {} + ResolveSetEntry(ExecutableCompilationUnit *module, QV4::String *exportName) + : module(module), exportName(exportName) {} + ExecutableCompilationUnit *module = nullptr; + QV4::String *exportName = nullptr; + }; + + ExecutableCompilationUnit(); + ExecutableCompilationUnit(CompiledData::CompilationUnit &&compilationUnit); + ~ExecutableCompilationUnit(); + + const Value *resolveExportRecursively(QV4::String *exportName, + QVector *resolveSet); + + QUrl urlAt(int index) const { return QUrl(stringAt(index)); } + + Q_NEVER_INLINE IdentifierHash createNamedObjectsPerComponent(int componentObjectIndex); + const CompiledData::ExportEntry *lookupNameInExportTable( + const CompiledData::ExportEntry *firstExportEntry, int tableSize, + QV4::String *name) const; + + void getExportedNamesRecursively( + QStringList *names, QVector *exportNameSet, + bool includeDefaultExport = true) const; +}; + +struct ResolvedTypeReference +{ + ResolvedTypeReference() + : majorVersion(0) + , minorVersion(0) + , isFullyDynamicType(false) + {} + + QQmlType type; + QQmlRefPointer typePropertyCache; + QQmlRefPointer compilationUnit; + + int majorVersion; + int minorVersion; + // Types such as QQmlPropertyMap can add properties dynamically at run-time and + // therefore cannot have a property cache installed when instantiated. + bool isFullyDynamicType; + + QQmlRefPointer propertyCache() const; + QQmlRefPointer createPropertyCache(QQmlEngine *); + bool addToHash(QCryptographicHash *hash, QQmlEngine *engine); + + void doDynamicTypeCheck(); +}; + +IdentifierHash ExecutableCompilationUnit::namedObjectsPerComponent(int componentObjectIndex) +{ + auto it = namedObjectsPerComponentCache.find(componentObjectIndex); + if (Q_UNLIKELY(it == namedObjectsPerComponentCache.end())) + return createNamedObjectsPerComponent(componentObjectIndex); + return *it; +} + +} // namespace QV4 + +QT_END_NAMESPACE + +#endif // QV4EXECUTABLECOMPILATIONUNIT_P_H diff --git a/src/qml/debugger/qqmlprofiler_p.h b/src/qml/debugger/qqmlprofiler_p.h index d01e2bc429..d3eedab1c6 100644 --- a/src/qml/debugger/qqmlprofiler_p.h +++ b/src/qml/debugger/qqmlprofiler_p.h @@ -171,10 +171,11 @@ public: : Location(ref->sourceLocation()), locationType(Binding), sent(false) { function = ref; - function->compilationUnit->addref(); + function->executableCompilationUnit()->addref(); } - RefLocation(QV4::CompiledData::CompilationUnit *ref, const QUrl &url, const QV4::CompiledData::Object *obj, const QString &type) + RefLocation(QV4::ExecutableCompilationUnit *ref, const QUrl &url, + const QV4::CompiledData::Object *obj, const QString &type) : Location(QQmlSourceLocation(type, obj->location.line, obj->location.column), url), locationType(Creating), sent(false) { @@ -230,7 +231,7 @@ public: switch (locationType) { case Binding: - function->compilationUnit->addref(); + function->executableCompilationUnit()->addref(); break; case Creating: unit->addref(); @@ -254,7 +255,7 @@ public: switch (locationType) { case Binding: - function->compilationUnit->release(); + function->executableCompilationUnit()->release(); break; case Creating: unit->release(); @@ -284,7 +285,7 @@ public: RangeType locationType; union { QV4::Function *function; - QV4::CompiledData::CompilationUnit *unit; + QV4::ExecutableCompilationUnit *unit; QQmlBoundSignalExpression *boundSignal; QQmlDataBlob *blob; void *something; @@ -356,7 +357,7 @@ public: } void updateCreating(const QV4::CompiledData::Object *obj, - QV4::CompiledData::CompilationUnit *ref, + QV4::ExecutableCompilationUnit *ref, const QUrl &url, const QString &type) { quintptr locationId(id(obj)); @@ -492,7 +493,7 @@ public: Q_QML_PROFILE(QQmlProfilerDefinitions::ProfileCreating, profiler, endRange()); } - void update(QV4::CompiledData::CompilationUnit *ref, const QV4::CompiledData::Object *obj, + void update(QV4::ExecutableCompilationUnit *ref, const QV4::CompiledData::Object *obj, const QString &typeName, const QUrl &url) { profiler->updateCreating(obj, ref, url, typeName); diff --git a/src/qml/jsruntime/qv4context.cpp b/src/qml/jsruntime/qv4context.cpp index b3bcfe21d5..130727378d 100644 --- a/src/qml/jsruntime/qv4context.cpp +++ b/src/qml/jsruntime/qv4context.cpp @@ -60,7 +60,7 @@ Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int b { Function *function = frame->v4Function; - Heap::InternalClass *ic = function->compilationUnit->runtimeBlocks.at(blockIndex); + Heap::InternalClass *ic = function->executableCompilationUnit()->runtimeBlocks.at(blockIndex); uint nLocals = ic->size; size_t requiredMemory = sizeof(CallContext::Data) - sizeof(Value) + sizeof(Value) * nLocals; @@ -76,7 +76,7 @@ Heap::CallContext *ExecutionContext::newBlockContext(CppStackFrame *frame, int b c->locals.size = nLocals; c->locals.alloc = nLocals; - c->setupLocalTemporalDeadZone(function->compilationUnit->unitData()->blockAt(blockIndex)); + c->setupLocalTemporalDeadZone(function->executableCompilationUnit()->unitData()->blockAt(blockIndex)); return c; } diff --git a/src/qml/jsruntime/qv4engine.cpp b/src/qml/jsruntime/qv4engine.cpp index b04a879c7f..cd77ebd22a 100644 --- a/src/qml/jsruntime/qv4engine.cpp +++ b/src/qml/jsruntime/qv4engine.cpp @@ -1743,7 +1743,7 @@ ReturnedValue ExecutionEngine::global() return globalObject->asReturnedValue(); } -QQmlRefPointer ExecutionEngine::compileModule(const QUrl &url) +QQmlRefPointer ExecutionEngine::compileModule(const QUrl &url) { QFile f(QQmlFile::urlToLocalFileOrQrc(url)); if (!f.open(QIODevice::ReadOnly)) { @@ -1760,7 +1760,8 @@ QQmlRefPointer ExecutionEngine::compileModule(con } -QQmlRefPointer ExecutionEngine::compileModule(const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp) +QQmlRefPointer ExecutionEngine::compileModule( + const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp) { QList diagnostics; auto unit = Compiler::Codegen::compileModule(/*debugMode*/debugger() != nullptr, url.toString(), @@ -1774,10 +1775,11 @@ QQmlRefPointer ExecutionEngine::compileModule(con << ": warning: " << m.message; } } - return unit; + + return ExecutableCompilationUnit::create(std::move(unit)); } -void ExecutionEngine::injectModule(const QQmlRefPointer &moduleUnit) +void ExecutionEngine::injectModule(const QQmlRefPointer &moduleUnit) { // Injection can happen from the QML type loader thread for example, but instantiation and // evaluation must be limited to the ExecutionEngine's thread. @@ -1785,7 +1787,7 @@ void ExecutionEngine::injectModule(const QQmlRefPointerfinalUrl(), moduleUnit); } -QQmlRefPointer ExecutionEngine::moduleForUrl(const QUrl &_url, const CompiledData::CompilationUnit *referrer) const +QQmlRefPointer ExecutionEngine::moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer) const { QUrl url = QQmlTypeLoader::normalize(_url); if (referrer) @@ -1798,7 +1800,7 @@ QQmlRefPointer ExecutionEngine::moduleForUrl(cons return *existingModule; } -QQmlRefPointer ExecutionEngine::loadModule(const QUrl &_url, const CompiledData::CompilationUnit *referrer) +QQmlRefPointer ExecutionEngine::loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer) { QUrl url = QQmlTypeLoader::normalize(_url); if (referrer) diff --git a/src/qml/jsruntime/qv4engine_p.h b/src/qml/jsruntime/qv4engine_p.h index 0d113754c0..f8ac0e0268 100644 --- a/src/qml/jsruntime/qv4engine_p.h +++ b/src/qml/jsruntime/qv4engine_p.h @@ -64,6 +64,7 @@ #include "qv4function_p.h" #include +#include namespace WTF { class BumpPointerAllocator; @@ -489,7 +490,7 @@ public: Symbol *symbol_unscopables() const { return reinterpret_cast(jsSymbols + Symbol_unscopables); } Symbol *symbol_revokableProxy() const { return reinterpret_cast(jsSymbols + Symbol_revokableProxy); } - QIntrusiveList compilationUnits; + QIntrusiveList compilationUnits; quint32 m_engineId; @@ -698,14 +699,15 @@ public: double localTZA = 0.0; // local timezone, initialized at startup - QQmlRefPointer compileModule(const QUrl &url); - QQmlRefPointer compileModule(const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp); + QQmlRefPointer compileModule(const QUrl &url); + QQmlRefPointer compileModule( + const QUrl &url, const QString &sourceCode, const QDateTime &sourceTimeStamp); mutable QMutex moduleMutex; - QHash> modules; - void injectModule(const QQmlRefPointer &moduleUnit); - QQmlRefPointer moduleForUrl(const QUrl &_url, const CompiledData::CompilationUnit *referrer = nullptr) const; - QQmlRefPointer loadModule(const QUrl &_url, const CompiledData::CompilationUnit *referrer = nullptr); + QHash> modules; + void injectModule(const QQmlRefPointer &moduleUnit); + QQmlRefPointer moduleForUrl(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr) const; + QQmlRefPointer loadModule(const QUrl &_url, const ExecutableCompilationUnit *referrer = nullptr); private: #if QT_CONFIG(qml_debug) diff --git a/src/qml/jsruntime/qv4function.cpp b/src/qml/jsruntime/qv4function.cpp index debdf23d27..d870cec68a 100644 --- a/src/qml/jsruntime/qv4function.cpp +++ b/src/qml/jsruntime/qv4function.cpp @@ -73,7 +73,8 @@ ReturnedValue Function::call(const Value *thisObject, const Value *argv, int arg return result; } -Function *Function::create(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function) +Function *Function::create(ExecutionEngine *engine, ExecutableCompilationUnit *unit, + const CompiledData::Function *function) { return new Function(engine, unit, function); } @@ -83,7 +84,8 @@ void Function::destroy() delete this; } -Function::Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function) +Function::Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit, + const CompiledData::Function *function) : FunctionData(unit) , compiledFunction(function) , codeData(function->code()) @@ -146,8 +148,11 @@ void Function::updateInternalClass(ExecutionEngine *engine, const QListlocalsTable(); - for (quint32 i = 0; i < compiledFunction->nLocals; ++i) - internalClass = internalClass->addMember(engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), Attr_NotConfigurable); + for (quint32 i = 0; i < compiledFunction->nLocals; ++i) { + internalClass = internalClass->addMember( + engine->identifierTable->asPropertyKey(compilationUnit->runtimeStrings[localsIndices[i]]), + Attr_NotConfigurable); + } Scope scope(engine); ScopedString arg(scope); diff --git a/src/qml/jsruntime/qv4function_p.h b/src/qml/jsruntime/qv4function_p.h index 01b212370d..cbbb61c68c 100644 --- a/src/qml/jsruntime/qv4function_p.h +++ b/src/qml/jsruntime/qv4function_p.h @@ -51,7 +51,7 @@ // #include "qv4global_p.h" -#include +#include #include namespace JSC { @@ -65,9 +65,13 @@ struct QQmlSourceLocation; namespace QV4 { struct Q_QML_EXPORT FunctionData { - CompiledData::CompilationUnit *compilationUnit; + CompiledData::CompilationUnitBase *compilationUnit; - FunctionData(CompiledData::CompilationUnit *compilationUnit) + // Intentionally require an ExecutableCompilationUnit but save only a pointer to + // CompilationUnitBase. This is so that we can take advantage of the standard layout + // of CompilationUnitBase in the JIT. Furthermore we can safely static_cast to + // ExecutableCompilationUnit where we need it. + FunctionData(ExecutableCompilationUnit *compilationUnit) : compilationUnit(compilationUnit) {} }; @@ -76,12 +80,24 @@ Q_STATIC_ASSERT(std::is_standard_layout< FunctionData >::value); struct Q_QML_EXPORT Function : public FunctionData { private: - Function(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function); + Function(ExecutionEngine *engine, ExecutableCompilationUnit *unit, + const CompiledData::Function *function); ~Function(); public: const CompiledData::Function *compiledFunction; + QV4::ExecutableCompilationUnit *executableCompilationUnit() const + { + // This is safe: We require an ExecutableCompilationUnit in the ctor. + return static_cast(compilationUnit); + } + + QV4::Heap::String *runtimeString(uint i) + { + return compilationUnit->runtimeStrings[i]; + } + ReturnedValue call(const Value *thisObject, const Value *argv, int argc, const ExecutionContext *context); const char *codeData; @@ -96,7 +112,8 @@ public: int interpreterCallCount = 0; bool isEval = false; - static Function *create(ExecutionEngine *engine, CompiledData::CompilationUnit *unit, const CompiledData::Function *function); + static Function *create(ExecutionEngine *engine, ExecutableCompilationUnit *unit, + const CompiledData::Function *function); void destroy(); // used when dynamically assigning signal handlers (QQmlConnection) @@ -108,8 +125,8 @@ public: static QString prettyName(const Function *function, const void *address); - inline QString sourceFile() const { return compilationUnit->fileName(); } - inline QUrl finalUrl() const { return compilationUnit->finalUrl(); } + inline QString sourceFile() const { return executableCompilationUnit()->fileName(); } + inline QUrl finalUrl() const { return executableCompilationUnit()->finalUrl(); } inline bool isStrict() const { return compiledFunction->flags & CompiledData::Function::IsStrict; } inline bool isArrowFunction() const { return compiledFunction->flags & CompiledData::Function::IsArrowFunction; } @@ -121,7 +138,7 @@ public: { if (compiledFunction->nestedFunctionIndex == std::numeric_limits::max()) return nullptr; - return compilationUnit->runtimeFunctions[compiledFunction->nestedFunctionIndex]; + return executableCompilationUnit()->runtimeFunctions[compiledFunction->nestedFunctionIndex]; } }; diff --git a/src/qml/jsruntime/qv4functionobject.cpp b/src/qml/jsruntime/qv4functionobject.cpp index 41a21ba379..b1b0d67e64 100644 --- a/src/qml/jsruntime/qv4functionobject.cpp +++ b/src/qml/jsruntime/qv4functionobject.cpp @@ -135,13 +135,13 @@ void Heap::FunctionObject::setFunction(Function *f) { if (f) { function = f; - function->compilationUnit->addref(); + function->executableCompilationUnit()->addref(); } } void Heap::FunctionObject::destroy() { if (function) - function->compilationUnit->release(); + function->executableCompilationUnit()->release(); Object::destroy(); } @@ -229,7 +229,7 @@ void Heap::FunctionCtor::init(QV4::ExecutionContext *scope) } // 15.3.2 -QQmlRefPointer FunctionCtor::parse(ExecutionEngine *engine, const Value *argv, int argc, Type t) +QQmlRefPointer FunctionCtor::parse(ExecutionEngine *engine, const Value *argv, int argc, Type t) { QString arguments; QString body; @@ -273,14 +273,15 @@ QQmlRefPointer FunctionCtor::parse(ExecutionEngin if (engine->hasException) return nullptr; - return cg.generateCompilationUnit(); + return ExecutableCompilationUnit::create(cg.generateCompilationUnit()); } ReturnedValue FunctionCtor::virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *newTarget) { ExecutionEngine *engine = f->engine(); - QQmlRefPointer compilationUnit = parse(engine, argv, argc, Type_Function); + QQmlRefPointer compilationUnit + = parse(engine, argv, argc, Type_Function); if (engine->hasException) return Encode::undefined(); diff --git a/src/qml/jsruntime/qv4functionobject_p.h b/src/qml/jsruntime/qv4functionobject_p.h index 4fee26f341..c99cad8e33 100644 --- a/src/qml/jsruntime/qv4functionobject_p.h +++ b/src/qml/jsruntime/qv4functionobject_p.h @@ -244,7 +244,7 @@ protected: Type_Function, Type_Generator }; - static QQmlRefPointer parse(ExecutionEngine *engine, const Value *argv, int argc, Type t = Type_Function); + static QQmlRefPointer parse(ExecutionEngine *engine, const Value *argv, int argc, Type t = Type_Function); }; struct FunctionPrototype: FunctionObject diff --git a/src/qml/jsruntime/qv4generatorobject.cpp b/src/qml/jsruntime/qv4generatorobject.cpp index 14caa6953f..4eee6f4338 100644 --- a/src/qml/jsruntime/qv4generatorobject.cpp +++ b/src/qml/jsruntime/qv4generatorobject.cpp @@ -58,7 +58,7 @@ ReturnedValue GeneratorFunctionCtor::virtualCallAsConstructor(const FunctionObje { ExecutionEngine *engine = f->engine(); - QQmlRefPointer compilationUnit = parse(engine, argv, argc, Type_Generator); + QQmlRefPointer compilationUnit = parse(engine, argv, argc, Type_Generator); if (engine->hasException) return Encode::undefined(); diff --git a/src/qml/jsruntime/qv4module.cpp b/src/qml/jsruntime/qv4module.cpp index 237ada8321..08a1900383 100644 --- a/src/qml/jsruntime/qv4module.cpp +++ b/src/qml/jsruntime/qv4module.cpp @@ -52,7 +52,7 @@ using namespace QV4; DEFINE_OBJECT_VTABLE(Module); -void Heap::Module::init(ExecutionEngine *engine, CompiledData::CompilationUnit *moduleUnit) +void Heap::Module::init(ExecutionEngine *engine, ExecutableCompilationUnit *moduleUnit) { Object::init(); @@ -106,7 +106,7 @@ void Module::evaluate() return; d()->evaluated = true; - CompiledData::CompilationUnit *unit = d()->unit; + ExecutableCompilationUnit *unit = d()->unit; unit->evaluateModuleRequests(); diff --git a/src/qml/jsruntime/qv4module_p.h b/src/qml/jsruntime/qv4module_p.h index dca0678fe9..aabb2e005e 100644 --- a/src/qml/jsruntime/qv4module_p.h +++ b/src/qml/jsruntime/qv4module_p.h @@ -60,7 +60,7 @@ namespace QV4 { namespace Heap { #define ModuleMembers(class, Member) \ - Member(class, NoMark, CompiledData::CompilationUnit *, unit) \ + Member(class, NoMark, ExecutableCompilationUnit *, unit) \ Member(class, Pointer, CallContext *, scope) \ Member(class, HeapValue, HeapValue, self) \ Member(class, NoMark, bool, evaluated) @@ -68,7 +68,7 @@ namespace Heap { DECLARE_EXPORTED_HEAP_OBJECT(Module, Object) { DECLARE_MARKOBJECTS(Module) - void init(ExecutionEngine *engine, CompiledData::CompilationUnit *moduleUnit); + void init(ExecutionEngine *engine, ExecutableCompilationUnit *moduleUnit); }; } diff --git a/src/qml/jsruntime/qv4profiling.cpp b/src/qml/jsruntime/qv4profiling.cpp index b337243204..26e1074fe3 100644 --- a/src/qml/jsruntime/qv4profiling.cpp +++ b/src/qml/jsruntime/qv4profiling.cpp @@ -49,7 +49,7 @@ namespace Profiling { FunctionLocation FunctionCall::resolveLocation() const { return FunctionLocation(m_function->name()->toQString(), - m_function->compilationUnit->fileName(), + m_function->executableCompilationUnit()->fileName(), m_function->compiledFunction->location.line, m_function->compiledFunction->location.column); } diff --git a/src/qml/jsruntime/qv4profiling_p.h b/src/qml/jsruntime/qv4profiling_p.h index 8461384e9a..ccf7c9210d 100644 --- a/src/qml/jsruntime/qv4profiling_p.h +++ b/src/qml/jsruntime/qv4profiling_p.h @@ -144,19 +144,19 @@ public: FunctionCall(Function *function, qint64 start, qint64 end) : m_function(function), m_start(start), m_end(end) - { m_function->compilationUnit->addref(); } + { m_function->executableCompilationUnit()->addref(); } FunctionCall(const FunctionCall &other) : m_function(other.m_function), m_start(other.m_start), m_end(other.m_end) - { m_function->compilationUnit->addref(); } + { m_function->executableCompilationUnit()->addref(); } ~FunctionCall() - { m_function->compilationUnit->release(); } + { m_function->executableCompilationUnit()->release(); } FunctionCall &operator=(const FunctionCall &other) { if (&other != this) { - other.m_function->compilationUnit->addref(); - m_function->compilationUnit->release(); + other.m_function->executableCompilationUnit()->addref(); + m_function->executableCompilationUnit()->release(); m_function = other.m_function; m_start = other.m_start; m_end = other.m_end; @@ -189,22 +189,22 @@ public: SentMarker(const SentMarker &other) : m_function(other.m_function) { if (m_function) - m_function->compilationUnit->addref(); + m_function->executableCompilationUnit()->addref(); } ~SentMarker() { if (m_function) - m_function->compilationUnit->release(); + m_function->executableCompilationUnit()->release(); } SentMarker &operator=(const SentMarker &other) { if (&other != this) { if (m_function) - m_function->compilationUnit->release(); + m_function->executableCompilationUnit()->release(); m_function = other.m_function; - m_function->compilationUnit->addref(); + m_function->executableCompilationUnit()->addref(); } return *this; } @@ -213,7 +213,7 @@ public: { Q_ASSERT(m_function == nullptr); m_function = function; - m_function->compilationUnit->addref(); + m_function->executableCompilationUnit()->addref(); } bool isValid() const diff --git a/src/qml/jsruntime/qv4runtime.cpp b/src/qml/jsruntime/qv4runtime.cpp index 107dfbda6f..478114a38a 100644 --- a/src/qml/jsruntime/qv4runtime.cpp +++ b/src/qml/jsruntime/qv4runtime.cpp @@ -224,6 +224,11 @@ void RuntimeCounters::count(const char *func, uint tag1, uint tag2) #ifndef V4_BOOTSTRAP +static QV4::Lookup *runtimeLookup(Function *f, uint i) +{ + return f->executableCompilationUnit()->runtimeLookups + i; +} + void RuntimeHelpers::numberToString(QString *result, double num, int radix) { Q_ASSERT(result); @@ -314,7 +319,8 @@ void RuntimeHelpers::numberToString(QString *result, double num, int radix) ReturnedValue Runtime::Closure::call(ExecutionEngine *engine, int functionId) { - QV4::Function *clos = static_cast(engine->currentStackFrame->v4Function->compilationUnit)->runtimeFunctions[functionId]; + QV4::Function *clos = engine->currentStackFrame->v4Function->executableCompilationUnit() + ->runtimeFunctions[functionId]; Q_ASSERT(clos); ExecutionContext *current = static_cast(&engine->currentStackFrame->jsFrame->context); if (clos->isGenerator()) @@ -620,7 +626,7 @@ QV4::ReturnedValue RuntimeHelpers::addHelper(ExecutionEngine *engine, const Valu ReturnedValue Runtime::GetTemplateObject::call(Function *function, int index) { - return function->compilationUnit->templateObjectAt(index)->asReturnedValue(); + return function->executableCompilationUnit()->templateObjectAt(index)->asReturnedValue(); } void Runtime::StoreProperty::call(ExecutionEngine *engine, const Value &object, int nameIndex, const Value &value) @@ -1077,33 +1083,33 @@ void Runtime::StoreSuperProperty::call(ExecutionEngine *engine, const Value &pro ReturnedValue Runtime::LoadGlobalLookup::call(ExecutionEngine *engine, Function *f, int index) { - Lookup *l = f->compilationUnit->runtimeLookups + index; + Lookup *l = runtimeLookup(f, index); return l->globalGetter(l, engine); } ReturnedValue Runtime::LoadQmlContextPropertyLookup::call(ExecutionEngine *engine, uint index) { - Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index; + Lookup *l = runtimeLookup(engine->currentStackFrame->v4Function, index); return l->qmlContextPropertyGetter(l, engine, nullptr); } ReturnedValue Runtime::GetLookup::call(ExecutionEngine *engine, Function *f, const Value &base, int index) { - Lookup *l = f->compilationUnit->runtimeLookups + index; + Lookup *l = runtimeLookup(f, index); return l->getter(l, engine, base); } void Runtime::SetLookupSloppy::call(Function *f, const Value &base, int index, const Value &value) { ExecutionEngine *engine = f->internalClass->engine; - QV4::Lookup *l = f->compilationUnit->runtimeLookups + index; + QV4::Lookup *l = runtimeLookup(f, index); l->setter(l, engine, const_cast(base), value); } void Runtime::SetLookupStrict::call(Function *f, const Value &base, int index, const Value &value) { ExecutionEngine *engine = f->internalClass->engine; - QV4::Lookup *l = f->compilationUnit->runtimeLookups + index; + QV4::Lookup *l = runtimeLookup(f, index); if (!l->setter(l, engine, const_cast(base), value)) engine->throwTypeError(); } @@ -1366,12 +1372,13 @@ static ReturnedValue throwPropertyIsNotAFunctionTypeError(ExecutionEngine *engin ReturnedValue Runtime::CallGlobalLookup::call(ExecutionEngine *engine, uint index, Value argv[], int argc) { Scope scope(engine); - Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index; + Lookup *l = runtimeLookup(engine->currentStackFrame->v4Function, index); Value function = Value::fromReturnedValue(l->globalGetter(l, engine)); Value thisObject = Value::undefinedValue(); - if (!function.isFunctionObject()) + if (!function.isFunctionObject()) { return throwPropertyIsNotAFunctionTypeError(engine, &thisObject, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()); + } return static_cast(function).call(&thisObject, argv, argc); } @@ -1381,11 +1388,12 @@ ReturnedValue Runtime::CallQmlContextPropertyLookup::call(ExecutionEngine *engin { Scope scope(engine); ScopedValue thisObject(scope); - Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index; + Lookup *l = runtimeLookup(engine->currentStackFrame->v4Function, index); Value function = Value::fromReturnedValue(l->qmlContextPropertyGetter(l, engine, thisObject)); - if (!function.isFunctionObject()) + if (!function.isFunctionObject()) { return throwPropertyIsNotAFunctionTypeError(engine, thisObject, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[l->nameIndex]->toQString()); + } return static_cast(function).call(thisObject, argv, argc); } @@ -1420,9 +1428,11 @@ ReturnedValue Runtime::CallName::call(ExecutionEngine *engine, int nameIndex, Va if (engine->hasException) return Encode::undefined(); - if (!f) - return throwPropertyIsNotAFunctionTypeError(engine, thisObject, - engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]->toQString()); + if (!f) { + return throwPropertyIsNotAFunctionTypeError( + engine, thisObject, engine->currentStackFrame->v4Function->compilationUnit + ->runtimeStrings[nameIndex]->toQString()); + } return f->call(thisObject, argv, argc); } @@ -1431,7 +1441,9 @@ ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value & { const Value *base = &baseRef; Scope scope(engine); - ScopedString name(scope, engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); + ScopedString name( + scope, + engine->currentStackFrame->v4Function->compilationUnit->runtimeStrings[nameIndex]); ScopedObject lookupObject(scope, base); if (!lookupObject) { @@ -1469,7 +1481,7 @@ ReturnedValue Runtime::CallProperty::call(ExecutionEngine *engine, const Value & ReturnedValue Runtime::CallPropertyLookup::call(ExecutionEngine *engine, const Value &base, uint index, Value *argv, int argc) { - Lookup *l = engine->currentStackFrame->v4Function->compilationUnit->runtimeLookups + index; + Lookup *l = runtimeLookup(engine->currentStackFrame->v4Function, index); // ok to have the value on the stack here Value f = Value::fromReturnedValue(l->getter(l, engine, base)); @@ -1789,7 +1801,8 @@ ReturnedValue Runtime::ObjectLiteral::call(ExecutionEngine *engine, int classId, if (arg != ObjectLiteralArgument::Value) { Q_ASSERT(args[2].isInteger()); int functionId = args[2].integerValue(); - QV4::Function *clos = static_cast(engine->currentStackFrame->v4Function->compilationUnit)->runtimeFunctions[functionId]; + QV4::Function *clos = engine->currentStackFrame->v4Function->executableCompilationUnit() + ->runtimeFunctions[functionId]; Q_ASSERT(clos); PropertyKey::FunctionNamePrefix prefix = PropertyKey::None; @@ -1833,7 +1846,8 @@ ReturnedValue Runtime::ObjectLiteral::call(ExecutionEngine *engine, int classId, ReturnedValue Runtime::CreateClass::call(ExecutionEngine *engine, int classIndex, const Value &superClass, Value computedNames[]) { - const CompiledData::CompilationUnit *unit = engine->currentStackFrame->v4Function->compilationUnit; + const QV4::ExecutableCompilationUnit *unit + = engine->currentStackFrame->v4Function->executableCompilationUnit(); const QV4::CompiledData::Class *cls = unit->unitData()->classAt(classIndex); Scope scope(engine); diff --git a/src/qml/jsruntime/qv4script.cpp b/src/qml/jsruntime/qv4script.cpp index 6cb2e95cdc..ee7f4dff0b 100644 --- a/src/qml/jsruntime/qv4script.cpp +++ b/src/qml/jsruntime/qv4script.cpp @@ -61,7 +61,7 @@ using namespace QV4; -Script::Script(ExecutionEngine *v4, QmlContext *qml, const QQmlRefPointer &compilationUnit) +Script::Script(ExecutionEngine *v4, QmlContext *qml, const QQmlRefPointer &compilationUnit) : line(1), column(0), context(v4->rootContext()), strictMode(false), inheritContext(true), parsed(false) , compilationUnit(compilationUnit), vmFunction(nullptr), parseAsBinding(true) { @@ -133,7 +133,7 @@ void Script::parse() if (v4->hasException) return; - compilationUnit = cg.generateCompilationUnit(); + compilationUnit = QV4::ExecutableCompilationUnit::create(cg.generateCompilationUnit()); vmFunction = compilationUnit->linkToEngine(v4); } @@ -172,10 +172,11 @@ Function *Script::function() return vmFunction; } -QQmlRefPointer Script::precompile(QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine, Compiler::JSUnitGenerator *unitGenerator, - const QString &fileName, const QString &finalUrl, const QString &source, - QList *reportedErrors, - QV4::Compiler::ContextType contextType) +QV4::CompiledData::CompilationUnit Script::precompile( + QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine, + Compiler::JSUnitGenerator *unitGenerator, const QString &fileName, const QString &finalUrl, + const QString &source, QList *reportedErrors, + QV4::Compiler::ContextType contextType) { using namespace QV4::Compiler; using namespace QQmlJS::AST; @@ -219,8 +220,9 @@ Script *Script::createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlCo QQmlMetaType::CachedUnitLookupError cacheError = QQmlMetaType::CachedUnitLookupError::NoError; if (const QV4::CompiledData::Unit *cachedUnit = QQmlMetaType::findCachedCompilationUnit(originalUrl, &cacheError)) { - QQmlRefPointer jsUnit; - jsUnit.adopt(new QV4::CompiledData::CompilationUnit(cachedUnit)); + QQmlRefPointer jsUnit + = QV4::ExecutableCompilationUnit::create( + QV4::CompiledData::CompilationUnit(cachedUnit)); return new QV4::Script(engine, qmlContext, jsUnit); } diff --git a/src/qml/jsruntime/qv4script_p.h b/src/qml/jsruntime/qv4script_p.h index a1e9b83a8b..aecedea701 100644 --- a/src/qml/jsruntime/qv4script_p.h +++ b/src/qml/jsruntime/qv4script_p.h @@ -80,7 +80,7 @@ struct Q_QML_EXPORT Script { if (qml) qmlContext.set(engine, *qml); } - Script(ExecutionEngine *engine, QmlContext *qml, const QQmlRefPointer &compilationUnit); + Script(ExecutionEngine *engine, QmlContext *qml, const QQmlRefPointer &compilationUnit); ~Script(); QString sourceFile; int line; @@ -92,7 +92,7 @@ struct Q_QML_EXPORT Script { bool parsed; QV4::Compiler::ContextType contextType = QV4::Compiler::ContextType::Eval; QV4::PersistentValue qmlContext; - QQmlRefPointer compilationUnit; + QQmlRefPointer compilationUnit; Function *vmFunction; bool parseAsBinding; @@ -101,8 +101,10 @@ struct Q_QML_EXPORT Script { Function *function(); - static QQmlRefPointer precompile(QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine, Compiler::JSUnitGenerator *unitGenerator, - const QString &fileName, const QString &finalUrl, const QString &source, + static QV4::CompiledData::CompilationUnit precompile( + QV4::Compiler::Module *module, QQmlJS::Engine *jsEngine, + Compiler::JSUnitGenerator *unitGenerator, const QString &fileName, + const QString &finalUrl, const QString &source, QList *reportedErrors = nullptr, QV4::Compiler::ContextType contextType = QV4::Compiler::ContextType::Global); static Script *createFromFileOrCache(ExecutionEngine *engine, QmlContext *qmlContext, const QString &fileName, const QUrl &originalUrl, QString *error); diff --git a/src/qml/jsruntime/qv4vme_moth.cpp b/src/qml/jsruntime/qv4vme_moth.cpp index d348a79861..c6322fb504 100644 --- a/src/qml/jsruntime/qv4vme_moth.cpp +++ b/src/qml/jsruntime/qv4vme_moth.cpp @@ -565,14 +565,14 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(LoadGlobalLookup) STORE_IP(); - QV4::Lookup *l = function->compilationUnit->runtimeLookups + index; + QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index; acc = l->globalGetter(l, engine); CHECK_EXCEPTION; MOTH_END_INSTR(LoadGlobalLookup) MOTH_BEGIN_INSTR(LoadQmlContextPropertyLookup) STORE_IP(); - QV4::Lookup *l = function->compilationUnit->runtimeLookups + index; + QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index; acc = l->qmlContextPropertyGetter(l, engine, nullptr); CHECK_EXCEPTION; MOTH_END_INSTR(LoadQmlContextPropertyLookup) @@ -616,7 +616,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, STORE_IP(); STORE_ACC(); - QV4::Lookup *l = function->compilationUnit->runtimeLookups + index; + QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index; if (accumulator.isNullOrUndefined()) { QString message = QStringLiteral("Cannot read property '%1' of %2") @@ -640,7 +640,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(SetLookup) STORE_IP(); STORE_ACC(); - QV4::Lookup *l = function->compilationUnit->runtimeLookups + index; + QV4::Lookup *l = function->executableCompilationUnit()->runtimeLookups + index; if (!l->setter(l, engine, STACK_VALUE(base), accumulator) && function->isStrict()) engine->throwTypeError(); CHECK_EXCEPTION; @@ -722,7 +722,7 @@ QV4::ReturnedValue VME::interpret(CppStackFrame *frame, ExecutionEngine *engine, MOTH_BEGIN_INSTR(CallPropertyLookup) STORE_IP(); - Lookup *l = function->compilationUnit->runtimeLookups + lookupIndex; + Lookup *l = function->executableCompilationUnit()->runtimeLookups + lookupIndex; if (stack[base].isNullOrUndefined()) { QString message = QStringLiteral("Cannot call method '%1' of %2") diff --git a/src/qml/qml/qqmlbinding.cpp b/src/qml/qml/qqmlbinding.cpp index 656c7dd515..7fb15af570 100644 --- a/src/qml/qml/qqmlbinding.cpp +++ b/src/qml/qml/qqmlbinding.cpp @@ -335,7 +335,7 @@ protected: class QQmlTranslationBinding : public GenericBinding { public: - QQmlTranslationBinding(const QQmlRefPointer &compilationUnit, const QV4::CompiledData::Binding *binding) + QQmlTranslationBinding(const QQmlRefPointer &compilationUnit, const QV4::CompiledData::Binding *binding) { setCompilationUnit(compilationUnit); m_binding = binding; @@ -356,7 +356,7 @@ public: if (!isAddedToObject() || hasError()) return; - const QString result = m_binding->valueAsString(m_compilationUnit.data()); + const QString result = m_compilationUnit->bindingValueAsString(m_binding); Q_ASSERT(targetObject()); @@ -378,7 +378,7 @@ private: const QV4::CompiledData::Binding *m_binding; }; -QQmlBinding *QQmlBinding::createTranslationBinding(const QQmlRefPointer &unit, const QV4::CompiledData::Binding *binding, QObject *obj, QQmlContextData *ctxt) +QQmlBinding *QQmlBinding::createTranslationBinding(const QQmlRefPointer &unit, const QV4::CompiledData::Binding *binding, QObject *obj, QQmlContextData *ctxt) { QQmlTranslationBinding *b = new QQmlTranslationBinding(unit, binding); diff --git a/src/qml/qml/qqmlbinding_p.h b/src/qml/qml/qqmlbinding_p.h index f192de4342..85b02dcde4 100644 --- a/src/qml/qml/qqmlbinding_p.h +++ b/src/qml/qml/qqmlbinding_p.h @@ -79,7 +79,7 @@ public: const QString &url = QString(), quint16 lineNumber = 0); static QQmlBinding *create(const QQmlPropertyData *property, QV4::Function *function, QObject *obj, QQmlContextData *ctxt, QV4::ExecutionContext *scope); - static QQmlBinding *createTranslationBinding(const QQmlRefPointer &unit, const QV4::CompiledData::Binding *binding, + static QQmlBinding *createTranslationBinding(const QQmlRefPointer &unit, const QV4::CompiledData::Binding *binding, QObject *obj, QQmlContextData *ctxt); ~QQmlBinding() override; diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index f9f26b6b1e..04debc0615 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -550,7 +550,8 @@ QQmlComponent::QQmlComponent(QQmlEngine *engine, const QString &fileName, /*! \internal */ -QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::CompiledData::CompilationUnit *compilationUnit, int start, QObject *parent) +QQmlComponent::QQmlComponent(QQmlEngine *engine, QV4::ExecutableCompilationUnit *compilationUnit, + int start, QObject *parent) : QQmlComponent(engine, parent) { Q_D(QQmlComponent); diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h index 20199d0b21..39b6d4526f 100644 --- a/src/qml/qml/qqmlcomponent.h +++ b/src/qml/qml/qqmlcomponent.h @@ -59,9 +59,7 @@ class QQmlComponentPrivate; class QQmlComponentAttached; namespace QV4 { -namespace CompiledData { -struct CompilationUnit; -} +class ExecutableCompilationUnit; } class Q_QML_EXPORT QQmlComponent : public QObject @@ -128,7 +126,8 @@ protected: Q_INVOKABLE void incubateObject(QQmlV4Function *); private: - QQmlComponent(QQmlEngine *, QV4::CompiledData::CompilationUnit *compilationUnit, int, QObject *parent); + QQmlComponent(QQmlEngine *, QV4::ExecutableCompilationUnit *compilationUnit, int, + QObject *parent); Q_DISABLE_COPY(QQmlComponent) friend class QQmlTypeData; diff --git a/src/qml/qml/qqmlcomponent_p.h b/src/qml/qml/qqmlcomponent_p.h index 4d9e4c6c15..71275a2cd3 100644 --- a/src/qml/qml/qqmlcomponent_p.h +++ b/src/qml/qml/qqmlcomponent_p.h @@ -105,7 +105,7 @@ public: qreal progress; int start; - QQmlRefPointer compilationUnit; + QQmlRefPointer compilationUnit; struct ConstructionState { ConstructionState() diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index 3710cee162..e23f1e1e73 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -845,7 +845,7 @@ QQmlContextPrivate *QQmlContextData::asQQmlContextPrivate() return QQmlContextPrivate::get(asQQmlContext()); } -void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer &unit, int subComponentIndex) +void QQmlContextData::initFromTypeCompilationUnit(const QQmlRefPointer &unit, int subComponentIndex) { typeCompilationUnit = unit; componentObjectIndex = subComponentIndex == -1 ? /*root object*/0 : subComponentIndex; diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h index 7e3cef8e1d..1ddd04c9ff 100644 --- a/src/qml/qml/qqmlcontext_p.h +++ b/src/qml/qml/qqmlcontext_p.h @@ -66,7 +66,7 @@ #include #include -#include +#include #include QT_BEGIN_NAMESPACE @@ -152,12 +152,12 @@ public: QQmlIncubatorPrivate *incubator; // Compilation unit for contexts that belong to a compiled type. - QQmlRefPointer typeCompilationUnit; + QQmlRefPointer typeCompilationUnit; // object index in CompiledData::Unit to component that created this context int componentObjectIndex; - void initFromTypeCompilationUnit(const QQmlRefPointer &unit, int subComponentIndex); + void initFromTypeCompilationUnit(const QQmlRefPointer &unit, int subComponentIndex); // flag indicates whether the context owns the cache (after mutation) or not. mutable QV4::IdentifierHash propertyNameCache; diff --git a/src/qml/qml/qqmlcustomparser_p.h b/src/qml/qml/qqmlcustomparser_p.h index aa933553a8..c8e1300a1b 100644 --- a/src/qml/qml/qqmlcustomparser_p.h +++ b/src/qml/qml/qqmlcustomparser_p.h @@ -80,8 +80,8 @@ public: void clearErrors(); Flags flags() const { return m_flags; } - virtual void verifyBindings(const QQmlRefPointer &, const QList &) = 0; - virtual void applyBindings(QObject *, const QQmlRefPointer &, const QList &) = 0; + virtual void verifyBindings(const QQmlRefPointer &, const QList &) = 0; + virtual void applyBindings(QObject *, const QQmlRefPointer &, const QList &) = 0; QVector errors() const { return exceptions; } diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h index f4c03fc17c..299476f5c8 100644 --- a/src/qml/qml/qqmldata_p.h +++ b/src/qml/qml/qqmldata_p.h @@ -76,8 +76,8 @@ class QQmlDataExtended; class QQmlNotifierEndpoint; namespace QV4 { +class ExecutableCompilationUnit; namespace CompiledData { -struct CompilationUnit; struct Binding; } } @@ -226,14 +226,14 @@ public: ~DeferredData(); unsigned int deferredIdx; QMultiHash bindings; - QQmlRefPointer compilationUnit;//Not always the same as the other compilation unit + QQmlRefPointer compilationUnit;//Not always the same as the other compilation unit QQmlContextData *context;//Could be either context or outerContext Q_DISABLE_COPY(DeferredData); }; - QQmlRefPointer compilationUnit; + QQmlRefPointer compilationUnit; QVector deferredData; - void deferData(int objectIndex, const QQmlRefPointer &, QQmlContextData *); + void deferData(int objectIndex, const QQmlRefPointer &, QQmlContextData *); void releaseDeferredData(); QV4::WeakValue jsWrapper; diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index ea639d870b..8faace521a 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -1770,7 +1770,7 @@ void QQmlData::NotifyList::layout() todo = nullptr; } -void QQmlData::deferData(int objectIndex, const QQmlRefPointer &compilationUnit, QQmlContextData *context) +void QQmlData::deferData(int objectIndex, const QQmlRefPointer &compilationUnit, QQmlContextData *context) { QQmlData::DeferredData *deferData = new QQmlData::DeferredData; deferData->deferredIdx = objectIndex; @@ -2407,7 +2407,7 @@ QQmlPropertyCache *QQmlEnginePrivate::rawPropertyCacheForType(int t, int minorVe } } -void QQmlEnginePrivate::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) +void QQmlEnginePrivate::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) { compilationUnit->isRegisteredWithEngine = true; @@ -2417,7 +2417,7 @@ void QQmlEnginePrivate::registerInternalCompositeType(QV4::CompiledData::Compila m_compositeTypes.insert(compilationUnit->metaTypeId, compilationUnit); } -void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) +void QQmlEnginePrivate::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) { compilationUnit->isRegisteredWithEngine = false; diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h index ffe0e36d75..3b716683fd 100644 --- a/src/qml/qml/qqmlengine_p.h +++ b/src/qml/qml/qqmlengine_p.h @@ -219,8 +219,8 @@ public: QQmlMetaObject metaObjectForType(int) const; QQmlPropertyCache *propertyCacheForType(int); QQmlPropertyCache *rawPropertyCacheForType(int, int minorVersion = -1); - void registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit); - void unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit); + void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); + void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); bool isTypeLoaded(const QUrl &url) const; bool isScriptLoaded(const QUrl &url) const; @@ -265,7 +265,7 @@ private: // These members must be protected by a QQmlEnginePrivate::Locker as they are required by // the threaded loader. Only access them through their respective accessor methods. - QHash m_compositeTypes; + QHash m_compositeTypes; static bool s_designerMode; // These members is protected by the full QQmlEnginePrivate::mutex mutex diff --git a/src/qml/qml/qqmlincubator_p.h b/src/qml/qml/qqmlincubator_p.h index 676ba1a29a..57ec8249cb 100644 --- a/src/qml/qml/qqmlincubator_p.h +++ b/src/qml/qml/qqmlincubator_p.h @@ -87,7 +87,7 @@ public: QPointer result; QQmlGuardedContextData rootContext; QQmlEnginePrivate *enginePriv; - QQmlRefPointer compilationUnit; + QQmlRefPointer compilationUnit; QScopedPointer creator; int subComponentToCreate; QQmlVMEGuard vmeGuard; diff --git a/src/qml/qml/qqmljavascriptexpression.cpp b/src/qml/qml/qqmljavascriptexpression.cpp index 9a3a5218e0..e799267769 100644 --- a/src/qml/qml/qqmljavascriptexpression.cpp +++ b/src/qml/qml/qqmljavascriptexpression.cpp @@ -392,10 +392,10 @@ void QQmlJavaScriptExpression::setupFunction(QV4::ExecutionContext *qmlContext, return; m_qmlScope.set(qmlContext->engine(), *qmlContext); m_v4Function = f; - setCompilationUnit(m_v4Function->compilationUnit); + setCompilationUnit(m_v4Function->executableCompilationUnit()); } -void QQmlJavaScriptExpression::setCompilationUnit(const QQmlRefPointer &compilationUnit) +void QQmlJavaScriptExpression::setCompilationUnit(const QQmlRefPointer &compilationUnit) { m_compilationUnit = compilationUnit; } diff --git a/src/qml/qml/qqmljavascriptexpression_p.h b/src/qml/qml/qqmljavascriptexpression_p.h index 92f2ccbb4a..eecee08062 100644 --- a/src/qml/qml/qqmljavascriptexpression_p.h +++ b/src/qml/qml/qqmljavascriptexpression_p.h @@ -153,7 +153,7 @@ protected: void createQmlBinding(QQmlContextData *ctxt, QObject *scope, const QString &code, const QString &filename, quint16 line); void setupFunction(QV4::ExecutionContext *qmlContext, QV4::Function *f); - void setCompilationUnit(const QQmlRefPointer &compilationUnit); + void setCompilationUnit(const QQmlRefPointer &compilationUnit); // We store some flag bits in the following flag pointers. // activeGuards:flag1 - notifyOnValueChanged @@ -178,7 +178,7 @@ private: QQmlJavaScriptExpression *m_nextExpression; QV4::PersistentValue m_qmlScope; - QQmlRefPointer m_compilationUnit; + QQmlRefPointer m_compilationUnit; QV4::Function *m_v4Function; }; diff --git a/src/qml/qml/qqmlmetatype.cpp b/src/qml/qml/qqmlmetatype.cpp index 09df23de51..a5b92d14f7 100644 --- a/src/qml/qml/qqmlmetatype.cpp +++ b/src/qml/qml/qqmlmetatype.cpp @@ -499,7 +499,7 @@ QQmlType QQmlMetaType::registerCompositeType(const QQmlPrivate::RegisterComposit return QQmlType(priv); } -void QQmlMetaType::registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) +void QQmlMetaType::registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) { QByteArray name = compilationUnit->rootPropertyCache()->className(); @@ -526,7 +526,7 @@ void QQmlMetaType::registerInternalCompositeType(QV4::CompiledData::CompilationU data->qmlLists.insert(lst_type, ptr_type); } -void QQmlMetaType::unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit) +void QQmlMetaType::unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit) { int ptr_type = compilationUnit->metaTypeId; int lst_type = compilationUnit->listMetaTypeId; diff --git a/src/qml/qml/qqmlmetatype_p.h b/src/qml/qml/qqmlmetatype_p.h index 9af982d1c3..911e519cf2 100644 --- a/src/qml/qml/qqmlmetatype_p.h +++ b/src/qml/qml/qqmlmetatype_p.h @@ -61,6 +61,8 @@ class QQmlTypeModule; class QMutex; class QQmlError; +namespace QV4 { class ExecutableCompilationUnit; } + class Q_QML_PRIVATE_EXPORT QQmlMetaType { public: @@ -78,8 +80,8 @@ public: static void unregisterType(int type); - static void registerInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit); - static void unregisterInternalCompositeType(QV4::CompiledData::CompilationUnit *compilationUnit); + static void registerInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); + static void unregisterInternalCompositeType(QV4::ExecutableCompilationUnit *compilationUnit); static void registerModule(const char *uri, int versionMajor, int versionMinor); static bool protectModule(const char *uri, int majVersion); diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 18105aa75f..177c0d38bd 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -73,7 +73,7 @@ struct ActiveOCRestorer }; } -QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer &compilationUnit, QQmlContextData *creationContext, +QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer &compilationUnit, QQmlContextData *creationContext, QQmlIncubatorPrivate *incubator) : phase(Startup) , compilationUnit(compilationUnit) @@ -100,7 +100,7 @@ QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlR } } -QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState) +QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState) : phase(Startup) , compilationUnit(compilationUnit) , propertyCaches(&compilationUnit->propertyCaches) @@ -373,7 +373,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const propertyType = QMetaType::Int; } else { // ### This should be resolved earlier at compile time and the binding value should be changed accordingly. - QVariant value = binding->valueAsString(compilationUnit.data()); + QVariant value = compilationUnit->bindingValueAsString(binding); bool ok = QQmlPropertyPrivate::write(_qobject, *property, value, context); Q_ASSERT(ok); Q_UNUSED(ok); @@ -438,7 +438,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const property->writeProperty(_qobject, &nullValue, propertyWriteFlags); } } else { - QString stringValue = binding->valueAsString(compilationUnit.data()); + QString stringValue = compilationUnit->bindingValueAsString(binding); if (property->isVarProperty()) { QV4::ScopedString s(scope, v4->newString(stringValue)); _vmeMetaObject->setVMEProperty(property->coreIndex(), s); @@ -451,25 +451,25 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const break; case QVariant::String: { assertOrNull(binding->evaluatesToString()); - QString value = binding->valueAsString(compilationUnit.data()); + QString value = compilationUnit->bindingValueAsString(binding); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::StringList: { assertOrNull(binding->evaluatesToString()); - QStringList value(binding->valueAsString(compilationUnit.data())); + QStringList value(compilationUnit->bindingValueAsString(binding)); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::ByteArray: { assertType(QV4::CompiledData::Binding::Type_String); - QByteArray value(binding->valueAsString(compilationUnit.data()).toUtf8()); + QByteArray value(compilationUnit->bindingValueAsString(binding).toUtf8()); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Url: { assertType(QV4::CompiledData::Binding::Type_String); - QString string = binding->valueAsString(compilationUnit.data()); + QString string = compilationUnit->bindingValueAsString(binding); // Encoded dir-separators defeat QUrl processing - decode them first string.replace(QLatin1String("%2f"), QLatin1String("/"), Qt::CaseInsensitive); QUrl value = string.isEmpty() ? QUrl() : compilationUnit->finalUrl().resolved(QUrl(string)); @@ -509,7 +509,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const break; case QVariant::Color: { bool ok = false; - uint colorValue = QQmlStringConverters::rgbaFromString(binding->valueAsString(compilationUnit.data()), &ok); + uint colorValue = QQmlStringConverters::rgbaFromString(compilationUnit->bindingValueAsString(binding), &ok); assertOrNull(ok); struct { void *data[4]; } buffer; if (QQml_valueTypeProvider()->storeValueType(property->propType(), &colorValue, &buffer, sizeof(buffer))) { @@ -520,21 +520,21 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const #if QT_CONFIG(datestring) case QVariant::Date: { bool ok = false; - QDate value = QQmlStringConverters::dateFromString(binding->valueAsString(compilationUnit.data()), &ok); + QDate value = QQmlStringConverters::dateFromString(compilationUnit->bindingValueAsString(binding), &ok); assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Time: { bool ok = false; - QTime value = QQmlStringConverters::timeFromString(binding->valueAsString(compilationUnit.data()), &ok); + QTime value = QQmlStringConverters::timeFromString(compilationUnit->bindingValueAsString(binding), &ok); assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::DateTime: { bool ok = false; - QDateTime value = QQmlStringConverters::dateTimeFromString(binding->valueAsString(compilationUnit.data()), &ok); + QDateTime value = QQmlStringConverters::dateTimeFromString(compilationUnit->bindingValueAsString(binding), &ok); // ### VME compatibility :( { const qint64 date = value.date().toJulianDay(); @@ -548,42 +548,42 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const #endif // datestring case QVariant::Point: { bool ok = false; - QPoint value = QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok).toPoint(); + QPoint value = QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok).toPoint(); assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::PointF: { bool ok = false; - QPointF value = QQmlStringConverters::pointFFromString(binding->valueAsString(compilationUnit.data()), &ok); + QPointF value = QQmlStringConverters::pointFFromString(compilationUnit->bindingValueAsString(binding), &ok); assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Size: { bool ok = false; - QSize value = QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok).toSize(); + QSize value = QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok).toSize(); assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::SizeF: { bool ok = false; - QSizeF value = QQmlStringConverters::sizeFFromString(binding->valueAsString(compilationUnit.data()), &ok); + QSizeF value = QQmlStringConverters::sizeFFromString(compilationUnit->bindingValueAsString(binding), &ok); assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Rect: { bool ok = false; - QRect value = QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok).toRect(); + QRect value = QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok).toRect(); assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::RectF: { bool ok = false; - QRectF value = QQmlStringConverters::rectFFromString(binding->valueAsString(compilationUnit.data()), &ok); + QRectF value = QQmlStringConverters::rectFFromString(compilationUnit->bindingValueAsString(binding), &ok); assertOrNull(ok); property->writeProperty(_qobject, &value, propertyWriteFlags); } @@ -599,7 +599,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const float xp; float yp; } vec; - bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec)); + bool ok = QQmlStringConverters::createFromString(QMetaType::QVector2D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec)); assertOrNull(ok); Q_UNUSED(ok); property->writeProperty(_qobject, &vec, propertyWriteFlags); @@ -611,7 +611,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const float yp; float zy; } vec; - bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec)); + bool ok = QQmlStringConverters::createFromString(QMetaType::QVector3D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec)); assertOrNull(ok); Q_UNUSED(ok); property->writeProperty(_qobject, &vec, propertyWriteFlags); @@ -624,7 +624,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const float zy; float wp; } vec; - bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec)); + bool ok = QQmlStringConverters::createFromString(QMetaType::QVector4D, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec)); assertOrNull(ok); Q_UNUSED(ok); property->writeProperty(_qobject, &vec, propertyWriteFlags); @@ -637,7 +637,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const float yp; float zp; } vec; - bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, binding->valueAsString(compilationUnit.data()), &vec, sizeof(vec)); + bool ok = QQmlStringConverters::createFromString(QMetaType::QQuaternion, compilationUnit->bindingValueAsString(binding), &vec, sizeof(vec)); assertOrNull(ok); Q_UNUSED(ok); property->writeProperty(_qobject, &vec, propertyWriteFlags); @@ -669,7 +669,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const break; } else if (property->propType() == qMetaTypeId >()) { assertType(QV4::CompiledData::Binding::Type_String); - QString urlString = binding->valueAsString(compilationUnit.data()); + QString urlString = compilationUnit->bindingValueAsString(binding); QUrl u = urlString.isEmpty() ? QUrl() : compilationUnit->finalUrl().resolved(QUrl(urlString)); QList value; @@ -679,7 +679,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } else if (property->propType() == qMetaTypeId >()) { assertOrNull(binding->evaluatesToString()); QList value; - value.append(binding->valueAsString(compilationUnit.data())); + value.append(compilationUnit->bindingValueAsString(binding)); property->writeProperty(_qobject, &value, propertyWriteFlags); break; } else if (property->propType() == qMetaTypeId()) { @@ -695,14 +695,14 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const } else if (binding->type == QV4::CompiledData::Binding::Type_Null) { value = QJSValue::NullValue; } else { - value = QJSValue(binding->valueAsString(compilationUnit.data())); + value = QJSValue(compilationUnit->bindingValueAsString(binding)); } property->writeProperty(_qobject, &value, propertyWriteFlags); break; } // otherwise, try a custom type assignment - QString stringValue = binding->valueAsString(compilationUnit.data()); + QString stringValue = compilationUnit->bindingValueAsString(binding); QQmlMetaType::StringConverter converter = QQmlMetaType::customStringConverter(property->propType()); Q_ASSERT(converter); QVariant value = (*converter)(stringValue); @@ -816,7 +816,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper { if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) { Q_ASSERT(stringAt(compilationUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty()); - QV4::CompiledData::ResolvedTypeReference *tr = resolvedType(binding->propertyNameIndex); + QV4::ResolvedTypeReference *tr = resolvedType(binding->propertyNameIndex); Q_ASSERT(tr); QQmlType attachedType = tr->type; if (!attachedType.isValid()) { @@ -835,7 +835,8 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper // ### resolve this at compile time if (bindingProperty && bindingProperty->propType() == qMetaTypeId()) { - QQmlScriptString ss(binding->valueAsScriptString(compilationUnit.data()), context->asQQmlContext(), _scopeObject); + QQmlScriptString ss(compilationUnit->bindingValueAsScriptString(binding), + context->asQQmlContext(), _scopeObject); ss.d.data()->bindingId = binding->type == QV4::CompiledData::Binding::Type_Script ? binding->value.compiledScriptIndex : (quint32)QQmlBinding::Invalid; ss.d.data()->lineNumber = binding->location.line; ss.d.data()->columnNumber = binding->location.column; @@ -1184,8 +1185,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo instance = component; ddata = QQmlData::get(instance, /*create*/true); } else { - QV4::CompiledData::ResolvedTypeReference *typeRef - = resolvedType(obj->inheritedTypeNameIndex); + QV4::ResolvedTypeReference *typeRef = resolvedType(obj->inheritedTypeNameIndex); Q_ASSERT(typeRef); installPropertyCache = !typeRef->isFullyDynamicType; QQmlType type = typeRef->type; diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 5aca60e2f0..0766e2082e 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -85,7 +85,7 @@ class Q_QML_PRIVATE_EXPORT QQmlObjectCreator { Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator) public: - QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer &compilationUnit, QQmlContextData *creationContext, QQmlIncubatorPrivate *incubator = nullptr); + QQmlObjectCreator(QQmlContextData *parentContext, const QQmlRefPointer &compilationUnit, QQmlContextData *creationContext, QQmlIncubatorPrivate *incubator = nullptr); ~QQmlObjectCreator(); QObject *create(int subComponentIndex = -1, QObject *parent = nullptr, QQmlInstantiationInterrupt *interrupt = nullptr); @@ -104,7 +104,7 @@ public: QFiniteStack > &allCreatedObjects() const { return sharedState->allCreatedObjects; } private: - QQmlObjectCreator(QQmlContextData *contextData, const QQmlRefPointer &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState); + QQmlObjectCreator(QQmlContextData *contextData, const QQmlRefPointer &compilationUnit, QQmlObjectCreatorSharedState *inheritedSharedState); void init(QQmlContextData *parentContext); @@ -125,7 +125,7 @@ private: inline QV4::QmlContext *currentQmlContext(); Q_NEVER_INLINE void createQmlContext(); - QV4::CompiledData::ResolvedTypeReference *resolvedType(int id) const + QV4::ResolvedTypeReference *resolvedType(int id) const { return compilationUnit->resolvedType(id); } @@ -141,7 +141,7 @@ private: QQmlEngine *engine; QV4::ExecutionEngine *v4; - QQmlRefPointer compilationUnit; + QQmlRefPointer compilationUnit; const QV4::CompiledData::Unit *qmlUnit; QQmlGuardedContextData parentContext; QQmlContextData *context; diff --git a/src/qml/qml/qqmlproperty_p.h b/src/qml/qml/qqmlproperty_p.h index bafcba5971..285c34d7fa 100644 --- a/src/qml/qml/qqmlproperty_p.h +++ b/src/qml/qml/qqmlproperty_p.h @@ -59,6 +59,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE diff --git a/src/qml/qml/qqmltype.cpp b/src/qml/qml/qqmltype.cpp index 926e2810d5..6b4e0a0734 100644 --- a/src/qml/qml/qqmltype.cpp +++ b/src/qml/qml/qqmltype.cpp @@ -178,7 +178,7 @@ QQmlType QQmlType::resolveCompositeBaseType(QQmlEnginePrivate *engine) const QQmlRefPointer td(engine->typeLoader.getType(sourceUrl())); if (td.isNull() || !td->isComplete()) return QQmlType(); - QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit(); + QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit(); const QMetaObject *mo = compilationUnit->rootPropertyCache()->firstCppMetaObject(); return QQmlMetaType::qmlType(mo); } @@ -192,7 +192,7 @@ QQmlPropertyCache *QQmlType::compositePropertyCache(QQmlEnginePrivate *engine) c QQmlRefPointer td(engine->typeLoader.getType(sourceUrl())); if (td.isNull() || !td->isComplete()) return nullptr; - QV4::CompiledData::CompilationUnit *compilationUnit = td->compilationUnit(); + QV4::ExecutableCompilationUnit *compilationUnit = td->compilationUnit(); return compilationUnit->rootPropertyCache().data(); } diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp index 2233af6cd8..1022412292 100644 --- a/src/qml/qml/qqmltypeloader.cpp +++ b/src/qml/qml/qqmltypeloader.cpp @@ -2136,7 +2136,7 @@ const QList &QQmlTypeData::resolvedScripts() cons return m_scripts; } -QV4::CompiledData::CompilationUnit *QQmlTypeData::compilationUnit() const +QV4::ExecutableCompilationUnit *QQmlTypeData::compilationUnit() const { return m_compiledData.data(); } @@ -2166,7 +2166,7 @@ bool QQmlTypeData::tryLoadFromDiskCache() if (!v4) return false; - QQmlRefPointer unit = QV4::Compiler::Codegen::createUnitForLoading(); + QQmlRefPointer unit = QV4::ExecutableCompilationUnit::create(); { QString error; if (!unit->loadFromDisk(url(), m_backupSourceCode.sourceTimeStamp(), &error)) { @@ -2176,7 +2176,7 @@ bool QQmlTypeData::tryLoadFromDiskCache() } if (unit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation) { - restoreIR(unit); + restoreIR(std::move(*unit)); return true; } @@ -2232,8 +2232,9 @@ bool QQmlTypeData::tryLoadFromDiskCache() return true; } -void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer &typeNameCache, - const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache) +void QQmlTypeData::createTypeAndPropertyCaches( + const QQmlRefPointer &typeNameCache, + const QV4::ResolvedTypeReferenceMap &resolvedTypeCache) { Q_ASSERT(m_compiledData); m_compiledData->typeNameCache = typeNameCache; @@ -2244,9 +2245,9 @@ void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer propertyCacheCreator(&m_compiledData->propertyCaches, - &pendingGroupPropertyBindings, - engine, m_compiledData.data(), &m_importCache); + QQmlPropertyCacheCreator propertyCacheCreator( + &m_compiledData->propertyCaches, &pendingGroupPropertyBindings, engine, + m_compiledData.data(), &m_importCache); QQmlCompileError error = propertyCacheCreator.buildMetaObjects(); if (error.isSet()) { setError(error); @@ -2254,7 +2255,8 @@ void QQmlTypeData::createTypeAndPropertyCaches(const QQmlRefPointer aliasCreator(&m_compiledData->propertyCaches, m_compiledData.data()); + QQmlPropertyCacheAliasCreator aliasCreator( + &m_compiledData->propertyCaches, m_compiledData.data()); aliasCreator.appendAliasPropertiesToMetaObjects(); pendingGroupPropertyBindings.resolveMissingPropertyCaches(engine, &m_compiledData->propertyCaches); @@ -2346,7 +2348,7 @@ void QQmlTypeData::done() } QQmlRefPointer typeNameCache; - QV4::CompiledData::ResolvedTypeReferenceMap resolvedTypeCache; + QV4::ResolvedTypeReferenceMap resolvedTypeCache; { QQmlCompileError error = buildTypeResolutionCaches(&typeNameCache, &resolvedTypeCache); if (error.isSet()) { @@ -2509,7 +2511,7 @@ void QQmlTypeData::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) loader.load(); m_document->jsModule.fileName = urlString(); m_document->jsModule.finalUrl = finalUrlString(); - m_document->javaScriptCompilationUnit.adopt(new QV4::CompiledData::CompilationUnit(unit)); + m_document->javaScriptCompilationUnit = QV4::CompiledData::CompilationUnit(unit); continueLoadFromIR(); } @@ -2544,14 +2546,14 @@ bool QQmlTypeData::loadFromSource() return true; } -void QQmlTypeData::restoreIR(QQmlRefPointer unit) +void QQmlTypeData::restoreIR(QV4::CompiledData::CompilationUnit &&unit) { m_document.reset(new QmlIR::Document(isDebugging())); - QQmlIRLoader loader(unit->unitData(), m_document.data()); + QQmlIRLoader loader(unit.unitData(), m_document.data()); loader.load(); m_document->jsModule.fileName = urlString(); m_document->jsModule.finalUrl = finalUrlString(); - m_document->javaScriptCompilationUnit = unit; + m_document->javaScriptCompilationUnit = std::move(unit); continueLoadFromIR(); } @@ -2650,12 +2652,13 @@ QString QQmlTypeData::stringAt(int index) const } void QQmlTypeData::compile(const QQmlRefPointer &typeNameCache, - QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache, + QV4::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher) { Q_ASSERT(m_compiledData.isNull()); - const bool typeRecompilation = m_document && m_document->javaScriptCompilationUnit && m_document->javaScriptCompilationUnit->unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation; + const bool typeRecompilation = m_document && m_document->javaScriptCompilationUnit.unitData() + && (m_document->javaScriptCompilationUnit.unitData()->flags & QV4::CompiledData::Unit::PendingTypeCompilation); QQmlEnginePrivate * const enginePrivate = QQmlEnginePrivate::get(typeLoader()->engine()); QQmlTypeCompiler compiler(enginePrivate, this, m_document.data(), typeNameCache, resolvedTypeCache, dependencyHasher); @@ -2774,7 +2777,7 @@ void QQmlTypeData::resolveTypes() QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( QQmlRefPointer *typeNameCache, - QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache + QV4::ResolvedTypeReferenceMap *resolvedTypeCache ) const { typeNameCache->adopt(new QQmlTypeNameCache(m_importCache)); @@ -2791,7 +2794,7 @@ QQmlCompileError QQmlTypeData::buildTypeResolutionCaches( QQmlEnginePrivate * const engine = QQmlEnginePrivate::get(typeLoader()->engine()); for (auto resolvedType = m_resolvedTypes.constBegin(), end = m_resolvedTypes.constEnd(); resolvedType != end; ++resolvedType) { - QScopedPointer ref(new QV4::CompiledData::ResolvedTypeReference); + QScopedPointer ref(new QV4::ResolvedTypeReference); QQmlType qmlType = resolvedType->type; if (resolvedType->typeData) { if (resolvedType->needsCreation && qmlType.isCompositeSingleton()) { @@ -3022,7 +3025,8 @@ QQmlRefPointer QQmlScriptBlob::scriptData() const void QQmlScriptBlob::dataReceived(const SourceCodeData &data) { if (!disableDiskCache() || forceDiskCache()) { - QQmlRefPointer unit = QV4::Compiler::Codegen::createUnitForLoading(); + QQmlRefPointer unit + = QV4::ExecutableCompilationUnit::create(); QString error; if (unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) { initializeFromCompilationUnit(unit); @@ -3047,7 +3051,7 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) return; } - QQmlRefPointer unit; + QV4::CompiledData::CompilationUnit unit; if (m_isModule) { QList diagnostics; @@ -3067,44 +3071,43 @@ void QQmlScriptBlob::dataReceived(const SourceCodeData &data) irUnit.jsParserEngine.setDirectives(&collector); QList errors; - unit = QV4::Script::precompile( - &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(), - source, &errors, QV4::Compiler::ContextType::ScriptImportedByQML); - // No need to addref on unit, it's initial refcount is 1 + irUnit.javaScriptCompilationUnit = QV4::Script::precompile( + &irUnit.jsModule, &irUnit.jsParserEngine, &irUnit.jsGenerator, urlString(), finalUrlString(), + source, &errors, QV4::Compiler::ContextType::ScriptImportedByQML); + source.clear(); if (!errors.isEmpty()) { setError(errors); return; } - if (!unit) { - unit.adopt(new QV4::CompiledData::CompilationUnit); - } - irUnit.javaScriptCompilationUnit = unit; QmlIR::QmlUnitGenerator qmlGenerator; qmlGenerator.generate(irUnit); + unit = std::move(irUnit.javaScriptCompilationUnit); } + auto executableUnit = QV4::ExecutableCompilationUnit::create(std::move(unit)); + if ((!disableDiskCache() || forceDiskCache()) && !isDebugging()) { QString errorString; - if (unit->saveToDisk(url(), &errorString)) { + if (executableUnit->saveToDisk(url(), &errorString)) { QString error; - if (!unit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) { + if (!executableUnit->loadFromDisk(url(), data.sourceTimeStamp(), &error)) { // ignore error, keep using the in-memory compilation unit. } } else { - qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" << unit->fileName() << "to disk:" << errorString; + qCDebug(DBG_DISK_CACHE()) << "Error saving cached version of" + << executableUnit->fileName() << "to disk:" << errorString; } } - initializeFromCompilationUnit(unit); + initializeFromCompilationUnit(executableUnit); } void QQmlScriptBlob::initializeFromCachedUnit(const QV4::CompiledData::Unit *unit) { - QQmlRefPointer compilationUnit; - compilationUnit.adopt(new QV4::CompiledData::CompilationUnit(unit, urlString(), finalUrlString())); - initializeFromCompilationUnit(compilationUnit); + initializeFromCompilationUnit(QV4::ExecutableCompilationUnit::create( + QV4::CompiledData::CompilationUnit(unit, urlString(), finalUrlString()))); } void QQmlScriptBlob::done() @@ -3169,7 +3172,7 @@ void QQmlScriptBlob::scriptImported(const QQmlRefPointer &blob, m_scripts << ref; } -void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer &unit) +void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer &unit) { Q_ASSERT(!m_scriptData); m_scriptData.adopt(new QQmlScriptData()); @@ -3179,7 +3182,7 @@ void QQmlScriptBlob::initializeFromCompilationUnit(const QQmlRefPointer script = m_scriptData->m_precompiledScript; + QQmlRefPointer script = m_scriptData->m_precompiledScript; if (!m_isModule) { QList errors; diff --git a/src/qml/qml/qqmltypeloader_p.h b/src/qml/qml/qqmltypeloader_p.h index 987e47222d..d87812d48e 100644 --- a/src/qml/qml/qqmltypeloader_p.h +++ b/src/qml/qml/qqmltypeloader_p.h @@ -70,6 +70,7 @@ #include #include #include +#include #include #include @@ -453,7 +454,7 @@ public: const QList &resolvedScripts() const; - QV4::CompiledData::CompilationUnit *compilationUnit() const; + QV4::ExecutableCompilationUnit *compilationUnit() const; // Used by QQmlComponent to get notifications struct TypeDataCallback { @@ -477,18 +478,18 @@ protected: private: bool tryLoadFromDiskCache(); bool loadFromSource(); - void restoreIR(QQmlRefPointer unit); + void restoreIR(QV4::CompiledData::CompilationUnit &&unit); void continueLoadFromIR(); void resolveTypes(); QQmlCompileError buildTypeResolutionCaches( QQmlRefPointer *typeNameCache, - QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache + QV4::ResolvedTypeReferenceMap *resolvedTypeCache ) const; void compile(const QQmlRefPointer &typeNameCache, - QV4::CompiledData::ResolvedTypeReferenceMap *resolvedTypeCache, + QV4::ResolvedTypeReferenceMap *resolvedTypeCache, const QV4::CompiledData::DependentTypesHasher &dependencyHasher); void createTypeAndPropertyCaches(const QQmlRefPointer &typeNameCache, - const QV4::CompiledData::ResolvedTypeReferenceMap &resolvedTypeCache); + const QV4::ResolvedTypeReferenceMap &resolvedTypeCache); bool resolveType(const QString &typeName, int &majorVersion, int &minorVersion, TypeReference &ref, int lineNumber = -1, int columnNumber = -1, bool reportErrors = true, @@ -512,7 +513,7 @@ private: QMap m_resolvedTypes; bool m_typesResolved:1; - QQmlRefPointer m_compiledData; + QQmlRefPointer m_compiledData; QList m_callbacks; @@ -542,7 +543,7 @@ public: QV4::ReturnedValue scriptValueForContext(QQmlContextData *parentCtxt); - QQmlRefPointer compilationUnit() const { return m_precompiledScript; } + QQmlRefPointer compilationUnit() const { return m_precompiledScript; } protected: void clear() override; // From QQmlCleanup @@ -554,7 +555,7 @@ private: QQmlContextData *qmlContextDataForContext(QQmlContextData *parentQmlContextData); bool m_loaded; - QQmlRefPointer m_precompiledScript; + QQmlRefPointer m_precompiledScript; QV4::PersistentValue m_value; }; @@ -587,7 +588,7 @@ protected: private: void scriptImported(const QQmlRefPointer &blob, const QV4::CompiledData::Location &location, const QString &qualifier, const QString &nameSpace) override; - void initializeFromCompilationUnit(const QQmlRefPointer &unit); + void initializeFromCompilationUnit(const QQmlRefPointer &unit); QList m_scripts; QQmlRefPointer m_scriptData; diff --git a/src/qml/qml/qqmltypewrapper.cpp b/src/qml/qml/qqmltypewrapper.cpp index 236daac75c..9db089c330 100644 --- a/src/qml/qml/qqmltypewrapper.cpp +++ b/src/qml/qml/qqmltypewrapper.cpp @@ -418,7 +418,7 @@ ReturnedValue QQmlTypeWrapper::virtualInstanceOf(const Object *typeObject, const return Encode(false); QQmlRefPointer td = qenginepriv->typeLoader.getType(typeWrapper->d()->type().sourceUrl()); - CompiledData::CompilationUnit *cu = td->compilationUnit(); + ExecutableCompilationUnit *cu = td->compilationUnit(); myQmlType = qenginepriv->metaObjectForType(cu->metaTypeId); } else { myQmlType = qenginepriv->metaObjectForType(myTypeId); diff --git a/src/qml/qml/qqmlvmemetaobject.cpp b/src/qml/qml/qqmlvmemetaobject.cpp index 5d13415513..2881e71805 100644 --- a/src/qml/qml/qqmlvmemetaobject.cpp +++ b/src/qml/qml/qqmlvmemetaobject.cpp @@ -316,7 +316,7 @@ QAbstractDynamicMetaObject *QQmlInterceptorMetaObject::toDynamicMetaObject(QObje QQmlVMEMetaObject::QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj, - const QQmlRefPointer &cache, const QQmlRefPointer &qmlCompilationUnit, int qmlObjectId) + const QQmlRefPointer &cache, const QQmlRefPointer &qmlCompilationUnit, int qmlObjectId) : QQmlInterceptorMetaObject(obj, cache), engine(engine), ctxt(QQmlData::get(obj, true)->outerContext), diff --git a/src/qml/qml/qqmlvmemetaobject_p.h b/src/qml/qml/qqmlvmemetaobject_p.h index 2371d70f10..5025987586 100644 --- a/src/qml/qml/qqmlvmemetaobject_p.h +++ b/src/qml/qml/qqmlvmemetaobject_p.h @@ -144,7 +144,7 @@ class QQmlVMEMetaObjectEndpoint; class Q_QML_PRIVATE_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject { public: - QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj, const QQmlRefPointer &cache, const QQmlRefPointer &qmlCompilationUnit, int qmlObjectId); + QQmlVMEMetaObject(QV4::ExecutionEngine *engine, QObject *obj, const QQmlRefPointer &cache, const QQmlRefPointer &qmlCompilationUnit, int qmlObjectId); ~QQmlVMEMetaObject() override; bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const; @@ -226,7 +226,7 @@ public: // keep a reference to the compilation unit in order to still // do property access when the context has been invalidated. - QQmlRefPointer compilationUnit; + QQmlRefPointer compilationUnit; const QV4::CompiledData::Object *compiledObject; }; diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp index 532bfa8754..4838ef3814 100644 --- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp +++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp @@ -1950,7 +1950,8 @@ ReturnedValue GlobalExtensions::method_qsTr(const FunctionObject *b, const Value CppStackFrame *frame = scope.engine->currentStackFrame; // The first non-empty source URL in the call stack determines the translation context. while (frame && context.isEmpty()) { - if (CompiledData::CompilationUnit *unit = frame->v4Function->compilationUnit) { + if (CompiledData::CompilationUnitBase *baseUnit = frame->v4Function->compilationUnit) { + const auto *unit = static_cast(baseUnit); QString fileName = unit->fileName(); QUrl url(unit->fileName()); if (url.isValid() && url.isRelative()) { diff --git a/src/qml/types/qqmlconnections.cpp b/src/qml/types/qqmlconnections.cpp index f601087690..8ec754a9df 100644 --- a/src/qml/types/qqmlconnections.cpp +++ b/src/qml/types/qqmlconnections.cpp @@ -66,7 +66,7 @@ public: bool ignoreUnknownSignals; bool componentcomplete; - QQmlRefPointer compilationUnit; + QQmlRefPointer compilationUnit; QList bindings; }; @@ -231,7 +231,7 @@ void QQmlConnections::setIgnoreUnknownSignals(bool ignore) d->ignoreUnknownSignals = ignore; } -void QQmlConnectionsParser::verifyBindings(const QQmlRefPointer &compilationUnit, const QList &props) +void QQmlConnectionsParser::verifyBindings(const QQmlRefPointer &compilationUnit, const QList &props) { for (int ii = 0; ii < props.count(); ++ii) { const QV4::CompiledData::Binding *binding = props.at(ii); @@ -256,7 +256,7 @@ void QQmlConnectionsParser::verifyBindings(const QQmlRefPointer &compilationUnit, const QList &bindings) +void QQmlConnectionsParser::applyBindings(QObject *object, const QQmlRefPointer &compilationUnit, const QList &bindings) { QQmlConnectionsPrivate *p = static_cast(QObjectPrivate::get(object)); diff --git a/src/qml/types/qqmlconnections_p.h b/src/qml/types/qqmlconnections_p.h index bd03d7e152..f6ad1eb46c 100644 --- a/src/qml/types/qqmlconnections_p.h +++ b/src/qml/types/qqmlconnections_p.h @@ -98,8 +98,8 @@ private: class QQmlConnectionsParser : public QQmlCustomParser { public: - void verifyBindings(const QQmlRefPointer &compilationUnit, const QList &props) override; - void applyBindings(QObject *object, const QQmlRefPointer &compilationUnit, const QList &bindings) override; + void verifyBindings(const QQmlRefPointer &compilationUnit, const QList &props) override; + void applyBindings(QObject *object, const QQmlRefPointer &compilationUnit, const QList &bindings) override; }; -- cgit v1.2.3 From ae1c2375f596258c878933adc46a19a541a43a6c Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 13 May 2019 11:07:39 +0200 Subject: Add abstraction for temporarily setting StaticData when saving The StaticData flag needs to be saved to disk, but removed again afterwards so that we can free() the malloc'd data. This also allows us to avoid copying all the data into a byte array before saving. Change-Id: I96513f8d98acf0ea0b4514d96376b487e8444917 Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlirbuilder.cpp | 3 --- src/qml/compiler/qv4compileddata.cpp | 19 +++------------- src/qml/compiler/qv4compileddata_p.h | 43 ++++++++++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 19 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index e63aa3b66d..6f46648572 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -1565,9 +1565,6 @@ void QmlUnitGenerator::generate(Document &output, const QV4::CompiledData::Depen break; } } - // This unit's memory was allocated with malloc on the heap, so it's - // definitely not suitable for StaticData access. - createdUnit->flags &= ~QV4::CompiledData::Unit::StaticData; if (dependencyHasher) { const QByteArray checksum = dependencyHasher(); diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 091c29c8c7..71015107ad 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -82,14 +82,8 @@ CompilationUnit::~CompilationUnit() free(const_cast(qmlData)); qmlData = nullptr; -#ifndef V4_BOOTSTRAP if (!(data->flags & QV4::CompiledData::Unit::StaticData)) free(const_cast(data)); -#else - // Unconditionally free the memory. In the dev tools we create units that have - // the flag set and will be saved to disk, so intended to persist later. - free(const_cast(data)); -#endif } data = nullptr; #if Q_BYTE_ORDER == Q_BIG_ENDIAN @@ -113,16 +107,9 @@ bool CompilationUnit::saveToDisk(const QString &outputFileName, QString *errorSt return false; } - QByteArray modifiedUnit; - modifiedUnit.resize(data->unitSize); - memcpy(modifiedUnit.data(), data, data->unitSize); - const char *dataPtr = modifiedUnit.data(); - Unit *unitPtr; - memcpy(&unitPtr, &dataPtr, sizeof(unitPtr)); - unitPtr->flags |= Unit::StaticData; - - qint64 headerWritten = cacheFile.write(modifiedUnit); - if (headerWritten != modifiedUnit.size()) { + SaveableUnitPointer saveable(this); + qint64 headerWritten = cacheFile.write(saveable.data(), saveable.size()); + if (headerWritten != saveable.size()) { *errorString = cacheFile.errorString(); return false; } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 9301939bff..629adf8231 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -1158,6 +1158,49 @@ public: bool saveToDisk(const QString &outputFileName, QString *errorString) const; }; +class SaveableUnitPointer +{ + Q_DISABLE_COPY_MOVE(SaveableUnitPointer) +public: + SaveableUnitPointer(const CompilationUnit *unit, quint32 temporaryFlags = Unit::StaticData) : + unit(unit) + { + quint32_le &unitFlags = mutableFlags(); + quint32 origFlags = unitFlags; + unitFlags |= temporaryFlags; + changedFlags = origFlags ^ unitFlags; + } + + ~SaveableUnitPointer() + { + mutableFlags() ^= changedFlags; + } + + const CompilationUnit *operator->() const { return unit; } + const CompilationUnit &operator*() const { return *unit; } + operator const CompilationUnit *() { return unit; } + + template + const Char *data() const + { + Q_STATIC_ASSERT(sizeof(Char) == 1); + const Char *dataPtr; + memcpy(&dataPtr, &unit->data, sizeof(dataPtr)); + return dataPtr; + } + + quint32 size() const + { + return unit->data->unitSize; + } + +private: + quint32_le &mutableFlags() { return const_cast(unit->unitData())->flags; }; + const CompilationUnit *unit; + quint32 changedFlags; +}; + + } // CompiledData namespace } // QV4 namespace -- cgit v1.2.3 From bc9f502d5ff7b6fc874f0e65019f7967916eab11 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 9 May 2019 14:01:58 +0200 Subject: Inline dumpConstantTable() into the only place where it's used ... and don't copy byte arrays around for each character of padding prepended to a number. Change-Id: I6963d4c9d42aedd780bec9517b4b7a2a83f10185 Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4executablecompilationunit.cpp | 27 ++++++++++++++++++- src/qml/compiler/qv4instr_moth.cpp | 33 +---------------------- src/qml/compiler/qv4instr_moth_p.h | 1 - 3 files changed, 27 insertions(+), 34 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qv4executablecompilationunit.cpp b/src/qml/compiler/qv4executablecompilationunit.cpp index 432e0c5e37..88e5c1dc0e 100644 --- a/src/qml/compiler/qv4executablecompilationunit.cpp +++ b/src/qml/compiler/qv4executablecompilationunit.cpp @@ -87,6 +87,31 @@ QString ExecutableCompilationUnit::localCacheFilePath(const QUrl &url) return directory + QString::fromUtf8(fileNameHash.result().toHex()) + QLatin1Char('.') + cacheFileSuffix; } +static QString toString(QV4::ReturnedValue v) +{ + Value val = Value::fromReturnedValue(v); + QString result; + if (val.isInt32()) + result = QLatin1String("int "); + else if (val.isDouble()) + result = QLatin1String("double "); + if (val.isEmpty()) + result += QLatin1String("empty"); + else + result += val.toQStringNoThrow(); + return result; +} + +static void dumpConstantTable(const Value *constants, uint count) +{ + QDebug d = qDebug(); + d.nospace() << right; + for (uint i = 0; i < count; ++i) { + d << qSetFieldWidth(8) << i << qSetFieldWidth(0) << ": " + << toString(constants[i].asReturnedValue()).toUtf8().constData() << "\n"; + } +} + QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine) { this->engine = engine; @@ -185,7 +210,7 @@ QV4::Function *ExecutableCompilationUnit::linkToEngine(ExecutionEngine *engine) static const bool showCode = qEnvironmentVariableIsSet("QV4_SHOW_BYTECODE"); if (showCode) { qDebug() << "=== Constant table"; - Moth::dumpConstantTable(constants, data->constantTableSize); + dumpConstantTable(constants, data->constantTableSize); qDebug() << "=== String table"; for (uint i = 0, end = totalStringCount(); i < end; ++i) qDebug() << " " << i << ":" << runtimeStrings[i]->toQString(); diff --git a/src/qml/compiler/qv4instr_moth.cpp b/src/qml/compiler/qv4instr_moth.cpp index 5b637ea567..8a9bd66103 100644 --- a/src/qml/compiler/qv4instr_moth.cpp +++ b/src/qml/compiler/qv4instr_moth.cpp @@ -56,9 +56,7 @@ int InstrInfo::size(Instr::Type type) static QByteArray alignedNumber(int n) { QByteArray number = QByteArray::number(n); - while (number.size() < 8) - number.prepend(' '); - return number; + return number.prepend(8 - number.size(), ' '); } static QByteArray alignedLineNumber(int line) { @@ -83,25 +81,6 @@ static QByteArray rawBytes(const char *data, int n) return ba; } -static QString toString(QV4::ReturnedValue v) -{ -#ifdef V4_BOOTSTRAP - return QStringLiteral("string-const(%1)").arg(v); -#else // !V4_BOOTSTRAP - Value val = Value::fromReturnedValue(v); - QString result; - if (val.isInt32()) - result = QLatin1String("int "); - else if (val.isDouble()) - result = QLatin1String("double "); - if (val.isEmpty()) - result += QLatin1String("empty"); - else - result += val.toQStringNoThrow(); - return result; -#endif // V4_BOOTSTRAP -} - #define ABSOLUTE_OFFSET() \ (code - start + offset) @@ -128,16 +107,6 @@ const int InstrInfo::argumentCount[] = { FOR_EACH_MOTH_INSTR_ALL(MOTH_COLLECT_NARGS) }; - -void dumpConstantTable(const Value *constants, uint count) -{ - QDebug d = qDebug(); - d.nospace(); - for (uint i = 0; i < count; ++i) - d << alignedNumber(int(i)).constData() << ": " - << toString(constants[i].asReturnedValue()).toUtf8().constData() << "\n"; -} - QString dumpRegister(int reg, int nFormals) { Q_STATIC_ASSERT(offsetof(CallData, function) == 0); diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index 35a5fdfba5..e517c6d8b9 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -534,7 +534,6 @@ inline bool operator!=(const StackSlot &l, const StackSlot &r) { return l.stackS // When making changes to the instructions, make sure to bump QV4_DATA_STRUCTURE_VERSION in qv4compileddata_p.h -void dumpConstantTable(const Value *constants, uint count); void dumpBytecode(const char *bytecode, int len, int nLocals, int nFormals, int startLine = 1, const QVector &lineNumberMapping = QVector()); inline void dumpBytecode(const QByteArray &bytecode, int nLocals, int nFormals, int startLine = 1, -- cgit v1.2.3 From f38e071f5b353cbf9ce6c6c104bd82099ae0aa14 Mon Sep 17 00:00:00 2001 From: Erik Verbruggen Date: Mon, 29 Apr 2019 10:42:00 +0200 Subject: Restore value bindings when disabling a Binding element We previously only restored script bindings that were replaced by a Binding. Now we handle both. [ChangeLog] QML Binding elements now support restoring previous values of the bound property when the binding is disabled. This will be the default behavior in Qt 5.15. Reliance on the old behavior of only restoring binding, not literal values results in a warning now. Fixes: QTBUG-33444 Change-Id: I833403b0645c08eee486fbd4acf5d3c7de2ef73a Reviewed-by: Michael Brasser --- src/qml/qml/qqmlengine.cpp | 1 + src/qml/types/qqmlbind.cpp | 142 +++++++++++++++++++++++++++++++++++++++++++-- src/qml/types/qqmlbind_p.h | 18 ++++++ 3 files changed, 156 insertions(+), 5 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp index 8faace521a..f977934b3e 100644 --- a/src/qml/qml/qqmlengine.cpp +++ b/src/qml/qml/qqmlengine.cpp @@ -204,6 +204,7 @@ void QQmlEnginePrivate::defineModule() qmlRegisterType(uri, 2, 0, "QtObject"); qmlRegisterType(uri, 2, 0, "Binding"); qmlRegisterType(uri, 2, 8, "Binding"); // Only available in >= 2.8 + qmlRegisterType(uri, 2, 14, "Binding"); qmlRegisterCustomType(uri, 2, 0, "Connections", new QQmlConnectionsParser); qmlRegisterCustomType(uri, 2, 3, "Connections", new QQmlConnectionsParser); // Only available in QtQml >= 2.3 #if QT_CONFIG(qml_animation) diff --git a/src/qml/types/qqmlbind.cpp b/src/qml/types/qqmlbind.cpp index 513f7f2997..1ba015f796 100644 --- a/src/qml/types/qqmlbind.cpp +++ b/src/qml/types/qqmlbind.cpp @@ -43,6 +43,8 @@ #include #include #include +#include +#include #include #include @@ -60,7 +62,21 @@ QT_BEGIN_NAMESPACE class QQmlBindPrivate : public QObjectPrivate { public: - QQmlBindPrivate() : obj(nullptr), componentComplete(true), delayed(false), pendingEval(false) {} + QQmlBindPrivate() + : obj(nullptr) + , prevBind(QQmlAbstractBinding::Ptr()) + , prevIsVariant(false) + , componentComplete(true) + , delayed(false) + , pendingEval(false) + , restoreBinding(true) +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + , restoreValue(false) + , restoreModeExplicit(false) +#else + , restoreValue(true) +#endif + {} ~QQmlBindPrivate() { } QQmlNullableValue when; @@ -69,11 +85,20 @@ public: QQmlNullableValue value; QQmlProperty prop; QQmlAbstractBinding::Ptr prevBind; + QV4::PersistentValue v4Value; + QVariant prevValue; + bool prevIsVariant:1; bool componentComplete:1; bool delayed:1; bool pendingEval:1; + bool restoreBinding:1; + bool restoreValue:1; +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + bool restoreModeExplicit:1; +#endif void validate(QObject *binding) const; + void clearPrev(); }; void QQmlBindPrivate::validate(QObject *binding) const @@ -323,6 +348,57 @@ void QQmlBind::setDelayed(bool delayed) eval(); } +/*! + \qmlproperty enumeration QtQml::Binding::restoreMode + \since 5.14 + + This property can be used to describe if and how the original value should + be restored when the binding is disabled. + + The possible values are: + \list + \li Binding.RestoreNone The original value is not restored at all + \li Binding.RestoreBinding The original value is restored if it was another + binding. In that case the old binding is in effect again. + \li Binding.RestoreValue The original value is restored if it was a plain + value rather than a binding. + \li Binding.RestoreBindingOrValue The original value is always restored. + \list + + \warning The default value is Binding.RestoreBinding. This will change in + Qt 5.15 to Binding.RestoreBindingOrValue. + + If you rely on any specific behavior regarding the restoration of plain + values when bindings get disabled you should migrate to explicitly set the + restoreMode. + + Reliance on a restoreMode that doesn't restore the previous binding or value + for a specific property results in a run-time warning. +*/ +QQmlBind::RestorationMode QQmlBind::restoreMode() const +{ + Q_D(const QQmlBind); + unsigned result = RestoreNone; + if (d->restoreValue) + result |= RestoreValue; + if (d->restoreBinding) + result |= RestoreBinding; + return RestorationMode(result); +} + +void QQmlBind::setRestoreMode(RestorationMode newMode) +{ + Q_D(QQmlBind); + if (newMode != restoreMode()) { + d->restoreValue = (newMode & RestoreValue); + d->restoreBinding = (newMode & RestoreBinding); +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + d->restoreModeExplicit = true; +#endif + emit restoreModeChanged(); + } +} + void QQmlBind::setTarget(const QQmlProperty &p) { Q_D(QQmlBind); @@ -358,6 +434,14 @@ void QQmlBind::prepareEval() } } +void QQmlBindPrivate::clearPrev() +{ + prevBind = nullptr; + v4Value.clear(); + prevValue.clear(); + prevIsVariant = false; +} + void QQmlBind::eval() { Q_D(QQmlBind); @@ -369,16 +453,64 @@ void QQmlBind::eval() if (!d->when) { //restore any previous binding if (d->prevBind) { - QQmlAbstractBinding::Ptr p = d->prevBind; - d->prevBind = nullptr; - QQmlPropertyPrivate::setBinding(p.data()); + if (d->restoreBinding) { + QQmlAbstractBinding::Ptr p = d->prevBind; + d->clearPrev(); // Do that before setBinding(), as setBinding() may recurse. + QQmlPropertyPrivate::setBinding(p.data()); + } + } else if (!d->v4Value.isEmpty()) { + if (d->restoreValue) { + auto propPriv = QQmlPropertyPrivate::get(d->prop); + QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object); + Q_ASSERT(vmemo); + vmemo->setVMEProperty(propPriv->core.coreIndex(), *d->v4Value.valueRef()); + d->clearPrev(); +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + } else if (!d->restoreModeExplicit) { + qmlWarning(this) + << "Not restoring previous value because restoreMode has not been set." + << "This behavior is deprecated." + << "In Qt < 5.15 the default is Binding.RestoreBinding." + << "In Qt >= 5.15 the default is Binding.RestoreBindingOrValue."; +#endif + } + } else if (d->prevIsVariant) { + if (d->restoreValue) { + d->prop.write(d->prevValue); + d->clearPrev(); +#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) + } else if (!d->restoreModeExplicit) { + qmlWarning(this) + << "Not restoring previous value because restoreMode has not been set." + << "This behavior is deprecated." + << "In Qt < 5.15 the default is Binding.RestoreBinding." + << "In Qt >= 5.15 the default is Binding.RestoreBindingOrValue."; +#endif + } } return; } //save any set binding for restoration - if (!d->prevBind) + if (!d->prevBind && d->v4Value.isEmpty() && !d->prevIsVariant) { + // try binding first d->prevBind = QQmlPropertyPrivate::binding(d->prop); + + if (!d->prevBind) { // nope, try a V4 value next + auto propPriv = QQmlPropertyPrivate::get(d->prop); + auto propData = propPriv->core; + if (!propPriv->valueTypeData.isValid() && propData.isVarProperty()) { + QQmlVMEMetaObject *vmemo = QQmlVMEMetaObject::get(propPriv->object); + Q_ASSERT(vmemo); + auto retVal = vmemo->vmeProperty(propData.coreIndex()); + d->v4Value = QV4::PersistentValue(vmemo->engine, retVal); + } else { // nope, use the meta object to get a QVariant + d->prevValue = d->prop.read(); + d->prevIsVariant = true; + } + } + } + QQmlPropertyPrivate::removeBinding(d->prop); } diff --git a/src/qml/types/qqmlbind_p.h b/src/qml/types/qqmlbind_p.h index 5bf9ef85c6..22007a3d25 100644 --- a/src/qml/types/qqmlbind_p.h +++ b/src/qml/types/qqmlbind_p.h @@ -60,6 +60,15 @@ QT_BEGIN_NAMESPACE class QQmlBindPrivate; class Q_AUTOTEST_EXPORT QQmlBind : public QObject, public QQmlPropertyValueSource, public QQmlParserStatus { +public: + enum RestorationMode { + RestoreNone = 0x0, + RestoreBinding = 0x1, + RestoreValue = 0x2, + RestoreBindingOrValue = RestoreBinding | RestoreValue + }; + +private: Q_OBJECT Q_DECLARE_PRIVATE(QQmlBind) Q_INTERFACES(QQmlParserStatus) @@ -69,6 +78,9 @@ class Q_AUTOTEST_EXPORT QQmlBind : public QObject, public QQmlPropertyValueSourc Q_PROPERTY(QVariant value READ value WRITE setValue) Q_PROPERTY(bool when READ when WRITE setWhen) Q_PROPERTY(bool delayed READ delayed WRITE setDelayed REVISION 8) + Q_PROPERTY(RestorationMode restoreMode READ restoreMode WRITE setRestoreMode + NOTIFY restoreModeChanged REVISION 14) + Q_ENUM(RestorationMode) public: QQmlBind(QObject *parent=nullptr); @@ -89,6 +101,12 @@ public: bool delayed() const; void setDelayed(bool); + RestorationMode restoreMode() const; + void setRestoreMode(RestorationMode); + +Q_SIGNALS: + void restoreModeChanged(); + protected: void setTarget(const QQmlProperty &) override; void classBegin() override; -- cgit v1.2.3 From 510378d180cdaa85be47e7e3af6844d20e772037 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Mon, 6 May 2019 13:50:06 +0200 Subject: Remove QUrl-related special casing in the compiler QUrl is being added to the bootstrap set. Change-Id: Ia96bbcf6e0ef808435ecddfa114fdcd213361bbf Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4codegen.cpp | 9 +-------- src/qml/compiler/qv4codegen_p.h | 2 -- 2 files changed, 1 insertion(+), 10 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index d17d58588c..b145ceb51e 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -53,10 +53,7 @@ #include #include #include - -#ifndef V4_BOOTSTRAP -# include -#endif +#include #include #include @@ -3947,8 +3944,6 @@ Codegen::VolatileMemoryLocations Codegen::scanVolatileMemoryLocations(AST::Node } -#ifndef V4_BOOTSTRAP - QList Codegen::qmlErrors() const { QList qmlErrors; @@ -3972,8 +3967,6 @@ QList Codegen::qmlErrors() const return qmlErrors; } -#endif // V4_BOOTSTRAP - bool Codegen::RValue::operator==(const RValue &other) const { switch (type) { diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index 8cf56b6cb7..e519da0142 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -662,9 +662,7 @@ protected: public: QList errors() const; -#ifndef V4_BOOTSTRAP QList qmlErrors() const; -#endif Reference binopHelper(QSOperator::Op oper, Reference &left, Reference &right); Reference jumpBinop(QSOperator::Op oper, Reference &left, Reference &right); -- cgit v1.2.3 From 540134d66dd0a235ace91ddc28940d2d88c24ac3 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 10 May 2019 15:48:50 +0200 Subject: Move valueAsNumber into ExecutableCompilationUnit This reduces our dependence on QV4::Value in the devtools. Change-Id: I4b3f937bc08c16f7e2543fdc5cc34c0cfb121f8f Reviewed-by: Simon Hausmann --- src/qml/compiler/qqmlpropertyvalidator.cpp | 6 +++--- src/qml/compiler/qv4compileddata_p.h | 8 -------- src/qml/compiler/qv4executablecompilationunit.cpp | 2 +- src/qml/compiler/qv4executablecompilationunit_p.h | 6 ++++++ src/qml/compiler/qv4instr_moth_p.h | 1 - src/qml/qml/qqmlobjectcreator.cpp | 18 +++++++++--------- 6 files changed, 19 insertions(+), 22 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qqmlpropertyvalidator.cpp b/src/qml/compiler/qqmlpropertyvalidator.cpp index 5b0bd8858a..71d5318652 100644 --- a/src/qml/compiler/qqmlpropertyvalidator.cpp +++ b/src/qml/compiler/qqmlpropertyvalidator.cpp @@ -397,7 +397,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache break; case QVariant::UInt: { if (binding->type == QV4::CompiledData::Binding::Type_Number) { - double d = binding->valueAsNumber(compilationUnit->constants); + double d = compilationUnit->bindingValueAsNumber(binding); if (double(uint(d)) == d) return noError; } @@ -406,7 +406,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache break; case QVariant::Int: { if (binding->type == QV4::CompiledData::Binding::Type_Number) { - double d = binding->valueAsNumber(compilationUnit->constants); + double d = compilationUnit->bindingValueAsNumber(binding); if (double(int(d)) == d) return noError; } @@ -571,7 +571,7 @@ QQmlCompileError QQmlPropertyValidator::validateLiteralBinding(QQmlPropertyCache } else if (property->propType() == qMetaTypeId >()) { bool ok = (binding->type == QV4::CompiledData::Binding::Type_Number); if (ok) { - double n = binding->valueAsNumber(compilationUnit->constants); + double n = compilationUnit->bindingValueAsNumber(binding); if (double(int(n)) != n) ok = false; } diff --git a/src/qml/compiler/qv4compileddata_p.h b/src/qml/compiler/qv4compileddata_p.h index 629adf8231..94b64694ae 100644 --- a/src/qml/compiler/qv4compileddata_p.h +++ b/src/qml/compiler/qv4compileddata_p.h @@ -57,7 +57,6 @@ #include #include -#include #include #include #include @@ -522,13 +521,6 @@ struct Q_QML_PRIVATE_EXPORT Binding bool isTranslationBinding() const { return type == Type_Translation || type == Type_TranslationById; } bool evaluatesToString() const { return type == Type_String || isTranslationBinding(); } - double valueAsNumber(const Value *constantTable) const - { - if (type != Type_Number) - return 0.0; - return constantTable[value.constantValueIndex].doubleValue(); - } - bool valueAsBoolean() const { if (type == Type_Boolean) diff --git a/src/qml/compiler/qv4executablecompilationunit.cpp b/src/qml/compiler/qv4executablecompilationunit.cpp index 88e5c1dc0e..97c828d4d8 100644 --- a/src/qml/compiler/qv4executablecompilationunit.cpp +++ b/src/qml/compiler/qv4executablecompilationunit.cpp @@ -760,7 +760,7 @@ QString ExecutableCompilationUnit::bindingValueAsString(const CompiledData::Bind case Binding::Type_Boolean: return binding->value.b ? QStringLiteral("true") : QStringLiteral("false"); case Binding::Type_Number: - return QString::number(binding->valueAsNumber(constants)); + return QString::number(bindingValueAsNumber(binding)); case Binding::Type_Invalid: return QString(); #if !QT_CONFIG(translation) diff --git a/src/qml/compiler/qv4executablecompilationunit_p.h b/src/qml/compiler/qv4executablecompilationunit_p.h index dd3918cc84..4e3aadf28a 100644 --- a/src/qml/compiler/qv4executablecompilationunit_p.h +++ b/src/qml/compiler/qv4executablecompilationunit_p.h @@ -244,6 +244,12 @@ public: QString bindingValueAsString(const CompiledData::Binding *binding) const; QString bindingValueAsScriptString(const CompiledData::Binding *binding) const; + double bindingValueAsNumber(const CompiledData::Binding *binding) const + { + if (binding->type != CompiledData::Binding::Type_Number) + return 0.0; + return constants[binding->value.constantValueIndex].doubleValue(); + } protected: quint32 totalStringCount() const diff --git a/src/qml/compiler/qv4instr_moth_p.h b/src/qml/compiler/qv4instr_moth_p.h index e517c6d8b9..5338583164 100644 --- a/src/qml/compiler/qv4instr_moth_p.h +++ b/src/qml/compiler/qv4instr_moth_p.h @@ -51,7 +51,6 @@ // We mean it. // #include -#include #include #include // for CompiledData::CodeOffsetToLine used by the dumper #include diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index 177c0d38bd..e5f376fd34 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -406,7 +406,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const switch (propertyType) { case QMetaType::QVariant: { if (binding->type == QV4::CompiledData::Binding::Type_Number) { - double n = binding->valueAsNumber(compilationUnit->constants); + double n = compilationUnit->bindingValueAsNumber(binding); if (double(int(n)) == n) { if (property->isVarProperty()) { _vmeMetaObject->setVMEProperty(property->coreIndex(), QV4::Value::fromInt32(int(n))); @@ -481,7 +481,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const break; case QVariant::UInt: { assertType(QV4::CompiledData::Binding::Type_Number); - double d = binding->valueAsNumber(compilationUnit->constants); + double d = compilationUnit->bindingValueAsNumber(binding); uint value = uint(d); property->writeProperty(_qobject, &value, propertyWriteFlags); break; @@ -489,7 +489,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const break; case QVariant::Int: { assertType(QV4::CompiledData::Binding::Type_Number); - double d = binding->valueAsNumber(compilationUnit->constants); + double d = compilationUnit->bindingValueAsNumber(binding); int value = int(d); property->writeProperty(_qobject, &value, propertyWriteFlags); break; @@ -497,13 +497,13 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const break; case QMetaType::Float: { assertType(QV4::CompiledData::Binding::Type_Number); - float value = float(binding->valueAsNumber(compilationUnit->constants)); + float value = float(compilationUnit->bindingValueAsNumber(binding)); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; case QVariant::Double: { assertType(QV4::CompiledData::Binding::Type_Number); - double value = binding->valueAsNumber(compilationUnit->constants); + double value = compilationUnit->bindingValueAsNumber(binding); property->writeProperty(_qobject, &value, propertyWriteFlags); } break; @@ -651,12 +651,12 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const if (property->propType() == qMetaTypeId >()) { assertType(QV4::CompiledData::Binding::Type_Number); QList value; - value.append(binding->valueAsNumber(compilationUnit->constants)); + value.append(compilationUnit->bindingValueAsNumber(binding)); property->writeProperty(_qobject, &value, propertyWriteFlags); break; } else if (property->propType() == qMetaTypeId >()) { assertType(QV4::CompiledData::Binding::Type_Number); - double n = binding->valueAsNumber(compilationUnit->constants); + double n = compilationUnit->bindingValueAsNumber(binding); QList value; value.append(int(n)); property->writeProperty(_qobject, &value, propertyWriteFlags); @@ -687,7 +687,7 @@ void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const if (binding->type == QV4::CompiledData::Binding::Type_Boolean) { value = QJSValue(binding->valueAsBoolean()); } else if (binding->type == QV4::CompiledData::Binding::Type_Number) { - double n = binding->valueAsNumber(compilationUnit->constants); + double n = compilationUnit->bindingValueAsNumber(binding); if (double(int(n)) == n) { value = QJSValue(int(n)); } else @@ -842,7 +842,7 @@ bool QQmlObjectCreator::setPropertyBinding(const QQmlPropertyData *bindingProper ss.d.data()->columnNumber = binding->location.column; ss.d.data()->isStringLiteral = binding->type == QV4::CompiledData::Binding::Type_String; ss.d.data()->isNumberLiteral = binding->type == QV4::CompiledData::Binding::Type_Number; - ss.d.data()->numberValue = binding->valueAsNumber(compilationUnit->constants); + ss.d.data()->numberValue = compilationUnit->bindingValueAsNumber(binding); QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite; -- cgit v1.2.3 From 32e3cb51d9849f3731f3db1c412892c4dc2309d8 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 9 May 2019 11:52:31 +0200 Subject: Remove V4_BOOTSTRAP condition around header verification It's unclear why that was needed. Change-Id: I0b4d4ebe1992cd2252cfc3eb10baa7f1b3ae1a5a Reviewed-by: Simon Hausmann --- src/qml/compiler/qv4compileddata.cpp | 6 ------ 1 file changed, 6 deletions(-) (limited to 'src/qml') diff --git a/src/qml/compiler/qv4compileddata.cpp b/src/qml/compiler/qv4compileddata.cpp index 71015107ad..0fed0a03b2 100644 --- a/src/qml/compiler/qv4compileddata.cpp +++ b/src/qml/compiler/qv4compileddata.cpp @@ -230,7 +230,6 @@ void Unit::generateChecksum() bool Unit::verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) const { -#ifndef V4_BOOTSTRAP if (strncmp(magic, CompiledData::magic_str, sizeof(magic))) { *errorString = QStringLiteral("Magic bytes in the header do not match"); return false; @@ -268,11 +267,6 @@ bool Unit::verifyHeader(QDateTime expectedSourceTimeStamp, QString *errorString) #endif return true; -#else - Q_UNUSED(expectedSourceTimeStamp) - Q_UNUSED(errorString) - return false; -#endif } Location &Location::operator=(const QQmlJS::AST::SourceLocation &astLocation) -- cgit v1.2.3 From dc68b297ca9007e6ea9d96a23a58316c5aae0eb1 Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Fri, 10 May 2019 14:58:28 +0200 Subject: Remove now dead V4_BOOTSTRAP #if-ery Change-Id: I04f8f69ed8ee415ca330e2f7beeffc4ee4c38e65 Reviewed-by: Simon Hausmann --- src/qml/jsruntime/qv4enginebase_p.h | 3 --- src/qml/jsruntime/qv4lookup_p.h | 3 --- src/qml/jsruntime/qv4object_p.h | 2 -- src/qml/jsruntime/qv4stackframe_p.h | 4 ---- src/qml/jsruntime/qv4string.cpp | 6 ------ src/qml/jsruntime/qv4string_p.h | 11 ----------- 6 files changed, 29 deletions(-) (limited to 'src/qml') diff --git a/src/qml/jsruntime/qv4enginebase_p.h b/src/qml/jsruntime/qv4enginebase_p.h index 00876c71a2..788897bdad 100644 --- a/src/qml/jsruntime/qv4enginebase_p.h +++ b/src/qml/jsruntime/qv4enginebase_p.h @@ -147,10 +147,7 @@ Q_STATIC_ASSERT(offsetof(EngineBase, jsStackTop) == offsetof(EngineBase, current Q_STATIC_ASSERT(offsetof(EngineBase, hasException) == offsetof(EngineBase, jsStackTop) + QT_POINTER_SIZE); Q_STATIC_ASSERT(offsetof(EngineBase, memoryManager) == offsetof(EngineBase, hasException) + 8); Q_STATIC_ASSERT(offsetof(EngineBase, runtime) == offsetof(EngineBase, memoryManager) + QT_POINTER_SIZE); - -#ifndef V4_BOOTSTRAP Q_STATIC_ASSERT(offsetof(EngineBase, isInterrupted) + sizeof(EngineBase::isInterrupted) <= offsetof(EngineBase, hasException) + 4); -#endif } diff --git a/src/qml/jsruntime/qv4lookup_p.h b/src/qml/jsruntime/qv4lookup_p.h index f2e0afd797..94bf1a98ae 100644 --- a/src/qml/jsruntime/qv4lookup_p.h +++ b/src/qml/jsruntime/qv4lookup_p.h @@ -54,11 +54,8 @@ #include "qv4runtime_p.h" #include "qv4engine_p.h" #include "qv4context_p.h" - -#if !defined(V4_BOOTSTRAP) #include "qv4object_p.h" #include "qv4internalclass_p.h" -#endif QT_BEGIN_NAMESPACE diff --git a/src/qml/jsruntime/qv4object_p.h b/src/qml/jsruntime/qv4object_p.h index 52ad3ea319..f3375929a3 100644 --- a/src/qml/jsruntime/qv4object_p.h +++ b/src/qml/jsruntime/qv4object_p.h @@ -543,13 +543,11 @@ inline const ArrayObject *Value::as() const { return isManaged() && m()->internalClass->vtable->type == Managed::Type_ArrayObject ? static_cast(this) : nullptr; } -#ifndef V4_BOOTSTRAP template<> inline ReturnedValue value_convert(ExecutionEngine *e, const Value &v) { return v.toObject(e)->asReturnedValue(); } -#endif } diff --git a/src/qml/jsruntime/qv4stackframe_p.h b/src/qml/jsruntime/qv4stackframe_p.h index 51a6acf43c..bf689a74bc 100644 --- a/src/qml/jsruntime/qv4stackframe_p.h +++ b/src/qml/jsruntime/qv4stackframe_p.h @@ -53,9 +53,7 @@ #include #include #include -#ifndef V4_BOOTSTRAP #include -#endif QT_BEGIN_NAMESPACE @@ -107,7 +105,6 @@ struct Q_QML_EXPORT CppStackFrame { engine->jsStackTop = savedStackTop; } -#ifndef V4_BOOTSTRAP static uint requiredJSStackFrameSize(uint nRegisters) { return CallData::HeaderSize() + nRegisters; } @@ -150,7 +147,6 @@ struct Q_QML_EXPORT CppStackFrame { *v = Value::emptyValue().asReturnedValue(); } } -#endif QString source() const; QString function() const; diff --git a/src/qml/jsruntime/qv4string.cpp b/src/qml/jsruntime/qv4string.cpp index 24a17bf5d5..223f4a4769 100644 --- a/src/qml/jsruntime/qv4string.cpp +++ b/src/qml/jsruntime/qv4string.cpp @@ -39,19 +39,15 @@ #include "qv4string_p.h" #include "qv4value_p.h" -#ifndef V4_BOOTSTRAP #include "qv4identifiertable_p.h" #include "qv4runtime_p.h" #include "qv4objectproto_p.h" #include "qv4stringobject_p.h" -#endif #include #include using namespace QV4; -#ifndef V4_BOOTSTRAP - void Heap::StringOrSymbol::markObjects(Heap::Base *that, MarkStack *markStack) { StringOrSymbol *s = static_cast(that); @@ -254,5 +250,3 @@ qint64 String::virtualGetLength(const Managed *m) { return static_cast(m)->d()->length(); } - -#endif // V4_BOOTSTRAP diff --git a/src/qml/jsruntime/qv4string_p.h b/src/qml/jsruntime/qv4string_p.h index a986fe185e..7888809490 100644 --- a/src/qml/jsruntime/qv4string_p.h +++ b/src/qml/jsruntime/qv4string_p.h @@ -105,7 +105,6 @@ struct Q_QML_PRIVATE_EXPORT StringOrSymbol : Base struct Q_QML_PRIVATE_EXPORT String : StringOrSymbol { static void markObjects(Heap::Base *that, MarkStack *markStack); -#ifndef V4_BOOTSTRAP const VTable *vtable() const { return internalClass->vtable; } @@ -141,11 +140,9 @@ struct Q_QML_PRIVATE_EXPORT String : StringOrSymbol { private: static void append(const String *data, QChar *ch); -#endif }; Q_STATIC_ASSERT(std::is_trivial< String >::value); -#ifndef V4_BOOTSTRAP struct ComplexString : String { void init(String *l, String *n); void init(String *ref, int from, int len); @@ -163,12 +160,10 @@ inline int String::length() const { return text ? text->size : static_cast(this)->len; } -#endif } struct Q_QML_PRIVATE_EXPORT StringOrSymbol : public Managed { -#ifndef V4_BOOTSTRAP V4_MANAGED(StringOrSymbol, Managed) V4_NEEDS_DESTROY enum { @@ -185,11 +180,9 @@ public: inline QString toQString() const { return d()->toQString(); } -#endif }; struct Q_QML_PRIVATE_EXPORT String : public StringOrSymbol { -#ifndef V4_BOOTSTRAP V4_MANAGED(String, StringOrSymbol) Q_MANAGED_TYPE(String) V4_INTERNALCLASS(String) @@ -240,7 +233,6 @@ struct Q_QML_PRIVATE_EXPORT String : public StringOrSymbol { protected: static bool virtualIsEqualTo(Managed *that, Managed *o); static qint64 virtualGetLength(const Managed *m); -#endif public: template @@ -265,7 +257,6 @@ public: } }; -#ifndef V4_BOOTSTRAP struct ComplexString : String { typedef QV4::Heap::ComplexString Data; QV4::Heap::ComplexString *d_unchecked() const { return static_cast(m()); } @@ -304,8 +295,6 @@ inline ReturnedValue value_convert(ExecutionEngine *e, const Value &v) { return v.toString(e)->asReturnedValue(); } -#endif - } -- cgit v1.2.3 From 19ca4af1a248486844ea9bf96eba62ce564ecdc9 Mon Sep 17 00:00:00 2001 From: Pavel Tumakaev Date: Wed, 22 May 2019 17:32:25 +0300 Subject: Remove null pointer checks for "this" from QQmlContextData::resolvedUrl() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to ISO/IEC 14882 §5.2.5/3 "If E1 has the type “pointer to class X,” then the expression E1->E2 is converted to the equivalent form (*(E1)).E2;". Thus, as QQmlContextData::resolvedUrl() is non-static method, it cannot be called on a null pointer because it leads to undefined behavior, and “this“ in QQmlContextData::resolvedUrl() cannot be a null pointer. According to this document: https://gcc.gnu.org/gcc-6/porting_to.html , starting from version 6, GCC optimizations remove null pointer checks for "this", since "the this pointer can never be null, which is guaranteed by the language rules." Thus, on the one hand the “if (ctxt)“ check in QQmlContextData::resolvedUrl() does nothing, on the other “if (engine“ check leads to undefined behavior if ctxt/this == nullptr. Task-number: QTBUG-75983 Change-Id: Idfb1e26758d83223bb0845139d63e2e8e80dc714 Reviewed-by: Ulf Hermann --- src/qml/qml/qqmlcontext.cpp | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) (limited to 'src/qml') diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp index e23f1e1e73..bd59409475 100644 --- a/src/qml/qml/qqmlcontext.cpp +++ b/src/qml/qml/qqmlcontext.cpp @@ -438,23 +438,20 @@ QUrl QQmlContext::resolvedUrl(const QUrl &src) QUrl QQmlContextData::resolvedUrl(const QUrl &src) { - QQmlContextData *ctxt = this; - QUrl resolved; if (src.isRelative() && !src.isEmpty()) { - if (ctxt) { - while(ctxt) { - if (ctxt->url().isValid()) - break; - else - ctxt = ctxt->parent; - } - - if (ctxt) - resolved = ctxt->url().resolved(src); - else if (engine) - resolved = engine->baseUrl().resolved(src); - } + QQmlContextData *ctxt = this; + do { + if (ctxt->url().isValid()) + break; + else + ctxt = ctxt->parent; + } while (ctxt); + + if (ctxt) + resolved = ctxt->url().resolved(src); + else if (engine) + resolved = engine->baseUrl().resolved(src); } else { resolved = src; } -- cgit v1.2.3