aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/jsruntime/qv4qmlcontext.cpp9
-rw-r--r--src/qml/jsruntime/qv4qmlcontext_p.h13
-rw-r--r--src/qml/jsruntime/qv4qobjectwrapper.cpp8
-rw-r--r--src/qml/qml/qqmlcontext.cpp59
-rw-r--r--src/qml/qml/qqmlcontext_p.h132
-rw-r--r--src/qml/qml/qqmldata_p.h36
-rw-r--r--src/qml/qml/qqmlengine.cpp20
-rw-r--r--src/qml/qml/qqmlobjectcreator.cpp2
-rw-r--r--src/qml/qml/qqmltypeloader.cpp6
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp2
-rw-r--r--src/qml/qml/v8/qqmlbuiltinfunctions.cpp4
-rw-r--r--src/qml/types/qqmldelegatemodel.cpp23
-rw-r--r--src/qml/types/qqmldelegatemodel_p_p.h2
-rw-r--r--tests/auto/qml/qqmlcontext/data/Singleton.qml5
-rw-r--r--tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml14
-rw-r--r--tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp28
16 files changed, 257 insertions, 106 deletions
diff --git a/src/qml/jsruntime/qv4qmlcontext.cpp b/src/qml/jsruntime/qv4qmlcontext.cpp
index 144ab1b1a5..d97d44379d 100644
--- a/src/qml/jsruntime/qv4qmlcontext.cpp
+++ b/src/qml/jsruntime/qv4qmlcontext.cpp
@@ -62,20 +62,17 @@ using namespace QV4;
DEFINE_OBJECT_VTABLE(QmlContextWrapper);
DEFINE_MANAGED_VTABLE(QmlContext);
-void Heap::QmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject, bool ownsContext)
+void Heap::QmlContextWrapper::init(QQmlContextData *context, QObject *scopeObject)
{
Object::init();
readOnly = true;
- this->ownsContext = ownsContext;
isNullWrapper = false;
- this->context = new QQmlGuardedContextData(context);
+ this->context = new QQmlContextDataRef(context);
this->scopeObject.init(scopeObject);
}
void Heap::QmlContextWrapper::destroy()
{
- if (*context && ownsContext)
- (*context)->destroy();
delete context;
scopeObject.destroy();
Object::destroy();
@@ -321,7 +318,7 @@ Heap::QmlContext *QmlContext::createWorkerContext(ExecutionContext *parent, cons
context->isInternal = true;
context->isJSContext = true;
- Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, (QObject*)0, true));
+ Scoped<QmlContextWrapper> qml(scope, scope.engine->memoryManager->allocObject<QmlContextWrapper>(context, (QObject*)0));
qml->d()->isNullWrapper = true;
qml->setReadOnly(false);
diff --git a/src/qml/jsruntime/qv4qmlcontext_p.h b/src/qml/jsruntime/qv4qmlcontext_p.h
index 9aec7467da..9caeb75b8c 100644
--- a/src/qml/jsruntime/qv4qmlcontext_p.h
+++ b/src/qml/jsruntime/qv4qmlcontext_p.h
@@ -67,13 +67,12 @@ struct QmlContextWrapper;
namespace Heap {
struct QmlContextWrapper : Object {
- void init(QQmlContextData *context, QObject *scopeObject, bool ownsContext = false);
+ void init(QQmlContextData *context, QObject *scopeObject);
void destroy();
bool readOnly;
- bool ownsContext;
bool isNullWrapper;
- QQmlGuardedContextData *context;
+ QQmlContextDataRef *context;
QQmlQPointer<QObject> scopeObject;
};
@@ -90,10 +89,6 @@ struct Q_QML_EXPORT QmlContextWrapper : Object
V4_OBJECT2(QmlContextWrapper, Object)
V4_NEEDS_DESTROY
- void takeContextOwnership() {
- d()->ownsContext = true;
- }
-
inline QObject *getScopeObject() const { return d()->scopeObject; }
inline QQmlContextData *getContext() const { return *d()->context; }
@@ -116,10 +111,6 @@ struct Q_QML_EXPORT QmlContext : public ExecutionContext
QQmlContextData *qmlContext() const {
return *d()->qml->context;
}
-
- void takeContextOwnership() {
- d()->qml->ownsContext = true;
- }
};
}
diff --git a/src/qml/jsruntime/qv4qobjectwrapper.cpp b/src/qml/jsruntime/qv4qobjectwrapper.cpp
index 5dc5f5d568..8d96f5b480 100644
--- a/src/qml/jsruntime/qv4qobjectwrapper.cpp
+++ b/src/qml/jsruntime/qv4qobjectwrapper.cpp
@@ -977,8 +977,12 @@ void QObjectWrapper::destroyObject(bool lastCall)
QQmlData *ddata = QQmlData::get(h->object(), false);
if (ddata) {
if (!h->object()->parent() && !ddata->indestructible) {
- if (ddata && ddata->ownContext && ddata->context)
- ddata->context->emitDestruction();
+ if (ddata && ddata->ownContext) {
+ Q_ASSERT(ddata->ownContext == ddata->context);
+ ddata->ownContext->emitDestruction();
+ ddata->ownContext = 0;
+ ddata->context = 0;
+ }
// This object is notionally destroyed now
ddata->isQueuedForDeletion = true;
if (lastCall)
diff --git a/src/qml/qml/qqmlcontext.cpp b/src/qml/qml/qqmlcontext.cpp
index 531d9ae457..e06491a814 100644
--- a/src/qml/qml/qqmlcontext.cpp
+++ b/src/qml/qml/qqmlcontext.cpp
@@ -161,6 +161,7 @@ QQmlContext::QQmlContext(QQmlEngine *e, bool)
{
Q_D(QQmlContext);
d->data = new QQmlContextData(this);
+ ++d->data->refCount;
d->data->engine = e;
}
@@ -174,6 +175,7 @@ QQmlContext::QQmlContext(QQmlEngine *engine, QObject *parent)
{
Q_D(QQmlContext);
d->data = new QQmlContextData(this);
+ ++d->data->refCount;
d->data->setParent(engine?QQmlContextData::get(engine->rootContext()):0);
}
@@ -187,6 +189,7 @@ QQmlContext::QQmlContext(QQmlContext *parentContext, QObject *parent)
{
Q_D(QQmlContext);
d->data = new QQmlContextData(this);
+ ++d->data->refCount;
d->data->setParent(parentContext?QQmlContextData::get(parentContext):0);
}
@@ -199,6 +202,7 @@ QQmlContext::QQmlContext(QQmlContextData *data)
{
Q_D(QQmlContext);
d->data = data;
+ // don't add a refcount here, as the data owns this context
}
/*!
@@ -212,7 +216,8 @@ QQmlContext::~QQmlContext()
{
Q_D(QQmlContext);
- if (!d->data->isInternal)
+ d->data->publicContext = 0;
+ if (!--d->data->refCount)
d->data->destroy();
}
@@ -521,12 +526,12 @@ QQmlContextData::QQmlContextData()
}
QQmlContextData::QQmlContextData(QQmlContext *ctxt)
-: parent(0), engine(0), isInternal(false), ownedByParent(false), isJSContext(false),
- isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
- publicContext(ctxt), incubator(0), componentObjectIndex(-1),
- contextObject(0), childContexts(0), nextChild(0), prevChild(0),
- expressions(0), contextObjects(0), contextGuards(0), idValues(0), idValueCount(0), linkedContext(0),
- componentAttached(0)
+ : engine(0), isInternal(false), isJSContext(false),
+ isPragmaLibraryContext(false), unresolvedNames(false), hasEmittedDestruction(false), isRootObjectInCreation(false),
+ publicContext(ctxt), incubator(0), componentObjectIndex(-1),
+ contextObject(0), nextChild(0), prevChild(0),
+ expressions(0), contextObjects(0), idValues(0), idValueCount(0),
+ componentAttached(0)
{
}
@@ -563,11 +568,8 @@ void QQmlContextData::invalidate()
emitDestruction();
while (childContexts) {
- if (childContexts->ownedByParent) {
- childContexts->destroy();
- } else {
- childContexts->invalidate();
- }
+ Q_ASSERT(childContexts != this);
+ childContexts->invalidate();
}
if (prevChild) {
@@ -601,12 +603,17 @@ void QQmlContextData::clearContext()
void QQmlContextData::destroy()
{
- if (linkedContext)
- linkedContext->destroy();
+ Q_ASSERT(refCount == 0);
+ linkedContext = 0;
- if (engine) invalidate();
+ // avoid recursion
+ ++refCount;
+ if (engine)
+ invalidate();
+ Q_ASSERT(refCount == 1);
clearContext();
+ Q_ASSERT(refCount == 1);
while (contextObjects) {
QQmlData *co = contextObjects;
@@ -617,6 +624,7 @@ void QQmlContextData::destroy()
co->nextContextObject = 0;
co->prevContextObject = 0;
}
+ Q_ASSERT(refCount == 1);
QQmlGuardedContextData *contextGuard = contextGuards;
while (contextGuard) {
@@ -627,17 +635,29 @@ void QQmlContextData::destroy()
contextGuard = next;
}
contextGuards = 0;
+ Q_ASSERT(refCount == 1);
delete [] idValues;
+ idValues = 0;
- if (isInternal)
+ Q_ASSERT(refCount == 1);
+ if (publicContext) {
+ // the QQmlContext destructor will remove one ref again
+ ++refCount;
delete publicContext;
+ }
+
+ Q_ASSERT(refCount == 1);
+ --refCount;
+ Q_ASSERT(refCount == 0);
delete this;
}
-void QQmlContextData::setParent(QQmlContextData *p, bool parentTakesOwnership)
+void QQmlContextData::setParent(QQmlContextData *p)
{
+ if (p == parent)
+ return;
if (p) {
parent = p;
engine = p->engine;
@@ -645,7 +665,6 @@ void QQmlContextData::setParent(QQmlContextData *p, bool parentTakesOwnership)
if (nextChild) nextChild->prevChild = &nextChild;
prevChild = &p->childContexts;
p->childContexts = this;
- ownedByParent = parentTakesOwnership;
}
}
@@ -660,6 +679,10 @@ void QQmlContextData::refreshExpressionsRecursive(QQmlJavaScriptExpression *expr
expression->refresh();
}
+QQmlContextData::~QQmlContextData()
+{
+}
+
static inline bool expressions_to_run(QQmlContextData *ctxt, bool isGlobalRefresh)
{
return ctxt->expressions && (!isGlobalRefresh || ctxt->unresolvedNames);
diff --git a/src/qml/qml/qqmlcontext_p.h b/src/qml/qml/qqmlcontext_p.h
index a259fd62d8..d01820a430 100644
--- a/src/qml/qml/qqmlcontext_p.h
+++ b/src/qml/qml/qqmlcontext_p.h
@@ -78,6 +78,7 @@ class QQmlExpression;
class QQmlExpressionPrivate;
class QQmlJavaScriptExpression;
class QQmlContextData;
+class QQmlGuardedContextData;
class QQmlIncubatorPrivate;
class QQmlContextPrivate : public QObjectPrivate
@@ -106,7 +107,7 @@ public:
};
class QQmlComponentAttached;
-class QQmlGuardedContextData;
+
class Q_QML_PRIVATE_EXPORT QQmlContextData
{
public:
@@ -114,7 +115,6 @@ public:
QQmlContextData(QQmlContext *);
void emitDestruction();
void clearContext();
- void destroy();
void invalidate();
inline bool isValid() const {
@@ -122,10 +122,10 @@ public:
}
// My parent context and engine
- QQmlContextData *parent;
+ QQmlContextData *parent = nullptr;
QQmlEngine *engine;
- void setParent(QQmlContextData *, bool parentTakesOwnership = false);
+ void setParent(QQmlContextData *);
void refreshExpressions();
void addObject(QObject *);
@@ -136,14 +136,14 @@ public:
// If internal is false publicContext owns this.
QQmlContext *asQQmlContext();
QQmlContextPrivate *asQQmlContextPrivate();
+ quint32 refCount = 0;
quint32 isInternal:1;
- quint32 ownedByParent:1; // unrelated to isInternal; parent context deletes children if true.
quint32 isJSContext:1;
quint32 isPragmaLibraryContext:1;
quint32 unresolvedNames:1; // True if expressions in this context failed to resolve a toplevel name
quint32 hasEmittedDestruction:1;
quint32 isRootObjectInCreation:1;
- quint32 dummy:25;
+ quint32 dummy:26;
QQmlContext *publicContext;
// The incubator that is constructing this context if any
@@ -178,7 +178,7 @@ public:
QQmlRefPointer<QQmlTypeNameCache> imports;
// My children
- QQmlContextData *childContexts;
+ QQmlContextData *childContexts = 0;
// My peers in parent's childContexts list
QQmlContextData *nextChild;
@@ -191,7 +191,7 @@ public:
QQmlData *contextObjects;
// Doubly-linked list of context guards (XXX merge with contextObjects)
- QQmlGuardedContextData *contextGuards;
+ QQmlGuardedContextData *contextGuards = 0;
// id guards
struct ContextGuard : public QQmlGuard<QObject>
@@ -210,7 +210,7 @@ public:
void setIdProperty(int, QObject *);
// Linked contexts. this owns linkedContext.
- QQmlContextData *linkedContext;
+ QQmlContextDataRef linkedContext;
// Linked list of uses of the Component attached property in this
// context
@@ -224,91 +224,137 @@ public:
}
private:
+ friend class QQmlContextDataRef;
+ friend class QQmlContext; // needs to do manual refcounting :/
void refreshExpressionsRecursive(bool isGlobal);
void refreshExpressionsRecursive(QQmlJavaScriptExpression *);
- ~QQmlContextData() {}
+ ~QQmlContextData();
+ void destroy();
};
+
class QQmlGuardedContextData
{
public:
- inline QQmlGuardedContextData();
- inline QQmlGuardedContextData(QQmlContextData *);
- inline ~QQmlGuardedContextData();
-
- inline QQmlContextData *contextData() const;
+ inline QQmlGuardedContextData() = default;
+ inline QQmlGuardedContextData(QQmlContextData *data)
+ { setContextData(data); }
+ inline ~QQmlGuardedContextData()
+ { clear(); }
+
+ inline QQmlContextData *contextData() const
+ { return m_contextData; }
inline void setContextData(QQmlContextData *);
inline bool isNull() const { return !m_contextData; }
inline operator QQmlContextData*() const { return m_contextData; }
inline QQmlContextData* operator->() const { return m_contextData; }
- inline QQmlGuardedContextData &operator=(QQmlContextData *d);
+ inline QQmlGuardedContextData &operator=(QQmlContextData *d) {
+ setContextData(d); return *this;
+ }
private:
- QQmlGuardedContextData &operator=(const QQmlGuardedContextData &);
- QQmlGuardedContextData(const QQmlGuardedContextData &);
+ QQmlGuardedContextData &operator=(const QQmlGuardedContextData &) = delete;
+ QQmlGuardedContextData(const QQmlGuardedContextData &) = delete;
friend class QQmlContextData;
inline void clear();
- QQmlContextData *m_contextData;
- QQmlGuardedContextData *m_next;
- QQmlGuardedContextData **m_prev;
+ QQmlContextData *m_contextData = 0;
+ QQmlGuardedContextData *m_next = 0;
+ QQmlGuardedContextData **m_prev = 0;
};
-QQmlGuardedContextData::QQmlGuardedContextData()
-: m_contextData(0), m_next(0), m_prev(0)
+
+void QQmlGuardedContextData::setContextData(QQmlContextData *contextData)
+ {
+ if (m_contextData == contextData)
+ return;
+ clear();
+
+ if (contextData) {
+ m_contextData = contextData;
+ m_next = contextData->contextGuards;
+ if (m_next) m_next->m_prev = &m_next;
+ m_prev = &contextData->contextGuards;
+ contextData->contextGuards = this;
+ }
+}
+
+void QQmlGuardedContextData::clear()
+{
+ if (m_prev) {
+ *m_prev = m_next;
+ if (m_next) m_next->m_prev = m_prev;
+ m_contextData = 0;
+ m_next = 0;
+ m_prev = 0;
+ }
+}
+
+QQmlContextDataRef::QQmlContextDataRef()
+ : m_contextData(0)
{
}
-QQmlGuardedContextData::QQmlGuardedContextData(QQmlContextData *data)
-: m_contextData(0), m_next(0), m_prev(0)
+QQmlContextDataRef::QQmlContextDataRef(const QQmlContextDataRef &other)
+ : m_contextData(other.m_contextData)
{
- setContextData(data);
+ if (m_contextData)
+ ++m_contextData->refCount;
}
-QQmlGuardedContextData::~QQmlGuardedContextData()
+QQmlContextDataRef::QQmlContextDataRef(QQmlContextData *data)
+ : m_contextData(data)
+{
+ if (m_contextData)
+ ++m_contextData->refCount;
+}
+
+QQmlContextDataRef::~QQmlContextDataRef()
{
clear();
}
-void QQmlGuardedContextData::setContextData(QQmlContextData *contextData)
+void QQmlContextDataRef::setContextData(QQmlContextData *contextData)
{
+ if (m_contextData == contextData)
+ return;
clear();
if (contextData) {
m_contextData = contextData;
- m_next = contextData->contextGuards;
- if (m_next) m_next->m_prev = &m_next;
- m_prev = &contextData->contextGuards;
- contextData->contextGuards = this;
+ ++m_contextData->refCount;
}
}
-QQmlContextData *QQmlGuardedContextData::contextData() const
+QQmlContextData *QQmlContextDataRef::contextData() const
{
return m_contextData;
}
-void QQmlGuardedContextData::clear()
+void QQmlContextDataRef::clear()
{
- if (m_prev) {
- *m_prev = m_next;
- if (m_next) m_next->m_prev = m_prev;
- m_contextData = 0;
- m_next = 0;
- m_prev = 0;
- }
+ if (m_contextData && !--m_contextData->refCount)
+ m_contextData->destroy();
+ m_contextData = 0;
}
-QQmlGuardedContextData &
-QQmlGuardedContextData::operator=(QQmlContextData *d)
+QQmlContextDataRef &
+QQmlContextDataRef::operator=(QQmlContextData *d)
{
setContextData(d);
return *this;
}
+QQmlContextDataRef &
+QQmlContextDataRef::operator=(const QQmlContextDataRef &other)
+{
+ setContextData(other.m_contextData);
+ return *this;
+}
+
QQmlContextData::ContextGuard::ContextGuard()
: context(0)
{
diff --git a/src/qml/qml/qqmldata_p.h b/src/qml/qml/qqmldata_p.h
index 2083326cd5..75ea720358 100644
--- a/src/qml/qml/qqmldata_p.h
+++ b/src/qml/qml/qqmldata_p.h
@@ -78,6 +78,34 @@ struct CompilationUnit;
}
}
+// This is declared here because QQmlData below needs it and this file
+// in turn is included from qqmlcontext_p.h.
+class QQmlContextData;
+class Q_QML_PRIVATE_EXPORT QQmlContextDataRef
+{
+public:
+ inline QQmlContextDataRef();
+ inline QQmlContextDataRef(QQmlContextData *);
+ inline QQmlContextDataRef(const QQmlContextDataRef &);
+ inline ~QQmlContextDataRef();
+
+ inline QQmlContextData *contextData() const;
+ inline void setContextData(QQmlContextData *);
+
+ inline bool isNull() const { return !m_contextData; }
+
+ inline operator QQmlContextData*() const { return m_contextData; }
+ inline QQmlContextData* operator->() const { return m_contextData; }
+ inline QQmlContextDataRef &operator=(QQmlContextData *d);
+ inline QQmlContextDataRef &operator=(const QQmlContextDataRef &other);
+
+private:
+
+ inline void clear();
+
+ QQmlContextData *m_contextData;
+};
+
// This class is structured in such a way, that simply zero'ing it is the
// default state for elemental object allocations. This is crucial in the
// workings of the QQmlInstruction::CreateSimpleObject instruction.
@@ -114,7 +142,6 @@ public:
quint32 ownedByQml1:1; // This bit is shared with QML1's QDeclarativeData.
quint32 ownMemory:1;
- quint32 ownContext:1;
quint32 indestructible:1;
quint32 explicitIndestructibleSet:1;
quint32 hasTaintedV4Object:1;
@@ -127,7 +154,7 @@ public:
quint32 hasInterceptorMetaObject:1;
quint32 hasVMEMetaObject:1;
quint32 parentFrozen:1;
- quint32 dummy:21;
+ quint32 dummy:22;
// When bindingBitsSize < sizeof(ptr), we store the binding bit flags inside
// bindingBitsValue. When we need more than sizeof(ptr) bits, we allocated
@@ -161,9 +188,10 @@ public:
void disconnectNotifiers();
// The context that created the C++ object
- QQmlContextData *context;
+ QQmlContextData *context = 0;
// The outermost context in which this object lives
- QQmlContextData *outerContext;
+ QQmlContextData *outerContext = 0;
+ QQmlContextDataRef ownContext;
QQmlAbstractBinding *bindings;
QQmlBoundSignal *signalHandlers;
diff --git a/src/qml/qml/qqmlengine.cpp b/src/qml/qml/qqmlengine.cpp
index 9676feb279..f31db457d3 100644
--- a/src/qml/qml/qqmlengine.cpp
+++ b/src/qml/qml/qqmlengine.cpp
@@ -712,8 +712,11 @@ QQmlEnginePrivate::~QQmlEnginePrivate()
void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
{
if (QQmlData *d = QQmlData::get(o)) {
- if (d->ownContext && d->context) {
- d->context->destroy();
+ if (d->ownContext) {
+ for (QQmlContextData *lc = d->ownContext->linkedContext; lc; lc = lc->linkedContext)
+ lc->invalidate();
+ d->ownContext->invalidate();
+ d->ownContext = 0;
d->context = 0;
}
@@ -729,10 +732,10 @@ void QQmlPrivate::qdeclarativeelement_destructor(QObject *o)
}
QQmlData::QQmlData()
- : ownedByQml1(false), ownMemory(true), ownContext(false), indestructible(true), explicitIndestructibleSet(false),
+ : ownedByQml1(false), ownMemory(true), indestructible(true), explicitIndestructibleSet(false),
hasTaintedV4Object(false), isQueuedForDeletion(false), rootObjectInCreation(false),
hasInterceptorMetaObject(false), hasVMEMetaObject(false), parentFrozen(false),
- bindingBitsSize(MaxInlineBits), bindingBitsValue(0), notifyList(0), context(0), outerContext(0),
+ bindingBitsSize(MaxInlineBits), bindingBitsValue(0), notifyList(0),
bindings(0), signalHandlers(0), nextContextObject(0), prevContextObject(0),
lineNumber(0), columnNumber(0), jsEngineId(0), compilationUnit(0), deferredData(0),
propertyCache(0), guards(0), extendedData(0)
@@ -882,8 +885,12 @@ void QQmlData::setQueuedForDeletion(QObject *object)
{
if (object) {
if (QQmlData *ddata = QQmlData::get(object)) {
- if (ddata->ownContext && ddata->context)
+ if (ddata->ownContext) {
+ Q_ASSERT(ddata->ownContext == ddata->context);
ddata->context->emitDestruction();
+ ddata->ownContext = 0;
+ ddata->context = 0;
+ }
ddata->isQueuedForDeletion = true;
}
}
@@ -1753,8 +1760,7 @@ void QQmlData::destroyed(QObject *object)
if (propertyCache)
propertyCache->release();
- if (ownContext && context)
- context->destroy();
+ ownContext = 0;
while (guards) {
QQmlGuard<QObject> *guard = static_cast<QQmlGuard<QObject> *>(guards);
diff --git a/src/qml/qml/qqmlobjectcreator.cpp b/src/qml/qml/qqmlobjectcreator.cpp
index b34c2ea5e6..890d1ca7fe 100644
--- a/src/qml/qml/qqmlobjectcreator.cpp
+++ b/src/qml/qml/qqmlobjectcreator.cpp
@@ -1131,7 +1131,7 @@ QObject *QQmlObjectCreator::createInstance(int index, QObject *parent, bool isCo
c->linkedContext = context;
} else
context->addObject(instance);
- ddata->ownContext = true;
+ ddata->ownContext = ddata->context;
} else if (!ddata->context)
context->addObject(instance);
diff --git a/src/qml/qml/qqmltypeloader.cpp b/src/qml/qml/qqmltypeloader.cpp
index ce795be757..342e6c0725 100644
--- a/src/qml/qml/qqmltypeloader.cpp
+++ b/src/qml/qml/qqmltypeloader.cpp
@@ -2817,7 +2817,7 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
effectiveCtxt = 0;
// Create the script context if required
- QQmlContextData *ctxt = new QQmlContextData;
+ QQmlContextDataRef ctxt(new QQmlContextData);
ctxt->isInternal = true;
ctxt->isJSContext = true;
if (shared)
@@ -2837,7 +2837,7 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
}
if (effectiveCtxt) {
- ctxt->setParent(effectiveCtxt, true);
+ ctxt->setParent(effectiveCtxt);
} else {
ctxt->engine = parentCtxt->engine; // Fix for QTBUG-21620
}
@@ -2859,12 +2859,10 @@ QV4::ReturnedValue QQmlScriptData::scriptValueForContext(QQmlContextData *parent
if (!m_program) {
if (shared)
m_loaded = true;
- ctxt->destroy();
return QV4::Encode::undefined();
}
QV4::Scoped<QV4::QmlContext> qmlContext(scope, QV4::QmlContext::create(v4->rootContext(), ctxt, 0));
- qmlContext->takeContextOwnership();
m_program->qmlContext.set(scope.engine, qmlContext);
m_program->run();
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index f3a39313c1..58d8322675 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1058,7 +1058,7 @@ private:
void readEncoding();
PersistentValue m_thisObject;
- QQmlGuardedContextData m_qmlContext;
+ QQmlContextDataRef m_qmlContext;
static void dispatchCallback(Object *thisObj, QQmlContextData *context);
void dispatchCallback();
diff --git a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
index 8cc0b32168..96d83b9870 100644
--- a/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
+++ b/src/qml/qml/v8/qqmlbuiltinfunctions.cpp
@@ -1150,6 +1150,10 @@ void QtObject::method_createQmlObject(const BuiltinFunction *, Scope &scope, Cal
if (!component.isReady())
THROW_GENERIC_ERROR("Qt.createQmlObject(): Component is not ready");
+ if (!effectiveContext->isValid()) {
+ THROW_GENERIC_ERROR("Qt.createQmlObject(): Cannot create a component in an invalid context");
+ }
+
QObject *obj = component.beginCreate(effectiveContext);
if (obj) {
QQmlData::get(obj, true)->explicitIndestructibleSet = false;
diff --git a/src/qml/types/qqmldelegatemodel.cpp b/src/qml/types/qqmldelegatemodel.cpp
index 6584ecfb84..9b1417eccd 100644
--- a/src/qml/types/qqmldelegatemodel.cpp
+++ b/src/qml/types/qqmldelegatemodel.cpp
@@ -269,7 +269,8 @@ QQmlDelegateModel::~QQmlDelegateModel()
delete cacheItem->object;
cacheItem->object = 0;
- cacheItem->contextData->destroy();
+ cacheItem->contextData->invalidate();
+ Q_ASSERT(cacheItem->contextData->refCount == 1);
cacheItem->contextData = 0;
cacheItem->scriptRef -= 1;
}
@@ -840,7 +841,8 @@ void QQDMIncubationTask::statusChanged(Status status)
delete incubating->object;
incubating->object = 0;
if (incubating->contextData) {
- incubating->contextData->destroy();
+ incubating->contextData->invalidate();
+ Q_ASSERT(incubating->contextData->refCount == 1);
incubating->contextData = 0;
}
incubating->scriptRef = 0;
@@ -900,8 +902,10 @@ void QQmlDelegateModelPrivate::incubatorStatusChanged(QQDMIncubationTask *incuba
delete cacheItem->object;
cacheItem->object = 0;
cacheItem->scriptRef -= 1;
- if (cacheItem->contextData)
- cacheItem->contextData->destroy();
+ if (cacheItem->contextData) {
+ cacheItem->contextData->invalidate();
+ Q_ASSERT(cacheItem->contextData->refCount == 1);
+ }
cacheItem->contextData = 0;
if (!cacheItem->isReferenced()) {
@@ -983,7 +987,7 @@ QObject *QQmlDelegateModelPrivate::object(Compositor::Group group, int index, bo
if (QQmlAdaptorModelProxyInterface *proxy
= qobject_cast<QQmlAdaptorModelProxyInterface *>(cacheItem)) {
ctxt = new QQmlContextData;
- ctxt->setParent(cacheItem->contextData, true);
+ ctxt->setParent(cacheItem->contextData);
ctxt->contextObject = proxy->proxiedObject();
}
}
@@ -1966,8 +1970,11 @@ void QQmlDelegateModelItem::destroyObject()
QQmlData *data = QQmlData::get(object);
Q_ASSERT(data);
- if (data->ownContext && data->context)
- data->context->clearContext();
+ if (data->ownContext) {
+ data->ownContext->clearContext();
+ data->ownContext = 0;
+ data->context = 0;
+ }
object->deleteLater();
if (attached) {
@@ -1975,7 +1982,7 @@ void QQmlDelegateModelItem::destroyObject()
attached = 0;
}
- contextData->destroy();
+ contextData->invalidate();
contextData = 0;
object = 0;
}
diff --git a/src/qml/types/qqmldelegatemodel_p_p.h b/src/qml/types/qqmldelegatemodel_p_p.h
index cb4a1f79ba..0f8438870a 100644
--- a/src/qml/types/qqmldelegatemodel_p_p.h
+++ b/src/qml/types/qqmldelegatemodel_p_p.h
@@ -140,7 +140,7 @@ public:
QV4::ExecutionEngine *v4;
QQmlDelegateModelItemMetaType * const metaType;
- QQmlContextData *contextData;
+ QQmlContextDataRef contextData;
QPointer<QObject> object;
QPointer<QQmlDelegateModelAttached> attached;
QQDMIncubationTask *incubationTask;
diff --git a/tests/auto/qml/qqmlcontext/data/Singleton.qml b/tests/auto/qml/qqmlcontext/data/Singleton.qml
new file mode 100644
index 0000000000..68ef5850e3
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/Singleton.qml
@@ -0,0 +1,5 @@
+pragma Singleton
+import QtQml 2.0
+QtObject {
+ readonly property string song: "Highway to Hell"
+}
diff --git a/tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml b/tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml
new file mode 100644
index 0000000000..2e0e6f20e2
--- /dev/null
+++ b/tests/auto/qml/qqmlcontext/data/contextViaClosureAfterDestruction.qml
@@ -0,0 +1,14 @@
+import QtQml 2.0
+
+import constants 1.0
+
+QtObject {
+ function createClosure() {
+ return function() { return Sing.song; }
+ }
+ function createComponentFactory() {
+ return function(parentObj) {
+ return Qt.createQmlObject('import QtQml 2.0; QtObject { property string test: "ok"; }', parentObj);
+ }
+ }
+}
diff --git a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
index f49fd391ac..5f57b9ebb0 100644
--- a/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
+++ b/tests/auto/qml/qqmlcontext/tst_qqmlcontext.cpp
@@ -62,6 +62,7 @@ private slots:
void evalAfterInvalidate();
void qobjectDerived();
void qtbug_49232();
+ void contextViaClosureAfterDestruction();
private:
QQmlEngine engine;
@@ -723,6 +724,33 @@ void tst_qqmlcontext::qtbug_49232()
QCOMPARE(obj->property("valueTwo"), QVariant(97));
}
+void tst_qqmlcontext::contextViaClosureAfterDestruction()
+{
+ qmlRegisterSingletonType(testFileUrl("Singleton.qml"), "constants", 1, 0, "Sing");
+ QQmlEngine engine;
+ QQmlComponent component(&engine, testFileUrl("contextViaClosureAfterDestruction.qml"));
+ QJSValue valueClosure;
+ QJSValue componentFactoryClosure;
+ {
+ QScopedPointer<QObject> obj(component.create());
+ QVERIFY(!obj.isNull());
+ // meta-calls don't support QJSValue return types, so do the call "by hand"
+ valueClosure = engine.newQObject(obj.data()).property(QStringLiteral("createClosure")).call();
+ QVERIFY(valueClosure.isCallable());
+ componentFactoryClosure = engine.newQObject(obj.data()).property(QStringLiteral("createComponentFactory")).call();
+ QVERIFY(componentFactoryClosure.isCallable());
+ }
+ QCOMPARE(valueClosure.call().toString(), QLatin1String("Highway to Hell"));
+
+ QScopedPointer<QObject> parent(new QObject);
+ QJSValue parentWrapper = engine.newQObject(parent.data());
+ QQmlEngine::setObjectOwnership(parent.data(), QQmlEngine::CppOwnership);
+
+ QJSValue subObject = componentFactoryClosure.callWithInstance(componentFactoryClosure, QJSValueList() << parentWrapper);
+ QVERIFY(subObject.isError());
+ QCOMPARE(subObject.toString(), QLatin1String("Error: Qt.createQmlObject(): Cannot create a component in an invalid context"));
+}
+
QTEST_MAIN(tst_qqmlcontext)
#include "tst_qqmlcontext.moc"