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