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 QV4FUNCTIONOBJECT_H |
4 | #define QV4FUNCTIONOBJECT_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 "qv4object_p.h" |
18 | #include "qv4function_p.h" |
19 | #include "qv4context_p.h" |
20 | #include <private/qv4mm_p.h> |
21 | |
22 | QT_BEGIN_NAMESPACE |
23 | |
24 | struct QQmlSourceLocation; |
25 | |
26 | namespace QV4 { |
27 | |
28 | struct IndexedBuiltinFunction; |
29 | struct JSCallData; |
30 | |
31 | // A FunctionObject is generally something that can be called, either with a JavaScript |
32 | // signature (QV4::Value etc) or with a C++ signature (QMetaType etc). For this, it has |
33 | // the Call and CallWithMetaTypes VTable entries. |
34 | // Some FunctionObjects need to select the actual implementation of the call at run time. |
35 | // This comese in two flavors: |
36 | // 1. The implementation is a JavaScript function. For these we have |
37 | // JavaScriptFunctionObject that holds a QV4::Function member to defer the call to. |
38 | // 2. The implementation is a C++ function. For these we have DynamicFunctionObject that |
39 | // holds another Call member in the heap object to defer the call to. |
40 | // In addition, a FunctionObject may want to be called as constructor. For this we have |
41 | // another VTable entry and a flag in the heap object. |
42 | |
43 | namespace Heap { |
44 | |
45 | #define FunctionObjectMembers(class, Member) |
46 | DECLARE_HEAP_OBJECT(FunctionObject, Object) { |
47 | enum { |
48 | Index_ProtoConstructor = 0, |
49 | Index_Prototype = 0, |
50 | Index_HasInstance = 1, |
51 | }; |
52 | |
53 | Q_QML_EXPORT void init(QV4::ExecutionEngine *engine, QV4::String *name = nullptr); |
54 | Q_QML_EXPORT void init(QV4::ExecutionEngine *engine, const QString &name); |
55 | Q_QML_EXPORT void init(); |
56 | }; |
57 | |
58 | #define JavaScriptFunctionObjectMembers(class, Member) \ |
59 | Member(class, Pointer, ExecutionContext *, scope) \ |
60 | Member(class, NoMark, Function *, function) |
61 | |
62 | DECLARE_HEAP_OBJECT(JavaScriptFunctionObject, FunctionObject) { |
63 | DECLARE_MARKOBJECTS(JavaScriptFunctionObject) |
64 | |
65 | void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr); |
66 | Q_QML_EXPORT void destroy(); |
67 | |
68 | void setFunction(Function *f); |
69 | |
70 | unsigned int formalParameterCount() { return function ? function->nFormals : 0; } |
71 | unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } |
72 | }; |
73 | |
74 | #define DynamicFunctionObjectMembers(class, Member) \ |
75 | Member(class, NoMark, VTable::Call, jsCall) |
76 | |
77 | DECLARE_HEAP_OBJECT(DynamicFunctionObject, FunctionObject) { |
78 | // NB: We might add a CallWithMetaTypes member to this struct and implement our |
79 | // builtins with metatypes, to be called from C++ code. This would make them |
80 | // available to qmlcachegen's C++ code generation. |
81 | void init(ExecutionEngine *engine, QV4::String *name, VTable::Call call); |
82 | }; |
83 | |
84 | struct FunctionCtor : FunctionObject { |
85 | void init(QV4::ExecutionEngine *engine); |
86 | }; |
87 | |
88 | struct FunctionPrototype : FunctionObject { |
89 | void init(); |
90 | }; |
91 | |
92 | // A function object with an additional index into a list. |
93 | // Used by Models to refer to property roles. |
94 | struct IndexedBuiltinFunction : DynamicFunctionObject { |
95 | inline void init(QV4::ExecutionEngine *engine, qsizetype index, VTable::Call call); |
96 | qsizetype index; |
97 | }; |
98 | |
99 | struct ArrowFunction : JavaScriptFunctionObject { |
100 | enum { |
101 | Index_Name = Index_HasInstance + 1, |
102 | Index_Length |
103 | }; |
104 | void init(QV4::ExecutionContext *scope, Function *function, QV4::String *name = nullptr); |
105 | }; |
106 | |
107 | #define ScriptFunctionMembers(class, Member) \ |
108 | Member(class, Pointer, InternalClass *, cachedClassForConstructor) |
109 | |
110 | DECLARE_HEAP_OBJECT(ScriptFunction, ArrowFunction) { |
111 | DECLARE_MARKOBJECTS(ScriptFunction) |
112 | void init(QV4::ExecutionContext *scope, Function *function); |
113 | }; |
114 | |
115 | #define MemberFunctionMembers(class, Member) \ |
116 | Member(class, Pointer, Object *, homeObject) |
117 | |
118 | DECLARE_HEAP_OBJECT(MemberFunction, ArrowFunction) { |
119 | DECLARE_MARKOBJECTS(MemberFunction) |
120 | |
121 | void init(QV4::ExecutionContext *scope, Function *function, QV4::String *name = nullptr) { |
122 | ArrowFunction::init(scope, function, name); |
123 | } |
124 | }; |
125 | |
126 | #define ConstructorFunctionMembers(class, Member) \ |
127 | Member(class, Pointer, Object *, homeObject) |
128 | |
129 | DECLARE_HEAP_OBJECT(ConstructorFunction, ScriptFunction) { |
130 | DECLARE_MARKOBJECTS(ConstructorFunction) |
131 | bool isDerivedConstructor; |
132 | }; |
133 | |
134 | #define DefaultClassConstructorFunctionMembers(class, Member) \ |
135 | Member(class, Pointer, ExecutionContext *, scope) |
136 | |
137 | DECLARE_HEAP_OBJECT(DefaultClassConstructorFunction, FunctionObject) { |
138 | DECLARE_MARKOBJECTS(DefaultClassConstructorFunction) |
139 | |
140 | bool isDerivedConstructor; |
141 | |
142 | void init(QV4::ExecutionContext *scope); |
143 | }; |
144 | |
145 | #define BoundFunctionMembers(class, Member) \ |
146 | Member(class, Pointer, FunctionObject *, target) \ |
147 | Member(class, HeapValue, HeapValue, boundThis) \ |
148 | Member(class, Pointer, MemberData *, boundArgs) |
149 | |
150 | DECLARE_HEAP_OBJECT(BoundFunction, JavaScriptFunctionObject) { |
151 | DECLARE_MARKOBJECTS(BoundFunction) |
152 | |
153 | void init(QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs); |
154 | }; |
155 | |
156 | struct BoundConstructor : BoundFunction {}; |
157 | |
158 | } |
159 | |
160 | struct Q_QML_EXPORT FunctionObject: Object { |
161 | V4_OBJECT2(FunctionObject, Object) |
162 | Q_MANAGED_TYPE(FunctionObject) |
163 | V4_INTERNALCLASS(FunctionObject) |
164 | V4_PROTOTYPE(functionPrototype) |
165 | enum { NInlineProperties = 1 }; |
166 | |
167 | bool canBeTailCalled() const { return vtable()->isTailCallable; } |
168 | |
169 | ReturnedValue name() const; |
170 | |
171 | void setName(String *name) { |
172 | defineReadonlyConfigurableProperty(name: engine()->id_name(), value: *name); |
173 | } |
174 | void createDefaultPrototypeProperty(uint protoConstructorSlot); |
175 | |
176 | ReturnedValue callAsConstructor( |
177 | const Value *argv, int argc, const Value *newTarget = nullptr) const |
178 | { |
179 | if (const auto callAsConstructor = vtable()->callAsConstructor) |
180 | return callAsConstructor(this, argv, argc, newTarget ? newTarget : this); |
181 | return failCallAsConstructor(); |
182 | } |
183 | |
184 | ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const |
185 | { |
186 | if (const auto call = vtable()->call) |
187 | return call(this, thisObject, argv, argc); |
188 | return failCall(); |
189 | } |
190 | |
191 | void call(QObject *thisObject, void **argv, const QMetaType *types, int argc) const |
192 | { |
193 | if (const auto callWithMetaTypes = vtable()->callWithMetaTypes) |
194 | callWithMetaTypes(this, thisObject, argv, types, argc); |
195 | else |
196 | failCall(); |
197 | } |
198 | |
199 | inline ReturnedValue callAsConstructor(const JSCallData &data) const; |
200 | inline ReturnedValue call(const JSCallData &data) const; |
201 | |
202 | ReturnedValue failCall() const; |
203 | ReturnedValue failCallAsConstructor() const; |
204 | static void virtualConvertAndCall( |
205 | const FunctionObject *f, QObject *thisObject, |
206 | void **argv, const QMetaType *types, int argc); |
207 | |
208 | static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function); |
209 | static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor); |
210 | static Heap::FunctionObject *createMemberFunction(ExecutionContext *scope, Function *function, Object *homeObject, String *name); |
211 | static Heap::FunctionObject *createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount); |
212 | |
213 | bool isBinding() const; |
214 | bool isBoundFunction() const; |
215 | bool isConstructor() const { return vtable()->callAsConstructor; } |
216 | |
217 | ReturnedValue getHomeObject() const; |
218 | |
219 | ReturnedValue protoProperty() const { |
220 | return getValueByIndex(propertyIndex: Heap::FunctionObject::Index_Prototype); |
221 | } |
222 | bool hasHasInstanceProperty() const { |
223 | return !internalClass()->propertyData.at(i: Heap::FunctionObject::Index_HasInstance).isEmpty(); |
224 | } |
225 | }; |
226 | |
227 | template<> |
228 | inline const FunctionObject *Value::as() const { |
229 | if (!isManaged()) |
230 | return nullptr; |
231 | |
232 | const VTable *vtable = m()->internalClass->vtable; |
233 | return (vtable->call || vtable->callAsConstructor) |
234 | ? reinterpret_cast<const FunctionObject *>(this) |
235 | : nullptr; |
236 | } |
237 | |
238 | struct Q_QML_EXPORT JavaScriptFunctionObject: FunctionObject |
239 | { |
240 | V4_OBJECT2(JavaScriptFunctionObject, FunctionObject) |
241 | V4_NEEDS_DESTROY |
242 | |
243 | Heap::ExecutionContext *scope() const { return d()->scope; } |
244 | |
245 | Function *function() const { return d()->function; } |
246 | unsigned int formalParameterCount() const { return d()->formalParameterCount(); } |
247 | unsigned int varCount() const { return d()->varCount(); } |
248 | bool strictMode() const { return d()->function ? d()->function->isStrict() : false; } |
249 | QQmlSourceLocation sourceLocation() const; |
250 | }; |
251 | |
252 | struct Q_QML_EXPORT DynamicFunctionObject: FunctionObject |
253 | { |
254 | V4_OBJECT2(DynamicFunctionObject, FunctionObject) |
255 | |
256 | static ReturnedValue virtualCall( |
257 | const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); |
258 | }; |
259 | |
260 | struct FunctionCtor: FunctionObject |
261 | { |
262 | V4_OBJECT2(FunctionCtor, FunctionObject) |
263 | |
264 | static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *); |
265 | static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); |
266 | protected: |
267 | enum Type { |
268 | Type_Function, |
269 | Type_Generator |
270 | }; |
271 | static QQmlRefPointer<ExecutableCompilationUnit> parse(ExecutionEngine *engine, const Value *argv, int argc, Type t = Type_Function); |
272 | }; |
273 | |
274 | struct FunctionPrototype: FunctionObject |
275 | { |
276 | V4_OBJECT2(FunctionPrototype, FunctionObject) |
277 | |
278 | void init(ExecutionEngine *engine, Object *ctor); |
279 | |
280 | static ReturnedValue virtualCall( |
281 | const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); |
282 | |
283 | static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); |
284 | static ReturnedValue method_apply(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); |
285 | static ReturnedValue method_call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); |
286 | static ReturnedValue method_bind(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); |
287 | static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); |
288 | }; |
289 | |
290 | struct Q_QML_EXPORT IndexedBuiltinFunction : DynamicFunctionObject |
291 | { |
292 | V4_OBJECT2(IndexedBuiltinFunction, DynamicFunctionObject) |
293 | }; |
294 | |
295 | void Heap::IndexedBuiltinFunction::init( |
296 | QV4::ExecutionEngine *engine, qsizetype index, VTable::Call call) |
297 | { |
298 | Heap::FunctionObject::init(engine); |
299 | this->jsCall = call; |
300 | this->index = index; |
301 | } |
302 | |
303 | struct ArrowFunction : JavaScriptFunctionObject { |
304 | V4_OBJECT2(ArrowFunction, JavaScriptFunctionObject) |
305 | V4_INTERNALCLASS(ArrowFunction) |
306 | enum { |
307 | NInlineProperties = 3, |
308 | IsTailCallable = true, |
309 | }; |
310 | |
311 | static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject, |
312 | void **a, const QMetaType *types, int argc); |
313 | static ReturnedValue virtualCall(const QV4::FunctionObject *f, const QV4::Value *thisObject, |
314 | const QV4::Value *argv, int argc); |
315 | }; |
316 | |
317 | struct ScriptFunction : ArrowFunction { |
318 | V4_OBJECT2(ScriptFunction, ArrowFunction) |
319 | V4_INTERNALCLASS(ScriptFunction) |
320 | |
321 | static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *); |
322 | |
323 | Heap::InternalClass *classForConstructor() const; |
324 | }; |
325 | |
326 | struct MemberFunction : ArrowFunction { |
327 | V4_OBJECT2(MemberFunction, ArrowFunction) |
328 | V4_INTERNALCLASS(MemberFunction) |
329 | }; |
330 | |
331 | struct ConstructorFunction : ScriptFunction { |
332 | V4_OBJECT2(ConstructorFunction, ScriptFunction) |
333 | V4_INTERNALCLASS(ConstructorFunction) |
334 | static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *); |
335 | static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); |
336 | }; |
337 | |
338 | struct DefaultClassConstructorFunction : FunctionObject { |
339 | V4_OBJECT2(DefaultClassConstructorFunction, FunctionObject) |
340 | |
341 | Heap::ExecutionContext *scope() const { return d()->scope; } |
342 | static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *); |
343 | static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); |
344 | }; |
345 | |
346 | struct BoundFunction: JavaScriptFunctionObject { |
347 | V4_OBJECT2(BoundFunction, JavaScriptFunctionObject) |
348 | |
349 | Heap::FunctionObject *target() const { return d()->target; } |
350 | Value boundThis() const { return d()->boundThis; } |
351 | Heap::MemberData *boundArgs() const { return d()->boundArgs; } |
352 | |
353 | static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); |
354 | }; |
355 | |
356 | struct BoundConstructor: BoundFunction { |
357 | V4_OBJECT2(BoundConstructor, BoundFunction) |
358 | |
359 | static ReturnedValue virtualCallAsConstructor( |
360 | const FunctionObject *f, const Value *argv, int argc, const Value *); |
361 | }; |
362 | |
363 | inline bool FunctionObject::isBoundFunction() const |
364 | { |
365 | const VTable *vtable = d()->vtable(); |
366 | return vtable == BoundFunction::staticVTable() || vtable == BoundConstructor::staticVTable(); |
367 | } |
368 | |
369 | inline ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result) |
370 | { |
371 | return v4->hasException ? QV4::Encode::undefined() : result; |
372 | } |
373 | |
374 | } |
375 | |
376 | QT_END_NAMESPACE |
377 | |
378 | #endif // QMLJS_OBJECTS_H |
379 |
Definitions
- FunctionObject
- JavaScriptFunctionObject
- formalParameterCount
- varCount
- DynamicFunctionObject
- FunctionCtor
- FunctionPrototype
- IndexedBuiltinFunction
- ArrowFunction
- ScriptFunction
- MemberFunction
- init
- ConstructorFunction
- DefaultClassConstructorFunction
- BoundFunction
- BoundConstructor
- FunctionObject
- FunctionObject
- FunctionObject
- canBeTailCalled
- setName
- callAsConstructor
- call
- call
- isConstructor
- protoProperty
- hasHasInstanceProperty
- as
- JavaScriptFunctionObject
- JavaScriptFunctionObject
- JavaScriptFunctionObject
- scope
- function
- formalParameterCount
- varCount
- strictMode
- DynamicFunctionObject
- DynamicFunctionObject
- DynamicFunctionObject
- FunctionCtor
- FunctionCtor
- FunctionCtor
- Type
- FunctionPrototype
- FunctionPrototype
- FunctionPrototype
- IndexedBuiltinFunction
- IndexedBuiltinFunction
- IndexedBuiltinFunction
- init
- ArrowFunction
- ArrowFunction
- ArrowFunction
- ScriptFunction
- ScriptFunction
- ScriptFunction
- MemberFunction
- MemberFunction
- MemberFunction
- ConstructorFunction
- ConstructorFunction
- ConstructorFunction
- DefaultClassConstructorFunction
- DefaultClassConstructorFunction
- DefaultClassConstructorFunction
- scope
- BoundFunction
- BoundFunction
- BoundFunction
- target
- boundThis
- boundArgs
- BoundConstructor
- BoundConstructor
- BoundConstructor
- isBoundFunction
Learn to use CMake with our Intro Training
Find out more