• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef ECMASCRIPT_JSFUNCTION_H
17 #define ECMASCRIPT_JSFUNCTION_H
18 
19 #include "ecmascript/accessor_data.h"
20 #include "ecmascript/ecma_macros.h"
21 #include "ecmascript/js_object-inl.h"
22 #include "ecmascript/lexical_env.h"
23 
24 namespace panda::ecmascript {
25 class JSThread;
26 struct EcmaRuntimeCallInfo;
27 
28 class JSFunctionBase : public JSObject {
29 public:
30     CAST_CHECK(JSFunctionBase, IsJSFunctionBase);
31 
SetConstructor(bool flag)32     inline void SetConstructor(bool flag)
33     {
34         JSHClass *hclass = GetJSHClass();
35         hclass->SetConstructor(flag);
36     }
37 
38     static bool SetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func,
39                                 const JSHandle<JSTaggedValue> &name, const JSHandle<JSTaggedValue> &prefix);
40     static JSHandle<JSTaggedValue> GetFunctionName(JSThread *thread, const JSHandle<JSFunctionBase> &func);
41 
SetCallNapi(bool isCallNapi)42     void SetCallNapi(bool isCallNapi)
43     {
44         JSTaggedValue method = GetMethod();
45         Method::Cast(method.GetTaggedObject())->SetCallNapi(isCallNapi);
46     }
47 
IsCallNapi()48     bool IsCallNapi() const
49     {
50         JSTaggedValue method = GetMethod();
51         return Method::ConstCast(method.GetTaggedObject())->IsCallNapi();
52     }
53 
GetFunctionKind()54     FunctionKind GetFunctionKind() const
55     {
56         JSTaggedValue method = GetMethod();
57         return Method::ConstCast(method.GetTaggedObject())->GetFunctionKind();
58     }
59 
60     static constexpr size_t METHOD_OFFSET = JSObject::SIZE;
61     ACCESSORS(Method, METHOD_OFFSET, LAST_OFFSET)
62     DEFINE_ALIGN_SIZE(LAST_OFFSET);
63 
64     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, METHOD_OFFSET, LAST_OFFSET)
65     DECL_DUMP()
66 };
67 
68 static_assert((JSFunctionBase::SIZE % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT)) == 0);
69 
70 class JSFunction : public JSFunctionBase {
71 public:
72     static constexpr int LENGTH_OF_INLINE_PROPERTIES = 3;
73     static constexpr int LENGTH_INLINE_PROPERTY_INDEX = 0;
74     static constexpr int NAME_INLINE_PROPERTY_INDEX = 1;
75     static constexpr int PROTOTYPE_INLINE_PROPERTY_INDEX = 2;
76     static constexpr int CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX = 1;
77 
78     CAST_CHECK(JSFunction, IsJSFunction);
79 
80     static void InitializeJSFunction(JSThread *thread, const JSHandle<GlobalEnv> &env, const JSHandle<JSFunction> &func,
81                                      FunctionKind kind = FunctionKind::NORMAL_FUNCTION);
82     // ecma6 7.3
83     static bool OrdinaryHasInstance(JSThread *thread, const JSHandle<JSTaggedValue> &constructor,
84                                     const JSHandle<JSTaggedValue> &obj);
85 
86     static JSTaggedValue SpeciesConstructor(const JSHandle<JSFunction> &func,
87                                             const JSHandle<JSFunction> &defaultConstructor);
88 
89     // ecma6 9.2
90     // 7.3.12 Call(F, V, argumentsList)
91 
92     static JSTaggedValue Call(EcmaRuntimeCallInfo *info);
93 
94     static JSTaggedValue Construct(EcmaRuntimeCallInfo *info);
95     static JSTaggedValue Invoke(EcmaRuntimeCallInfo *info, const JSHandle<JSTaggedValue> &key);
96     // 9.2.2[[Construct]](argumentsList, newTarget)
97     // 9.3.2[[Construct]](argumentsList, newTarget)
98     static JSTaggedValue ConstructInternal(EcmaRuntimeCallInfo *info);
99 
100     static bool AddRestrictedFunctionProperties(const JSHandle<JSFunction> &func, const JSHandle<JSTaggedValue> &realm);
101     static bool MakeConstructor(JSThread *thread, const JSHandle<JSFunction> &func,
102                                 const JSHandle<JSTaggedValue> &proto, bool writable = true);
103     static bool SetFunctionLength(JSThread *thread, const JSHandle<JSFunction> &func, JSTaggedValue length,
104                                   bool cfg = true);
105     static JSHandle<JSObject> NewJSFunctionPrototype(JSThread *thread, ObjectFactory *factory,
106                                                      const JSHandle<JSFunction> &func);
107     static JSTaggedValue AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo *argv);
108     static JSTaggedValue PrototypeGetter(JSThread *thread, const JSHandle<JSObject> &self);
109     static bool PrototypeSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
110                                 bool mayThrow);
111     static JSTaggedValue NameGetter(JSThread *thread, const JSHandle<JSObject> &self);
112     static bool NameSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value,
113                            bool mayThrow);
114     static void SetFunctionNameNoPrefix(JSThread *thread, JSFunction *func, JSTaggedValue name);
115 
GetFunctionPrototype()116     inline JSTaggedValue GetFunctionPrototype() const
117     {
118         ASSERT(HasFunctionPrototype());
119         JSTaggedValue protoOrHClass = GetProtoOrHClass();
120         if (protoOrHClass.IsJSHClass()) {
121             return JSHClass::Cast(protoOrHClass.GetTaggedObject())->GetPrototype();
122         }
123 
124         return protoOrHClass;
125     }
126 
SetFunctionPrototype(const JSThread * thread,JSTaggedValue proto)127     inline void SetFunctionPrototype(const JSThread *thread, JSTaggedValue proto)
128     {
129         SetProtoOrHClass(thread, proto);
130         if (proto.IsJSHClass()) {
131             proto = JSHClass::Cast(proto.GetTaggedObject())->GetPrototype();
132         }
133         if (proto.IsECMAObject()) {
134             proto.GetTaggedObject()->GetClass()->SetIsPrototype(true);
135         }
136     }
137 
HasInitialClass()138     inline bool HasInitialClass() const
139     {
140         JSTaggedValue protoOrHClass = GetProtoOrHClass();
141         return protoOrHClass.IsJSHClass();
142     }
143 
HasFunctionPrototype()144     inline bool HasFunctionPrototype() const
145     {
146         JSTaggedValue protoOrHClass = GetProtoOrHClass();
147         return !protoOrHClass.IsHole();
148     }
149 
SetFunctionLength(const JSThread * thread,JSTaggedValue length)150     inline void SetFunctionLength(const JSThread *thread, JSTaggedValue length)
151     {
152         ASSERT(!IsPropertiesDict());
153         SetPropertyInlinedProps(thread, LENGTH_INLINE_PROPERTY_INDEX, length);
154     }
155 
IsBase()156     inline bool IsBase() const
157     {
158         FunctionKind kind = GetFunctionKind();
159         return kind <= FunctionKind::CLASS_CONSTRUCTOR;
160     }
161 
IsDerivedConstructor()162     inline bool IsDerivedConstructor() const
163     {
164         FunctionKind kind = GetFunctionKind();
165         return kind == FunctionKind::DERIVED_CONSTRUCTOR;
166     }
167 
IsArrowFunction(FunctionKind kind)168     inline static bool IsArrowFunction(FunctionKind kind)
169     {
170         return (kind >= FunctionKind::ARROW_FUNCTION) && (kind <= FunctionKind::ASYNC_ARROW_FUNCTION);
171     }
172 
IsClassConstructor(FunctionKind kind)173     inline static bool IsClassConstructor(FunctionKind kind)
174     {
175         return (kind == FunctionKind::CLASS_CONSTRUCTOR) || (kind == FunctionKind::DERIVED_CONSTRUCTOR);
176     }
177 
IsConstructorKind(FunctionKind kind)178     inline static bool IsConstructorKind(FunctionKind kind)
179     {
180         return (kind >= FunctionKind::BASE_CONSTRUCTOR) && (kind <= FunctionKind::DERIVED_CONSTRUCTOR);
181     }
182 
IsBuiltinConstructor()183     inline bool IsBuiltinConstructor()
184     {
185         FunctionKind kind = GetFunctionKind();
186         return kind >= FunctionKind::BUILTIN_PROXY_CONSTRUCTOR && kind <= FunctionKind::BUILTIN_CONSTRUCTOR;
187     }
188 
HasPrototype(FunctionKind kind)189     inline static bool HasPrototype(FunctionKind kind)
190     {
191         return (kind >= FunctionKind::BASE_CONSTRUCTOR) && (kind <= FunctionKind::ASYNC_GENERATOR_FUNCTION)
192             && (kind != FunctionKind::BUILTIN_PROXY_CONSTRUCTOR);
193     }
194 
HasAccessor(FunctionKind kind)195     inline static bool HasAccessor(FunctionKind kind)
196     {
197         return kind >= FunctionKind::NORMAL_FUNCTION && kind <= FunctionKind::ASYNC_FUNCTION;
198     }
199 
IsClassConstructor()200     inline bool IsClassConstructor() const
201     {
202         return GetClass()->IsClassConstructor();
203     }
204 
SetClassConstructor(bool flag)205     inline void SetClassConstructor(bool flag)
206     {
207         GetClass()->SetClassConstructor(flag);
208     }
209 
210     void SetFunctionExtraInfo(JSThread *thread, void *nativeFunc, const DeleteEntryPoint &deleter,
211         void *data, size_t nativeBindingsize = 0);
212 
213     JSTaggedValue GetFunctionExtraInfo() const;
214     JSTaggedValue GetNativeFunctionExtraInfo() const;
215     JSTaggedValue GetRecordName() const;
216 
217     static void InitializeJSFunction(JSThread *thread, const JSHandle<JSFunction> &func,
218                                      FunctionKind kind = FunctionKind::NORMAL_FUNCTION);
219     static JSHClass *GetOrCreateInitialJSHClass(JSThread *thread, const JSHandle<JSFunction> &fun);
220     static JSHandle<JSHClass> GetInstanceJSHClass(JSThread *thread, JSHandle<JSFunction> constructor,
221                                                   JSHandle<JSTaggedValue> newTarget);
222 
223     static constexpr size_t PROTO_OR_DYNCLASS_OFFSET = JSFunctionBase::SIZE;
224     ACCESSORS(ProtoOrHClass, PROTO_OR_DYNCLASS_OFFSET, LEXICAL_ENV_OFFSET)
225     ACCESSORS(LexicalEnv, LEXICAL_ENV_OFFSET, HOME_OBJECT_OFFSET)
226     ACCESSORS(HomeObject, HOME_OBJECT_OFFSET, ECMA_MODULE_OFFSET)
227     ACCESSORS(Module, ECMA_MODULE_OFFSET, LAST_OFFSET)
228     DEFINE_ALIGN_SIZE(LAST_OFFSET);
229 
230     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunctionBase, PROTO_OR_DYNCLASS_OFFSET, SIZE)
231     DECL_DUMP()
232 
233 private:
234     static JSHandle<JSHClass> GetOrCreateDerivedJSHClass(JSThread *thread, JSHandle<JSFunction> derived,
235                                                          JSHandle<JSHClass> ctorInitialClass);
236 };
237 
238 class JSGeneratorFunction : public JSFunction {
239 public:
240     CAST_CHECK(JSGeneratorFunction, IsGeneratorFunction);
241 
242     static constexpr size_t SIZE = JSFunction::SIZE;
243 
244     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, SIZE, SIZE)
245 
246     DECL_DUMP()
247 };
248 
249 class JSBoundFunction : public JSFunctionBase {
250 public:
251     CAST_CHECK(JSBoundFunction, IsBoundFunction);
252 
253     // 9.4.1.2[[Construct]](argumentsList, newTarget)
254     static JSTaggedValue ConstructInternal(EcmaRuntimeCallInfo *info);
255 
256     static constexpr size_t BOUND_TARGET_OFFSET = JSFunctionBase::SIZE;
257     ACCESSORS(BoundTarget, BOUND_TARGET_OFFSET, BOUND_THIS_OFFSET);
258     ACCESSORS(BoundThis, BOUND_THIS_OFFSET, BOUND_ARGUMENTS_OFFSET);
259     ACCESSORS(BoundArguments, BOUND_ARGUMENTS_OFFSET, SIZE);
260 
261     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunctionBase, BOUND_TARGET_OFFSET, SIZE)
262 
263     DECL_DUMP()
264 };
265 
266 class JSProxyRevocFunction : public JSFunction {
267 public:
268     CAST_CHECK(JSProxyRevocFunction, IsProxyRevocFunction);
269 
270     static void ProxyRevocFunctions(const JSThread *thread, const JSHandle<JSProxyRevocFunction> &revoker);
271 
272     static constexpr size_t REVOCABLE_PROXY_OFFSET = JSFunction::SIZE;
273     ACCESSORS(RevocableProxy, REVOCABLE_PROXY_OFFSET, SIZE);
274 
275     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, REVOCABLE_PROXY_OFFSET, SIZE)
276 
277     DECL_DUMP()
278 };
279 
280 // ResolveFunction/RejectFunction
281 class JSPromiseReactionsFunction : public JSFunction {
282 public:
283     CAST_CHECK(JSPromiseReactionsFunction, IsJSPromiseReactionFunction);
284 
285     static constexpr size_t PROMISE_OFFSET = JSFunction::SIZE;
286     ACCESSORS(Promise, PROMISE_OFFSET, ALREADY_RESOLVED_OFFSET);
287     ACCESSORS(AlreadyResolved, ALREADY_RESOLVED_OFFSET, SIZE);
288 
289     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, PROMISE_OFFSET, SIZE)
290 
291     DECL_DUMP()
292 };
293 
294 // ExecutorFunction
295 class JSPromiseExecutorFunction : public JSFunction {
296 public:
297     CAST_CHECK(JSPromiseExecutorFunction, IsJSPromiseExecutorFunction);
298 
299     static constexpr size_t CAPABILITY_OFFSET = JSFunction::SIZE;
300     ACCESSORS(Capability, CAPABILITY_OFFSET, SIZE);
301 
302     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, CAPABILITY_OFFSET, SIZE)
303 
304     DECL_DUMP()
305 };
306 
307 class JSPromiseAllResolveElementFunction : public JSFunction {
308 public:
309     CAST_CHECK(JSPromiseAllResolveElementFunction, IsJSPromiseAllResolveElementFunction);
310 
311     static constexpr size_t INDEX_OFFSET = JSFunction::SIZE;
312     ACCESSORS(Index, INDEX_OFFSET, VALUES_OFFSET);
313     ACCESSORS(Values, VALUES_OFFSET, CAPABILITIES_OFFSET);
314     ACCESSORS(Capabilities, CAPABILITIES_OFFSET, REMAINING_ELEMENTS_OFFSET);
315     ACCESSORS(RemainingElements, REMAINING_ELEMENTS_OFFSET, ALREADY_CALLED_OFFSET);
316     ACCESSORS(AlreadyCalled, ALREADY_CALLED_OFFSET, SIZE);
317 
318     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, INDEX_OFFSET, SIZE)
319 
320     DECL_DUMP()
321 };
322 
323 // PromiseAnyRejectElementFunction
324 class JSPromiseAnyRejectElementFunction : public JSFunction {
325 public:
326     CAST_CHECK(JSPromiseAnyRejectElementFunction, IsJSPromiseAnyRejectElementFunction);
327 
328     static constexpr size_t ERRORS_OFFSET = JSFunction::SIZE;
329 
330     ACCESSORS(Errors, ERRORS_OFFSET, CAPABILITY_OFFSET);
331     ACCESSORS(Capability, CAPABILITY_OFFSET, REMAINING_ELEMENTS_OFFSET);
332     ACCESSORS(RemainingElements, REMAINING_ELEMENTS_OFFSET, ALREADY_CALLED_OFFSET);
333     ACCESSORS(AlreadyCalled, ALREADY_CALLED_OFFSET, INDEX_OFFSET);
334     ACCESSORS_PRIMITIVE_FIELD(Index, uint32_t, INDEX_OFFSET, LAST_OFFSET);
335     DEFINE_ALIGN_SIZE(LAST_OFFSET);
336 
337     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, ERRORS_OFFSET, INDEX_OFFSET)
338 
339     DECL_DUMP()
340 };
341 
342 // PromiseAllSettledElementFunction
343 class JSPromiseAllSettledElementFunction : public JSFunction {
344 public:
345     CAST_CHECK(JSPromiseAllSettledElementFunction, IsJSPromiseAllSettledElementFunction);
346 
347     static constexpr size_t ALREADY_CALLED_OFFSET = JSFunction::SIZE;
348     ACCESSORS(AlreadyCalled, ALREADY_CALLED_OFFSET, VALUES_OFFSET);
349     ACCESSORS(Values, VALUES_OFFSET, CAPABILITY_OFFSET);
350     ACCESSORS(Capability, CAPABILITY_OFFSET, REMAINING_ELEMENTS_OFFSET);
351     ACCESSORS(RemainingElements, REMAINING_ELEMENTS_OFFSET, INDEX_OFFSET);
352     ACCESSORS_PRIMITIVE_FIELD(Index, uint32_t, INDEX_OFFSET, LAST_OFFSET);
353     DEFINE_ALIGN_SIZE(LAST_OFFSET);
354 
355     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, ALREADY_CALLED_OFFSET, INDEX_OFFSET)
356 
357     DECL_DUMP()
358 };
359 
360 // PromiseFinallyFunction
361 class JSPromiseFinallyFunction : public JSFunction {
362 public:
363     CAST_CHECK(JSPromiseFinallyFunction, IsJSPromiseFinallyFunction);
364 
365     static constexpr size_t CONSTRUCTOR_OFFSET = JSFunction::SIZE;
366     ACCESSORS(Constructor, CONSTRUCTOR_OFFSET, ONFINALLY_OFFSET);
367     ACCESSORS(OnFinally, ONFINALLY_OFFSET, SIZE);
368 
369     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, CONSTRUCTOR_OFFSET, SIZE)
370 
371     DECL_DUMP()
372 };
373 
374 // ValueThunkOrThrowReason
375 class JSPromiseValueThunkOrThrowerFunction : public JSFunction {
376 public:
377     CAST_CHECK(JSPromiseValueThunkOrThrowerFunction, IsJSPromiseValueThunkOrThrowerFunction);
378 
379     static constexpr size_t RESULT_OFFSET = JSFunction::SIZE;
380     ACCESSORS(Result, RESULT_OFFSET, SIZE);
381 
382     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, RESULT_OFFSET, SIZE)
383 
384     DECL_DUMP()
385 };
386 
387 class JSIntlBoundFunction : public JSFunction {
388 public:
389     CAST_CHECK(JSIntlBoundFunction, IsJSIntlBoundFunction);
390 
391     static JSTaggedValue IntlNameGetter(JSThread *thread, const JSHandle<JSObject> &self);
392 
393     static constexpr size_t NUMBER_FORMAT_OFFSET = JSFunction::SIZE;
394 
395     ACCESSORS(NumberFormat, NUMBER_FORMAT_OFFSET, DATETIME_FORMAT_OFFSET);
396     ACCESSORS(DateTimeFormat, DATETIME_FORMAT_OFFSET, COLLATOR_OFFSET);
397     ACCESSORS(Collator, COLLATOR_OFFSET, SIZE);
398 
399     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, NUMBER_FORMAT_OFFSET, SIZE)
400     DECL_DUMP()
401 };
402 
403 class JSAsyncGeneratorFunction : public JSFunction {
404 public:
405     CAST_CHECK(JSAsyncGeneratorFunction, IsAsyncGeneratorFunction);
406     static constexpr size_t  SIZE = JSFunction::SIZE;
407     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, SIZE, SIZE)
408     DECL_DUMP()
409 };
410 
411 class JSAsyncFromSyncIterUnwarpFunction : public JSFunction {
412 public:
413     CAST_CHECK(JSAsyncFromSyncIterUnwarpFunction, IsJSAsyncFromSyncIterUnwarpFunction);
414     static constexpr size_t DONE_OFFSET = JSFunction::SIZE;
415     ACCESSORS(Done, DONE_OFFSET, SIZE);
416 
417     DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, DONE_OFFSET, SIZE);
418     DECL_DUMP()
419 };
420 
421 }  // namespace panda::ecmascript
422 
423 #endif  // ECMASCRIPT_JSFUNCTION_H
424