Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqmldata_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#ifndef QQMLDATA_P_H
5#define QQMLDATA_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <private/qtqmlglobal_p.h>
19#include <private/qobject_p.h>
20#include <private/qqmlpropertyindex_p.h>
21#include <private/qv4value_p.h>
22#include <private/qv4persistent_p.h>
23#include <private/qqmlrefcount_p.h>
24#include <private/qqmlpropertycache_p.h>
25#include <qqmlprivate.h>
26#include <qjsengine.h>
27#include <qvector.h>
28
30
31template <class Key, class T> class QHash;
32class QQmlEngine;
33class QQmlGuardImpl;
35class QQmlBoundSignal;
36class QQmlContext;
38class QQmlContextData;
39class QQmlNotifier;
43
44namespace QV4 {
45class ExecutableCompilationUnit;
46namespace CompiledData {
47struct Binding;
48}
49}
50
51// This class is structured in such a way, that simply zero'ing it is the
52// default state for elemental object allocations. This is crucial in the
53// workings of the QQmlInstruction::CreateSimpleObject instruction.
54// Don't change anything here without first considering that case!
55class Q_QML_EXPORT QQmlData : public QAbstractDeclarativeData
56{
57public:
58 enum Ownership { DoesNotOwnMemory, OwnsMemory };
59
60 QQmlData(Ownership ownership);
61 ~QQmlData();
62
63 static inline void init() {
64 static bool initialized = false;
65 if (!initialized) {
66 initialized = true;
71 }
72 }
73
74 static void destroyed(QAbstractDeclarativeData *, QObject *);
75 static void signalEmitted(QAbstractDeclarativeData *, QObject *, int, void **);
76 static int receivers(QAbstractDeclarativeData *, const QObject *, int);
77 static bool isSignalConnected(QAbstractDeclarativeData *, const QObject *, int);
78
79 void destroyed(QObject *);
80
82 if (!explicitIndestructibleSet) indestructible = false;
83 }
84
85 // If ownMemomry is true, the QQmlData was normally allocated. Otherwise it was allocated
86 // with placement new and QQmlData::destroyed is not allowed to free the memory
88 // indestructible is set if and only if the object has CppOwnership
89 // This can be explicitly set with QJSEngine::setObjectOwnership
90 // Top level objects generally have CppOwnership (see QQmlcCmponentprivate::beginCreate),
91 // unless created by special methods like the QML component.createObject() function
93 // indestructible was explicitly set with setObjectOwnership
94 // or the object is a top-level object
96 // set when one QObject has been wrapped into QObjectWrapper in multiple engines
97 // at the same time - a rather rare case
100 /*
101 * rootObjectInCreation should be true only when creating top level CPP and QML objects,
102 * v4 GC will check this flag, only deletes the objects when rootObjectInCreation is false.
103 */
105 // set when at least one of the object's properties is intercepted
108 // If we have another wrapper for a const QObject * in the multiply wrapped QObjects.
111
112 // When bindingBitsSize < sizeof(ptr), we store the binding bit flags inside
113 // bindingBitsValue. When we need more than sizeof(ptr) bits, we allocated
114 // sufficient space and use bindingBits to point to it.
117 enum {
118 BitsPerType = sizeof(BindingBitsType) * 8,
119 InlineBindingArraySize = 2
120 };
121 union {
123 BindingBitsType bindingBitsValue[InlineBindingArraySize];
124 };
125
126 struct NotifyList {
127 QAtomicInteger<quint64> connectionMask;
128 QQmlNotifierEndpoint *todo = nullptr;
129 QQmlNotifierEndpoint**notifies = nullptr;
130 quint16 maximumTodoIndex = 0;
131 quint16 notifiesSize = 0;
132 void layout();
133 private:
135 };
136 QAtomicPointer<NotifyList> notifyList;
137
138 inline QQmlNotifierEndpoint *notify(int index) const;
139 void addNotify(int index, QQmlNotifierEndpoint *);
140 int endpointCount(int index);
141 bool signalHasEndpoint(int index) const;
142
143 enum class DeleteNotifyList { Yes, No };
144 void disconnectNotifiers(DeleteNotifyList doDelete);
145
146 // The context that created the C++ object; not refcounted to prevent cycles
148 // The outermost context in which this object lives; not refcounted to prevent cycles
149 QQmlContextData *outerContext = nullptr;
150 QQmlRefPointer<QQmlContextData> ownContext;
151
152 QQmlAbstractBinding *bindings = nullptr;
153 QQmlBoundSignal *signalHandlers = nullptr;
154 std::vector<QQmlPropertyObserver> propertyObservers;
155
156 // Linked list for QQmlContext::contextObjects
157 QQmlData *nextContextObject = nullptr;
158 QQmlData**prevContextObject = nullptr;
159
160 inline bool hasBindingBit(int) const;
161 inline void setBindingBit(QObject *obj, int);
162 inline void clearBindingBit(int);
163
164 inline bool hasPendingBindingBit(int index) const;
165 inline void setPendingBindingBit(QObject *obj, int);
166 inline void clearPendingBindingBit(int);
167
168 quint16 lineNumber = 0;
169 quint16 columnNumber = 0;
170
171 quint32 jsEngineId = 0; // id of the engine that created the jsWrapper
172
176 unsigned int deferredIdx;
177 QMultiHash<int, const QV4::CompiledData::Binding *> bindings;
178
179 // Not always the same as the other compilation unit
180 QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
181
182 // Could be either context or outerContext
183 QQmlRefPointer<QQmlContextData> context;
185 };
186 QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit;
187 QVector<DeferredData *> deferredData;
188
189 void deferData(int objectIndex, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &,
190 const QQmlRefPointer<QQmlContextData> &);
191 void releaseDeferredData();
192
194
196
197 QQmlGuardImpl *guards = nullptr;
198
200 // If QObjectData::isDeletingChildren is set then access to QObjectPrivate::declarativeData has
201 // to be avoided because QObjectPrivate::currentChildBeingDeleted is in use.
202 if (priv->isDeletingChildren || priv->wasDeleted) {
204 return nullptr;
205 } else if (priv->declarativeData) {
206 return static_cast<QQmlData *>(priv->declarativeData);
207 } else if (create) {
208 return createQQmlData(priv);
209 } else {
210 return nullptr;
211 }
212 }
213
214 static QQmlData *get(const QObjectPrivate *priv) {
215 // If QObjectData::isDeletingChildren is set then access to QObjectPrivate::declarativeData has
216 // to be avoided because QObjectPrivate::currentChildBeingDeleted is in use.
217 if (priv->isDeletingChildren || priv->wasDeleted)
218 return nullptr;
219 if (priv->declarativeData)
220 return static_cast<QQmlData *>(priv->declarativeData);
221 return nullptr;
222 }
223
224 static QQmlData *get(QObject *object, bool create) {
226 }
227
228 static QQmlData *get(const QObject *object) {
229 return QQmlData::get(QObjectPrivate::get(object));
230
231 }
232
233 static bool keepAliveDuringGarbageCollection(const QObject *object) {
234 QQmlData *ddata = get(object);
235 if (!ddata || ddata->indestructible || ddata->rootObjectInCreation)
236 return true;
237 return false;
238 }
239
240 bool hasExtendedData() const { return extendedData != nullptr; }
241 QHash<QQmlAttachedPropertiesFunc, QObject *> *attachedProperties() const;
242
243 static inline bool wasDeleted(const QObject *);
244 static inline bool wasDeleted(const QObjectPrivate *);
245
246 static void markAsDeleted(QObject *);
247 static void setQueuedForDeletion(QObject *);
248
249 static inline void flushPendingBinding(QObject *object, int coreIndex);
250 void flushPendingBinding(int coreIndex);
251
253 {
254 QQmlData *ddata = QQmlData::get(object, /*create*/true);
255 if (Q_LIKELY(ddata->propertyCache))
256 return ddata->propertyCache;
257 return createPropertyCache(object);
258 }
259
260 Q_ALWAYS_INLINE static uint offsetForBit(int bit) { return static_cast<uint>(bit) / BitsPerType; }
261 Q_ALWAYS_INLINE static BindingBitsType bitFlagForBit(int bit) { return BindingBitsType(1) << (static_cast<uint>(bit) & (BitsPerType - 1)); }
262
263private:
264 // For attachedProperties
265 mutable QQmlDataExtended *extendedData = nullptr;
266
267 Q_NEVER_INLINE static QQmlData *createQQmlData(QObjectPrivate *priv);
268 Q_NEVER_INLINE static QQmlPropertyCache::ConstPtr createPropertyCache(QObject *object);
269
270 Q_ALWAYS_INLINE bool hasBitSet(int bit) const
271 {
272 uint offset = offsetForBit(bit);
273 if (bindingBitsArraySize <= offset)
274 return false;
275
276 const BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
277 return bits[offset] & bitFlagForBit(bit);
278 }
279
280 Q_ALWAYS_INLINE void clearBit(int bit)
281 {
283 if (bindingBitsArraySize > offset) {
284 BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
285 bits[offset] &= ~QQmlData::bitFlagForBit(bit);
286 }
287 }
288
289 Q_ALWAYS_INLINE void setBit(QObject *obj, int bit)
290 {
292 BindingBitsType *bits = (bindingBitsArraySize == InlineBindingArraySize) ? bindingBitsValue : bindingBits;
293 if (Q_UNLIKELY(bindingBitsArraySize <= offset))
294 bits = growBits(obj, bit);
296 }
297
298 Q_NEVER_INLINE BindingBitsType *growBits(QObject *obj, int bit);
299
300 Q_DISABLE_COPY_MOVE(QQmlData);
301};
302
304{
305 if (!priv || priv->wasDeleted || priv->isDeletingChildren)
306 return true;
307
308 const QQmlData *ddata = QQmlData::get(priv);
309 return ddata && ddata->isQueuedForDeletion;
310}
311
312bool QQmlData::wasDeleted(const QObject *object)
313{
314 if (!object)
315 return true;
316
317 const QObjectPrivate *priv = QObjectPrivate::get(object);
319}
320
321inline bool isIndexInConnectionMask(quint64 connectionMask, int index)
322{
323 return connectionMask & (1ULL << quint64(index % 64));
324}
325
327{
328 // Can only happen on "home" thread. We apply relaxed semantics when loading the atomics.
329
330 Q_ASSERT(index <= 0xFFFF);
331
332 NotifyList *list = notifyList.loadRelaxed();
333 if (!list || !isIndexInConnectionMask(list->connectionMask.loadRelaxed(), index))
334 return nullptr;
335
336 if (index < list->notifiesSize)
337 return list->notifies[index];
338
339 if (index <= list->maximumTodoIndex) {
340 list->layout();
341 if (index < list->notifiesSize)
342 return list->notifies[index];
343 }
344
345 return nullptr;
346}
347
348/*
349 The index MUST be in the range returned by QObjectPrivate::signalIndex()
350 This is different than the index returned by QMetaMethod::methodIndex()
351*/
352inline bool QQmlData::signalHasEndpoint(int index) const
353{
354 // This can be called from any thread.
355 // We still use relaxed semantics. If we're on a thread different from the "home" thread
356 // of the QQmlData, two interesting things might happen:
357 //
358 // 1. The list might go away while we hold it. In that case we are dealing with an object whose
359 // QObject dtor is being executed concurrently. This is UB already without the notify lists.
360 // Therefore, we don't need to consider it.
361 // 2. The connectionMask may be amended or zeroed while we are looking at it. In that case
362 // we "misreport" the endpoint. Since ordering of events across threads is inherently
363 // nondeterministic, either result is correct in that case. We can accept it.
364
365 NotifyList *list = notifyList.loadRelaxed();
366 return list && isIndexInConnectionMask(list->connectionMask.loadRelaxed(), index);
367}
368
369bool QQmlData::hasBindingBit(int coreIndex) const
370{
371 Q_ASSERT(coreIndex >= 0);
372 Q_ASSERT(coreIndex <= 0xffff);
373
374 return hasBitSet(coreIndex * 2);
375}
376
378{
379 Q_ASSERT(coreIndex >= 0);
380 Q_ASSERT(coreIndex <= 0xffff);
381 setBit(obj, coreIndex * 2);
382}
383
384void QQmlData::clearBindingBit(int coreIndex)
385{
386 Q_ASSERT(coreIndex >= 0);
387 Q_ASSERT(coreIndex <= 0xffff);
388 clearBit(coreIndex * 2);
389}
390
391bool QQmlData::hasPendingBindingBit(int coreIndex) const
392{
393 Q_ASSERT(coreIndex >= 0);
394 Q_ASSERT(coreIndex <= 0xffff);
395
396 return hasBitSet(coreIndex * 2 + 1);
397}
398
400{
401 Q_ASSERT(coreIndex >= 0);
402 Q_ASSERT(coreIndex <= 0xffff);
403 setBit(obj, coreIndex * 2 + 1);
404}
405
407{
408 Q_ASSERT(coreIndex >= 0);
409 Q_ASSERT(coreIndex <= 0xffff);
410 clearBit(coreIndex * 2 + 1);
411}
412
413void QQmlData::flushPendingBinding(QObject *object, int coreIndex)
414{
415 QQmlData *data = QQmlData::get(object, false);
416 if (data && data->hasPendingBindingBit(coreIndex))
417 data->flushPendingBinding(coreIndex);
418}
419
421
422#endif // QQMLDATA_P_H
static bool(* isSignalConnected)(QAbstractDeclarativeData *, const QObject *, int)
Definition qobject_p.h:69
static int(* receivers)(QAbstractDeclarativeData *, const QObject *, int)
Definition qobject_p.h:68
static void(* destroyed)(QAbstractDeclarativeData *, QObject *)
Definition qobject_p.h:66
static void(* signalEmitted)(QAbstractDeclarativeData *, QObject *, int, void **)
Definition qobject_p.h:67
\inmodule QtCore
Definition qhash.h:820
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
\inmodule QtCore
Definition qobject.h:103
The QQmlContext class defines a context within a QML engine.
Definition qqmlcontext.h:25
static void init()
Definition qqmldata_p.h:63
void setPendingBindingBit(QObject *obj, int)
Definition qqmldata_p.h:399
quint32 hasConstWrapper
Definition qqmldata_p.h:109
static void flushPendingBinding(QObject *object, int coreIndex)
Definition qqmldata_p.h:413
QV4::WeakValue jsWrapper
Definition qqmldata_p.h:193
static QQmlPropertyCache::ConstPtr ensurePropertyCache(QObject *object)
Definition qqmldata_p.h:252
bool hasExtendedData() const
Definition qqmldata_p.h:240
QVector< DeferredData * > deferredData
Definition qqmldata_p.h:187
QQmlRefPointer< QV4::ExecutableCompilationUnit > compilationUnit
Definition qqmldata_p.h:186
QQmlPropertyCache::ConstPtr propertyCache
Definition qqmldata_p.h:195
static QQmlData * get(const QObject *object)
Definition qqmldata_p.h:228
quint32 hasTaintedV4Object
Definition qqmldata_p.h:98
static bool keepAliveDuringGarbageCollection(const QObject *object)
Definition qqmldata_p.h:233
bool signalHasEndpoint(int index) const
Definition qqmldata_p.h:352
QQmlRefPointer< QQmlContextData > ownContext
Definition qqmldata_p.h:150
void clearBindingBit(int)
Definition qqmldata_p.h:384
quint32 hasVMEMetaObject
Definition qqmldata_p.h:107
bool hasPendingBindingBit(int index) const
Definition qqmldata_p.h:391
std::vector< QQmlPropertyObserver > propertyObservers
Definition qqmldata_p.h:154
quint32 explicitIndestructibleSet
Definition qqmldata_p.h:95
quint32 hasInterceptorMetaObject
Definition qqmldata_p.h:106
BindingBitsType * bindingBits
Definition qqmldata_p.h:122
quint32 bindingBitsArraySize
Definition qqmldata_p.h:115
QAtomicPointer< NotifyList > notifyList
Definition qqmldata_p.h:136
void clearPendingBindingBit(int)
Definition qqmldata_p.h:406
static bool wasDeleted(const QObject *)
Definition qqmldata_p.h:312
static QQmlData * get(const QObjectPrivate *priv)
Definition qqmldata_p.h:214
void setBindingBit(QObject *obj, int)
Definition qqmldata_p.h:377
@ DoesNotOwnMemory
Definition qqmldata_p.h:58
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
quint32 dummy
Definition qqmldata_p.h:110
void setImplicitDestructible()
Definition qqmldata_p.h:81
quint32 isQueuedForDeletion
Definition qqmldata_p.h:99
static Q_ALWAYS_INLINE uint offsetForBit(int bit)
Definition qqmldata_p.h:260
quint32 rootObjectInCreation
Definition qqmldata_p.h:104
quint32 ownMemory
Definition qqmldata_p.h:87
quint32 indestructible
Definition qqmldata_p.h:92
quintptr BindingBitsType
Definition qqmldata_p.h:116
QQmlNotifierEndpoint * notify(int index) const
Definition qqmldata_p.h:326
static QQmlData * get(QObject *object, bool create)
Definition qqmldata_p.h:224
static Q_ALWAYS_INLINE BindingBitsType bitFlagForBit(int bit)
Definition qqmldata_p.h:261
bool hasBindingBit(int) const
Definition qqmldata_p.h:369
The QQmlEngine class provides an environment for instantiating QML components.
Definition qqmlengine.h:57
Combined button and popup list for selecting options.
static void * context
#define Q_UNLIKELY(x)
#define Q_NEVER_INLINE
#define Q_LIKELY(x)
#define Q_ALWAYS_INLINE
static QDBusError::ErrorType get(const char *name)
static const QMetaObjectPrivate * priv(const uint *data)
GLuint index
[2]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLhandleARB obj
[2]
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
bool isIndexInConnectionMask(quint64 connectionMask, int index)
Definition qqmldata_p.h:321
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
unsigned int quint32
Definition qtypes.h:50
unsigned short quint16
Definition qtypes.h:48
size_t quintptr
Definition qtypes.h:167
unsigned long long quint64
Definition qtypes.h:61
unsigned int uint
Definition qtypes.h:34
QList< int > list
[14]
QVBoxLayout * layout
ba setBit(0, true)
view create()
QQmlRefPointer< QQmlContextData > context
Definition qqmldata_p.h:183
unsigned int deferredIdx
Definition qqmldata_p.h:176
QQmlRefPointer< QV4::ExecutableCompilationUnit > compilationUnit
Definition qqmldata_p.h:180
QMultiHash< int, const QV4::CompiledData::Binding * > bindings
Definition qqmldata_p.h:177
Q_DISABLE_COPY(DeferredData)
QAtomicInteger< quint64 > connectionMask
Definition qqmldata_p.h:127