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
qv4qobjectwrapper_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 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
31
32class QObject;
33class QQmlData;
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(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
69
71 alignas(alignof(QQmlPropertyData)) std::byte _singleMethod[sizeof(QQmlPropertyData)];
72 int methodCount;
73 int index;
74
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
102 void init(QObject *object, int signalIndex);
103 void destroy() {
104 qObj.destroy();
105 Object::destroy();
106 }
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{
122
123 enum Flag {
124 NoFlag = 0x0,
125 CheckRevision = 0x1,
126 AttachMethods = 0x2,
127 AllowOverride = 0x4,
128 IncludeImports = 0x8,
129 };
130
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
145 const QQmlRefPointer<QQmlContextData> &qmlContext, String *name,
146 Flags flags, bool *hasProperty = nullptr) const;
147
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")
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(
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,
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(
195
196protected:
197 static bool virtualIsEqualTo(Managed *that, Managed *o);
199
200 static const QQmlPropertyData *findProperty(
203
204 const QQmlPropertyData *findProperty(
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
224
226{
227 if (Q_UNLIKELY(QQmlData::wasDeleted(object)))
228 return QV4::Encode::null();
229
230 auto ddata = QQmlData::get(object);
231 if (Q_LIKELY(ddata && ddata->jsEngineId == engine->m_engineId && !ddata->jsWrapper.isUndefined())) {
232 // We own the JS object
233 return ddata->jsWrapper.value();
234 }
235
236 return wrap_slowPath(engine, object);
237}
238
239// Unfortunately we still need a non-const QObject* here because QQmlData needs to register itself in QObjectPrivate.
240inline ReturnedValue QObjectWrapper::wrapConst(ExecutionEngine *engine, QObject *object)
241{
242 if (Q_UNLIKELY(QQmlData::wasDeleted(object)))
243 return QV4::Encode::null();
244
245 return wrapConst_slowPath(engine, object);
246}
247
248inline bool canConvert(const QQmlPropertyCache *fromMo, const QQmlPropertyCache *toMo)
249{
250 while (fromMo) {
251 if (fromMo == toMo)
252 return true;
253 fromMo = fromMo->parent().data();
254 }
255 return false;
256}
257
258template <typename ReversalFunctor>
259inline ReturnedValue QObjectWrapper::lookupPropertyGetterImpl(
260 Lookup *lookup, ExecutionEngine *engine, const Value &object,
261 QObjectWrapper::Flags flags, ReversalFunctor revertLookup)
262{
263 // we can safely cast to a QV4::Object here. If object is something else,
264 // the internal class won't match
265 Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
266 if (!o || o->internalClass != lookup->qobjectLookup.ic)
267 return revertLookup();
268
269 Heap::QObjectWrapper *This = static_cast<Heap::QObjectWrapper *>(o);
270 QObject *qobj = This->object();
271 if (QQmlData::wasDeleted(qobj))
272 return QV4::Encode::undefined();
273
274 QQmlData *ddata = QQmlData::get(qobj, /*create*/false);
275 if (!ddata)
276 return revertLookup();
277
278 const QQmlPropertyData *property = lookup->qobjectLookup.propertyData;
279 if (ddata->propertyCache.data() != lookup->qobjectLookup.propertyCache) {
280 // If the property is overridden and the lookup allows overrides to be considered,
281 // we have to revert here and redo the lookup from scratch.
282 if (property->isOverridden()
283 && ((flags & AllowOverride)
284 || property->isFunction()
285 || property->isSignalHandler())) {
286 return revertLookup();
287 }
288
289 if (!canConvert(ddata->propertyCache.data(), lookup->qobjectLookup.propertyCache))
290 return revertLookup();
291 }
292
293 return getProperty(engine, This, qobj, property, flags);
294}
295
296template <typename ReversalFunctor>
297inline ReturnedValue QObjectWrapper::lookupMethodGetterImpl(
298 Lookup *lookup, ExecutionEngine *engine, const Value &object,
299 QObjectWrapper::Flags flags, ReversalFunctor revertLookup)
300{
301 // we can safely cast to a QV4::Object here. If object is something else,
302 // the internal class won't match
303 Heap::Object *o = static_cast<Heap::Object *>(object.heapObject());
304 if (!o || o->internalClass != lookup->qobjectMethodLookup.ic)
305 return revertLookup();
306
307 Heap::QObjectWrapper *This = static_cast<Heap::QObjectWrapper *>(o);
308 QObject *qobj = This->object();
309 if (QQmlData::wasDeleted(qobj))
310 return QV4::Encode::undefined();
311
312 QQmlData *ddata = QQmlData::get(qobj, /*create*/false);
313 if (!ddata)
314 return revertLookup();
315
316 const QQmlPropertyData *property = lookup->qobjectMethodLookup.propertyData;
317 if (ddata->propertyCache.data() != lookup->qobjectMethodLookup.propertyCache) {
318 if (property && property->isOverridden())
319 return revertLookup();
320
321 if (!canConvert(ddata->propertyCache.data(), lookup->qobjectMethodLookup.propertyCache))
322 return revertLookup();
323 }
324
325 if (Heap::QObjectMethod *method = lookup->qobjectMethodLookup.method) {
326 if (method->isDetached())
327 return method->asReturnedValue();
328 }
329
330 if (!property) // was toString() or destroy()
331 return revertLookup();
332
333 QV4::Scope scope(engine);
334 QV4::ScopedValue v(scope, getProperty(engine, This, qobj, property, flags));
335 if (!v->as<QObjectMethod>())
336 return revertLookup();
337
338 lookup->qobjectMethodLookup.method.set(engine, static_cast<Heap::QObjectMethod *>(v->heapObject()));
339 return v->asReturnedValue();
340}
341
343
344struct Q_QML_EXPORT QObjectMethod : public QV4::FunctionObject
345{
348
349 enum { DestroyMethod = -1, ToStringMethod = -2 };
350
351 static ReturnedValue create(ExecutionEngine *engine, Heap::Object *wrapper, int index);
352 static ReturnedValue create(
353 ExecutionEngine *engine, Heap::QQmlValueTypeWrapper *valueType, int index);
354 static ReturnedValue create(
355 ExecutionEngine *engine, Heap::QObjectMethod *cloneFrom,
356 Heap::Object *wrapper, Heap::Object *object);
357
358 int methodIndex() const { return d()->index; }
359 QObject *object() const { return d()->object(); }
360
361 QV4::ReturnedValue method_toString(QV4::ExecutionEngine *engine, QObject *o) const;
362 QV4::ReturnedValue method_destroy(
363 QV4::ExecutionEngine *ctx, QObject *o, const Value *args, int argc) const;
366 void **argv, const QMetaType *types, int argc) const;
367
368 static ReturnedValue virtualCall(
369 const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
370 static void virtualCallWithMetaTypes(
371 const FunctionObject *m, QObject *thisObject,
372 void **argv, const QMetaType *types, int argc);
373
374 ReturnedValue callInternal(
375 const Value *thisObject, const Value *argv, int argc) const;
376 void callInternalWithMetaTypes(
377 QObject *thisObject, void **argv, const QMetaType *types, int argc) const;
378
379 static QPair<QObject *, int> extractQtMethod(const QV4::FunctionObject *function);
380
381private:
382 friend struct QMetaObjectWrapper;
383
384 static const QQmlPropertyData *resolveOverloaded(
385 const QQmlObjectOrGadget &object, const QQmlPropertyData *methods, int methodCount,
386 ExecutionEngine *engine, CallData *callArgs);
387
388 static const QQmlPropertyData *resolveOverloaded(
389 const QQmlPropertyData *methods, int methodCount,
390 void **argv, int argc, const QMetaType *types);
391
392 static ReturnedValue callPrecise(
393 const QQmlObjectOrGadget &object, const QQmlPropertyData &data,
394 ExecutionEngine *engine, CallData *callArgs,
396};
397
398struct Q_QML_EXPORT QmlSignalHandler : public QV4::Object
399{
401 V4_PROTOTYPE(signalHandlerPrototype)
403
404 int signalIndex() const { return d()->signalIndex; }
405 QObject *object() const { return d()->object(); }
406
407 ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const;
408
409 static void initProto(ExecutionEngine *v4);
410};
411
412using QObjectBiPointer = QBiPointer<QObject, const QObject>;
413
415 private QHash<QObjectBiPointer, QV4::WeakValue>
416{
418public:
421
423
428
429 template<typename Pointer>
430 void insert(Pointer key, Heap::Object *value)
431 {
433 connect(key, SIGNAL(destroyed(QObject*)), this, SLOT(removeDestroyedObject(QObject*)));
434 }
435
436 template<typename Pointer>
437 ReturnedValue value(Pointer key) const
438 {
439 ConstIterator it = find(key);
440 return it == end()
442 : it->value();
443 }
444
445 Iterator erase(Iterator it);
446
447 template<typename Pointer>
448 void remove(Pointer key)
449 {
450 Iterator it = find(key);
451 if (it == end())
452 return;
453 erase(it);
454 }
455
456 template<typename Pointer>
457 void mark(Pointer key, MarkStack *markStack)
458 {
459 Iterator it = find(key);
460 if (it == end())
461 return;
462 it->markOnce(markStack);
463 }
464
465private Q_SLOTS:
466 void removeDestroyedObject(QObject*);
467};
468
469}
470
472
473#endif // QV4QOBJECTWRAPPER_P_H
474
475
static JNINativeMethod methods[]
\inmodule QtCore
Definition qhash.h:1145
\inmodule QtCore
Definition qhash.h:1103
\inmodule QtCore
Definition qhash.h:820
T value_type
Definition qhash.h:832
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1212
T & operator[](const Key &key)
Returns the value associated with the key as a modifiable reference.
Definition qhash.h:1064
const_iterator constEnd() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the ...
Definition qhash.h:1219
const_iterator constBegin() const noexcept
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
Definition qhash.h:1215
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
Definition qhash.h:1216
\inmodule QtCore
Definition qmetatype.h:341
\inmodule QtCore
Definition qobject.h:103
static bool wasDeleted(const QObject *)
Definition qqmldata_p.h:312
static QQmlData * get(QObjectPrivate *priv, bool create)
Definition qqmldata_p.h:199
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
void insert(Pointer key, Heap::Object *value)
QHash< QObjectBiPointer, QV4::WeakValue >::ConstIterator ConstIterator
void mark(Pointer key, MarkStack *markStack)
QHash< QObjectBiPointer, QV4::WeakValue >::Iterator Iterator
ReturnedValue value(Pointer key) const
QHash< QObjectBiPointer, QV4::WeakValue >::value_type value_type
ReturnedValue value() const
EGLContext ctx
QSet< QString >::iterator it
Combined button and popup list for selecting options.
QBiPointer< QObject, const QObject > QObjectBiPointer
quint64 ReturnedValue
@ Invalid
Definition qv4mm_p.h:47
bool canConvert(const QQmlPropertyCache *fromMo, const QQmlPropertyCache *toMo)
qsizetype erase(QByteArray &ba, const T &t)
Definition qbytearray.h:782
#define Q_NODISCARD_X(message)
#define Q_UNLIKELY(x)
#define Q_NEVER_INLINE
#define Q_LIKELY(x)
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char * method
static QDBusError::ErrorType get(const char *name)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define Q_DECLARE_OPERATORS_FOR_FLAGS(Flags)
Definition qflags.h:194
Flags
#define SLOT(a)
Definition qobjectdefs.h:52
#define SIGNAL(a)
Definition qobjectdefs.h:53
GLsizei const GLfloat * v
[13]
const GLfloat * m
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint index
[2]
GLuint GLuint end
GLsizei GLenum GLenum * types
GLuint object
[3]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum target
GLbitfield flags
GLuint name
GLfloat GLfloat p
[1]
QQmlContext * qmlContext(const QObject *obj)
Definition qqml.cpp:75
static QT_BEGIN_NAMESPACE QAsn1Element wrap(quint8 type, const QAsn1Element &child)
static QT_BEGIN_NAMESPACE void init(QTextBoundaryFinder::BoundaryType type, QStringView str, QCharAttributes *attributes)
#define Q_OBJECT
#define Q_SLOTS
#define V4_NEEDS_DESTROY
#define DECLARE_EXPORTED_HEAP_OBJECT(name, base)
#define DECLARE_MARKOBJECTS(class)
#define V4_PROTOTYPE(p)
#define V4_OBJECT2(DataClass, superClass)
const char property[13]
Definition qwizard.cpp:101
connect(quitButton, &QPushButton::clicked, &app, &QCoreApplication::quit, Qt::QueuedConnection)
obj metaObject() -> className()
view create()
args<< 1<< 2;QJSValue threeAgain=fun.call(args);QString fileName="helloworld.qs";QFile scriptFile(fileName);if(!scriptFile.open(QIODevice::ReadOnly)) QTextStream stream(&scriptFile);QString contents=stream.readAll();scriptFile.close();myEngine.evaluate(contents, fileName);myEngine.globalObject().setProperty("myNumber", 123);...QJSValue myNumberPlusOne=myEngine.evaluate("myNumber + 1");QJSValue result=myEngine.evaluate(...);if(result.isError()) qDebug()<< "Uncaught exception at line"<< result.property("lineNumber").toInt()<< ":"<< result.toString();QPushButton *button=new QPushButton;QJSValue scriptButton=myEngine.newQObject(button);myEngine.globalObject().setProperty("button", scriptButton);myEngine.evaluate("button.checkable = true");qDebug()<< scriptButton.property("checkable").toBool();scriptButton.property("show").call();QJSEngine engine;QObject *myQObject=new QObject();myQObject- setProperty)("dynamicProperty", 3)
QJSValueList args
QJSEngine engine
[0]
\inmodule QtCore
static constexpr ReturnedValue undefined()
static constexpr ReturnedValue null()
void init(QObject *object)
void init(QObject *object, int signalIndex)
struct QV4::Lookup::@584::@598 qobjectLookup
struct QV4::Lookup::@584::@599 qobjectMethodLookup
QObject * object() const
void method_destroy(QV4::ExecutionEngine *engine, QObject *o, void **argv, const QMetaType *types, int argc) const
ReturnedValue getQmlProperty(const QQmlRefPointer< QQmlContextData > &qmlContext, String *name, Flags flags, bool *hasProperty=nullptr) const
Q_DECLARE_FLAGS(Flags, Flag)
static ReturnedValue getQmlProperty(ExecutionEngine *engine, const QQmlRefPointer< QQmlContextData > &qmlContext, Heap::Object *wrapper, QObject *object, String *name, Flags flags, bool *hasProperty=nullptr, const QQmlPropertyData **property=nullptr)
const QMetaObject * metaObject() const
QObject * object() const
T * data() const
Definition qv4heap_p.h:193
V4_NEEDS_DESTROY int signalIndex() const
void wrapper()