aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2011-10-03 15:45:51 +1000
committerQt by Nokia <qt-info@nokia.com>2011-10-03 11:43:03 +0200
commit95cd185fa4bfe872458988d0b5ffb36fd1b56bd3 (patch)
tree2e8091c278db670eddb09ebc060581ccb208d27e /src
parent0eec42dff07073d9e0cb955b0888f63e073f2a2a (diff)
QDeclarativeIncubator::clear() and autotests
Change-Id: I2a14c01c7f9412459572e9960cb95a4c24e068aa Task-number: QTBUG-21151 Reviewed-on: http://codereview.qt-project.org/5911 Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
Diffstat (limited to 'src')
-rw-r--r--src/declarative/qml/qdeclarativeincubator.cpp29
-rw-r--r--src/declarative/qml/qdeclarativeincubator_p.h1
-rw-r--r--src/declarative/qml/qdeclarativevme.cpp119
-rw-r--r--src/declarative/qml/qdeclarativevme_p.h32
4 files changed, 155 insertions, 26 deletions
diff --git a/src/declarative/qml/qdeclarativeincubator.cpp b/src/declarative/qml/qdeclarativeincubator.cpp
index 053a026882..b6eb4e478a 100644
--- a/src/declarative/qml/qdeclarativeincubator.cpp
+++ b/src/declarative/qml/qdeclarativeincubator.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qdeclarativeincubator.h"
+#include "qdeclarativecomponent.h"
#include "qdeclarativeincubator_p.h"
#include <private/qdeclarativecompiler_p.h>
@@ -121,7 +122,6 @@ QDeclarativeIncubatorPrivate::QDeclarativeIncubatorPrivate(QDeclarativeIncubator
QDeclarativeIncubatorPrivate::~QDeclarativeIncubatorPrivate()
{
- clear();
}
void QDeclarativeIncubatorPrivate::clear()
@@ -236,13 +236,26 @@ void QDeclarativeIncubatorPrivate::incubate(QDeclarativeVME::Interrupt &i)
QDeclarativeEngine *engine = component->engine;
QDeclarativeEnginePrivate *enginePriv = QDeclarativeEnginePrivate::get(engine);
+ bool guardOk = vmeGuard.isOK();
+ vmeGuard.clear();
+
+ if (!guardOk) {
+ QDeclarativeError error;
+ error.setUrl(component->url);
+ error.setDescription(QDeclarativeComponent::tr("Object destroyed during incubation"));
+ errors << error;
+ progress = QDeclarativeIncubatorPrivate::Completed;
+
+ goto finishIncubate;
+ }
+
if (progress == QDeclarativeIncubatorPrivate::Execute) {
enginePriv->referenceScarceResources();
result = vme.execute(&errors, i);
enginePriv->dereferenceScarceResources();
if (errors.isEmpty() && result == 0)
- return; // Interrupted
+ goto finishIncubate;
if (result) {
QDeclarativeData *ddata = QDeclarativeData::get(result);
@@ -288,6 +301,8 @@ finishIncubate:
enginePriv->erroredBindings->removeError();
}
}
+ } else {
+ vmeGuard.guard(&vme);
}
}
@@ -419,6 +434,8 @@ QDeclarativeIncubator::QDeclarativeIncubator(IncubationMode mode)
/*! \internal */
QDeclarativeIncubator::~QDeclarativeIncubator()
{
+ clear();
+
delete d; d = 0;
}
@@ -456,12 +473,14 @@ void QDeclarativeIncubator::clear()
{
Status s = status();
- if (s == Loading)
- qFatal("QDeclarativeIncubator::clear(): Clear not implemented for loading incubator");
-
if (s == Null)
return;
+ d->clear();
+
+ d->vme.reset();
+ d->vmeGuard.clear();
+
Q_ASSERT(d->component == 0);
Q_ASSERT(d->waitingOnMe == 0);
Q_ASSERT(d->waitingFor.isEmpty());
diff --git a/src/declarative/qml/qdeclarativeincubator_p.h b/src/declarative/qml/qdeclarativeincubator_p.h
index 57c54d3a07..e736aabd5c 100644
--- a/src/declarative/qml/qdeclarativeincubator_p.h
+++ b/src/declarative/qml/qdeclarativeincubator_p.h
@@ -79,6 +79,7 @@ public:
QObject *result;
QDeclarativeCompiledData *component;
QDeclarativeVME vme;
+ QDeclarativeVMEGuard vmeGuard;
typedef QDeclarativeIncubatorPrivate QIP;
QIP *waitingOnMe;
diff --git a/src/declarative/qml/qdeclarativevme.cpp b/src/declarative/qml/qdeclarativevme.cpp
index f8405be2db..bf8bd29c34 100644
--- a/src/declarative/qml/qdeclarativevme.cpp
+++ b/src/declarative/qml/qdeclarativevme.cpp
@@ -130,6 +130,7 @@ bool QDeclarativeVME::initDeferred(QObject *object)
int start = data->deferredIdx;
State initState;
+ initState.flags = State::Deferred;
initState.context = ctxt;
initState.compiledData = comp;
initState.instructionStream = comp->bytecode.constData() + start;
@@ -195,7 +196,6 @@ static void removeBindingOnProperty(QObject *o, int index)
// XXX we probably need some form of "work count" here to prevent us checking this
// for every instruction.
#define QML_BEGIN_INSTR_COMMON(I) { \
- if (interrupt.shouldInterrupt()) return 0; \
const QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::DataType &instr = QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::data(*genericInstr); \
INSTRUCTIONSTREAM += QDeclarativeInstructionMeta<(int)QDeclarativeInstruction::I>::Size; \
Q_UNUSED(instr);
@@ -211,6 +211,7 @@ static void removeBindingOnProperty(QObject *o, int index)
# define QML_END_INSTR(I) } \
genericInstr = reinterpret_cast<const QDeclarativeInstruction *>(INSTRUCTIONSTREAM); \
+ if (interrupt.shouldInterrupt()) return 0; \
goto *genericInstr->common.code;
#else
@@ -219,7 +220,9 @@ static void removeBindingOnProperty(QObject *o, int index)
QML_BEGIN_INSTR_COMMON(I)
# define QML_NEXT_INSTR(I) break;
-# define QML_END_INSTR(I) } break;
+# define QML_END_INSTR(I) \
+ if (interrupt.shouldInterrupt()) return 0; \
+ } break;
#endif
#define CLEAN_PROPERTY(o, index) if (fastHasBinding(o, index)) removeBindingOnProperty(o, index)
@@ -1099,23 +1102,10 @@ QObject *QDeclarativeVME::run(QList<QDeclarativeError> *errors,
#endif
exceptionExit:
- if (!objects.isEmpty())
- delete objects.at(0); // XXX What about failures in deferred creation?
-
- // XXX does context get leaked in this case?
-
+ Q_ASSERT(!states.isEmpty());
Q_ASSERT(!errors->isEmpty());
- // Remove the QDeclarativeParserStatus and QDeclarativeAbstractBinding back pointers
- blank(parserStatus);
- blank(bindValues);
-
- objects.deallocate();
- lists.deallocate();
- states.clear();
- bindValues.deallocate();
- parserStatus.deallocate();
- finalizeCallbacks.clear();
+ reset();
return 0;
@@ -1131,6 +1121,35 @@ normalExit:
return rv;
}
+void QDeclarativeVME::reset()
+{
+ Q_ASSERT(!states.isEmpty() || objects.isEmpty());
+
+ if (!objects.isEmpty() && !(states.at(0).flags & State::Deferred))
+ delete objects.at(0);
+
+ if (!rootContext.isNull())
+ rootContext->activeVME = 0;
+
+ // Remove the QDeclarativeParserStatus and QDeclarativeAbstractBinding back pointers
+ blank(parserStatus);
+ blank(bindValues);
+
+ while (componentAttached) {
+ QDeclarativeComponentAttached *a = componentAttached;
+ a->rem();
+ }
+
+ engine = 0;
+ objects.deallocate();
+ lists.deallocate();
+ bindValues.deallocate();
+ parserStatus.deallocate();
+ finalizeCallbacks.clear();
+ states.clear();
+ rootContext = 0;
+}
+
// Must be called with a handle scope and context
void QDeclarativeScriptData::initialize(QDeclarativeEngine *engine)
{
@@ -1242,6 +1261,16 @@ void **QDeclarativeVME::instructionJumpTable()
bool QDeclarativeVME::complete(const Interrupt &interrupt)
{
+ Q_ASSERT(engine ||
+ (bindValues.isEmpty() &&
+ parserStatus.isEmpty() &&
+ componentAttached == 0 &&
+ rootContext.isNull() &&
+ finalizeCallbacks.isEmpty()));
+
+ if (!engine)
+ return true;
+
ActiveVMERestorer restore(this, QDeclarativeEnginePrivate::get(engine));
while (!bindValues.isEmpty()) {
@@ -1284,8 +1313,7 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt)
return false;
}
- // XXX (what if its deleted?)
- if (rootContext)
+ if (!rootContext.isNull())
rootContext->activeVME = 0;
for (int ii = 0; ii < finalizeCallbacks.count(); ++ii) {
@@ -1298,6 +1326,8 @@ bool QDeclarativeVME::complete(const Interrupt &interrupt)
}
finalizeCallbacks.clear();
+ reset();
+
return true;
}
@@ -1317,4 +1347,55 @@ void QDeclarativeVME::blank(QFiniteStack<QDeclarativeParserStatus *> &pss)
}
}
+QDeclarativeVMEGuard::QDeclarativeVMEGuard()
+: m_objectCount(0), m_objects(0), m_contextCount(0), m_contexts(0)
+{
+}
+
+QDeclarativeVMEGuard::~QDeclarativeVMEGuard()
+{
+ clear();
+}
+
+void QDeclarativeVMEGuard::guard(QDeclarativeVME *vme)
+{
+ clear();
+
+ m_objectCount = vme->objects.count();
+ m_objects = new QDeclarativeGuard<QObject>[m_objectCount];
+ for (int ii = 0; ii < m_objectCount; ++ii)
+ m_objects[ii] = vme->objects[ii];
+
+ m_contextCount = (vme->rootContext.isNull())?0:1 + vme->states.count();
+ m_contexts = new QDeclarativeGuardedContextData[m_contextCount];
+ for (int ii = 0; ii < vme->states.count(); ++ii)
+ m_contexts[ii] = vme->states.at(ii).context;
+ if (!vme->rootContext.isNull())
+ m_contexts[m_contextCount - 1] = vme->rootContext.contextData();
+}
+
+void QDeclarativeVMEGuard::clear()
+{
+ delete [] m_objects;
+ delete [] m_contexts;
+
+ m_objectCount = 0;
+ m_objects = 0;
+ m_contextCount = 0;
+ m_contexts = 0;
+}
+
+bool QDeclarativeVMEGuard::isOK() const
+{
+ for (int ii = 0; ii < m_objectCount; ++ii)
+ if (m_objects[ii].isNull())
+ return false;
+
+ for (int ii = 0; ii < m_contextCount; ++ii)
+ if (m_contexts[ii].isNull())
+ return false;
+
+ return true;
+}
+
QT_END_NAMESPACE
diff --git a/src/declarative/qml/qdeclarativevme_p.h b/src/declarative/qml/qdeclarativevme_p.h
index 80c02b1b89..771a2b4c21 100644
--- a/src/declarative/qml/qdeclarativevme_p.h
+++ b/src/declarative/qml/qdeclarativevme_p.h
@@ -120,11 +120,14 @@ public:
void init(QDeclarativeContextData *, QDeclarativeCompiledData *, int start);
bool initDeferred(QObject *);
+ void reset();
QObject *execute(QList<QDeclarativeError> *errors, const Interrupt & = Interrupt());
bool complete(const Interrupt & = Interrupt());
private:
+ friend class QDeclarativeVMEGuard;
+
QObject *run(QList<QDeclarativeError> *errors, const Interrupt &
#ifdef QML_THREADED_VME_INTERPRETER
, void ***storeJumpTable = 0
@@ -138,15 +141,19 @@ private:
#endif
QDeclarativeEngine *engine;
+
QFiniteStack<QObject *> objects;
QFiniteStack<QDeclarativeVMETypes::List> lists;
QFiniteStack<QDeclarativeAbstractBinding *> bindValues;
QFiniteStack<QDeclarativeParserStatus *> parserStatus;
- QDeclarativeContextData *rootContext;
+ QDeclarativeGuardedContextData rootContext;
struct State {
- State() : context(0), compiledData(0), instructionStream(0) {}
+ enum Flag { Deferred = 0x00000001 };
+
+ State() : flags(0), context(0), compiledData(0), instructionStream(0) {}
+ quint32 flags;
QDeclarativeContextData *context;
QDeclarativeCompiledData *compiledData;
const char *instructionStream;
@@ -159,6 +166,27 @@ private:
static void blank(QFiniteStack<QDeclarativeAbstractBinding *> &);
};
+// Used to check that a QDeclarativeVME that is interrupted mid-execution
+// is still valid. Checks all the objects and contexts have not been
+// deleted.
+class QDeclarativeVMEGuard
+{
+public:
+ QDeclarativeVMEGuard();
+ ~QDeclarativeVMEGuard();
+
+ void guard(QDeclarativeVME *);
+ void clear();
+
+ bool isOK() const;
+
+private:
+ int m_objectCount;
+ QDeclarativeGuard<QObject> *m_objects;
+ int m_contextCount;
+ QDeclarativeGuardedContextData *m_contexts;
+};
+
QDeclarativeVME::Interrupt::Interrupt()
: mode(None)
{