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