We need to track the objects created and pass them over to the VME guard used in the
incubator. The incremental build nature of the incubator requires that to avoid crashes.
For nested incubators we need to set the activeVMEData field in the root QQmlContext, to allow
child incubators to locate the parent.
Lastly we need can emulate most of the VME behavior in terms of build states when running with
QQmlInstantiationInterrupt by presenting four build steps: The initial state, two build steps,
a finalization step and the state when we're done.
Change-Id: I16cd7f71744decb9d4735ec77e9d944fad18e88d
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
// Build property caches and VME meta object data
- const int objectCount = parsedQML->objects.count();
- compiledData->datas.reserve(objectCount);
- compiledData->propertyCaches.reserve(objectCount);
+ compiledData->datas.reserve(parsedQML->objects.count());
+ compiledData->propertyCaches.reserve(parsedQML->objects.count());
{
QQmlPropertyCacheCreator propertyCacheBuilder(this);
// Collect some data for instantiation later.
int bindingCount = 0;
int parserStatusCount = 0;
+ int objectCount = 0;
for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
bindingCount += obj->nBindings;
if (typeRef->component) {
bindingCount += typeRef->component->totalBindingsCount;
parserStatusCount += typeRef->component->totalParserStatusCount;
- }
+ objectCount += typeRef->component->totalObjectCount;
+ } else
+ ++objectCount;
}
}
compiledData->totalBindingsCount = bindingCount;
compiledData->totalParserStatusCount = parserStatusCount;
+ compiledData->totalObjectCount = objectCount;
return errors.isEmpty();
}
QVector<int> customParserBindings; // index is binding identifier, value is compiled function index.
int totalBindingsCount; // Number of bindings used in this type
int totalParserStatusCount; // Number of instantiated types that are QQmlParserStatus subclasses
+ int totalObjectCount; // Number of objects explicitly instantiated
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
bool isCompositeType() const { return !datas.at(qmlUnit->indexOfRootObject).isEmpty(); }
p->compiledData = d->cc;
p->compiledData->addref();
if (enginePriv->useNewCompiler) {
- p->creator.reset(new QQmlObjectCreator(contextData, d->cc, d->creationContext));
+ p->creator.reset(new QQmlObjectCreator(contextData, d->cc, d->creationContext, p.data()));
p->subComponentToCreate = d->start;
} else
p->vme.init(contextData, d->cc, d->start, d->creationContext);
enginePriv->referenceScarceResources();
QObject *tresult = 0;
if (enginePriv->useNewCompiler) {
- tresult = creator->create(subComponentToCreate);
+ tresult = creator->create(subComponentToCreate, /*parent*/0, &i);
if (!tresult)
errors = creator->errors;
} else {
i->clear();
}
+ bool guardOk = d->vmeGuard.isOK();
+
d->vme.reset();
d->vmeGuard.clear();
+ if (d->creator && guardOk)
+ d->creator->clear();
d->creator.reset(0);
Q_ASSERT(d->compiledData == 0);
if (binding) binding->destroy();
}
-QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext)
- : compiledData(compiledData)
+QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, void *activeVMEDataForRootContext)
+ : phase(Startup)
+ , compiledData(compiledData)
, resolvedTypes(compiledData->resolvedTypes)
, propertyCaches(compiledData->propertyCaches)
, vmeMetaObjectData(compiledData->datas)
+ , activeVMEDataForRootContext(activeVMEDataForRootContext)
{
init(parentContext);
sharedState->componentAttached = 0;
sharedState->allCreatedBindings.allocate(compiledData->totalBindingsCount);
sharedState->allParserStatusCallbacks.allocate(compiledData->totalParserStatusCount);
+ sharedState->allCreatedObjects.allocate(compiledData->totalObjectCount);
sharedState->creationContext = creationContext;
sharedState->rootContext = 0;
}
QQmlObjectCreator::QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState)
- : compiledData(compiledData)
+ : phase(Startup)
+ , compiledData(compiledData)
, resolvedTypes(compiledData->resolvedTypes)
, propertyCaches(compiledData->propertyCaches)
, vmeMetaObjectData(compiledData->datas)
+ , activeVMEDataForRootContext(0)
{
init(parentContext);
}
}
-QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent)
+QObject *QQmlObjectCreator::create(int subComponentIndex, QObject *parent, QQmlInstantiationInterrupt *interrupt)
{
+ if (phase == CreatingObjectsPhase2) {
+ phase = ObjectsCreated;
+ return context->contextObject;
+ }
+ Q_ASSERT(phase == Startup);
+ phase = CreatingObjects;
+
int objectToCreate;
if (subComponentIndex == -1) {
if (!sharedState->rootContext) {
sharedState->rootContext = context;
+ sharedState->rootContext->activeVMEData = activeVMEDataForRootContext;
sharedState->rootContext->isRootObjectInCreation = true;
}
context->contextObject = instance;
}
+ phase = CreatingObjectsPhase2;
+
+ if (interrupt && interrupt->shouldInterrupt())
+ return 0;
+
+ phase = ObjectsCreated;
+
return instance;
}
ddata->rootObjectInCreation = true;
sharedState->rootContext->isRootObjectInCreation = false;
}
+
+ sharedState->allCreatedObjects.push(instance);
} else {
Q_ASSERT(typeRef->component);
if (typeRef->component->qmlUnit->isSingleton())
QQmlContextData *QQmlObjectCreator::finalize(QQmlInstantiationInterrupt &interrupt)
{
+ Q_ASSERT(phase == ObjectsCreated || phase == Finalizing);
+ phase = Finalizing;
+
QRecursionWatcher<QQmlObjectCreatorSharedState, &QQmlObjectCreatorSharedState::recursionNode> watcher(sharedState.data());
ActiveOCRestorer ocRestorer(this, QQmlEnginePrivate::get(engine));
}
}
+ phase = Done;
+
return sharedState->rootContext;
}
+void QQmlObjectCreator::clear()
+{
+ if (phase == Done || phase == Finalizing || phase == Startup)
+ return;
+ Q_ASSERT(phase != Startup);
+
+ while (!sharedState->allCreatedObjects.isEmpty())
+ delete sharedState->allCreatedObjects.pop();
+
+ phase = Done;
+}
+
bool QQmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty, bool installPropertyCache, const QBitArray &bindingsToSkip)
{
const QV4::CompiledData::Object *obj = qmlUnit->objectAt(index);
QQmlContextData *creationContext;
QFiniteStack<QQmlAbstractBinding*> allCreatedBindings;
QFiniteStack<QQmlParserStatus*> allParserStatusCallbacks;
+ QFiniteStack<QObject*> allCreatedObjects;
QQmlComponentAttached *componentAttached;
QList<QQmlEnginePrivate::FinalizeCallback> finalizeCallbacks;
QRecursionNode recursionNode;
{
Q_DECLARE_TR_FUNCTIONS(QQmlObjectCreator)
public:
- QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext);
+ QQmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, void *activeVMEDataForRootContext = 0);
~QQmlObjectCreator();
- QObject *create(int subComponentIndex = -1, QObject *parent = 0);
+ QObject *create(int subComponentIndex = -1, QObject *parent = 0, QQmlInstantiationInterrupt *interrupt = 0);
QQmlContextData *finalize(QQmlInstantiationInterrupt &interrupt);
+ void clear();
QQmlComponentAttached **componentAttachment() { return &sharedState->componentAttached; }
QList<QQmlError> errors;
QQmlContextData *parentContextData() const { return parentContext; }
+ QFiniteStack<QObject*> &allCreatedObjects() const { return sharedState->allCreatedObjects; }
private:
QQmlObjectCreator(QQmlContextData *contextData, QQmlCompiledData *compiledData, QQmlObjectCreatorSharedState *inheritedSharedState);
QString stringAt(int idx) const { return qmlUnit->header.stringAt(idx); }
void recordError(const QV4::CompiledData::Location &location, const QString &description);
+ enum Phase {
+ Startup,
+ CreatingObjects,
+ CreatingObjectsPhase2,
+ ObjectsCreated,
+ Finalizing,
+ Done
+ } phase;
+
QQmlEngine *engine;
QQmlCompiledData *compiledData;
const QV4::CompiledData::QmlUnit *qmlUnit;
const QVector<QByteArray> &vmeMetaObjectData;
QHash<int, int> objectIndexToId;
QFlagPointer<QQmlObjectCreatorSharedState> sharedState;
+ void *activeVMEDataForRootContext;
QObject *_qobject;
QObject *_scopeObject;
void QQmlVMEGuard::guard(QQmlObjectCreator *creator)
{
clear();
+
+ QFiniteStack<QObject*> &objects = creator->allCreatedObjects();
+ m_objectCount = objects.count();
+ m_objects = new QPointer<QObject>[m_objectCount];
+ for (int ii = 0; ii < m_objectCount; ++ii)
+ m_objects[ii] = objects[ii];
+
m_contextCount = 1;
m_contexts = new QQmlGuardedContextData[m_contextCount];
m_contexts[0] = creator->parentContextData();