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 | |
23 | QT_BEGIN_NAMESPACE |
24 | |
25 | namespace QV4 { |
26 | |
27 | namespace 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. |
34 | struct 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 | |
238 | Q_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). |
241 | Q_STATIC_ASSERT(offsetof(Lookup, getter) == 0); |
242 | |
243 | inline 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 | |
253 | inline 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 | |
262 | inline 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 | |
270 | inline 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 | |
283 | inline 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 | |
293 | QT_END_NAMESPACE |
294 | |
295 | #endif |
296 | |