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