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 QV4QOBJECTWRAPPER_P_H
5#define QV4QOBJECTWRAPPER_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/qbipointer_p.h>
19#include <private/qintrusivelist_p.h>
20#include <private/qqmldata_p.h>
21#include <private/qv4functionobject_p.h>
22#include <private/qv4lookup_p.h>
23#include <private/qv4value_p.h>
24
25#include <QtCore/qglobal.h>
26#include <QtCore/qmetatype.h>
27#include <QtCore/qpair.h>
28#include <QtCore/qhash.h>
29
30QT_BEGIN_NAMESPACE
31
32class QObject;
33class QQmlData;
34class QQmlPropertyCache;
35class QQmlPropertyData;
36class QQmlObjectOrGadget;
37
38namespace QV4 {
39struct QObjectSlotDispatcher;
40
41namespace Heap {
42
43struct QQmlValueTypeWrapper;
44
45struct Q_QML_EXPORT QObjectWrapper : Object {
46 void init(QObject *object)
47 {
48 Object::init();
49 qObj.init(o: object);
50 }
51
52 void destroy() {
53 qObj.destroy();
54 Object::destroy();
55 }
56
57 QObject *object() const { return qObj.data(); }
58 static void markObjects(Heap::Base *that, MarkStack *markStack);
59
60private:
61 QV4QPointer<QObject> qObj;
62};
63
64#define QObjectMethodMembers(class, Member) \
65 Member(class, Pointer, Object *, wrapper) \
66
67DECLARE_EXPORTED_HEAP_OBJECT(QObjectMethod, FunctionObject) {
68 DECLARE_MARKOBJECTS(QObjectMethod)
69
70 QQmlPropertyData *methods;
71 alignas(alignof(QQmlPropertyData)) std::byte _singleMethod[sizeof(QQmlPropertyData)];
72 int methodCount;
73 int index;
74
75 void init(QV4::ExecutionEngine *engine, Object *wrapper, int index);
76 void destroy()
77 {
78 if (methods != reinterpret_cast<const QQmlPropertyData *>(&_singleMethod))
79 delete[] methods;
80 FunctionObject::destroy();
81 }
82
83 void ensureMethodsCache(const QMetaObject *thisMeta);
84 QString name() const;
85
86 const QMetaObject *metaObject() const;
87 QObject *object() const;
88
89 bool isDetached() const;
90 bool isAttachedTo(QObject *o) const;
91
92 enum ThisObjectMode {
93 Invalid,
94 Included,
95 Explicit,
96 };
97
98 QV4::Heap::QObjectMethod::ThisObjectMode checkThisObject(const QMetaObject *thisMeta) const;
99};
100
101struct QmlSignalHandler : Object {
102 void init(QObject *object, int signalIndex);
103 void destroy() {
104 qObj.destroy();
105 Object::destroy();
106 }
107 int signalIndex;
108
109 QObject *object() const { return qObj.data(); }
110 void setObject(QObject *o) { qObj = o; }
111
112private:
113 QV4QPointer<QObject> qObj;
114};
115
116}
117
118struct Q_QML_EXPORT QObjectWrapper : public Object
119{
120 V4_OBJECT2(QObjectWrapper, Object)
121 V4_NEEDS_DESTROY
122
123 enum Flag {
124 NoFlag = 0x0,
125 CheckRevision = 0x1,
126 AttachMethods = 0x2,
127 AllowOverride = 0x4,
128 IncludeImports = 0x8,
129 };
130
131 Q_DECLARE_FLAGS(Flags, Flag);
132
133 static void initializeBindings(ExecutionEngine *engine);
134
135 const QMetaObject *metaObject() const
136 {
137 if (QObject *o = object())
138 return o->metaObject();
139 return nullptr;
140 }
141
142 QObject *object() const { return d()->object(); }
143
144 ReturnedValue getQmlProperty(
145 const QQmlRefPointer<QQmlContextData> &qmlContext, String *name,
146 Flags flags, bool *hasProperty = nullptr) const;
147
148 static ReturnedValue getQmlProperty(
149 ExecutionEngine *engine, const QQmlRefPointer<QQmlContextData> &qmlContext,
150 Heap::Object *wrapper, QObject *object, String *name, Flags flags,
151 bool *hasProperty = nullptr, const QQmlPropertyData **property = nullptr);
152
153 static bool setQmlProperty(
154 ExecutionEngine *engine, const QQmlRefPointer<QQmlContextData> &qmlContext,
155 QObject *object, String *name, Flags flags, const Value &value);
156
157 Q_NODISCARD_X("Use ensureWrapper if you don't need the return value")
158 static ReturnedValue wrap(ExecutionEngine *engine, QObject *object);
159 Q_NODISCARD_X("Throwing the const wrapper away can cause it to be garbage collected")
160 static ReturnedValue wrapConst(ExecutionEngine *engine, QObject *object);
161 static void ensureWrapper(ExecutionEngine *engine, QObject *object);
162 static void markWrapper(QObject *object, MarkStack *markStack);
163
164 using Object::get;
165
166 static void setProperty(ExecutionEngine *engine, QObject *object, int propertyIndex, const Value &value);
167 void setProperty(ExecutionEngine *engine, int propertyIndex, const Value &value);
168 static void setProperty(
169 ExecutionEngine *engine, QObject *object,
170 const QQmlPropertyData *property, const Value &value);
171
172 void destroyObject(bool lastCall);
173
174 static ReturnedValue getProperty(
175 ExecutionEngine *engine, Heap::Object *wrapper, QObject *object,
176 const QQmlPropertyData *property, Flags flags);
177
178 static ReturnedValue virtualResolveLookupGetter(const Object *object, ExecutionEngine *engine, Lookup *lookup);
179 static ReturnedValue lookupAttached(Lookup *l, ExecutionEngine *engine, const Value &object);
180
181 template <typename ReversalFunctor> static ReturnedValue lookupPropertyGetterImpl(
182 Lookup *l, ExecutionEngine *engine, const Value &object,
183 Flags flags, ReversalFunctor revert);
184 template <typename ReversalFunctor> static ReturnedValue lookupMethodGetterImpl(
185 Lookup *l, ExecutionEngine *engine, const Value &object,
186 Flags flags, ReversalFunctor revert);
187 static bool virtualResolveLookupSetter(
188 Object *object, ExecutionEngine *engine, Lookup *lookup, const Value &value);
189 static OwnPropertyKeyIterator *virtualOwnPropertyKeys(const Object *m, Value *target);
190
191 static int virtualMetacall(Object *object, QMetaObject::Call call, int index, void **a);
192
193 static QString objectToString(
194 ExecutionEngine *engine, const QMetaObject *metaObject, QObject *object);
195
196protected:
197 static bool virtualIsEqualTo(Managed *that, Managed *o);
198 static ReturnedValue create(ExecutionEngine *engine, QObject *object);
199
200 static const QQmlPropertyData *findProperty(
201 QObject *o, const QQmlRefPointer<QQmlContextData> &qmlContext,
202 String *name, Flags flags, QQmlPropertyData *local);
203
204 const QQmlPropertyData *findProperty(
205 const QQmlRefPointer<QQmlContextData> &qmlContext,
206 String *name, Flags flags, QQmlPropertyData *local) const;
207
208 static ReturnedValue virtualGet(
209 const Managed *m, PropertyKey id, const Value *receiver, bool *hasProperty);
210 static bool virtualPut(Managed *m, PropertyKey id, const Value &value, Value *receiver);
211 static PropertyAttributes virtualGetOwnProperty(const Managed *m, PropertyKey id, Property *p);
212
213 static ReturnedValue method_connect(
214 const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
215 static ReturnedValue method_disconnect(
216 const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
217
218private:
219 Q_NEVER_INLINE static ReturnedValue wrap_slowPath(ExecutionEngine *engine, QObject *object);
220 Q_NEVER_INLINE static ReturnedValue wrapConst_slowPath(ExecutionEngine *engine, QObject *object);
221};
222
223Q_DECLARE_OPERATORS_FOR_FLAGS(QObjectWrapper::Flags)
224
225// We generally musn't pass ReturnedValue as arguments to other functions.
226// In this case, we do it solely for marking purposes so it's fine.
227inline void markIfPastMarkWeakValues(ExecutionEngine *engine, ReturnedValue rv)
228{
229 const auto gcState = engine->memoryManager->gcStateMachine->state;
230 if (gcState != GCStateMachine::Invalid && gcState >= GCState::MarkWeakValues) {
231 QV4::WriteBarrier::markCustom(engine, markFunction: [rv](QV4::MarkStack *ms) {
232 auto *m = StaticValue::fromReturnedValue(val: rv).m();
233 m->mark(markStack: ms);
234 });
235 }
236}
237
238inline ReturnedValue QObjectWrapper::wrap(ExecutionEngine *engine, QObject *object)
239{
240 if (Q_UNLIKELY(QQmlData::wasDeleted(object)))
241 return QV4::Encode::null();
242
243 auto ddata = QQmlData::get(object);
244 if (Q_LIKELY(ddata && ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) {
245 // We own the JS object
246 return ddata->jsWrapper.value();
247 }
248
249 const auto rv = wrap_slowPath(engine, object);
250 markIfPastMarkWeakValues(engine, rv);
251 return rv;
252}
253
254// Unfortunately we still need a non-const QObject* here because QQmlData needs to register itself in QObjectPrivate.
255inline ReturnedValue QObjectWrapper::wrapConst(ExecutionEngine *engine, QObject *object)
256{
257 if (Q_UNLIKELY(QQmlData::wasDeleted(object)))
258 return QV4::Encode::null();
259
260 const auto rv = wrapConst_slowPath(engine, object);
261 markIfPastMarkWeakValues(engine, rv);
262 return rv;
263}
264
265inline bool canConvert(const QQmlPropertyCache *fromMo, const QQmlPropertyCache *toMo)
266{
267 while (fromMo) {
268 if (fromMo == toMo)
269 return true;
270 fromMo = fromMo->parent().data();
271 }
272 return false;
273}
274
275template <typename ReversalFunctor>
276inline ReturnedValue QObjectWrapper::lookupPropertyGetterImpl(
277 Lookup *lookup, ExecutionEngine *engine, const Value &object,
278 QObjectWrapper::Flags flags, ReversalFunctor revertLookup)
279{
280 // we can safely cast to a QV4::Object here. If object is something else,
281 // the internal class won't match
282 Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
283 if (!o || o->internalClass != lookup->qobjectLookup.ic)
284 return revertLookup();
285
286 Heap::QObjectWrapper *This = static_cast<Heap::QObjectWrapper *>(o);
287 QObject *qobj = This->object();
288 if (QQmlData::wasDeleted(object: qobj))
289 return QV4::Encode::undefined();
290
291 QQmlData *ddata = QQmlData::get(object: qobj, /*create*/create: false);
292 if (!ddata)
293 return revertLookup();
294
295 const QQmlPropertyData *property = lookup->qobjectLookup.propertyData;
296 if (ddata->propertyCache.data() != lookup->qobjectLookup.propertyCache) {
297 // If the property is overridden and the lookup allows overrides to be considered,
298 // we have to revert here and redo the lookup from scratch.
299 if (property->isOverridden()
300 && ((flags & AllowOverride)
301 || property->isFunction()
302 || property->isSignalHandler())) {
303 return revertLookup();
304 }
305
306 if (!canConvert(fromMo: ddata->propertyCache.data(), toMo: lookup->qobjectLookup.propertyCache))
307 return revertLookup();
308 }
309
310 return getProperty(engine, wrapper: This, object: qobj, property, flags);
311}
312
313template <typename ReversalFunctor>
314inline ReturnedValue QObjectWrapper::lookupMethodGetterImpl(
315 Lookup *lookup, ExecutionEngine *engine, const Value &object,
316 QObjectWrapper::Flags flags, ReversalFunctor revertLookup)
317{
318 // we can safely cast to a QV4::Object here. If object is something else,
319 // the internal class won't match
320 Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
321 if (!o || o->internalClass != lookup->qobjectMethodLookup.ic)
322 return revertLookup();
323
324 Heap::QObjectWrapper *This = static_cast<Heap::QObjectWrapper *>(o);
325 QObject *qobj = This->object();
326 if (QQmlData::wasDeleted(object: qobj))
327 return QV4::Encode::undefined();
328
329 QQmlData *ddata = QQmlData::get(object: qobj, /*create*/create: false);
330 if (!ddata)
331 return revertLookup();
332
333 const QQmlPropertyData *property = lookup->qobjectMethodLookup.propertyData;
334 if (ddata->propertyCache.data() != lookup->qobjectMethodLookup.propertyCache) {
335 if (property && property->isOverridden())
336 return revertLookup();
337
338 if (!canConvert(fromMo: ddata->propertyCache.data(), toMo: lookup->qobjectMethodLookup.propertyCache))
339 return revertLookup();
340 }
341
342 if (Heap::QObjectMethod *method = lookup->qobjectMethodLookup.method) {
343 if (method->isDetached())
344 return method->asReturnedValue();
345 }
346
347 if (!property) // was toString() or destroy()
348 return revertLookup();
349
350 QV4::Scope scope(engine);
351 QV4::ScopedValue v(scope, getProperty(engine, wrapper: This, object: qobj, property, flags));
352 if (!v->as<QObjectMethod>())
353 return revertLookup();
354
355 lookup->qobjectMethodLookup.method.set(engine, heapObject: static_cast<Heap::QObjectMethod *>(v->heapObject()));
356 return v->asReturnedValue();
357}
358
359struct QQmlValueTypeWrapper;
360
361struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
362{
363 V4_OBJECT2(QObjectMethod, QV4::FunctionObject)
364 V4_NEEDS_DESTROY
365
366 enum { DestroyMethod = -1, ToStringMethod = -2 };
367
368 static ReturnedValue create(ExecutionEngine *engine, Heap::Object *wrapper, int index);
369 static ReturnedValue create(
370 ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *valueType, int index);
371 static ReturnedValue create(
372 ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
373 Heap::Object *wrapper, Heap::Object *object);
374
375 int methodIndex() const { return d()->index; }
376 QObject *object() const { return d()->object(); }
377
378 QV4::ReturnedValue method_toString(QV4::ExecutionEngine *engine, QObject *o) const;
379 QV4::ReturnedValue method_destroy(
380 QV4::ExecutionEngine *ctx, QObject *o, const Value *args, int argc) const;
381 void method_destroy(
382 QV4::ExecutionEngine *engine, QObject *o,
383 void **argv, const QMetaType *types, int argc) const;
384
385 static ReturnedValue virtualCall(
386 const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
387 static void virtualCallWithMetaTypes(
388 const FunctionObject *m, QObject *thisObject,
389 void **argv, const QMetaType *types, int argc);
390
391 ReturnedValue callInternal(
392 const Value *thisObject, const Value *argv, int argc) const;
393 void callInternalWithMetaTypes(
394 QObject *thisObject, void **argv, const QMetaType *types, int argc) const;
395
396 static QPair<QObject *, int> extractQtMethod(const QV4::FunctionObject *function);
397
398 static bool isExactMatch(
399 const QMetaMethod &method, void **argv, int argc, const QMetaType *types);
400
401private:
402 friend struct QMetaObjectWrapper;
403
404 static const QQmlPropertyData *resolveOverloaded(
405 const QQmlObjectOrGadget &object, const QQmlPropertyData *methods, int methodCount,
406 ExecutionEngine *engine, CallData *callArgs);
407
408 static const QQmlPropertyData *resolveOverloaded(
409 const QQmlPropertyData *methods, int methodCount,
410 void **argv, int argc, const QMetaType *types);
411
412 static ReturnedValue callPrecise(
413 const QQmlObjectOrGadget &object, const QQmlPropertyData &data,
414 ExecutionEngine *engine, CallData *callArgs,
415 QMetaObject::Call callType = QMetaObject::InvokeMetaMethod);
416};
417
418struct Q_QML_EXPORT QmlSignalHandler : public QV4::Object
419{
420 V4_OBJECT2(QmlSignalHandler, QV4::Object)
421 V4_PROTOTYPE(signalHandlerPrototype)
422 V4_NEEDS_DESTROY
423
424 int signalIndex() const { return d()->signalIndex; }
425 QObject *object() const { return d()->object(); }
426
427 ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const;
428
429 static void initProto(ExecutionEngine *v4);
430};
431
432using QObjectBiPointer = QBiPointer<QObject, const QObject>;
433
434class MultiplyWrappedQObjectMap : public QObject,
435 private QHash<QObjectBiPointer, QV4::WeakValue>
436{
437 Q_OBJECT
438public:
439 typedef QHash<QObjectBiPointer, QV4::WeakValue>::ConstIterator ConstIterator;
440 typedef QHash<QObjectBiPointer, QV4::WeakValue>::Iterator Iterator;
441
442 using value_type = QHash<QObjectBiPointer, QV4::WeakValue>::value_type;
443
444 ConstIterator begin() const { return QHash<QObjectBiPointer, QV4::WeakValue>::constBegin(); }
445 Iterator begin() { return QHash<QObjectBiPointer, QV4::WeakValue>::begin(); }
446 ConstIterator end() const { return QHash<QObjectBiPointer, QV4::WeakValue>::constEnd(); }
447 Iterator end() { return QHash<QObjectBiPointer, QV4::WeakValue>::end(); }
448
449 template<typename Pointer>
450 void insert(Pointer key, Heap::Object *value)
451 {
452 QHash<QObjectBiPointer, WeakValue>::operator[](key).set(value->internalClass->engine, value);
453 connect(key, SIGNAL(destroyed(QObject*)), this, SLOT(removeDestroyedObject(QObject*)));
454 }
455
456 template<typename Pointer>
457 ReturnedValue value(Pointer key) const
458 {
459 ConstIterator it = find(key);
460 return it == end()
461 ? QV4::WeakValue().value()
462 : it->value();
463 }
464
465 Iterator erase(Iterator it);
466
467 template<typename Pointer>
468 void remove(Pointer key)
469 {
470 Iterator it = find(key);
471 if (it == end())
472 return;
473 erase(it);
474 }
475
476 template<typename Pointer>
477 void mark(Pointer key, MarkStack *markStack)
478 {
479 Iterator it = find(key);
480 if (it == end())
481 return;
482 it->markOnce(markStack);
483 }
484
485private Q_SLOTS:
486 void removeDestroyedObject(QObject*);
487};
488
489}
490
491QT_END_NAMESPACE
492
493#endif // QV4QOBJECTWRAPPER_P_H
494
495
496

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtdeclarative/src/qml/jsruntime/qv4qobjectwrapper_p.h