aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@digia.com>2014-02-06 09:35:28 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2014-02-07 12:44:08 +0100
commit50ce88a53107f97664d928719c1877b8077e9a2e (patch)
treea43fdc574cf5028517443514b5d56be221b86dd1
parentd5a96399cec189251d8ee3e82493aceec112fbd8 (diff)
[new compiler] Fix parser status and created bindings allocation
Pre-calculate the amount of space we need for binding and parser status callbacks at compile time and therefore use a much simpler data structure (vector) to store the points to the bindings and callbacks. They need to be stored because during object construction and binding enabling phase, it may happen that they get destroyed and thus their m_mePtr pointing into the array gets deleted. The contiguous vector will also make it possible to interrupt the completion phase. Change-Id: Ic7c985bb8325ab355112e30e9d33d6ae4e7476d1 Reviewed-by: Lars Knoll <lars.knoll@digia.com>
-rw-r--r--src/qml/compiler/qqmltypecompiler.cpp21
-rw-r--r--src/qml/qml/ftw/qfinitestack_p.h2
-rw-r--r--src/qml/qml/qqmlcompileddata.cpp2
-rw-r--r--src/qml/qml/qqmlcompiler_p.h3
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp114
-rw-r--r--src/qml/qml/qqmlobjectcreator_p.h15
6 files changed, 100 insertions, 57 deletions
diff --git a/src/qml/compiler/qqmltypecompiler.cpp b/src/qml/compiler/qqmltypecompiler.cpp
index 4466b430fe..dae57fe6f4 100644
--- a/src/qml/compiler/qqmltypecompiler.cpp
+++ b/src/qml/compiler/qqmltypecompiler.cpp
@@ -244,6 +244,27 @@ bool QQmlTypeCompiler::compile()
if (!validator.validate())
return false;
+ // Collect some data for instantiation later.
+ int bindingCount = 0;
+ int parserStatusCount = 0;
+ for (quint32 i = 0; i < qmlUnit->nObjects; ++i) {
+ const QV4::CompiledData::Object *obj = qmlUnit->objectAt(i);
+ bindingCount += obj->nBindings;
+ if (QQmlCompiledData::TypeReference *typeRef = compiledData->resolvedTypes.value(obj->inheritedTypeNameIndex)) {
+ if (QQmlType *qmlType = typeRef->type) {
+ if (qmlType->parserStatusCast() != -1)
+ ++parserStatusCount;
+ }
+ if (typeRef->component) {
+ bindingCount += typeRef->component->totalBindingsCount;
+ parserStatusCount += typeRef->component->totalParserStatusCount;
+ }
+ }
+ }
+
+ compiledData->totalBindingsCount = bindingCount;
+ compiledData->totalParserStatusCount = parserStatusCount;
+
return errors.isEmpty();
}
diff --git a/src/qml/qml/ftw/qfinitestack_p.h b/src/qml/qml/ftw/qfinitestack_p.h
index 31a530fa64..6bfd353771 100644
--- a/src/qml/qml/ftw/qfinitestack_p.h
+++ b/src/qml/qml/ftw/qfinitestack_p.h
@@ -114,6 +114,7 @@ T &QFiniteStack<T>::top()
template<typename T>
void QFiniteStack<T>::push(const T &o)
{
+ Q_ASSERT(_size < _alloc);
if (QTypeInfo<T>::isComplex) {
new (_array + _size++) T(o);
} else {
@@ -124,6 +125,7 @@ void QFiniteStack<T>::push(const T &o)
template<typename T>
T QFiniteStack<T>::pop()
{
+ Q_ASSERT(_size > 0);
--_size;
if (QTypeInfo<T>::isComplex) {
diff --git a/src/qml/qml/qqmlcompileddata.cpp b/src/qml/qml/qqmlcompileddata.cpp
index 05ec0ab9c7..75740e17e6 100644
--- a/src/qml/qml/qqmlcompileddata.cpp
+++ b/src/qml/qml/qqmlcompileddata.cpp
@@ -88,7 +88,7 @@ int QQmlCompiledData::indexForUrl(const QUrl &data)
QQmlCompiledData::QQmlCompiledData(QQmlEngine *engine)
: engine(engine), importCache(0), metaTypeId(-1), listMetaTypeId(-1), isRegisteredWithEngine(false),
- rootPropertyCache(0), compilationUnit(0), qmlUnit(0)
+ rootPropertyCache(0), compilationUnit(0), qmlUnit(0), totalBindingsCount(0), totalParserStatusCount(0)
{
Q_ASSERT(engine);
diff --git a/src/qml/qml/qqmlcompiler_p.h b/src/qml/qml/qqmlcompiler_p.h
index c63f430b0a..2ce850da5d 100644
--- a/src/qml/qml/qqmlcompiler_p.h
+++ b/src/qml/qml/qqmlcompiler_p.h
@@ -85,6 +85,7 @@ class QQmlComponent;
class QQmlContext;
class QQmlContextData;
+// ### Merge with QV4::CompiledData::CompilationUnit
class Q_AUTOTEST_EXPORT QQmlCompiledData : public QQmlRefCount, public QQmlCleanup
{
public:
@@ -161,6 +162,8 @@ public:
// hash key is object index
QHash<int, QByteArray> customParserData;
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
bool isComponent(int objectIndex) const { return objectIndexToIdPerComponent.contains(objectIndex); }
bool isCompositeType() const { return !datas.at(qmlUnit->indexOfRootObject).isEmpty(); }
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index 38edfc0360..2b69955dde 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -80,7 +80,8 @@ static void removeBindingOnProperty(QObject *o, int index)
if (binding) binding->destroy();
}
-QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, QQmlContextData *rootContext)
+QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledData *compiledData, QQmlContextData *creationContext, QQmlContextData *rootContext,
+ QFiniteStack<QQmlAbstractBinding *> *inheritedBindingStack, QFiniteStack<QQmlParserStatus *> *inheritedParserStatusStack)
: componentAttached(0)
, url(compiledData->url)
, engine(parentContext->engine)
@@ -92,6 +93,9 @@ QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledD
, resolvedTypes(compiledData->resolvedTypes)
, propertyCaches(compiledData->propertyCaches)
, vmeMetaObjectData(compiledData->datas)
+ , allCreatedBindings(0)
+ , allParserStatusCallbacks(0)
+ , ownBindingAndParserStatusStacks(false)
, compiledData(compiledData)
, rootContext(rootContext)
, _qobject(0)
@@ -105,12 +109,48 @@ QmlObjectCreator::QmlObjectCreator(QQmlContextData *parentContext, QQmlCompiledD
{
if (!compiledData->isInitialized())
compiledData->initialize(engine);
+
+ if (inheritedBindingStack) {
+ Q_ASSERT(rootContext);
+ Q_ASSERT(inheritedParserStatusStack);
+ allCreatedBindings = inheritedBindingStack;
+ allParserStatusCallbacks = inheritedParserStatusStack;
+ ownBindingAndParserStatusStacks = false;
+ } else {
+ ownBindingAndParserStatusStacks = true;
+ allCreatedBindings = new QFiniteStack<QQmlAbstractBinding*>;
+ allCreatedBindings->allocate(compiledData->totalBindingsCount);
+ allParserStatusCallbacks = new QFiniteStack<QQmlParserStatus*>;
+ allParserStatusCallbacks->allocate(compiledData->totalParserStatusCount);
+ }
+}
+
+QmlObjectCreator::~QmlObjectCreator()
+{
+ if (ownBindingAndParserStatusStacks) {
+ for (int i = 0; i < allCreatedBindings->count(); ++i) {
+ QQmlAbstractBinding *b = allCreatedBindings->at(i);
+ if (b)
+ b->m_mePtr = 0;
+ }
+ for (int i = 0; i < allParserStatusCallbacks->count(); ++i) {
+ QQmlParserStatus *ps = allParserStatusCallbacks->at(i);
+ if (ps)
+ ps->d = 0;
+ }
+
+ delete allCreatedBindings;
+ delete allParserStatusCallbacks;
+ }
}
QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
{
int objectToCreate;
+ Q_ASSERT(!ownBindingAndParserStatusStacks || allCreatedBindings->isEmpty());
+ Q_ASSERT(!ownBindingAndParserStatusStacks || allParserStatusCallbacks->isEmpty());
+
if (subComponentIndex == -1) {
objectIndexToId = compiledData->objectIndexToIdForRoot;
objectToCreate = qmlUnit->indexOfRootObject;
@@ -158,10 +198,6 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
context->importedScripts = creationContext->importedScripts;
}
- QVector<QQmlParserStatus*> parserStatusCallbacks;
- parserStatusCallbacks.resize(qmlUnit->nObjects);
- qSwap(_parserStatusCallbacks, parserStatusCallbacks);
-
QObject *instance = createInstance(objectToCreate, parent);
if (instance) {
QQmlData *ddata = QQmlData::get(instance);
@@ -172,9 +208,6 @@ QObject *QmlObjectCreator::create(int subComponentIndex, QObject *parent)
context->contextObject = instance;
}
- qSwap(_parserStatusCallbacks, parserStatusCallbacks);
- allParserStatusCallbacks.prepend(parserStatusCallbacks);
-
return instance;
}
@@ -602,14 +635,14 @@ void QmlObjectCreator::setupBindings()
}
- if (!setPropertyValue(property, i, binding))
+ if (!setPropertyBinding(property, binding))
return;
}
qSwap(_currentList, savedList);
}
-bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingIndex, const QV4::CompiledData::Binding *binding)
+bool QmlObjectCreator::setPropertyBinding(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding)
{
if (binding->type == QV4::CompiledData::Binding::Type_AttachedProperty) {
Q_ASSERT(stringAt(qmlUnit->objectAt(binding->value.objectIndex)->inheritedTypeNameIndex).isEmpty());
@@ -747,8 +780,8 @@ bool QmlObjectCreator::setPropertyValue(QQmlPropertyData *property, int bindingI
qmlBinding->addToObject();
}
- _createdBindings[bindingIndex] = qmlBinding;
- qmlBinding->m_mePtr = &_createdBindings[bindingIndex];
+ allCreatedBindings->push(qmlBinding);
+ qmlBinding->m_mePtr = &allCreatedBindings->top();
}
return true;
}
@@ -940,7 +973,7 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
recordError(obj->location, tr("Composite Singleton Type %1 is not creatable").arg(stringAt(obj->inheritedTypeNameIndex)));
return 0;
}
- QmlObjectCreator subCreator(context, typeRef->component, creationContext, rootContext);
+ QmlObjectCreator subCreator(context, typeRef->component, creationContext, rootContext, allCreatedBindings, allParserStatusCallbacks);
instance = subCreator.create();
if (!instance) {
errors += subCreator.errors;
@@ -948,8 +981,6 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
}
if (subCreator.componentAttached)
subCreator.componentAttached->add(&componentAttached);
- allCreatedBindings << subCreator.allCreatedBindings;
- allParserStatusCallbacks << subCreator.allParserStatusCallbacks;
}
// ### use no-event variant
if (parent)
@@ -976,8 +1007,8 @@ QObject *QmlObjectCreator::createInstance(int index, QObject *parent)
if (parserStatus) {
parserStatus->classBegin();
- _parserStatusCallbacks[index] = parserStatus;
- parserStatus->d = &_parserStatusCallbacks[index];
+ allParserStatusCallbacks->push(parserStatus);
+ parserStatus->d = &allParserStatusCallbacks->top();
}
QHash<int, int>::ConstIterator idEntry = objectIndexToId.find(index);
@@ -1023,45 +1054,34 @@ QQmlContextData *QmlObjectCreator::finalize()
QQmlTrace trace("VME Binding Enable");
trace.event("begin binding eval");
- Q_ASSERT(allCreatedBindings.isEmpty() || allCreatedBindings.isDetached());
-
- for (QLinkedList<QVector<QQmlAbstractBinding*> >::Iterator it = allCreatedBindings.begin(), end = allCreatedBindings.end();
- it != end; ++it) {
- const QVector<QQmlAbstractBinding *> &bindings = *it;
- for (int i = 0; i < bindings.count(); ++i) {
- QQmlAbstractBinding *b = bindings.at(i);
- if (!b)
- continue;
- b->m_mePtr = 0;
- QQmlData *data = QQmlData::get(b->object());
- Q_ASSERT(data);
- data->clearPendingBindingBit(b->propertyIndex());
- b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
- QQmlPropertyPrivate::DontRemoveBinding);
- }
+ while (!allCreatedBindings->isEmpty()) {
+ QQmlAbstractBinding *b = allCreatedBindings->pop();
+ if (!b)
+ continue;
+ b->m_mePtr = 0;
+ QQmlData *data = QQmlData::get(b->object());
+ Q_ASSERT(data);
+ data->clearPendingBindingBit(b->propertyIndex());
+ b->setEnabled(true, QQmlPropertyPrivate::BypassInterceptor |
+ QQmlPropertyPrivate::DontRemoveBinding);
}
}
if (true /* ### componentCompleteEnabled()*/) { // the qml designer does the component complete later
QQmlTrace trace("VME Component Complete");
- for (QLinkedList<QVector<QQmlParserStatus*> >::ConstIterator it = allParserStatusCallbacks.constBegin(), end = allParserStatusCallbacks.constEnd();
- it != end; ++it) {
- const QVector<QQmlParserStatus *> &parserStatusCallbacks = *it;
- for (int i = parserStatusCallbacks.count() - 1; i >= 0; --i) {
- QQmlParserStatus *status = parserStatusCallbacks.at(i);
-
- if (status && status->d) {
- status->d = 0;
- status->componentComplete();
- }
+ while (!allParserStatusCallbacks->isEmpty()) {
+ QQmlParserStatus *status = allParserStatusCallbacks->pop();
+
+ if (status && status->d) {
+ status->d = 0;
+ status->componentComplete();
+ }
#if 0 // ###
if (watcher.hasRecursed() || interrupt.shouldInterrupt())
return 0;
#endif
- }
}
- allParserStatusCallbacks.clear();
}
{
@@ -1135,14 +1155,10 @@ bool QmlObjectCreator::populateInstance(int index, QObject *instance, QQmlRefPoi
qSwap(_vmeMetaObject, vmeMetaObject);
QVector<QQmlAbstractBinding*> createdBindings(_compiledObject->nBindings, 0);
- qSwap(_createdBindings, createdBindings);
setupFunctions();
setupBindings();
- allCreatedBindings.append(_createdBindings);
-
- qSwap(_createdBindings, createdBindings);
qSwap(_vmeMetaObject, vmeMetaObject);
qSwap(_bindingTarget, bindingTarget);
qSwap(_ddata, declarativeData);
diff --git a/src/qml/qml/qqmlobjectcreator_p.h b/src/qml/qml/qqmlobjectcreator_p.h
index e5fe4e3b81..cb23f61c84 100644
--- a/src/qml/qml/qqmlobjectcreator_p.h
+++ b/src/qml/qml/qqmlobjectcreator_p.h
@@ -46,7 +46,7 @@
#include <private/qv4compileddata_p.h>
#include <private/qqmlcompiler_p.h>
#include <private/qqmltypecompiler_p.h>
-#include <QLinkedList>
+#include <private/qfinitestack_p.h>
QT_BEGIN_NAMESPACE
@@ -57,7 +57,9 @@ class QmlObjectCreator
{
Q_DECLARE_TR_FUNCTIONS(QmlObjectCreator)
public:
- QmlObjectCreator(QQmlContextData *contextData, QQmlCompiledData *compiledData, QQmlContextData *creationContext, QQmlContextData *rootContext = 0);
+ QmlObjectCreator(QQmlContextData *contextData, QQmlCompiledData *compiledData, QQmlContextData *creationContext, QQmlContextData *rootContext = 0,
+ QFiniteStack<QQmlAbstractBinding*> *inheritedBindingStack = 0, QFiniteStack<QQmlParserStatus*> *inheritedParserStatusStack = 0);
+ ~QmlObjectCreator();
QObject *create(int subComponentIndex = -1, QObject *parent = 0);
QQmlContextData *finalize();
@@ -73,7 +75,7 @@ private:
bool populateInstance(int index, QObject *instance, QQmlRefPointer<QQmlPropertyCache> cache, QObject *bindingTarget, QQmlPropertyData *valueTypeProperty);
void setupBindings();
- bool setPropertyValue(QQmlPropertyData *property, int index, const QV4::CompiledData::Binding *binding);
+ bool setPropertyBinding(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setPropertyValue(QQmlPropertyData *property, const QV4::CompiledData::Binding *binding);
void setupFunctions();
@@ -91,8 +93,9 @@ private:
const QVector<QQmlPropertyCache *> propertyCaches;
const QVector<QByteArray> vmeMetaObjectData;
QHash<int, int> objectIndexToId;
- QLinkedList<QVector<QQmlAbstractBinding*> > allCreatedBindings;
- QLinkedList<QVector<QQmlParserStatus*> > allParserStatusCallbacks;
+ QFiniteStack<QQmlAbstractBinding*> *allCreatedBindings;
+ QFiniteStack<QQmlParserStatus*> *allParserStatusCallbacks;
+ bool ownBindingAndParserStatusStacks;
QQmlCompiledData *compiledData;
QQmlContextData *rootContext;
@@ -105,10 +108,8 @@ private:
QQmlData *_ddata;
QQmlRefPointer<QQmlPropertyCache> _propertyCache;
QQmlVMEMetaObject *_vmeMetaObject;
- QVector<QQmlAbstractBinding*> _createdBindings;
QQmlListProperty<void> _currentList;
QV4::ExecutionContext *_qmlContext;
- QVector<QQmlParserStatus*> _parserStatusCallbacks;
};
QT_END_NAMESPACE