aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml/qqmlobjectcreator_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml/qqmlobjectcreator_p.h')
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h210
1 files changed, 149 insertions, 61 deletions
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index 0059c6da7b..8b1c251e2b 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 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$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#ifndef QQMLOBJECTCREATOR_P_H
#define QQMLOBJECTCREATOR_P_H
@@ -58,6 +22,8 @@
#include <private/qqmlprofiler_p.h>
#include <private/qv4qmlcontext_p.h>
#include <private/qqmlguardedcontextdata_p.h>
+#include <private/qqmlfinalizer_p.h>
+#include <private/qqmlvmemetaobject_p.h>
#include <qpointer.h>
@@ -87,26 +53,69 @@ struct RequiredPropertyInfo
QVector<AliasToRequiredInfo> aliasesToRequired;
};
-class RequiredProperties : public QHash<QQmlPropertyData*, RequiredPropertyInfo> {};
+struct RequiredPropertyKey
+{
+ RequiredPropertyKey() = default;
+ RequiredPropertyKey(const QObject *object, const QQmlPropertyData *data)
+ : object(object)
+ , data(data)
+ {}
+
+ const QObject *object = nullptr;
+ const QQmlPropertyData *data = nullptr;
+
+private:
+ friend size_t qHash(const RequiredPropertyKey &key, size_t seed = 0)
+ {
+ return qHashMulti(seed, key.object, key.data);
+ }
+
+ friend bool operator==(const RequiredPropertyKey &a, const RequiredPropertyKey &b)
+ {
+ return a.object == b.object && a.data == b.data;
+ }
+};
+
+class RequiredProperties : public QHash<RequiredPropertyKey, RequiredPropertyInfo> {};
-struct QQmlObjectCreatorSharedState : public QSharedData
+struct DeferredQPropertyBinding {
+ QObject *target = nullptr;
+ int properyIndex = -1;
+ QUntypedPropertyBinding binding;
+};
+
+class ObjectInCreationGCAnchorList {
+public:
+ // this is a non owning view, rule of zero applies
+ ObjectInCreationGCAnchorList() = default;
+ ObjectInCreationGCAnchorList(const QV4::Scope &scope, int totalObjectCount)
+ {
+ allJavaScriptObjects = scope.alloc(totalObjectCount);
+ }
+ void trackObject(QV4::ExecutionEngine *engine, QObject *instance);
+ bool canTrack() const { return allJavaScriptObjects; }
+private:
+ QV4::Value *allJavaScriptObjects = nullptr; // pointer to vector on JS stack to reference JS wrappers during creation phase.
+};
+
+struct QQmlObjectCreatorSharedState final : QQmlRefCounted<QQmlObjectCreatorSharedState>
{
QQmlRefPointer<QQmlContextData> rootContext;
QQmlRefPointer<QQmlContextData> creationContext;
QFiniteStack<QQmlAbstractBinding::Ptr> allCreatedBindings;
QFiniteStack<QQmlParserStatus*> allParserStatusCallbacks;
- QFiniteStack<QPointer<QObject> > allCreatedObjects;
- QV4::Value *allJavaScriptObjects; // pointer to vector on JS stack to reference JS wrappers during creation phase.
+ QFiniteStack<QQmlGuard<QObject> > allCreatedObjects;
+ ObjectInCreationGCAnchorList allJavaScriptObjects; // pointer to vector on JS stack to reference JS wrappers during creation phase.
QQmlComponentAttached *componentAttached;
- QList<QQmlEnginePrivate::FinalizeCallback> finalizeCallbacks;
+ QList<QQmlFinalizerHook *> finalizeHooks;
QQmlVmeProfiler profiler;
QRecursionNode recursionNode;
RequiredProperties requiredProperties;
- QList<std::tuple<QObject *, int, QUntypedPropertyBinding>> allQPropertyBindings;
- bool hadRequiredProperties;
+ QList<DeferredQPropertyBinding> allQPropertyBindings;
+ bool hadTopLevelRequiredProperties;
};
-class Q_QML_PRIVATE_EXPORT QQmlObjectCreator
+class Q_QML_EXPORT QQmlObjectCreator
{
Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator)
public:
@@ -125,6 +134,10 @@ public:
void beginPopulateDeferred(const QQmlRefPointer<QQmlContextData> &context);
void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex,
const QV4::CompiledData::Binding *binding);
+ void populateDeferredInstance(QObject *outerObject, int deferredIndex,
+ int index, QObject *instance, QObject *bindingTarget,
+ const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding = nullptr);
void finalizePopulateDeferred();
bool finalize(QQmlInstantiationInterrupt &interrupt);
@@ -133,37 +146,59 @@ public:
QQmlRefPointer<QQmlContextData> rootContext() const { return sharedState->rootContext; }
QQmlComponentAttached **componentAttachment() { return &sharedState->componentAttached; }
- QList<QQmlEnginePrivate::FinalizeCallback> *finalizeCallbacks() { return &sharedState->finalizeCallbacks; }
-
QList<QQmlError> errors;
QQmlRefPointer<QQmlContextData> parentContextData() const
{
return parentContext.contextData();
}
- QFiniteStack<QPointer<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
+ QFiniteStack<QQmlGuard<QObject> > &allCreatedObjects() { return sharedState->allCreatedObjects; }
- RequiredProperties &requiredProperties() {return sharedState->requiredProperties;}
- bool componentHadRequiredProperties() const {return sharedState->hadRequiredProperties;}
+ RequiredProperties *requiredProperties() {return &sharedState->requiredProperties;}
+ bool componentHadTopLevelRequiredProperties() const {return sharedState->hadTopLevelRequiredProperties;}
+
+ static QQmlComponent *createComponent(QQmlEngine *engine,
+ QV4::ExecutableCompilationUnit *compilationUnit,
+ int index, QObject *parent,
+ const QQmlRefPointer<QQmlContextData> &context);
+
+ void removePendingBinding(QObject *target, int propertyIndex)
+ {
+ QList<DeferredQPropertyBinding> &pendingBindings = sharedState.data()->allQPropertyBindings;
+ pendingBindings.removeIf([&](const DeferredQPropertyBinding &deferred) {
+ return deferred.properyIndex == propertyIndex && deferred.target == target;
+ });
+ }
private:
QQmlObjectCreator(QQmlRefPointer<QQmlContextData> contextData,
const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit,
- QQmlObjectCreatorSharedState *inheritedSharedState);
+ QQmlObjectCreatorSharedState *inheritedSharedState,
+ bool isContextObject);
void init(QQmlRefPointer<QQmlContextData> parentContext);
QObject *createInstance(int index, QObject *parent = nullptr, bool isContextObject = false);
- bool populateInstance(int index, QObject *instance,
- QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty);
+ bool populateInstance(int index, QObject *instance, QObject *bindingTarget,
+ const QQmlPropertyData *valueTypeProperty,
+ const QV4::CompiledData::Binding *binding = nullptr);
// If qmlProperty and binding are null, populate all properties, otherwise only the given one.
+ void populateDeferred(QObject *instance, int deferredIndex);
void populateDeferred(QObject *instance, int deferredIndex,
- const QQmlPropertyPrivate *qmlProperty = nullptr,
- const QV4::CompiledData::Binding *binding = nullptr);
-
- void setupBindings(bool applyDeferredBindings = false);
+ const QQmlPropertyPrivate *qmlProperty,
+ const QV4::CompiledData::Binding *binding);
+
+ enum BindingMode {
+ ApplyNone = 0x0,
+ ApplyImmediate = 0x1,
+ ApplyDeferred = 0x2,
+ ApplyAll = ApplyImmediate | ApplyDeferred,
+ };
+ Q_DECLARE_FLAGS(BindingSetupFlags, BindingMode);
+
+ void setupBindings(BindingSetupFlags mode = BindingMode::ApplyImmediate);
bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setupFunctions();
@@ -195,8 +230,9 @@ private:
QQmlGuardedContextData parentContext;
QQmlRefPointer<QQmlContextData> context;
const QQmlPropertyCacheVector *propertyCaches;
- QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState;
+ QQmlRefPointer<QQmlObjectCreatorSharedState> sharedState;
bool topLevelCreator;
+ bool isContextObject;
QQmlIncubatorPrivate *incubator;
QObject *_qobject;
@@ -207,7 +243,7 @@ private:
int _compiledObjectIndex;
const QV4::CompiledData::Object *_compiledObject;
QQmlData *_ddata;
- QQmlRefPointer<QQmlPropertyCache> _propertyCache;
+ QQmlPropertyCache::ConstPtr _propertyCache;
QQmlVMEMetaObject *_vmeMetaObject;
QQmlListProperty<void> _currentList;
QV4::QmlContext *_qmlContext;
@@ -216,6 +252,58 @@ private:
typedef std::function<bool(QQmlObjectCreatorSharedState *sharedState)> PendingAliasBinding;
std::vector<PendingAliasBinding> pendingAliasBindings;
+
+ template<typename Functor>
+ void doPopulateDeferred(QObject *instance, int deferredIndex, Functor f)
+ {
+ QQmlData *declarativeData = QQmlData::get(instance);
+
+ // We're in the process of creating the object. We sure hope it's still alive.
+ Q_ASSERT(declarativeData && declarativeData->propertyCache);
+
+ QObject *bindingTarget = instance;
+
+ QQmlPropertyCache::ConstPtr cache = declarativeData->propertyCache;
+ QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance);
+
+ QObject *scopeObject = instance;
+ qt_ptr_swap(_scopeObject, scopeObject);
+
+ QV4::Scope valueScope(v4);
+ QScopedValueRollback<ObjectInCreationGCAnchorList> jsObjectGuard(
+ sharedState->allJavaScriptObjects,
+ ObjectInCreationGCAnchorList(valueScope, compilationUnit->totalObjectCount()));
+
+ Q_ASSERT(topLevelCreator);
+ QV4::QmlContext *qmlContext = static_cast<QV4::QmlContext *>(valueScope.alloc());
+
+ qt_ptr_swap(_qmlContext, qmlContext);
+
+ _propertyCache.swap(cache);
+ qt_ptr_swap(_qobject, instance);
+
+ int objectIndex = deferredIndex;
+ std::swap(_compiledObjectIndex, objectIndex);
+
+ const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex);
+ qt_ptr_swap(_compiledObject, obj);
+ qt_ptr_swap(_ddata, declarativeData);
+ qt_ptr_swap(_bindingTarget, bindingTarget);
+ qt_ptr_swap(_vmeMetaObject, vmeMetaObject);
+
+ f();
+
+ qt_ptr_swap(_vmeMetaObject, vmeMetaObject);
+ qt_ptr_swap(_bindingTarget, bindingTarget);
+ qt_ptr_swap(_ddata, declarativeData);
+ qt_ptr_swap(_compiledObject, obj);
+ std::swap(_compiledObjectIndex, objectIndex);
+ qt_ptr_swap(_qobject, instance);
+ _propertyCache.swap(cache);
+
+ qt_ptr_swap(_qmlContext, qmlContext);
+ qt_ptr_swap(_scopeObject, scopeObject);
+ }
};
struct QQmlObjectCreatorRecursionWatcher
@@ -225,7 +313,7 @@ struct QQmlObjectCreatorRecursionWatcher
bool hasRecursed() const { return watcher.hasRecursed(); }
private:
- QExplicitlySharedDataPointer<QQmlObjectCreatorSharedState> sharedState;
+ QQmlRefPointer<QQmlObjectCreatorSharedState> sharedState;
QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher;
};