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#ifndef QV4LOOKUP_H
4#define QV4LOOKUP_H
5
6//
7// W A R N I N G
8// -------------
9//
10// This file is not part of the Qt API. It exists purely as an
11// implementation detail. This header file may change from version to
12// version without notice, or even be removed.
13//
14// We mean it.
15//
16
17#include "qv4engine_p.h"
18#include "qv4object_p.h"
19#include "qv4internalclass_p.h"
20#include "qv4qmlcontext_p.h"
21#include <private/qqmltypewrapper_p.h>
22
23QT_BEGIN_NAMESPACE
24
25namespace QV4 {
26
27namespace Heap {
28 struct QObjectMethod;
29}
30
31// Note: We cannot hide the copy ctor and assignment operator of this class because it needs to
32// be trivially copyable. But you should never ever copy it. There are refcounted members
33// in there.
34struct Q_QML_PRIVATE_EXPORT Lookup {
35 union {
36 ReturnedValue (*getter)(Lookup *l, ExecutionEngine *engine, const Value &object);
37 ReturnedValue (*globalGetter)(Lookup *l, ExecutionEngine *engine);
38 ReturnedValue (*qmlContextPropertyGetter)(Lookup *l, ExecutionEngine *engine, Value *thisObject);
39 bool (*setter)(Lookup *l, ExecutionEngine *engine, Value &object, const Value &v);
40 };
41 // NOTE: gc assumes the first two entries in the struct are pointers to heap objects or null
42 // or that the least significant bit is 1 (see the Lookup::markObjects function)
43 union {
44 struct {
45 Heap::Base *h1;
46 Heap::Base *h2;
47 quintptr unused;
48 quintptr unused2;
49 } markDef;
50 struct {
51 Heap::InternalClass *ic;
52 quintptr unused;
53 uint index;
54 uint offset;
55 } objectLookup;
56 struct {
57 quintptr protoId;
58 quintptr _unused;
59 const Value *data;
60 } protoLookup;
61 struct {
62 Heap::InternalClass *ic;
63 Heap::InternalClass *ic2;
64 uint offset;
65 uint offset2;
66 } objectLookupTwoClasses;
67 struct {
68 quintptr protoId;
69 quintptr protoId2;
70 const Value *data;
71 const Value *data2;
72 } protoLookupTwoClasses;
73 struct {
74 // Make sure the next two values are in sync with protoLookup
75 quintptr protoId;
76 Heap::Object *proto;
77 const Value *data;
78 quintptr type;
79 } primitiveLookup;
80 struct {
81 Heap::InternalClass *newClass;
82 quintptr protoId;
83 uint offset;
84 uint unused;
85 } insertionLookup;
86 struct {
87 quintptr _unused;
88 quintptr _unused2;
89 uint index;
90 uint unused;
91 } indexedLookup;
92 struct {
93 Heap::InternalClass *ic;
94 Heap::InternalClass *qmlTypeIc; // only used when lookup goes through QQmlTypeWrapper
95 const QQmlPropertyCache *propertyCache;
96 const QQmlPropertyData *propertyData;
97 } qobjectLookup;
98 struct {
99 Heap::InternalClass *ic;
100 Heap::QObjectMethod *method;
101 const QQmlPropertyCache *propertyCache;
102 const QQmlPropertyData *propertyData;
103 } qobjectMethodLookup;
104 struct {
105 quintptr isConstant; // This is a bool, encoded as 0 or 1. Both values are ignored by gc
106 quintptr metaObject; // a (const QMetaObject* & 1) or nullptr
107 int coreIndex;
108 int notifyIndex;
109 } qobjectFallbackLookup;
110 struct {
111 Heap::InternalClass *ic;
112 quintptr metaObject; // a (const QMetaObject* & 1) or nullptr
113 const QtPrivate::QMetaTypeInterface *metaType; // cannot use QMetaType; class must be trivial
114 quint16 coreIndex;
115 bool isFunction;
116 bool isEnum;
117 } qgadgetLookup;
118 struct {
119 quintptr unused1;
120 quintptr unused2;
121 int scriptIndex;
122 } qmlContextScriptLookup;
123 struct {
124 Heap::Base *singletonObject;
125 quintptr unused2;
126 QV4::ReturnedValue singletonValue;
127 } qmlContextSingletonLookup;
128 struct {
129 quintptr unused1;
130 quintptr unused2;
131 int objectId;
132 } qmlContextIdObjectLookup;
133 struct {
134 // Same as protoLookup, as used for global lookups
135 quintptr reserved1;
136 quintptr reserved2;
137 quintptr reserved3;
138 ReturnedValue (*getterTrampoline)(Lookup *l, ExecutionEngine *engine);
139 } qmlContextGlobalLookup;
140 struct {
141 Heap::Base *qmlTypeWrapper;
142 quintptr unused2;
143 } qmlTypeLookup;
144 struct {
145 Heap::InternalClass *ic;
146 quintptr unused;
147 ReturnedValue encodedEnumValue;
148 const QtPrivate::QMetaTypeInterface *metaType;
149 } qmlEnumValueLookup;
150 struct {
151 Heap::InternalClass *ic;
152 Heap::Object *qmlScopedEnumWrapper;
153 } qmlScopedEnumWrapperLookup;
154 };
155
156 uint nameIndex: 28; // Same number of bits we store in the compilation unit for name indices
157 uint forCall: 1; // Whether we are looking up a value in order to call it right away
158 uint reserved: 3;
159
160 ReturnedValue resolveGetter(ExecutionEngine *engine, const Object *object);
161 ReturnedValue resolvePrimitiveGetter(ExecutionEngine *engine, const Value &object);
162 ReturnedValue resolveGlobalGetter(ExecutionEngine *engine);
163 void resolveProtoGetter(PropertyKey name, const Heap::Object *proto);
164
165 static ReturnedValue getterGeneric(Lookup *l, ExecutionEngine *engine, const Value &object);
166 static ReturnedValue getterTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
167 static ReturnedValue getterFallback(Lookup *l, ExecutionEngine *engine, const Value &object);
168 static ReturnedValue getterFallbackAsVariant(Lookup *l, ExecutionEngine *engine, const Value &object);
169
170 static ReturnedValue getter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
171 static ReturnedValue getter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object);
172 static ReturnedValue getterProto(Lookup *l, ExecutionEngine *engine, const Value &object);
173 static ReturnedValue getter0Inlinegetter0Inline(Lookup *l, ExecutionEngine *engine, const Value &object);
174 static ReturnedValue getter0Inlinegetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
175 static ReturnedValue getter0MemberDatagetter0MemberData(Lookup *l, ExecutionEngine *engine, const Value &object);
176 static ReturnedValue getterProtoTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
177 static ReturnedValue getterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object);
178 static ReturnedValue getterProtoAccessor(Lookup *l, ExecutionEngine *engine, const Value &object);
179 static ReturnedValue getterProtoAccessorTwoClasses(Lookup *l, ExecutionEngine *engine, const Value &object);
180 static ReturnedValue getterIndexed(Lookup *l, ExecutionEngine *engine, const Value &object);
181 static ReturnedValue getterQObject(Lookup *l, ExecutionEngine *engine, const Value &object);
182 static ReturnedValue getterQObjectAsVariant(Lookup *l, ExecutionEngine *engine, const Value &object);
183 static ReturnedValue getterQObjectMethod(Lookup *l, ExecutionEngine *engine, const Value &object);
184
185 static ReturnedValue primitiveGetterProto(Lookup *l, ExecutionEngine *engine, const Value &object);
186 static ReturnedValue primitiveGetterAccessor(Lookup *l, ExecutionEngine *engine, const Value &object);
187 static ReturnedValue stringLengthGetter(Lookup *l, ExecutionEngine *engine, const Value &object);
188
189 static ReturnedValue globalGetterGeneric(Lookup *l, ExecutionEngine *engine);
190 static ReturnedValue globalGetterProto(Lookup *l, ExecutionEngine *engine);
191 static ReturnedValue globalGetterProtoAccessor(Lookup *l, ExecutionEngine *engine);
192
193 bool resolveSetter(ExecutionEngine *engine, Object *object, const Value &value);
194 static bool setterGeneric(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
195 Q_NEVER_INLINE static bool setterTwoClasses(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
196 static bool setterFallback(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
197 static bool setterFallbackAsVariant(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
198 static bool setter0MemberData(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
199 static bool setter0Inline(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
200 static bool setter0setter0(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
201 static bool setterInsert(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
202 static bool setterQObject(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
203 static bool setterQObjectAsVariant(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
204 static bool arrayLengthSetter(Lookup *l, ExecutionEngine *engine, Value &object, const Value &value);
205
206 void markObjects(MarkStack *stack) {
207 if (markDef.h1 && !(reinterpret_cast<quintptr>(markDef.h1) & 1))
208 markDef.h1->mark(markStack: stack);
209 if (markDef.h2 && !(reinterpret_cast<quintptr>(markDef.h2) & 1))
210 markDef.h2->mark(markStack: stack);
211 }
212
213 void clear() {
214 memset(s: &markDef, c: 0, n: sizeof(markDef));
215 }
216
217 void releasePropertyCache()
218 {
219 if (getter == getterQObject
220 || getter == QQmlTypeWrapper::lookupSingletonProperty
221 || setter == setterQObject
222 || qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectProperty
223 || qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectProperty
224 || getter == getterQObjectAsVariant
225 || setter == setterQObjectAsVariant) {
226 if (const QQmlPropertyCache *pc = qobjectLookup.propertyCache)
227 pc->release();
228 } else if (getter == getterQObjectMethod
229 || getter == QQmlTypeWrapper::lookupSingletonMethod
230 || qmlContextPropertyGetter == QQmlContextWrapper::lookupScopeObjectMethod
231 || qmlContextPropertyGetter == QQmlContextWrapper::lookupContextObjectMethod) {
232 if (const QQmlPropertyCache *pc = qobjectMethodLookup.propertyCache)
233 pc->release();
234 }
235 }
236};
237
238Q_STATIC_ASSERT(std::is_standard_layout<Lookup>::value);
239// Ensure that these offsets are always at this point to keep generated code compatible
240// across 32-bit and 64-bit (matters when cross-compiling).
241Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0);
242
243inline void setupQObjectLookup(
244 Lookup *lookup, const QQmlData *ddata, const QQmlPropertyData *propertyData)
245{
246 lookup->releasePropertyCache();
247 Q_ASSERT(!ddata->propertyCache.isNull());
248 lookup->qobjectLookup.propertyCache = ddata->propertyCache.data();
249 lookup->qobjectLookup.propertyCache->addref();
250 lookup->qobjectLookup.propertyData = propertyData;
251}
252
253inline void setupQObjectLookup(
254 Lookup *lookup, const QQmlData *ddata, const QQmlPropertyData *propertyData,
255 const Object *self)
256{
257 setupQObjectLookup(lookup, ddata, propertyData);
258 lookup->qobjectLookup.ic = self->internalClass();
259}
260
261
262inline void setupQObjectLookup(
263 Lookup *lookup, const QQmlData *ddata, const QQmlPropertyData *propertyData,
264 const Object *self, const Object *qmlType)
265{
266 setupQObjectLookup(lookup, ddata, propertyData, self);
267 lookup->qobjectLookup.qmlTypeIc = qmlType->internalClass();
268}
269
270inline void setupQObjectMethodLookup(
271 Lookup *lookup, const QQmlData *ddata, const QQmlPropertyData *propertyData,
272 const Object *self, Heap::QObjectMethod *method)
273{
274 lookup->releasePropertyCache();
275 Q_ASSERT(!ddata->propertyCache.isNull());
276 lookup->qobjectMethodLookup.method = method;
277 lookup->qobjectMethodLookup.ic = self->internalClass();
278 lookup->qobjectMethodLookup.propertyCache = ddata->propertyCache.data();
279 lookup->qobjectMethodLookup.propertyCache->addref();
280 lookup->qobjectMethodLookup.propertyData = propertyData;
281}
282
283inline bool qualifiesForMethodLookup(const QQmlPropertyData *propertyData)
284{
285 return propertyData->isFunction()
286 && !propertyData->isSignalHandler() // TODO: Optimize SignalHandler, too
287 && !propertyData->isVMEFunction() // Handled by QObjectLookup
288 && !propertyData->isVarProperty();
289}
290
291}
292
293QT_END_NAMESPACE
294
295#endif
296

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