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
22QT_BEGIN_NAMESPACE
23
24struct QQmlSourceLocation;
25
26namespace QV4 {
27
28struct IndexedBuiltinFunction;
29struct JSCallData;
30
31namespace Heap {
32
33
34#define FunctionObjectMembers(class, Member) \
35 Member(class, Pointer, ExecutionContext *, scope) \
36 Member(class, NoMark, Function *, function) \
37 Member(class, NoMark, VTable::Call, jsCall) \
38 Member(class, NoMark, VTable::CallAsConstructor, jsConstruct) \
39 Member(class, NoMark, VTable::CallWithMetaTypes, jsCallWithMetaTypes) \
40 Member(class, NoMark, bool, canBeTailCalled)
41
42DECLARE_HEAP_OBJECT(FunctionObject, Object) {
43 DECLARE_MARKOBJECTS(FunctionObject)
44 enum {
45 Index_ProtoConstructor = 0,
46 Index_Prototype = 0,
47 Index_HasInstance = 1,
48 };
49
50 bool isConstructor() const {
51 return jsConstruct != nullptr;
52 }
53
54 Q_QML_PRIVATE_EXPORT void init(
55 QV4::ExecutionContext *scope, QV4::String *name,
56 VTable::Call call, VTable::CallWithMetaTypes callWithMetaTypes = nullptr);
57 Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::String *name = nullptr);
58 Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, QV4::Function *function, QV4::String *n = nullptr);
59 Q_QML_PRIVATE_EXPORT void init(QV4::ExecutionContext *scope, const QString &name);
60 Q_QML_PRIVATE_EXPORT void init();
61 Q_QML_PRIVATE_EXPORT void destroy();
62
63 void setFunction(Function *f);
64
65 unsigned int formalParameterCount() { return function ? function->nFormals : 0; }
66 unsigned int varCount() { return function ? function->compiledFunction->nLocals : 0; }
67};
68
69struct FunctionCtor : FunctionObject {
70 void init(QV4::ExecutionContext *scope);
71};
72
73struct FunctionPrototype : FunctionObject {
74 void init();
75};
76
77// A function object with an additional index into a list.
78// Used by Models to refer to property roles.
79struct IndexedBuiltinFunction : FunctionObject {
80 inline void init(QV4::ExecutionContext *scope, qsizetype index, VTable::Call call);
81 qsizetype index;
82};
83
84struct ArrowFunction : FunctionObject {
85 enum {
86 Index_Name = Index_HasInstance + 1,
87 Index_Length
88 };
89 void init(QV4::ExecutionContext *scope, Function *function, QV4::String *name = nullptr);
90};
91
92#define ScriptFunctionMembers(class, Member) \
93 Member(class, Pointer, InternalClass *, cachedClassForConstructor)
94
95DECLARE_HEAP_OBJECT(ScriptFunction, ArrowFunction) {
96 DECLARE_MARKOBJECTS(ScriptFunction)
97 void init(QV4::ExecutionContext *scope, Function *function);
98};
99
100#define MemberFunctionMembers(class, Member) \
101 Member(class, Pointer, Object *, homeObject)
102
103DECLARE_HEAP_OBJECT(MemberFunction, ArrowFunction) {
104 DECLARE_MARKOBJECTS(MemberFunction)
105
106 void init(QV4::ExecutionContext *scope, Function *function, QV4::String *name = nullptr) {
107 ArrowFunction::init(scope, function, name);
108 }
109};
110
111#define ConstructorFunctionMembers(class, Member) \
112 Member(class, Pointer, Object *, homeObject)
113
114DECLARE_HEAP_OBJECT(ConstructorFunction, ScriptFunction) {
115 DECLARE_MARKOBJECTS(ConstructorFunction)
116 bool isDerivedConstructor;
117};
118
119struct DefaultClassConstructorFunction : FunctionObject
120{
121 bool isDerivedConstructor;
122};
123
124#define BoundFunctionMembers(class, Member) \
125 Member(class, Pointer, FunctionObject *, target) \
126 Member(class, HeapValue, HeapValue, boundThis) \
127 Member(class, Pointer, MemberData *, boundArgs)
128
129DECLARE_HEAP_OBJECT(BoundFunction, FunctionObject) {
130 DECLARE_MARKOBJECTS(BoundFunction)
131
132 void init(QV4::ExecutionContext *scope, QV4::FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs);
133};
134
135}
136
137struct Q_QML_EXPORT FunctionObject: Object {
138 enum {
139 IsFunctionObject = true
140 };
141 V4_OBJECT2(FunctionObject, Object)
142 Q_MANAGED_TYPE(FunctionObject)
143 V4_INTERNALCLASS(FunctionObject)
144 V4_PROTOTYPE(functionPrototype)
145 V4_NEEDS_DESTROY
146 enum { NInlineProperties = 1 };
147
148 bool canBeTailCalled() const { return d()->canBeTailCalled; }
149 Heap::ExecutionContext *scope() const { return d()->scope; }
150 Function *function() const { return d()->function; }
151
152 ReturnedValue name() const;
153 unsigned int formalParameterCount() const { return d()->formalParameterCount(); }
154 unsigned int varCount() const { return d()->varCount(); }
155
156 void setName(String *name) {
157 defineReadonlyConfigurableProperty(name: engine()->id_name(), value: *name);
158 }
159 void createDefaultPrototypeProperty(uint protoConstructorSlot);
160
161 inline ReturnedValue callAsConstructor(const JSCallData &data) const;
162 ReturnedValue callAsConstructor(const Value *argv, int argc, const Value *newTarget = nullptr) const {
163 if (!d()->jsConstruct)
164 return engine()->throwTypeError(QStringLiteral("Function is not a constructor."));
165 return d()->jsConstruct(this, argv, argc, newTarget ? newTarget : this);
166 }
167 inline ReturnedValue call(const JSCallData &data) const;
168 ReturnedValue call(const Value *thisObject, const Value *argv, int argc) const {
169 if (!d()->jsCall)
170 return engine()->throwTypeError(QStringLiteral("Function can only be called with |new|."));
171 return d()->jsCall(this, thisObject, argv, argc);
172 }
173 static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
174 void call(QObject *thisObject, void **a, const QMetaType *types, int argc);
175 static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject,
176 void **a, const QMetaType *types, int argc);
177
178 static Heap::FunctionObject *createScriptFunction(ExecutionContext *scope, Function *function);
179 static Heap::FunctionObject *createConstructorFunction(ExecutionContext *scope, Function *function, Object *homeObject, bool isDerivedConstructor);
180 static Heap::FunctionObject *createMemberFunction(ExecutionContext *scope, Function *function, Object *homeObject, String *name);
181 static Heap::FunctionObject *createBuiltinFunction(ExecutionEngine *engine, StringOrSymbol *nameOrSymbol, VTable::Call code, int argumentCount);
182
183 bool strictMode() const { return d()->function ? d()->function->isStrict() : false; }
184 bool isBinding() const;
185 bool isBoundFunction() const;
186 bool isConstructor() const {
187 return d()->isConstructor();
188 }
189
190 ReturnedValue getHomeObject() const;
191
192 ReturnedValue protoProperty() const {
193 return getValueByIndex(propertyIndex: Heap::FunctionObject::Index_Prototype);
194 }
195 bool hasHasInstanceProperty() const {
196 return !internalClass()->propertyData.at(i: Heap::FunctionObject::Index_HasInstance).isEmpty();
197 }
198
199 QQmlSourceLocation sourceLocation() const;
200};
201
202template<>
203inline const FunctionObject *Value::as() const {
204 return isManaged() && m()->internalClass->vtable->isFunctionObject ? reinterpret_cast<const FunctionObject *>(this) : nullptr;
205}
206
207
208struct FunctionCtor: FunctionObject
209{
210 V4_OBJECT2(FunctionCtor, FunctionObject)
211
212 static ReturnedValue virtualCallAsConstructor(const FunctionObject *f, const Value *argv, int argc, const Value *);
213 static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
214protected:
215 enum Type {
216 Type_Function,
217 Type_Generator
218 };
219 static QQmlRefPointer<ExecutableCompilationUnit> parse(ExecutionEngine *engine, const Value *argv, int argc, Type t = Type_Function);
220};
221
222struct FunctionPrototype: FunctionObject
223{
224 V4_OBJECT2(FunctionPrototype, FunctionObject)
225
226 void init(ExecutionEngine *engine, Object *ctor);
227
228 static ReturnedValue method_toString(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
229 static ReturnedValue method_apply(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
230 static ReturnedValue method_call(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
231 static ReturnedValue method_bind(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
232 static ReturnedValue method_hasInstance(const FunctionObject *, const Value *thisObject, const Value *argv, int argc);
233};
234
235struct Q_QML_PRIVATE_EXPORT IndexedBuiltinFunction : FunctionObject
236{
237 V4_OBJECT2(IndexedBuiltinFunction, FunctionObject)
238};
239
240void Heap::IndexedBuiltinFunction::init(
241 QV4::ExecutionContext *scope, qsizetype index, VTable::Call call)
242{
243 Heap::FunctionObject::init(scope);
244 this->jsCall = call;
245 this->index = index;
246}
247
248struct ArrowFunction : FunctionObject {
249 V4_OBJECT2(ArrowFunction, FunctionObject)
250 V4_INTERNALCLASS(ArrowFunction)
251 enum { NInlineProperties = 3 };
252
253 static void virtualCallWithMetaTypes(const FunctionObject *f, QObject *thisObject,
254 void **a, const QMetaType *types, int argc);
255 static ReturnedValue virtualCall(const QV4::FunctionObject *f, const QV4::Value *thisObject,
256 const QV4::Value *argv, int argc);
257};
258
259struct ScriptFunction : ArrowFunction {
260 V4_OBJECT2(ScriptFunction, ArrowFunction)
261 V4_INTERNALCLASS(ScriptFunction)
262
263 static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
264
265 Heap::InternalClass *classForConstructor() const;
266};
267
268struct MemberFunction : ArrowFunction {
269 V4_OBJECT2(MemberFunction, ArrowFunction)
270 V4_INTERNALCLASS(MemberFunction)
271};
272
273struct ConstructorFunction : ScriptFunction {
274 V4_OBJECT2(ConstructorFunction, ScriptFunction)
275 V4_INTERNALCLASS(ConstructorFunction)
276 static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
277 static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
278};
279
280struct DefaultClassConstructorFunction : FunctionObject {
281 V4_OBJECT2(DefaultClassConstructorFunction, FunctionObject)
282 static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
283 static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
284};
285
286struct BoundFunction: FunctionObject {
287 V4_OBJECT2(BoundFunction, FunctionObject)
288
289 static Heap::BoundFunction *create(ExecutionContext *scope, FunctionObject *target, const Value &boundThis, QV4::MemberData *boundArgs)
290 {
291 return scope->engine()->memoryManager->allocate<BoundFunction>(args&: scope, args&: target, args: boundThis, args&: boundArgs);
292 }
293
294 Heap::FunctionObject *target() const { return d()->target; }
295 Value boundThis() const { return d()->boundThis; }
296 Heap::MemberData *boundArgs() const { return d()->boundArgs; }
297
298 static ReturnedValue virtualCallAsConstructor(const FunctionObject *, const Value *argv, int argc, const Value *);
299 static ReturnedValue virtualCall(const FunctionObject *f, const Value *thisObject, const Value *argv, int argc);
300};
301
302inline bool FunctionObject::isBoundFunction() const
303{
304 return d()->vtable() == BoundFunction::staticVTable();
305}
306
307inline ReturnedValue checkedResult(QV4::ExecutionEngine *v4, ReturnedValue result)
308{
309 return v4->hasException ? QV4::Encode::undefined() : result;
310}
311
312}
313
314QT_END_NAMESPACE
315
316#endif // QMLJS_OBJECTS_H
317

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