aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
Diffstat (limited to 'src/qml/qml')
-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
8 files changed, 183 insertions, 78 deletions
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;