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