109 int objectIndex,
const QQmlPropertyCache::ConstPtr &cache)
111 QList<QV4::CompiledData::BindingPropertyData> &table =
112 cu->baseCompilationUnit()->bindingPropertyDataPerObject;
113 if (objectIndex >= table.size())
116 QV4::CompiledData::BindingPropertyData &bindingData = table[objectIndex];
118 const QV4::CompiledData::Object *obj = cu->objectAt(objectIndex);
119 const QQmlPropertyResolver resolver(cache);
121 const QV4::CompiledData::Binding *binding = obj->bindingTable();
122 for (qsizetype i = 0, end = bindingData.size(); i < end; ++i, ++binding) {
123 if (!bindingData.at(i))
126 Q_ASSERT(i < obj->nBindings);
127 const QString name = BindingPatchContext::targetPropertyName(cu, objectIndex, binding);
132 (binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerExpression)
133 || binding->hasFlag(QV4::CompiledData::Binding::IsSignalHandlerObject))
134 ? resolver.signal(name,
nullptr, QQmlPropertyResolver::IgnoreRevision)
135 : resolver.property(name,
nullptr, QQmlPropertyResolver::IgnoreRevision);
219 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &oldUnit,
220 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &newUnit)
222 std::vector<CompositeLevel> levels;
224 auto currentUnit = instanceLevel.newCu;
225 const QV4::CompiledData::Object *obj = currentUnit->objectAt(instanceLevel.objectIndex);
226 const QV4::ResolvedTypeReference *typeRef =
227 currentUnit->resolvedType(obj->inheritedTypeNameIndex);
229 while (typeRef && typeRef->type().isComposite()) {
230 QQmlRefPointer<QV4::ExecutableCompilationUnit> cu = typeRef->isSelfReference()
232 : currentUnit->engine->executableCompilationUnit(typeRef->compilationUnit());
236 const auto oldCu = cu;
242 if (typeRef->type().isInlineComponent()) {
243 icName = typeRef->type().elementName();
244 rootIndex = cu->inlineComponentId(icName);
249 levels.push_back({ oldCu, cu, rootIndex, icName,
nullptr });
251 if (rootIndex < 0 || rootIndex >= cu->objectCount())
255 const QV4::CompiledData::Object *rootObj = cu->objectAt(rootIndex);
256 typeRef = cu->resolvedType(rootObj->inheritedTypeNameIndex);
266 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &oldUnit,
267 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &newUnit)
270 if (cuIndex >= newUnit->objectCount())
273 QQmlData *ddata = QQmlData::get(object);
276 QQmlRefPointer<QQmlContextData> outerContext =
277 QQmlRefPointer<QQmlContextData>(ddata->outerContext);
280 if (!ddata->context || !outerContext || !outerContext->isValid() || ddata->isQueuedForDeletion)
283 CompositeLevel instanceLevel{ ddata->compilationUnit,
284 ddata->compilationUnit == oldUnit ? newUnit
285 : ddata->compilationUnit,
286 ddata->cuObjectIndex, QString(), outerContext };
290 if (instanceLevel.objectIndex >= instanceLevel.newCu->objectCount())
293 std::vector<CompositeLevel> levels = collectCompositeLevels(instanceLevel, oldUnit, newUnit);
297 std::vector<CompositeLevel> internalUnits;
298 internalUnits.push_back(instanceLevel);
299 for (
const auto &level : levels)
300 internalUnits.push_back(level);
302 BindingPatchContext patchCtx(object, ddata->compilationUnit, ddata->cuObjectIndex);
303 QDuplicateTracker<QObject *> seenChildren;
304 patchCtx.stashExternalState(internalUnits, &seenChildren);
309 std::vector<QQmlRefPointer<QV4::ExecutableCompilationUnit>> unitsToUnparent;
310 unitsToUnparent.push_back(oldUnit);
311 for (
const auto &level : levels)
312 unitsToUnparent.push_back(level.oldCu);
313 patchCtx.reset(unitsToUnparent, internalUnits);
315 QV4::ExecutionEngine *v4 = newUnit->engine;
317 QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(v4);
318 Q_ASSERT(enginePrivate);
320 if (outerContext->contextObject() == object) {
321 outerContext->setContextObject(
nullptr);
322 outerContext = enginePrivate->createComponentRootContext(
323 instanceLevel.newCu, outerContext->parent(), instanceLevel.objectIndex);
324 outerContext->setContextObject(object);
325 instanceLevel.context = outerContext;
328 for (QQmlRefPointer<QQmlContextData> ctx(ddata->context); ctx; ctx = ctx->linkedContext()) {
329 if (ctx->contextObject() == object)
330 ctx->setContextObject(
nullptr);
335 QObjectPrivate *objectPrivate = QObjectPrivate::get(object);
336 delete std::exchange(objectPrivate->metaObject,
nullptr);
338 QQmlRefPointer<QQmlContextData> levelContext = outerContext;
339 for (qsizetype i = 0, end = levels.size(); i < end; ++i) {
340 CompositeLevel &level = levels[i];
341 levelContext = level.context = enginePrivate->createComponentRootContext(
342 level.newCu, levelContext, level.objectIndex);
343 levelContext->setContextObject(object);
346 if (outerContext->contextObject() == object) {
347 ddata->ownContext = outerContext;
348 ddata->context = outerContext.data();
350 ddata->context->setLinkedContext(levels.front().context);
351 }
else if (!levels.empty()) {
352 ddata->ownContext = levels.back().context;
353 ddata->context = ddata->ownContext.data();
354 if (levels.size() > 1)
355 ddata->context->setLinkedContext(levels.front().context);
358 ddata->context = outerContext.data();
364 QQmlPropertyCache::ConstPtr parentCache;
365 for (
auto it = levels.crbegin(), end = levels.crend(); it != end; ++it) {
366 it->context->addOwnedObject(ddata);
367 QQmlPropertyCache::ConstPtr cache = relinkCache(it->newCu, it->objectIndex, parentCache);
368 if (it->newCu->propertyCachesPtr()->needsVMEMetaObject(it->objectIndex))
369 new QQmlVMEMetaObject(v4, object, cache, it->newCu, it->objectIndex);
373 outerContext->addOwnedObject(ddata);
374 if (QQmlPropertyCacheVector *caches = instanceLevel.newCu->propertyCachesPtr();
375 caches->count() > instanceLevel.objectIndex) {
376 QQmlPropertyCache::ConstPtr cache =
377 relinkCache(instanceLevel.newCu, instanceLevel.objectIndex, parentCache);
378 if (caches->needsVMEMetaObject(instanceLevel.objectIndex))
379 new QQmlVMEMetaObject(v4, object, cache, instanceLevel.newCu, instanceLevel.objectIndex);
386 for (
auto it = levels.crbegin(), end = levels.crend(); it != end && !ddata->isQueuedForDeletion;
388 QQmlObjectCreator creator(it->context, it->newCu, outerContext, it->icName,
nullptr);
389 creator.repopulateBindings(it->objectIndex, object, it->context,
390 QQmlObjectCreator::InitFlag::IsContextObject
391 | QQmlObjectCreator::InitFlag::IsDocumentRoot);
393 QQmlInstantiationInterrupt interrupt;
394 creator.finalize(interrupt);
399 if (!ddata->isQueuedForDeletion) {
401 QQmlObjectCreator creator(instanceLevel.context, instanceLevel.newCu, outerContext, QString(),
403 creator.repopulateBindings(instanceLevel.objectIndex, object, outerContext,
404 QQmlObjectCreator::InitFlag::None);
405 QQmlInstantiationInterrupt interrupt;
406 creator.finalize(interrupt);
410 patchCtx.refreshObjects();
411 patchCtx.restoreExternalState();
438 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &oldUnit,
439 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &newUnit)
441 using ChangeType = QV4::CompiledData::ChangeType;
442 switch (change.type) {
444 case ChangeType::AliasLocationChanged:
445 case ChangeType::BindingLocationChanged:
446 case ChangeType::EnumLocationChanged:
447 case ChangeType::FunctionLocationChanged:
448 case ChangeType::ImportLocationChanged:
449 case ChangeType::InlineComponentLocationChanged:
450 case ChangeType::ObjectLocationChanged:
451 case ChangeType::PropertyLocationChanged:
452 case ChangeType::SignalLocationChanged:
455 case ChangeType::UnitMetadataChanged:
456 case ChangeType::ConstantAdded:
457 case ChangeType::ConstantChanged:
458 case ChangeType::ConstantRemoved:
459 case ChangeType::StringDataAdded:
460 case ChangeType::StringDataChanged:
461 case ChangeType::StringDataRemoved:
462 case ChangeType::LookupAdded:
463 case ChangeType::LookupChanged:
464 case ChangeType::LookupRemoved:
465 case ChangeType::RegExpAdded:
466 case ChangeType::RegExpChanged:
467 case ChangeType::RegExpRemoved:
468 case ChangeType::ClassAdded:
469 case ChangeType::ClassChanged:
470 case ChangeType::ClassRemoved:
471 case ChangeType::BlockAdded:
472 case ChangeType::BlockChanged:
473 case ChangeType::BlockRemoved:
474 case ChangeType::TemplateObjectAdded:
475 case ChangeType::TemplateObjectChanged:
476 case ChangeType::TemplateObjectRemoved:
477 case ChangeType::JSClassAdded:
478 case ChangeType::JSClassChanged:
479 case ChangeType::JSClassRemoved:
480 case ChangeType::TranslationDataAdded:
481 case ChangeType::TranslationDataChanged:
482 case ChangeType::TranslationDataRemoved:
484 case ChangeType::FunctionChanged:
490 case ChangeType::BindingChanged: {
491 Q_ASSERT(change.objectIndex >= 0);
492 Q_ASSERT(change.objectIndex < oldUnit->objectCount());
493 Q_ASSERT(change.objectIndex < newUnit->objectCount());
495 const QV4::CompiledData::Object *oldObj = oldUnit->objectAt(change.objectIndex);
496 Q_ASSERT(change.index < oldObj->nBindings);
497 const QV4::CompiledData::Binding *oldBinding = oldObj->bindingTable() + change.index;
499 const QV4::CompiledData::Object *newObj = newUnit->objectAt(change.objectIndex);
500 Q_ASSERT(change.index < newObj->nBindings);
501 const QV4::CompiledData::Binding *newBinding = newObj->bindingTable() + change.index;
503 const BindingKind oldKind = bindingKind(oldBinding);
504 const BindingKind newKind = bindingKind(newBinding);
512 if (oldKind != newKind)
520 return BindingPatchContext::targetPropertyName(oldUnit, change.objectIndex, oldBinding)
521 == BindingPatchContext::targetPropertyName(newUnit, change.objectIndex, newBinding);
550 const QV4::CompiledData::CompilationUnitDiff &diff,
551 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &oldUnit,
552 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &newUnit)
554 for (QObject *object : objects) {
557 QQmlData *ddata = QQmlData::get(object);
558 if (!ddata->context || !ddata->outerContext || !ddata->outerContext->isValid()
559 || ddata->isQueuedForDeletion) {
563 QVarLengthArray<BindingPatchContext, 4> contexts;
564 for (
int index : objectIndices(object, oldUnit))
565 contexts.append(BindingPatchContext(object, oldUnit, index));
567 for (
const QV4::CompiledData::Change &change : diff.changes) {
568 if (change.type != QV4::CompiledData::ChangeType::BindingChanged)
571 for (BindingPatchContext &context : contexts) {
572 if (context.applyBindingChange(newUnit, change))
586 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &oldUnit,
587 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &newUnit)
589 for (QObject *object : objects) {
590 QQmlData *ddata = QQmlData::get(object);
594 if (QQmlComponent *component = qobject_cast<QQmlComponent *>(object)) {
595 QQmlComponentPrivate *cp = QQmlComponentPrivate::get(component);
596 if (cp->compilationUnit() == oldUnit)
597 cp->setCompilationUnit(newUnit);
603 if (ddata->compilationUnit == oldUnit && ddata->cuObjectIndex < newUnit->objectCount())
604 ddata->compilationUnit = newUnit;
606 if (!ddata->hasVMEMetaObject)
610 auto *mainVme =
static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(object)->metaObject);
611 for (QQmlVMEMetaObject *vmeMeta = mainVme; vmeMeta;
612 vmeMeta = vmeMeta->parentVMEMetaObject()) {
613 if (vmeMeta->compilationUnit() != oldUnit)
615 if (vmeMeta->qmlObjectId() < newUnit->objectCount()) {
616 vmeMeta->setCompilationUnit(newUnit);
620 const QQmlPropertyCache::ConstPtr newCache =
621 newUnit->propertyCachesPtr()->at(vmeMeta->qmlObjectId());
623 vmeMeta->setPropertyCache(newCache);
624 if (vmeMeta == mainVme)
625 ddata->propertyCache = newCache;
630 vmeMeta->setCompilationUnit(
nullptr);
692 QV4::ExecutionEngine *engine,
693 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &oldUnit,
694 const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &newUnit)
696 const auto units = engine->compilationUnits();
697 for (
const auto &cu : units) {
698 for (
auto *typeRef : std::as_const(cu->baseCompilationUnit()->resolvedTypes)) {
699 if (typeRef->isSelfReference())
701 if (typeRef->compilationUnit() != oldUnit)
704 typeRef->setCompilationUnit(newUnit);
706 QQmlPropertyCache::ConstPtr newCache;
707 const QQmlType type = typeRef->type();
708 if (type.isInlineComponent()) {
709 if (
const int icId = newUnit->inlineComponentId(type.elementName()); icId >= 0)
710 newCache = newUnit->propertyCaches.at(icId);
712 newCache = newUnit->rootPropertyCache();
718 const QQmlPropertyCache::ConstPtr oldCache = typeRef->typePropertyCache();
719 typeRef->setTypePropertyCache(newCache);
720 relinkDerivedCaches(cu, oldCache, newCache);
728 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &newUnit)
730 QV4::ExecutionEngine *v4 = newUnit->engine;
731 QV4::Scope scope(v4);
732 QV4::ScopedValue function(scope);
734 for (QObject *object : objects) {
735 QQmlData *ddata = QQmlData::get(object);
736 if (!ddata || !ddata->hasVMEMetaObject)
739 auto *mainVme =
static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(object)->metaObject);
740 for (QQmlVMEMetaObject *vme = mainVme; vme; vme = vme->parentVMEMetaObject()) {
741 const auto cu = vme->compilationUnit();
745 const QQmlRefPointer<QQmlContextData> context = vme->contextData();
749 const int objectIndex = vme->qmlObjectId();
750 if (objectIndex < 0 || objectIndex >= cu->objectCount())
753 const QV4::CompiledData::Object *obj = cu->objectAt(objectIndex);
754 const QQmlPropertyCache::ConstPtr cache = cu->propertyCachesPtr()->at(objectIndex);
758 QV4::Scoped<QV4::QmlContext> qmlContext(
759 scope, QV4::QmlContext::create(v4->rootContext(), context, object));
761 const quint32_le *functionIdx = obj->functionOffsetTable();
762 for (quint32 i = 0; i < obj->nFunctions; ++i, ++functionIdx) {
763 QV4::Function *runtimeFunction = cu->runtimeFunctions[*functionIdx];
764 const QString name = runtimeFunction->name()->toQString();
766 const QQmlPropertyData *property = cache->property(name, object, context);
767 if (!property || !property->isVMEFunction())
771 function = runtimeFunction->isGenerator()
772 ? QV4::GeneratorFunction::create(qmlContext, runtimeFunction)
773 : QV4::FunctionObject::createScriptFunction(qmlContext, runtimeFunction);
774 mainVme->setVmeMethod(property->coreIndex(), function);
781 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &oldUnit,
782 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &newUnit)
785 if (!newUnit->runtimeStrings)
795 const QV4::CompiledData::CompilationUnitDiff diff =
796 QV4::CompiledData::diffCompilationUnits(oldUnit->unitData(), newUnit->unitData());
797 if (diff.success && isTrivialDiff(diff, oldUnit, newUnit)) {
798 patchConstantBindings(objects, diff, oldUnit, newUnit);
799 remapObjectsToNewUnit(objects, oldUnit, newUnit);
800 refreshVmeMethods(objects, newUnit);
824 std::vector<RebuildTarget> rebuild;
825 QSet<QObject *> rebuildSet;
826 bool redirectedTypes =
false;
828 const auto addRebuild = [&](QObject *object,
int index,
829 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &oldCu,
830 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &newCu) {
831 if (rebuildSet.contains(object))
833 rebuildSet.insert(object);
834 rebuild.push_back({ object, index, oldCu, newCu });
837 for (QObject *object : objects) {
838 const QVarLengthArray<
int, 4> indices = objectIndices(object, oldUnit);
839 for (
int index : indices) {
843 if (index >= oldUnit->objectCount())
845 const auto flags = oldUnit->objectAt(index)->flags();
846 if (index != 0 && !(flags & QV4::CompiledData::Object::IsInlineComponentRoot))
854 if (!canRebuildComponentRootInPlace(oldUnit, newUnit, index)) {
855 QObject *outer = outerRebuildTarget(object, oldUnit, newUnit);
857 return PatchResult::Failed;
862 if (!redirectedTypes) {
863 redirectResolvedTypeReferences(newUnit->engine, oldUnit->baseCompilationUnit(),
864 newUnit->baseCompilationUnit());
865 redirectedTypes =
true;
871 const QQmlRefPointer<QV4::ExecutableCompilationUnit> outerOld =
872 QQmlData::get(outer)->compilationUnit;
873 const QQmlRefPointer<QV4::ExecutableCompilationUnit> outerNew =
874 outerOld->baseCompilationUnit() == oldUnit->baseCompilationUnit()
877 addRebuild(outer, QQmlData::get(outer)->cuObjectIndex, outerOld, outerNew);
881 addRebuild(object, indices.first(), oldUnit, newUnit);
890 std::sort(rebuild.begin(), rebuild.end(),
891 [](
const RebuildTarget &a,
const RebuildTarget &b) {
return a.index < b.index; });
896 QSet<QObject *> skip;
897 for (
const RebuildTarget &target : rebuild) {
898 const QObjectList &children = target.object->children();
899 for (QObject *child : children)
903 for (
const RebuildTarget &target : rebuild) {
904 if (skip.contains(target.object))
907 rebuildObject(target.object, target.index, target.oldCu, target.newCu);
910 remapObjectsToNewUnit(objects, oldUnit, newUnit);