1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtQml module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | #ifndef QV4FUNCTIONOBJECT_H |
40 | #define QV4FUNCTIONOBJECT_H |
41 | |
42 | // |
43 | // W A R N I N G |
44 | // ------------- |
45 | // |
46 | // This file is not part of the Qt API. It exists purely as an |
47 | // implementation detail. This header file may change from version to |
48 | // version without notice, or even be removed. |
49 | // |
50 | // We mean it. |
51 | // |
52 | |
53 | #include "qv4object_p.h" |
54 | #include "qv4function_p.h" |
55 | #include "qv4context_p.h" |
56 | #include <private/qv4mm_p.h> |
57 | |
58 | QT_BEGIN_NAMESPACE |
59 | |
60 | struct QQmlSourceLocation; |
61 | |
62 | namespace QV4 { |
63 | |
64 | struct IndexedBuiltinFunction; |
65 | struct JSCallData; |
66 | |
67 | namespace Heap { |
68 | |
69 | |
70 | #define FunctionObjectMembers(class, Member) \ |
71 | Member(class, Pointer, ExecutionContext *, scope) \ |
72 | Member(class, NoMark, Function *, function) \ |
73 | Member(class, NoMark, VTable::Call, jsCall) \ |
74 | Member(class, NoMark, VTable::CallAsConstructor, jsConstruct) \ |
75 | Member(class, NoMark, bool, canBeTailCalled) |
76 | |
77 | DECLARE_HEAP_OBJECT(FunctionObject, Object) { |
78 | DECLARE_MARKOBJECTS(FunctionObject); |
79 | enum { |
80 | Index_ProtoConstructor = 0, |
81 | Index_Prototype = 0, |
82 | Index_HasInstance = 1, |
83 | }; |
84 | |
85 | bool isConstructor() const { |
86 | return jsConstruct != nullptr; |
87 | } |
88 | |
89 | Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name, VTable::Call call); |
90 | Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr); |
91 | Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr); |
92 | Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, const QString &name); |
93 | Q_QML_PRIVATE_EXPORT void init(); |
94 | Q_QML_PRIVATE_EXPORT void destroy(); |
95 | |
96 | void setFunction(Function *f); |
97 | |
98 | unsigned int formalParameterCount() { return function ? function->nFormals : 0; } |
99 | unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; } |
100 | }; |
101 | |
102 | struct FunctionCtor : FunctionObject { |
103 | void init(QV4::ExecutionContext *scope); |
104 | }; |
105 | |
106 | struct FunctionPrototype : FunctionObject { |
107 | void init(); |
108 | }; |
109 | |
110 | struct IndexedBuiltinFunction : FunctionObject { |
111 | inline void init(QV4::ExecutionContext *scope, uint index, VTable::Call call); |
112 | uint index; |
113 | }; |
114 | |
115 | struct ArrowFunction : FunctionObject { |
116 | enum { |
117 | Index_Name = Index_HasInstance + 1, |
118 | Index_Length |
119 | }; |
120 | void init(QV4::ExecutionContext *scope, Function *function, QV4::String *name = nullptr); |
121 | }; |
122 | |
123 | #define ScriptFunctionMembers(class, Member) \ |
124 | Member(class, Pointer, InternalClass *, cachedClassForConstructor) |
125 | |
126 | DECLARE_HEAP_OBJECT(ScriptFunction, ArrowFunction) { |
127 | DECLARE_MARKOBJECTS(ScriptFunction) |
128 | void init(QV4::ExecutionContext *scope, Function *function); |
129 | }; |
130 | |
131 | #define MemberFunctionMembers(class, Member) \ |
132 | Member(class, Pointer, Object *, homeObject) |
133 | |
134 | DECLARE_HEAP_OBJECT(MemberFunction, ArrowFunction) { |
135 | DECLARE_MARKOBJECTS(MemberFunction) |
136 | |
137 | void init(QV4::ExecutionContext *scope, Function *function, QV4::String *name = nullptr) { |
138 | ArrowFunction::init(scope, function, name); |
139 | } |
140 | }; |
141 | |
142 | #define ConstructorFunctionMembers(class, Member) \ |
143 | Member(class, Pointer, Object *, homeObject) |
144 | |
145 | DECLARE_HEAP_OBJECT(ConstructorFunction, ScriptFunction) { |
146 | DECLARE_MARKOBJECTS(ConstructorFunction) |
147 | bool isDerivedConstructor; |
148 | }; |
149 | |
150 | struct DefaultClassConstructorFunction : FunctionObject |
151 | { |
152 | bool isDerivedConstructor; |
153 | }; |
154 | |
155 | #define BoundFunctionMembers(class, Member) \ |
156 | Member(class, Pointer, FunctionObject *, target) \ |
157 | Member(class, HeapValue, HeapValue, boundThis) \ |
158 | Member(class, Pointer, MemberData *, boundArgs) |
159 | |
160 | DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) { |
161 | DECLARE_MARKOBJECTS(BoundFunction); |
162 | |
163 | void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs); |
164 | }; |
165 | |
166 | } |
167 | |
168 | struct Q_QML_EXPORT FunctionObject: Object { |
169 | enum { |
170 | IsFunctionObject = true |
171 | }; |
172 | V4_OBJECT2(FunctionObject, Object) |
173 | Q_MANAGED_TYPE(FunctionObject) |
174 | V4_INTERNALCLASS(FunctionObject) |
175 | V4_PROTOTYPE(functionPrototype) |
176 | V4_NEEDS_DESTROY |
177 | enum { NInlineProperties = 1 }; |
178 | |
179 | bool canBeTailCalled() const { return d()->canBeTailCalled; } |
180 | Heap::ExecutionContext *scope() const { return d()->scope; } |
181 | Function *function() const { return d()->function; } |
182 | |
183 | ReturnedValue name() const; |
184 | unsigned int formalParameterCount() const { return d()->formalParameterCount(); } |
185 | unsigned int varCount() const { return d()->varCount(); } |
186 | |
187 | void setName(String *name) { |
188 | defineReadonlyConfigurableProperty(name: engine()->id_name(), value: *name); |
189 | } |
190 | void createDefaultPrototypeProperty(uint protoConstructorSlot); |
191 | |
192 | inline ReturnedValue callAsConstructor(const JSCallData &data) const; |
193 | ReturnedValue callAsConstructor(const Value *argv, int argc, const Value *newTarget = nullptr) const { |
194 | if (!d()->jsConstruct) |
195 | return engine()->throwTypeError(QStringLiteral("Function is not a constructor." )); |
196 | return d()->jsConstruct(this, argv, argc, newTarget ? newTarget : this); |
197 | } |
198 | inline ReturnedValue call(const JSCallData &data) const; |
199 | ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const { |
200 | if (!d()->jsCall) |
201 | return engine()->throwTypeError(QStringLiteral("Function can only be called with |new|." )); |
202 | return d()->jsCall(this, thisObject, argv, argc); |
203 | } |
204 | static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); |
205 | |
206 | static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function); |
207 | static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor); |
208 | static Heap::FunctionObject *createMemberFunction(ExecutionContext *scope, Function *function, Object *homeObject, String *name); |
209 | static Heap::FunctionObject *createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount); |
210 | |
211 | bool strictMode() const { return d()->function ? d()->function->isStrict() : false; } |
212 | bool isBinding() const; |
213 | bool isBoundFunction() const; |
214 | bool isConstructor() const { |
215 | return d()->isConstructor(); |
216 | } |
217 | |
218 | ReturnedValue getHomeObject() const; |
219 | |
220 | ReturnedValue protoProperty() const { |
221 | return getValueByIndex(propertyIndex: Heap::FunctionObject::Index_Prototype); |
222 | } |
223 | bool hasHasInstanceProperty() const { |
224 | return !internalClass()->propertyData.at(i: Heap::FunctionObject::Index_HasInstance).isEmpty(); |
225 | } |
226 | |
227 | QQmlSourceLocation sourceLocation() const; |
228 | }; |
229 | |
230 | template<> |
231 | inline const FunctionObject *Value::as() const { |
232 | return isManaged() && m()->internalClass->vtable->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : nullptr; |
233 | } |
234 | |
235 | |
236 | struct FunctionCtor: FunctionObject |
237 | { |
238 | V4_OBJECT2(FunctionCtor, FunctionObject) |
239 | |
240 | static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *); |
241 | static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); |
242 | protected: |
243 | enum Type { |
244 | Type_Function, |
245 | Type_Generator |
246 | }; |
247 | static QQmlRefPointer<ExecutableCompilationUnit> parse(ExecutionEngine *engine, const Value *argv, int argc, Type t = Type_Function); |
248 | }; |
249 | |
250 | struct FunctionPrototype: FunctionObject |
251 | { |
252 | V4_OBJECT2(FunctionPrototype, FunctionObject) |
253 | |
254 | void init(ExecutionEngine *engine, Object *ctor); |
255 | |
256 | static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); |
257 | static ReturnedValue method_apply(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); |
258 | static ReturnedValue method_call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); |
259 | static ReturnedValue method_bind(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); |
260 | static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc); |
261 | }; |
262 | |
263 | struct Q_QML_PRIVATE_EXPORT IndexedBuiltinFunction : FunctionObject |
264 | { |
265 | V4_OBJECT2(IndexedBuiltinFunction, FunctionObject) |
266 | }; |
267 | |
268 | void Heap::IndexedBuiltinFunction::init(QV4::ExecutionContext *scope, uint index, VTable::Call call) |
269 | { |
270 | Heap::FunctionObject::init(scope); |
271 | this->jsCall = call; |
272 | this->index = index; |
273 | } |
274 | |
275 | struct ArrowFunction : FunctionObject { |
276 | V4_OBJECT2(ArrowFunction, FunctionObject) |
277 | V4_INTERNALCLASS(ArrowFunction) |
278 | enum { NInlineProperties = 3 }; |
279 | |
280 | static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); |
281 | }; |
282 | |
283 | struct ScriptFunction : ArrowFunction { |
284 | V4_OBJECT2(ScriptFunction, ArrowFunction) |
285 | V4_INTERNALCLASS(ScriptFunction) |
286 | |
287 | static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *); |
288 | |
289 | Heap::InternalClass *classForConstructor() const; |
290 | }; |
291 | |
292 | struct MemberFunction : ArrowFunction { |
293 | V4_OBJECT2(MemberFunction, ArrowFunction) |
294 | V4_INTERNALCLASS(MemberFunction) |
295 | }; |
296 | |
297 | struct ConstructorFunction : ScriptFunction { |
298 | V4_OBJECT2(ConstructorFunction, ScriptFunction) |
299 | V4_INTERNALCLASS(ConstructorFunction) |
300 | static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *); |
301 | static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); |
302 | }; |
303 | |
304 | struct DefaultClassConstructorFunction : FunctionObject { |
305 | V4_OBJECT2(DefaultClassConstructorFunction, FunctionObject) |
306 | static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *); |
307 | static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); |
308 | }; |
309 | |
310 | struct BoundFunction: FunctionObject { |
311 | V4_OBJECT2(BoundFunction, FunctionObject) |
312 | |
313 | static Heap::BoundFunction *create(ExecutionContext *scope, FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs) |
314 | { |
315 | return scope->engine()->memoryManager->allocate<BoundFunction>(args: scope, args: target, args: boundThis, args: boundArgs); |
316 | } |
317 | |
318 | Heap::FunctionObject *target() const { return d()->target; } |
319 | Value boundThis() const { return d()->boundThis; } |
320 | Heap::MemberData *boundArgs() const { return d()->boundArgs; } |
321 | |
322 | static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *); |
323 | static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc); |
324 | }; |
325 | |
326 | inline bool FunctionObject::isBoundFunction() const |
327 | { |
328 | return d()->vtable() == BoundFunction::staticVTable(); |
329 | } |
330 | |
331 | inline ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result) |
332 | { |
333 | return v4->hasException ? QV4::Encode::undefined() : result; |
334 | } |
335 | |
336 | } |
337 | |
338 | QT_END_NAMESPACE |
339 | |
340 | #endif // QMLJS_OBJECTS_H |
341 | |