Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmlvmemetaobject_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 BasysKom GmbH.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant
5
6#ifndef QQMLVMEMETAOBJECT_P_H
7#define QQMLVMEMETAOBJECT_P_H
8
9//
10// W A R N I N G
11// -------------
12//
13// This file is not part of the Qt API. It exists purely as an
14// implementation detail. This header file may change from version to
15// version without notice, or even be removed.
16//
17// We mean it.
18//
19
20#include "qqmldata_p.h"
21#include <private/qbipointer_p.h>
22#include <private/qqmlguard_p.h>
23#include <private/qqmlguardedcontextdata_p.h>
24#include <private/qqmlpropertyvalueinterceptor_p.h>
25#include <private/qv4object_p.h>
26#include <private/qv4value_p.h>
27
28#include <QtCore/private/qobject_p.h>
29
30#if QT_CONFIG(regularexpression)
31#include <QtCore/qregularexpression.h>
32#endif
33
34#include <QtCore/qbitarray.h>
35#include <QtCore/qdatetime.h>
36#include <QtCore/qdebug.h>
37#include <QtCore/qlist.h>
38#include <QtCore/qmetaobject.h>
39
41
42class QQmlVMEMetaObject;
44{
46
47public:
50
51 QQmlVMEMetaObject *metaObject() const { return m_metaObject; }
52 QV4::Heap::Object *list() const { return m_list; }
53 quintptr id() const { return m_id; }
54
55 // if m_propertyAndMethodStorage of the object is gone,
56 // the list is unusable
57 bool isValid() const { return m_list; }
58
59 void append(QObject *o) const;
60 void replace(qsizetype i, QObject *o) const;
61 QObject *at(qsizetype i) const;
62
64 {
65 Q_ASSERT(isValid());
66 return m_list->arrayData->length();
67 }
68
69 void clear() const
70 {
71 Q_ASSERT(isValid());
72
73 QV4::Scope scope(m_list->internalClass->engine);
74 QV4::ScopedObject object(scope, m_list);
75 m_list->arrayData->vtable()->truncate(object, 0);
76 }
77
78 void removeLast() const
79 {
80 Q_ASSERT(isValid());
81
82 const uint length = m_list->arrayData->length();
83 if (length == 0)
84 return;
85
86 QV4::Scope scope(m_list->internalClass->engine);
87 QV4::ScopedObject object(scope, m_list);
88 m_list->arrayData->vtable()->truncate(object, length - 1);
89 }
90
91 void activateSignal() const;
92
93private:
94 QQmlVMEMetaObject *m_metaObject = nullptr;
95 QV4::Heap::Object *m_list = nullptr;
96 quintptr m_id = 0;
97};
98
100{
101public:
103
104 inline void setGuardedValue(QObject *obj, QQmlVMEMetaObject *target, int index);
105
106 QQmlVMEMetaObject *m_target;
108
109private:
110 static void objectDestroyedImpl(QQmlGuardImpl *guard);
111};
112
113
114class Q_QML_EXPORT QQmlInterceptorMetaObject : public QDynamicMetaObjectData
115{
116public:
117 QQmlInterceptorMetaObject(QObject *obj, const QQmlPropertyCache::ConstPtr &cache);
118 ~QQmlInterceptorMetaObject() override;
119
120 void registerInterceptor(QQmlPropertyIndex index, QQmlPropertyValueInterceptor *interceptor);
121
122 static QQmlInterceptorMetaObject *get(QObject *obj);
123
124#if QT_VERSION >= QT_VERSION_CHECK(7, 0, 0)
125 const QMetaObject *toDynamicMetaObject(QObject *o) const override;
126#else
127 QMetaObject *toDynamicMetaObject(QObject *o) override;
128#endif
129
130 // Used by auto-tests for inspection
131 QQmlPropertyCache::ConstPtr propertyCache() const { return cache; }
132
133 // Re-point this meta-object at an identically-shaped property cache. Used by the QML preview's
134 // in-place patch to give a live instance the reloaded type's identity, so it keeps satisfying
135 // is-a checks against consumers whose type references were redirected to the new unit. The
136 // lazily-built dynamic meta-object is dropped so it is rebuilt from the new cache on next use.
137 void setPropertyCache(const QQmlPropertyCache::ConstPtr &newCache)
138 {
139 cache = newCache;
140 metaObject = QTaggedPointer<const QMetaObject, MetaObjectValidity>();
141 }
142
143 bool intercepts(QQmlPropertyIndex propertyIndex) const
144 {
145 for (auto it = interceptors; it; it = it->m_next) {
146 if (it->m_propertyIndex == propertyIndex)
147 return true;
148 }
149 if (auto parentInterceptor = ((parent.isT1() && parent.flag()) ? static_cast<QQmlInterceptorMetaObject *>(parent.asT1()) : nullptr))
150 return parentInterceptor->intercepts(propertyIndex);
151 return false;
152 }
153
154 void invalidate() { metaObject.setTag(MetaObjectInvalid); }
155
156 // only used for Bindable so far; Write instead passes a flag via the metacall
157 enum InterceptionBehavior { Intercept, SkipInterception };
158 static void setInterceptionMode(QObject *object, InterceptionBehavior behavior);
159
160 QTaggedPointer<QObject> object = nullptr;
161 QQmlPropertyCache::ConstPtr cache;
162
163protected:
164 int metaCall(QObject *o, QMetaObject::Call c, int id, void **a) override;
165 bool intercept(QMetaObject::Call c, int id, void **a)
166 {
167 if (!interceptors)
168 return false;
169
170 switch (c) {
171 case QMetaObject::WriteProperty:
172 if (*reinterpret_cast<int*>(a[3]) & QQmlPropertyData::BypassInterceptor)
173 return false;
174 break;
175 case QMetaObject::BindableProperty:
176 if (object.tag() == SkipInterception) {
177 return false;
178 }
179 break;
180 default:
181 return false;
182 }
183
184 return doIntercept(c, id, a);
185 }
186
187 QBiPointer<QDynamicMetaObjectData, const QMetaObject> parent;
188
189 enum MetaObjectValidity { MetaObjectValid, MetaObjectInvalid };
190 QTaggedPointer<const QMetaObject, MetaObjectValidity> metaObject;
191
192private:
193 bool doIntercept(QMetaObject::Call c, int id, void **a);
194 QQmlPropertyValueInterceptor *interceptors = nullptr;
195};
196
197inline QQmlInterceptorMetaObject *QQmlInterceptorMetaObject::get(QObject *obj)
198{
199 if (obj) {
200 if (QQmlData *data = QQmlData::get(obj)) {
201 if (data->hasInterceptorMetaObject)
202 return static_cast<QQmlInterceptorMetaObject *>(QObjectPrivate::get(obj)->metaObject);
203 }
204 }
205
206 return nullptr;
207}
208
209inline void QQmlInterceptorMetaObject::setInterceptionMode(
210 QObject *object, QQmlInterceptorMetaObject::InterceptionBehavior behavior)
211{
212 QQmlInterceptorMetaObject *interceptorMetaObject = get(object);
213 while (interceptorMetaObject) {
214 interceptorMetaObject->object.setTag(behavior);
215 auto parent = interceptorMetaObject->parent;
216 interceptorMetaObject = ((parent.isT1() && parent.flag()) ? static_cast<QQmlInterceptorMetaObject *>(parent.asT1()) : nullptr);
217 }
218}
219
221class Q_QML_EXPORT QQmlVMEMetaObject : public QQmlInterceptorMetaObject
222{
223public:
224 QQmlVMEMetaObject(
225 QV4::ExecutionEngine *engine, QObject *obj, const QQmlPropertyCache::ConstPtr &cache,
226 const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlCompilationUnit,
227 int qmlObjectId);
228 ~QQmlVMEMetaObject() override;
229
230 bool aliasTarget(int index, QObject **target, int *coreIndex, int *valueTypeIndex) const;
231 QV4::ReturnedValue vmeMethod(int index) const;
232 void setVmeMethod(int index, const QV4::Value &function);
233 QV4::ReturnedValue vmeProperty(int index) const;
234 void setVMEProperty(int index, const QV4::Value &v);
235
236 void connectAliasSignal(int index, bool indexInSignalRange);
237
238 static inline QQmlVMEMetaObject *get(QObject *o);
239 static QQmlVMEMetaObject *getForProperty(QObject *o, int coreIndex);
240 static QQmlVMEMetaObject *getForMethod(QObject *o, int coreIndex);
241 static QQmlVMEMetaObject *getForSignal(QObject *o, int coreIndex);
242
243 static void list_append(QQmlListProperty<QObject> *prop, QObject *o);
244 static void list_clear(QQmlListProperty<QObject> *prop);
245 static void list_append_nosignal(QQmlListProperty<QObject> *prop, QObject *o);
246 static void list_clear_nosignal(QQmlListProperty<QObject> *prop);
247
248 inline int propOffset() const;
249 inline int propCount() const;
250 inline int aliasOffset() const;
251 inline int aliasCount() const;
252 inline int signalOffset() const;
253 inline int signalCount() const;
254 inline int methodOffset() const;
255 inline int methodCount() const;
256
257 QV4::MemberData *propertyAndMethodStorageAsMemberData() const;
258
259 int readPropertyAsInt(int id) const;
260 bool readPropertyAsBool(int id) const;
261 double readPropertyAsDouble(int id) const;
262 QString readPropertyAsString(int id) const;
263 QSizeF readPropertyAsSizeF(int id) const;
264 QPointF readPropertyAsPointF(int id) const;
265 QUrl readPropertyAsUrl(int id) const;
266 QDate readPropertyAsDate(int id) const;
267 QTime readPropertyAsTime(int id) const;
268 QDateTime readPropertyAsDateTime(int id) const;
269
270#if QT_CONFIG(regularexpression)
271 QRegularExpression readPropertyAsRegularExpression(int id) const;
272#endif
273
274 QRectF readPropertyAsRectF(int id) const;
275 QObject *readPropertyAsQObject(int id) const;
276 void initPropertyAsList(int id) const;
277
278 void writeProperty(int id, int v);
279 void writeProperty(int id, bool v);
280 void writeProperty(int id, double v);
281 void writeProperty(int id, const QString& v);
282
283 template<typename VariantCompatible>
284 void writeProperty(int id, const VariantCompatible &v)
285 {
286 QV4::MemberData *md = propertyAndMethodStorageAsMemberData();
287 if (md) {
288 QV4::Scope scope(m_engine);
289 QV4::Scoped<QV4::MemberData>(scope, md)->set(
290 m_engine, id, m_engine->newVariantObject(
291 QMetaType::fromType<VariantCompatible>(), &v));
292 }
293 }
294
295 void writeProperty(int id, QObject *v);
296
297 void ensureQObjectWrapper();
298
299 void mark(QV4::MarkStack *markStack);
300
301 void connectAlias(const QV4::CompiledData::Object *compiledObject, int aliasId);
302
303 QV4::ReturnedValue method(int) const;
304
305 QV4::ReturnedValue readVarProperty(int) const;
306 void writeVarProperty(int, const QV4::Value &);
307 QVariant readPropertyAsVariant(int) const;
308
309 inline QQmlVMEMetaObject *parentVMEMetaObject() const;
310 inline void setParentVMEMetaObject(QQmlVMEMetaObject *newParent);
311
312 void activate(QObject *, int, void **);
313
314 QQmlVMEVariantQObjectPtr *getQObjectGuardForProperty(int) const;
315
316 QQmlRefPointer<QQmlContextData> contextData() const { return m_ctxt.contextData(); }
317 QV4::ExecutionEngine *engine() const { return m_engine; }
318 QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit() const
319 {
320 return m_compilationUnit;
321 }
322
323 void setCompilationUnit(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit)
324 {
325 m_compilationUnit = compilationUnit;
326 }
327
328 int qmlObjectId() const { return m_qmlObjectId; }
329
330protected:
331 int metaCall(QObject *o, QMetaObject::Call _c, int _id, void **_a) override;
332 bool getListProperty(int id, QQmlListProperty<QObject> *target);
333
334private:
335 friend class QQmlVMEMetaObjectEndpoint;
336 friend class QQmlVMEResolvedList;
337 friend class QQmlVMEVariantQObjectPtr;
338
339 const QV4::CompiledData::Object *findCompiledObject() const {
340 // If the executable CU has been stripped of its engine, it has an empty base CU
341 if (!m_compilationUnit || !m_compilationUnit->engine)
342 return nullptr;
343
344 Q_ASSERT(m_qmlObjectId >= 0 && m_qmlObjectId < m_compilationUnit->objectCount());
345 return m_compilationUnit->objectAt(m_qmlObjectId);
346 }
347
348 void writeKnownVarProperty(int id, const QVariant &value);
349
350 QV4::ExecutionEngine *m_engine;
351 QQmlGuardedContextData m_ctxt;
352
353 QQmlVMEMetaObjectEndpoint *m_aliasEndpoints;
354 QV4::WeakValue m_propertyAndMethodStorage;
355
356 QList<QQmlVMEVariantQObjectPtr *> m_varObjectGuards;
357
358 // keep a reference to the compilation unit in order to still
359 // do property access when the context has been invalidated.
360 QQmlRefPointer<QV4::ExecutableCompilationUnit> m_compilationUnit;
361 int m_qmlObjectId = -1;
362 int m_numAliases = 0;
363};
364
365QQmlVMEMetaObject *QQmlVMEMetaObject::get(QObject *obj)
366{
367 if (obj) {
368 if (QQmlData *data = QQmlData::get(obj)) {
369 if (data->hasVMEMetaObject)
370 return static_cast<QQmlVMEMetaObject *>(QObjectPrivate::get(obj)->metaObject);
371 }
372 }
373
374 return nullptr;
375}
376
377int QQmlVMEMetaObject::propOffset() const
378{
379 // Regular properties are before aliases
380 return cache->propertyOffset();
381}
382
383int QQmlVMEMetaObject::propCount() const
384{
385 // Properties excluding aliases
386 return cache->ownPropertyCount() - m_numAliases;
387}
388
389int QQmlVMEMetaObject::aliasOffset() const
390{
391 // Aliases are after regular properties
392 return propOffset() + propCount();
393}
394
395int QQmlVMEMetaObject::aliasCount() const
396{
397 // We need to cache this since we don't want to count over and over.
398 return m_numAliases;
399}
400
401int QQmlVMEMetaObject::signalOffset() const
402{
403 // Signals are before regular methods
404 return cache->methodOffset();
405}
406
407int QQmlVMEMetaObject::signalCount() const
408{
409 // Signals including signals for properties and aliases
410 return cache->ownSignalCount();
411}
412
413int QQmlVMEMetaObject::methodOffset() const
414{
415 // Regular methods are after signals
416 return signalOffset() + signalCount();
417}
418
419int QQmlVMEMetaObject::methodCount() const
420{
421 // Methods excluding signals
422 return cache->ownMethodCount() - signalCount();
423}
424
425QQmlVMEMetaObject *QQmlVMEMetaObject::parentVMEMetaObject() const
426{
427 if (parent.isT1() && parent.flag())
428 return static_cast<QQmlVMEMetaObject *>(parent.asT1());
429
430 return nullptr;
431}
432
433inline void QQmlVMEMetaObject::setParentVMEMetaObject(QQmlVMEMetaObject *newParent)
434{
435 parent = newParent;
436 parent.setFlag();
437}
438
439QT_END_NAMESPACE
440
441#endif // QQMLVMEMETAOBJECT_P_H
QTaggedPointer< QQmlVMEMetaObject, Tag > metaObject
QQmlVMEMetaObject * metaObject() const
void replace(qsizetype i, QObject *o) const
qsizetype size() const
QV4::Heap::Object * list() const
void append(QObject *o) const
QObject * at(qsizetype i) const
void setGuardedValue(QObject *obj, QQmlVMEMetaObject *target, int index)
Combined button and popup list for selecting options.
void QQmlVMEMetaObjectEndpoint_callback(QQmlNotifierEndpoint *, void **)
static const QMetaObject * stringCastMetaObject(QObject *o, const QMetaObject *top)
static void list_removeLast(QQmlListProperty< QObject > *prop)
static QObject * list_at(QQmlListProperty< QObject > *prop, qsizetype index)
static qsizetype list_count(QQmlListProperty< QObject > *prop)
static void list_replace(QQmlListProperty< QObject > *prop, qsizetype index, QObject *o)
static bool propertyIndicesConflict(QQmlPropertyIndex a, QQmlPropertyIndex b)