From 738fe5730a55279bf3c033bad7317768d81f40af Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 11 May 2009 11:36:57 +1000 Subject: Handle QmlParserStatus's and QmlBindableValeus being deleted during component creation --- src/declarative/qml/qmlbindablevalue.cpp | 5 +++- src/declarative/qml/qmlbindablevalue_p.h | 2 ++ src/declarative/qml/qmlcompiler.cpp | 25 ++++++++++++++++---- src/declarative/qml/qmlcomponent.cpp | 40 +++++++++++++++++++++++--------- src/declarative/qml/qmlcomponent_p.h | 7 ++++-- src/declarative/qml/qmlengine.cpp | 29 +++++++++++++++++++++++ src/declarative/qml/qmlengine_p.h | 31 +++++++++++++++++++++++-- src/declarative/qml/qmlinstruction_p.h | 2 ++ src/declarative/qml/qmlparserstatus.cpp | 12 +++++++--- src/declarative/qml/qmlparserstatus.h | 7 ++++++ src/declarative/qml/qmlvme.cpp | 35 +++++++++++++++++++++------- 11 files changed, 164 insertions(+), 31 deletions(-) diff --git a/src/declarative/qml/qmlbindablevalue.cpp b/src/declarative/qml/qmlbindablevalue.cpp index 3950f82..9f4886a 100644 --- a/src/declarative/qml/qmlbindablevalue.cpp +++ b/src/declarative/qml/qmlbindablevalue.cpp @@ -52,7 +52,7 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(scriptWarnings, QML_SCRIPT_WARNINGS); QmlBindableValuePrivate::QmlBindableValuePrivate() -: inited(false) +: inited(false), mePtr(0) { } @@ -75,6 +75,9 @@ QmlBindableValue::QmlBindableValue(const QString &str, QObject *obj, bool sse, Q QmlBindableValue::~QmlBindableValue() { + Q_D(QmlBindableValue); + if(d->mePtr) + *(d->mePtr) = 0; } void QmlBindableValue::setTarget(const QmlMetaProperty &prop) diff --git a/src/declarative/qml/qmlbindablevalue_p.h b/src/declarative/qml/qmlbindablevalue_p.h index b6de5b7..70c001b 100644 --- a/src/declarative/qml/qmlbindablevalue_p.h +++ b/src/declarative/qml/qmlbindablevalue_p.h @@ -56,6 +56,8 @@ public: bool inited; QmlMetaProperty property; + + QmlBindableValue **mePtr; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 13fc332..5dbc5c3 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -526,6 +526,8 @@ void QmlCompiler::compileTree(Object *tree) init.type = QmlInstruction::Init; init.line = 0; init.init.dataSize = 0; + init.init.bindingsSize = 0; + init.init.parserStatusSize = 0; output->bytecode << init; if (!compileObject(tree, 0)) // Compile failed @@ -698,6 +700,8 @@ bool QmlCompiler::compileComponentFromRoot(Object *obj, int ctxt) QmlInstruction init; init.type = QmlInstruction::Init; init.init.dataSize = 0; + init.init.bindingsSize = 0; + init.init.parserStatusSize = 0; init.line = obj->location.start.line; output->bytecode << init; @@ -1378,6 +1382,8 @@ int QmlCompiler::optimizeExpressions(int start, int end, int patch) QHash ids; int saveCount = 0; int newInstrs = 0; + int bindingsCount = 0; + int parserStatusCount = 0; for (int ii = start; ii <= end; ++ii) { const QmlInstruction &instr = output->bytecode.at(ii); @@ -1400,6 +1406,17 @@ int QmlCompiler::optimizeExpressions(int start, int end, int patch) ii += instr.createComponent.count - 1; continue; } + + if (instr.type == QmlInstruction::AssignBinding || + instr.type == QmlInstruction::AssignCompiledBinding || + instr.type == QmlInstruction::StoreBinding || + instr.type == QmlInstruction::StoreCompiledBinding) { + ++bindingsCount; + } else if (instr.type == QmlInstruction::TryBeginObject || + instr.type == QmlInstruction::BeginObject) { + ++parserStatusCount; + } + if (instr.type == QmlInstruction::StoreCompiledBinding) { QmlBasicScript s(output->datas.at(instr.assignBinding.value).constData()); @@ -1437,12 +1454,12 @@ int QmlCompiler::optimizeExpressions(int start, int end, int patch) ++newInstrs; } } - } - + } } - if (saveCount) - output->bytecode[patch].init.dataSize = saveCount; + output->bytecode[patch].init.dataSize = saveCount; + output->bytecode[patch].init.bindingsSize = bindingsCount; + output->bytecode[patch].init.parserStatusSize = parserStatusCount;; return newInstrs; } diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index 027c2a8..da8f26d 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -171,6 +171,11 @@ QmlComponent::~QmlComponent() } if (d->cc) d->cc->release(); + + for(int ii = 0; ii < d->bindValues.count(); ++ii) + QmlEnginePrivate::clear(d->bindValues[ii]); + for(int ii = 0; ii < d->parserStatus.count(); ++ii) + QmlEnginePrivate::clear(d->parserStatus[ii]); } /*! @@ -483,10 +488,10 @@ QObject *QmlComponent::beginCreate(QmlContext *context) if (ep->rootComponent == this) { ep->rootComponent = 0; - d->bindValues = ep->currentBindValues; - d->parserStatus = ep->currentParserStatus; - ep->currentBindValues.clear(); - ep->currentParserStatus.clear(); + d->bindValues = ep->bindValues; + d->parserStatus = ep->parserStatus; + ep->bindValues.clear(); + ep->parserStatus.clear(); d->completePending = true; } } else { @@ -511,16 +516,29 @@ void QmlComponent::completeCreate() #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer bi; #endif - for (int ii = 0; ii < d->bindValues.count(); ++ii) - d->bindValues.at(ii)->init(); + for (int ii = 0; ii < d->bindValues.count(); ++ii) { + QmlEnginePrivate::SimpleList bv = + d->bindValues.at(ii); + for (int jj = 0; jj < bv.count; ++jj) { + if(bv.at(jj)) + bv.at(jj)->init(); + } + QmlEnginePrivate::clear(bv); + } } - QSet done; + for (int ii = 0; ii < d->parserStatus.count(); ++ii) { - QmlParserStatus *ps = d->parserStatus.at(ii); - if (!done.contains(ps)) { - done.insert(ps); - ps->componentComplete(); + QmlEnginePrivate::SimpleList ps = + d->parserStatus.at(ii); + + for (int jj = 0; jj < ps.count; ++jj) { + QmlParserStatus *status = ps.at(jj); + if (status && status->d) { + status->d = 0; + status->componentComplete(); + } } + QmlEnginePrivate::clear(ps); } d->bindValues.clear(); diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h index 6a5345e..4de47c6 100644 --- a/src/declarative/qml/qmlcomponent_p.h +++ b/src/declarative/qml/qmlcomponent_p.h @@ -46,6 +46,7 @@ #include #include #include "private/qobject_p.h" +#include "private/qmlengine_p.h" #include "private/qmlcompositetypemanager_p.h" #include #include "qmlcomponent.h" @@ -75,8 +76,10 @@ public: int start; int count; QmlCompiledComponent *cc; - QList bindValues; - QList parserStatus; + + QList > bindValues; + QList > parserStatus; + bool completePending; QmlEngine *engine; diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 50c0981..f0ec334 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -70,6 +70,7 @@ #include #include #include "private/qmlmetaproperty_p.h" +#include QT_BEGIN_NAMESPACE @@ -160,6 +161,34 @@ QmlEnginePrivate::~QmlEnginePrivate() objectClass = 0; delete networkAccessManager; networkAccessManager = 0; + + for(int ii = 0; ii < bindValues.count(); ++ii) + clear(bindValues[ii]); + for(int ii = 0; ii < parserStatus.count(); ++ii) + clear(parserStatus[ii]); +} + +void QmlEnginePrivate::clear(SimpleList &bvs) +{ + for (int ii = 0; ii < bvs.count; ++ii) { + QmlBindableValue *bv = bvs.at(ii); + if(bv) { + QmlBindableValuePrivate *p = + static_cast(QObjectPrivate::get(bv)); + p->mePtr = 0; + } + } + bvs.clear(); +} + +void QmlEnginePrivate::clear(SimpleList &pss) +{ + for (int ii = 0; ii < pss.count; ++ii) { + QmlParserStatus *ps = pss.at(ii); + if(ps) + ps->d = 0; + } + pss.clear(); } void QmlEnginePrivate::init() diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 63df0ba..9402fa9 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -107,8 +107,35 @@ public: QScriptEngine scriptEngine; - QList currentBindValues; - QList currentParserStatus; + template + struct SimpleList { + SimpleList() + : count(0), values(0) {} + SimpleList(int r) + : count(0), values(new T*[r]) {} + + int count; + T **values; + + void append(T *v) { + values[count++] = v; + } + + T *at(int idx) const { + return values[idx]; + } + + void clear() { + delete [] values; + } + }; + + static void clear(SimpleList &); + static void clear(SimpleList &); + + QList > bindValues; + QList > parserStatus; + QmlComponent *rootComponent; mutable QNetworkAccessManager *networkAccessManager; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 02e084d..86bddf8 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -173,6 +173,8 @@ public: union { struct { int dataSize; + int bindingsSize; + int parserStatusSize; } init; struct { int type; diff --git a/src/declarative/qml/qmlparserstatus.cpp b/src/declarative/qml/qmlparserstatus.cpp index 71b7adf..fceac05 100644 --- a/src/declarative/qml/qmlparserstatus.cpp +++ b/src/declarative/qml/qmlparserstatus.cpp @@ -48,11 +48,17 @@ QT_BEGIN_NAMESPACE \brief The QmlParserStatus class provides updates on the parser state. */ -/*! - Destroys the parser status instance. -*/ +/*! \internal */ +QmlParserStatus::QmlParserStatus() +: d(0) +{ +} + +/*! \internal */ QmlParserStatus::~QmlParserStatus() { + if(d) + (*d) = 0; } /*! diff --git a/src/declarative/qml/qmlparserstatus.h b/src/declarative/qml/qmlparserstatus.h index bb3691c..0e58229 100644 --- a/src/declarative/qml/qmlparserstatus.h +++ b/src/declarative/qml/qmlparserstatus.h @@ -53,11 +53,18 @@ QT_MODULE(Declarative) class Q_DECLARATIVE_EXPORT QmlParserStatus { public: + QmlParserStatus(); virtual ~QmlParserStatus(); virtual void classBegin(); virtual void classComplete(); virtual void componentComplete(); + +private: + friend class QmlVME; + friend class QmlComponent; + friend class QmlEnginePrivate; + QmlParserStatus **d; }; Q_DECLARE_INTERFACE(QmlParserStatus, "com.trolltech.qml.QmlParserStatus"); diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index ca4f9c9..e42b2fc 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -62,6 +62,8 @@ #include #include "private/qmlvmemetaobject_p.h" #include +#include +#include QT_BEGIN_NAMESPACE Q_DECLARE_PERFORMANCE_LOG(QFxCompiler) { @@ -219,9 +221,8 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer cr; #endif - - QList parserStatuses; - QList bindableValues; + QmlEnginePrivate::SimpleList bindValues; + QmlEnginePrivate::SimpleList parserStatus; QStack stack; QStack qliststack; @@ -252,6 +253,11 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in ::memset(savedObjects, 0, sizeof(QObject *)*instr.init.dataSize); } + + if (instr.init.bindingsSize) + bindValues = QmlEnginePrivate::SimpleList(instr.init.bindingsSize); + if (instr.init.parserStatusSize) + parserStatus = QmlEnginePrivate::SimpleList(instr.init.parserStatusSize); } break; @@ -523,8 +529,10 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in #endif QObject *target = stack.top(); QmlParserStatus *status = reinterpret_cast(reinterpret_cast(target) + instr.begin.castValue); + parserStatus.append(status); + status->d = &parserStatus.values[parserStatus.count - 1]; + status->classBegin(); - parserStatuses << status; } break; @@ -634,10 +642,13 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in VME_EXCEPTION("Cannot assign a binding to read-only property" << mp.name()); QmlBindableValue *bind = new QmlBindableValue((void *)datas.at(instr.assignBinding.value).constData(), comp, context, 0); + bindValues.append(bind); + QmlBindableValuePrivate *p = + static_cast(QObjectPrivate::get(bind)); + p->mePtr = &bindValues.values[bindValues.count - 1]; QFx_setParent_noEvent(bind, target); bind->setTarget(mp); - bindableValues << bind; } break; @@ -656,10 +667,13 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in VME_EXCEPTION("Cannot assign a binding to read-only property" << mp.name()); QmlBindableValue *bind = new QmlBindableValue(primitives.at(instr.assignBinding.value), context, false); + bindValues.append(bind); + QmlBindableValuePrivate *p = + static_cast(QObjectPrivate::get(bind)); + p->mePtr = &bindValues.values[bindValues.count - 1]; QFx_setParent_noEvent(bind, target); bind->setTarget(mp); - bindableValues << bind; } break; @@ -1045,12 +1059,17 @@ QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, in if (!stack.isEmpty()) { delete stack.at(0); } + + QmlEnginePrivate::clear(bindValues); + QmlEnginePrivate::clear(parserStatus); return 0; } QmlEnginePrivate *ep = ctxt->engine()->d_func(); - ep->currentBindValues << bindableValues; - ep->currentParserStatus << parserStatuses; + if (bindValues.count) + ep->bindValues << bindValues; + if (parserStatus.count) + ep->parserStatus << parserStatus; comp->dumpPost(); -- cgit v0.12