86 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &oldUnit,
87 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &newUnit)
89 std::vector<CompositeLevel> levels;
91 auto currentUnit = instanceLevel.newCu;
92 const QV4::CompiledData::Object *obj = currentUnit->objectAt(instanceLevel.objectIndex);
93 const QV4::ResolvedTypeReference *typeRef =
94 currentUnit->resolvedType(obj->inheritedTypeNameIndex);
96 while (typeRef && typeRef->type().isComposite()) {
97 QQmlRefPointer<QV4::ExecutableCompilationUnit> cu = typeRef->isSelfReference()
99 : currentUnit->engine->executableCompilationUnit(typeRef->compilationUnit());
103 const auto oldCu = cu;
109 if (typeRef->type().isInlineComponent()) {
110 icName = typeRef->type().elementName();
111 rootIndex = cu->inlineComponentId(icName);
116 levels.push_back({ oldCu, cu, rootIndex, icName,
nullptr });
118 if (rootIndex >= cu->objectCount())
122 const QV4::CompiledData::Object *rootObj = cu->objectAt(rootIndex);
123 typeRef = cu->resolvedType(rootObj->inheritedTypeNameIndex);
133 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &oldUnit,
134 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &newUnit)
137 if (cuIndex >= newUnit->objectCount())
140 QQmlData *ddata = QQmlData::get(object);
143 QQmlRefPointer<QQmlContextData> outerContext =
144 QQmlRefPointer<QQmlContextData>(ddata->outerContext);
147 if (!ddata->context || !outerContext || !outerContext->isValid() || ddata->isQueuedForDeletion)
150 CompositeLevel instanceLevel{ ddata->compilationUnit,
151 ddata->compilationUnit == oldUnit ? newUnit
152 : ddata->compilationUnit,
153 ddata->cuObjectIndex, QString(), outerContext };
157 if (instanceLevel.objectIndex >= instanceLevel.newCu->objectCount())
160 std::vector<CompositeLevel> levels = collectCompositeLevels(instanceLevel, oldUnit, newUnit);
164 std::vector<CompositeLevel> internalUnits;
165 internalUnits.push_back(instanceLevel);
166 for (
const auto &level : levels)
167 internalUnits.push_back(level);
169 BindingPatchContext patchCtx(object, ddata->compilationUnit, ddata->cuObjectIndex);
170 QDuplicateTracker<QObject *> seenChildren;
171 patchCtx.stashExternalState(internalUnits, &seenChildren);
176 std::vector<QQmlRefPointer<QV4::ExecutableCompilationUnit>> unitsToUnparent;
177 unitsToUnparent.push_back(oldUnit);
178 for (
const auto &level : levels)
179 unitsToUnparent.push_back(level.oldCu);
180 patchCtx.reset(unitsToUnparent, internalUnits);
182 QV4::ExecutionEngine *v4 = newUnit->engine;
184 QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(v4);
185 Q_ASSERT(enginePrivate);
187 if (outerContext->contextObject() == object) {
188 outerContext->setContextObject(
nullptr);
189 outerContext = enginePrivate->createComponentRootContext(
190 instanceLevel.newCu, outerContext->parent(), instanceLevel.objectIndex);
191 outerContext->setContextObject(object);
192 instanceLevel.context = outerContext;
195 for (QQmlRefPointer<QQmlContextData> ctx(ddata->context); ctx; ctx = ctx->linkedContext()) {
196 if (ctx->contextObject() == object)
197 ctx->setContextObject(
nullptr);
202 QObjectPrivate *objectPrivate = QObjectPrivate::get(object);
203 delete std::exchange(objectPrivate->metaObject,
nullptr);
205 QQmlRefPointer<QQmlContextData> levelContext = outerContext;
206 for (qsizetype i = 0, end = levels.size(); i < end; ++i) {
207 CompositeLevel &level = levels[i];
208 levelContext = level.context = enginePrivate->createComponentRootContext(
209 level.newCu, levelContext, level.objectIndex);
210 levelContext->setContextObject(object);
213 if (outerContext->contextObject() == object) {
214 ddata->ownContext = outerContext;
215 ddata->context = outerContext.data();
217 ddata->context->setLinkedContext(levels.front().context);
218 }
else if (!levels.empty()) {
219 ddata->ownContext = levels.back().context;
220 ddata->context = ddata->ownContext.data();
221 if (levels.size() > 1)
222 ddata->context->setLinkedContext(levels.front().context);
225 ddata->context = outerContext.data();
228 for (
auto it = levels.crbegin(), end = levels.crend(); it != end; ++it) {
229 it->context->addOwnedObject(ddata);
230 QQmlPropertyCache::ConstPtr cache = it->newCu->propertyCachesPtr()->at(it->objectIndex);
231 new QQmlVMEMetaObject(v4, object, cache, it->newCu, it->objectIndex);
234 outerContext->addOwnedObject(ddata);
235 if (QQmlPropertyCacheVector *caches = instanceLevel.newCu->propertyCachesPtr();
236 caches->count() > instanceLevel.objectIndex
237 && caches->needsVMEMetaObject(instanceLevel.objectIndex)) {
238 QQmlPropertyCache::ConstPtr cache = caches->at(instanceLevel.objectIndex);
239 new QQmlVMEMetaObject(v4, object, cache, instanceLevel.newCu, instanceLevel.objectIndex);
246 for (
auto it = levels.crbegin(), end = levels.crend(); it != end && !ddata->isQueuedForDeletion;
248 QQmlObjectCreator creator(it->context, it->newCu, outerContext, it->icName,
nullptr);
249 creator.repopulateBindings(it->objectIndex, object, it->context,
250 QQmlObjectCreator::InitFlag::IsContextObject
251 | QQmlObjectCreator::InitFlag::IsDocumentRoot);
253 QQmlInstantiationInterrupt interrupt;
254 creator.finalize(interrupt);
259 if (!ddata->isQueuedForDeletion) {
261 QQmlObjectCreator creator(instanceLevel.context, instanceLevel.newCu, outerContext, QString(),
263 creator.repopulateBindings(instanceLevel.objectIndex, object, outerContext,
264 QQmlObjectCreator::InitFlag::None);
265 QQmlInstantiationInterrupt interrupt;
266 creator.finalize(interrupt);
270 patchCtx.refreshObjects();
271 patchCtx.restoreExternalState();
276 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &oldUnit,
277 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &newUnit)
280 if (!newUnit->runtimeStrings)
315 std::vector<ObjectAndIndex> rebuild;
317 for (QObject *object : objects) {
318 const QVarLengthArray<
int, 4> indices = objectIndices(object, oldUnit);
319 for (
int index : indices) {
323 if (index >= oldUnit->objectCount())
325 const auto flags = oldUnit->objectAt(index)->flags();
326 if (index != 0 && !(flags & QV4::CompiledData::Object::IsInlineComponentRoot))
334 if (index < newUnit->objectCount()
335 && hasChangedNonCompositeBaseType(oldUnit, newUnit, index)) {
339 rebuild.push_back({ object, indices.first() });
348 std::sort(rebuild.begin(), rebuild.end(),
349 [](
const ObjectAndIndex &a,
const ObjectAndIndex &b) {
return a.index < b.index; });
354 QSet<QObject *> skip;
355 for (
const auto &[object, cuIndex] : rebuild) {
356 const QObjectList &children = object->children();
357 for (QObject *child : children)
361 for (
const auto &[object, cuIndex] : rebuild) {
362 if (skip.contains(object))
365 rebuildObject(object, cuIndex, oldUnit, newUnit);
368 for (QObject *object : objects) {
369 QQmlData *ddata = QQmlData::get(object);
370 if (ddata->compilationUnit == newUnit)
372 if (ddata->compilationUnit != oldUnit)
378 if (ddata->cuObjectIndex >= newUnit->objectCount()) {
382 if (ddata->hasVMEMetaObject) {
383 for (
auto *vmeMeta =
static_cast<QQmlVMEMetaObject *>(
384 QObjectPrivate::get(object)->metaObject);
385 vmeMeta; vmeMeta = vmeMeta->parentVMEMetaObject()) {
386 if (vmeMeta->compilationUnit() == oldUnit)
387 vmeMeta->setCompilationUnit(
nullptr);
393 ddata->compilationUnit = newUnit;
394 if (!ddata->hasVMEMetaObject)
397 for (QQmlVMEMetaObject *vmeMeta =
398 static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(object)->metaObject);
399 vmeMeta; vmeMeta = vmeMeta->parentVMEMetaObject()) {
400 if (vmeMeta->compilationUnit() == oldUnit
401 && vmeMeta->qmlObjectId() < newUnit->objectCount()) {
402 vmeMeta->setCompilationUnit(newUnit);