From 3f96bf1f43252daf26ed61df2b3456f2dc81183b Mon Sep 17 00:00:00 2001 From: Ulf Hermann Date: Thu, 15 Aug 2019 11:55:49 +0200 Subject: QQmlObjectCreator: Unify deferred setup of bindings Change-Id: I5e9ff550aa2875f41dbea797d814e1f0044ebd63 Reviewed-by: Fabian Kosmale Reviewed-by: Simon Hausmann --- src/qml/qml/qqmlcomponent.cpp | 1 + src/qml/qml/qqmlobjectcreator.cpp | 121 +++++++++-------------- src/qml/qml/qqmlobjectcreator_p.h | 15 ++- tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp | 6 +- 4 files changed, 64 insertions(+), 79 deletions(-) diff --git a/src/qml/qml/qqmlcomponent.cpp b/src/qml/qml/qqmlcomponent.cpp index f03f90e7f3..1d5f974d5c 100644 --- a/src/qml/qml/qqmlcomponent.cpp +++ b/src/qml/qml/qqmlcomponent.cpp @@ -969,6 +969,7 @@ void QQmlComponentPrivate::beginDeferred(QQmlEnginePrivate *enginePriv, if (!state->creator->populateDeferredProperties(object, deferredData)) state->errors << state->creator->errors; + deferredData->bindings.clear(); deferredState->constructionStates += state; } diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp index cf1795aafa..44006c3f6a 100644 --- a/src/qml/qml/qqmlobjectcreator.cpp +++ b/src/qml/qml/qqmlobjectcreator.cpp @@ -234,73 +234,23 @@ QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlI return instance; } -// ### unify or keep in sync with populateDeferredBinding() -bool QQmlObjectCreator::populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData) +void QQmlObjectCreator::beginPopulateDeferred(QQmlContextData *newContext) { - QQmlData *declarativeData = QQmlData::get(instance); - context = deferredData->context; - sharedState->rootContext = context; - - QObject *bindingTarget = instance; - - QQmlRefPointer cache = declarativeData->propertyCache; - QQmlVMEMetaObject *vmeMetaObject = QQmlVMEMetaObject::get(instance); - - QObject *scopeObject = instance; - qSwap(_scopeObject, scopeObject); - - QV4::Scope valueScope(v4); + context = newContext; + sharedState->rootContext = newContext; Q_ASSERT(topLevelCreator); Q_ASSERT(!sharedState->allJavaScriptObjects); - sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount); - - QV4::QmlContext *qmlContext = static_cast(valueScope.alloc()); - qSwap(_qmlContext, qmlContext); - - qSwap(_propertyCache, cache); - qSwap(_qobject, instance); - - int objectIndex = deferredData->deferredIdx; - qSwap(_compiledObjectIndex, objectIndex); - - const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex); - qSwap(_compiledObject, obj); - - qSwap(_ddata, declarativeData); - qSwap(_bindingTarget, bindingTarget); - qSwap(_vmeMetaObject, vmeMetaObject); - - setupBindings(/*applyDeferredBindings=*/true); - - qSwap(_vmeMetaObject, vmeMetaObject); - qSwap(_bindingTarget, bindingTarget); - qSwap(_ddata, declarativeData); - qSwap(_compiledObject, obj); - qSwap(_compiledObjectIndex, objectIndex); - qSwap(_qobject, instance); - qSwap(_propertyCache, cache); - - qSwap(_qmlContext, qmlContext); - qSwap(_scopeObject, scopeObject); - - deferredData->bindings.clear(); - phase = ObjectsCreated; - - return errors.isEmpty(); + QV4::Scope valueScope(v4); + sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount); } -// ### unify or keep in sync with populateDeferredProperties() -bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding) +void QQmlObjectCreator::populateDeferred(QObject *instance, int deferredIndex, + const QQmlPropertyPrivate *qmlProperty, + const QV4::CompiledData::Binding *binding) { - Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding); - - QObject *instance = qmlProperty.object(); QQmlData *declarativeData = QQmlData::get(instance); - context = deferredData->context; - sharedState->rootContext = context; - QObject *bindingTarget = instance; QQmlRefPointer cache = declarativeData->propertyCache; @@ -312,9 +262,6 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, QV4::Scope valueScope(v4); Q_ASSERT(topLevelCreator); - if (!sharedState->allJavaScriptObjects) - sharedState->allJavaScriptObjects = valueScope.alloc(compilationUnit->totalObjectCount); - QV4::QmlContext *qmlContext = static_cast(valueScope.alloc()); qSwap(_qmlContext, qmlContext); @@ -322,7 +269,7 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, qSwap(_propertyCache, cache); qSwap(_qobject, instance); - int objectIndex = deferredData->deferredIdx; + int objectIndex = deferredIndex; qSwap(_compiledObjectIndex, objectIndex); const QV4::CompiledData::Object *obj = compilationUnit->objectAt(_compiledObjectIndex); @@ -332,21 +279,28 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, qSwap(_bindingTarget, bindingTarget); qSwap(_vmeMetaObject, vmeMetaObject); - QQmlListProperty savedList; - qSwap(_currentList, savedList); + if (binding) { + Q_ASSERT(qmlProperty); + Q_ASSERT(binding->flags & QV4::CompiledData::Binding::IsDeferredBinding); - const QQmlPropertyData &property = QQmlPropertyPrivate::get(qmlProperty)->core; + QQmlListProperty savedList; + qSwap(_currentList, savedList); - if (property.isQList()) { - void *argv[1] = { (void*)&_currentList }; - QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv); - } else if (_currentList.object) { - _currentList = QQmlListProperty(); - } + const QQmlPropertyData &property = qmlProperty->core; + + if (property.isQList()) { + void *argv[1] = { (void*)&_currentList }; + QMetaObject::metacall(_qobject, QMetaObject::ReadProperty, property.coreIndex(), argv); + } else if (_currentList.object) { + _currentList = QQmlListProperty(); + } - setPropertyBinding(&property, binding); + setPropertyBinding(&property, binding); - qSwap(_currentList, savedList); + qSwap(_currentList, savedList); + } else { + setupBindings(/*applyDeferredBindings=*/true); + } qSwap(_vmeMetaObject, vmeMetaObject); qSwap(_bindingTarget, bindingTarget); @@ -358,12 +312,29 @@ bool QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, qSwap(_qmlContext, qmlContext); qSwap(_scopeObject, scopeObject); +} - phase = ObjectsCreated; - +bool QQmlObjectCreator::populateDeferredProperties(QObject *instance, + const QQmlData::DeferredData *deferredData) +{ + beginPopulateDeferred(deferredData->context); + populateDeferred(instance, deferredData->deferredIdx); + finalizePopulateDeferred(); return errors.isEmpty(); } +void QQmlObjectCreator::populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex, + const QV4::CompiledData::Binding *binding) +{ + populateDeferred(qmlProperty.object(), deferredIndex, QQmlPropertyPrivate::get(qmlProperty), + binding); +} + +void QQmlObjectCreator::finalizePopulateDeferred() +{ + phase = ObjectsCreated; +} + void QQmlObjectCreator::setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding) { QQmlPropertyData::WriteFlags propertyWriteFlags = QQmlPropertyData::BypassInterceptor | QQmlPropertyData::RemoveBindingOnAliasWrite; diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h index 59e236c855..8b6cb67341 100644 --- a/src/qml/qml/qqmlobjectcreator_p.h +++ b/src/qml/qml/qqmlobjectcreator_p.h @@ -112,8 +112,14 @@ public: ~QQmlObjectCreator(); QObject *create(int subComponentIndex = -1, QObject *parent = nullptr, QQmlInstantiationInterrupt *interrupt = nullptr); - bool populateDeferredProperties(QObject *instance, QQmlData::DeferredData *deferredData); - bool populateDeferredBinding(const QQmlProperty &qmlProperty, QQmlData::DeferredData *deferredData, const QV4::CompiledData::Binding *binding); + + bool populateDeferredProperties(QObject *instance, const QQmlData::DeferredData *deferredData); + + void beginPopulateDeferred(QQmlContextData *context); + void populateDeferredBinding(const QQmlProperty &qmlProperty, int deferredIndex, + const QV4::CompiledData::Binding *binding); + void finalizePopulateDeferred(); + QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt); void clear(); @@ -139,6 +145,11 @@ private: bool populateInstance(int index, QObject *instance, QObject *bindingTarget, const QQmlPropertyData *valueTypeProperty); + // If qmlProperty and binding are null, populate all properties, otherwise only the given one. + void populateDeferred(QObject *instance, int deferredIndex, + const QQmlPropertyPrivate *qmlProperty = nullptr, + const QV4::CompiledData::Binding *binding = nullptr); + void setupBindings(bool applyDeferredBindings = false); bool setPropertyBinding(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); void setPropertyValue(const QQmlPropertyData *property, const QV4::CompiledData::Binding *binding); diff --git a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp index e2032c3b86..17dfa3d8a1 100644 --- a/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp +++ b/tests/auto/qml/qqmllanguage/tst_qqmllanguage.cpp @@ -4728,11 +4728,13 @@ static void beginDeferredOnce(QQmlEnginePrivate *enginePriv, typedef QMultiHash QV4PropertyBindingHash; auto it = std::reverse_iterator(range.second); auto last = std::reverse_iterator(range.first); + state->creator->beginPopulateDeferred(deferData->context); while (it != last) { - if (!state->creator->populateDeferredBinding(property, deferData, *it)) - state->errors << state->creator->errors; + state->creator->populateDeferredBinding(property, deferData->deferredIdx, *it); ++it; } + state->creator->finalizePopulateDeferred(); + state->errors << state->creator->errors; deferredState->constructionStates += state; -- cgit v1.2.3