1 /* 2 * Copyright (c) 2021 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_JSFUCNTION_H 17 #define ECMASCRIPT_JSFUCNTION_H 18 19 #include "ecmascript/accessor_data.h" 20 #include "ecmascript/ecma_macros.h" 21 #include "ecmascript/ecma_runtime_call_info.h" 22 #include "ecmascript/js_object-inl.h" 23 #include "ecmascript/lexical_env.h" 24 25 namespace panda::ecmascript { 26 using panda::coretypes::DynClass; 27 class JSThread; 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 SetCallTarget(const JSThread * thread,JSMethod * p)43 void SetCallTarget([[maybe_unused]] const JSThread *thread, JSMethod *p) 44 { 45 SetMethod(p); 46 } 47 48 static constexpr size_t METHOD_OFFSET = JSObject::SIZE; 49 ACCESSORS_NATIVE_FIELD(Method, JSMethod, METHOD_OFFSET, LAST_OFFSET) 50 DEFINE_ALIGN_SIZE(LAST_OFFSET); 51 52 DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, SIZE, SIZE) 53 }; 54 55 static_assert((JSFunctionBase::SIZE % static_cast<uint8_t>(MemAlignment::MEM_ALIGN_OBJECT)) == 0); 56 57 class JSFunction : public JSFunctionBase { 58 public: 59 static constexpr int LENGTH_OF_INLINE_PROPERTIES = 3; 60 static constexpr int LENGTH_INLINE_PROPERTY_INDEX = 0; 61 static constexpr int NAME_INLINE_PROPERTY_INDEX = 1; 62 static constexpr int PROTOTYPE_INLINE_PROPERTY_INDEX = 2; 63 static constexpr int CLASS_PROTOTYPE_INLINE_PROPERTY_INDEX = 1; 64 65 /* -------------- Common API Begin, Don't change those interface!!! ----------------- */ 66 CAST_CHECK(JSFunction, IsJSFunction); 67 68 static void InitializeJSFunction(JSThread *thread, const JSHandle<GlobalEnv> &env, const JSHandle<JSFunction> &func, 69 FunctionKind kind = FunctionKind::NORMAL_FUNCTION, bool strict = true); 70 // ecma6 7.3 71 static bool OrdinaryHasInstance(JSThread *thread, const JSHandle<JSTaggedValue> &constructor, 72 const JSHandle<JSTaggedValue> &obj); 73 74 static JSTaggedValue SpeciesConstructor(const JSHandle<JSFunction> &func, 75 const JSHandle<JSFunction> &defaultConstructor); 76 77 // ecma6 9.2 78 // 7.3.12 Call(F, V, argumentsList) 79 80 static JSTaggedValue Call(JSThread *thread, const JSHandle<JSTaggedValue> &func, 81 const JSHandle<JSTaggedValue> &thisArg, uint32_t argc, const JSTaggedType argv[]); 82 83 static JSTaggedValue Construct(JSThread *thread, const JSHandle<JSTaggedValue> &func, uint32_t argc, 84 const JSTaggedType argv[], const JSHandle<JSTaggedValue> &newTarget); 85 static JSTaggedValue Invoke(JSThread *thread, const JSHandle<JSTaggedValue> &thisArg, 86 const JSHandle<JSTaggedValue> &key, uint32_t argc, const JSTaggedType argv[]); 87 // 9.2.1[[Call]](thisArgument, argumentsList) 88 // 9.3.1[[Call]](thisArgument, argumentsList) 89 static JSTaggedValue CallInternal(JSThread *thread, const JSHandle<JSFunction> &func, 90 const JSHandle<JSTaggedValue> &thisArg, uint32_t argc, const JSTaggedType argv[]); 91 // 9.2.2[[Construct]](argumentsList, newTarget) 92 // 9.3.2[[Construct]](argumentsList, newTarget) 93 static JSTaggedValue ConstructInternal(JSThread *thread, const JSHandle<JSFunction> &func, uint32_t argc, 94 const JSTaggedType argv[], const JSHandle<JSTaggedValue> &newTarget); 95 96 static bool AddRestrictedFunctionProperties(const JSHandle<JSFunction> &func, const JSHandle<JSTaggedValue> &realm); 97 static bool MakeConstructor(JSThread *thread, const JSHandle<JSFunction> &func, 98 const JSHandle<JSTaggedValue> &proto, bool writable = true); 99 static bool SetFunctionLength(JSThread *thread, const JSHandle<JSFunction> &func, JSTaggedValue length, 100 bool cfg = true); 101 static JSHandle<JSObject> NewJSFunctionPrototype(JSThread *thread, ObjectFactory *factory, 102 const JSHandle<JSFunction> &func); 103 static DynClass *GetOrCreateInitialDynClass(JSThread *thread, const JSHandle<JSFunction> &fun); 104 static JSTaggedValue AccessCallerArgumentsThrowTypeError(EcmaRuntimeCallInfo *argv); 105 static bool IsDynClass(JSTaggedValue object); 106 static JSTaggedValue PrototypeGetter(JSThread *thread, const JSHandle<JSObject> &self); 107 static bool PrototypeSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value, 108 bool mayThrow); 109 static JSTaggedValue NameGetter(JSThread *thread, const JSHandle<JSObject> &self); 110 static bool NameSetter(JSThread *thread, const JSHandle<JSObject> &self, const JSHandle<JSTaggedValue> &value, 111 bool mayThrow); 112 static void SetFunctionNameNoPrefix(JSThread *thread, JSFunction *func, JSTaggedValue name); 113 static JSHandle<DynClass> GetInstanceDynClass(JSThread *thread, JSHandle<JSFunction> constructor, 114 JSHandle<JSTaggedValue> newTarget); 115 GetFunctionPrototype()116 inline JSTaggedValue GetFunctionPrototype() const 117 { 118 ASSERT(HasFunctionPrototype()); 119 JSTaggedValue protoOrDyn = GetProtoOrDynClass(); 120 if (protoOrDyn.IsJSHClass()) { 121 return JSHClass::Cast(protoOrDyn.GetTaggedObject())->GetPrototype(); 122 } 123 124 return protoOrDyn; 125 } 126 SetFunctionPrototype(const JSThread * thread,JSTaggedValue proto)127 inline void SetFunctionPrototype(const JSThread *thread, JSTaggedValue proto) 128 { 129 SetProtoOrDynClass(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 HasInitialDynClass()138 inline bool HasInitialDynClass() const 139 { 140 JSTaggedValue protoOrDyn = GetProtoOrDynClass(); 141 return protoOrDyn.IsJSHClass(); 142 } 143 HasFunctionPrototype()144 inline bool HasFunctionPrototype() const 145 { 146 JSTaggedValue protoOrDyn = GetProtoOrDynClass(); 147 return !protoOrDyn.IsHole(); 148 } 149 GetInitialDynClass()150 inline DynClass *GetInitialDynClass() const 151 { 152 ASSERT(HasInitialDynClass()); 153 JSTaggedValue protoOrDyn = GetProtoOrDynClass(); 154 return reinterpret_cast<DynClass *>(protoOrDyn.GetTaggedObject()); 155 } 156 SetFunctionLength(const JSThread * thread,JSTaggedValue length)157 inline void SetFunctionLength(const JSThread *thread, JSTaggedValue length) 158 { 159 ASSERT(!IsPropertiesDict()); 160 SetPropertyInlinedProps(thread, LENGTH_INLINE_PROPERTY_INDEX, length); 161 } 162 IsBase()163 inline bool IsBase() const 164 { 165 FunctionKind kind = GetFunctionKind(); 166 return kind <= FunctionKind::CLASS_CONSTRUCTOR; 167 } 168 IsDerivedConstructor()169 inline bool IsDerivedConstructor() const 170 { 171 FunctionKind kind = GetFunctionKind(); 172 return kind == FunctionKind::DERIVED_CONSTRUCTOR; 173 } 174 IsArrowFunction(FunctionKind kind)175 inline static bool IsArrowFunction(FunctionKind kind) 176 { 177 return (kind >= FunctionKind::ARROW_FUNCTION) && (kind <= FunctionKind::ASYNC_ARROW_FUNCTION); 178 } 179 IsClassConstructor(FunctionKind kind)180 inline static bool IsClassConstructor(FunctionKind kind) 181 { 182 return (kind == FunctionKind::CLASS_CONSTRUCTOR) || (kind == FunctionKind::DERIVED_CONSTRUCTOR); 183 } 184 IsConstructorKind(FunctionKind kind)185 inline static bool IsConstructorKind(FunctionKind kind) 186 { 187 return (kind >= FunctionKind::BUILTIN_PROXY_CONSTRUCTOR) && (kind <= FunctionKind::DERIVED_CONSTRUCTOR); 188 } 189 IsBuiltinConstructor(FunctionKind kind)190 inline static bool IsBuiltinConstructor(FunctionKind kind) 191 { 192 return kind >= FunctionKind::BUILTIN_PROXY_CONSTRUCTOR && kind <= FunctionKind::BUILTIN_CONSTRUCTOR; 193 } 194 HasPrototype(FunctionKind kind)195 inline static bool HasPrototype(FunctionKind kind) 196 { 197 return kind >= FunctionKind::BUILTIN_CONSTRUCTOR && kind <= FunctionKind::GENERATOR_FUNCTION; 198 } 199 HasAccessor(FunctionKind kind)200 inline static bool HasAccessor(FunctionKind kind) 201 { 202 return kind >= FunctionKind::NORMAL_FUNCTION && kind <= FunctionKind::ASYNC_FUNCTION; 203 } 204 IsClassConstructor()205 inline bool IsClassConstructor() const 206 { 207 return GetClass()->IsClassConstructor(); 208 } 209 SetClassConstructor(bool flag)210 inline void SetClassConstructor(bool flag) 211 { 212 GetClass()->SetClassConstructor(flag); 213 } 214 215 /* -------------- Common API End, Don't change those interface!!! ----------------- */ 216 static void InitializeJSFunction(JSThread *thread, const JSHandle<JSFunction> &func, 217 FunctionKind kind = FunctionKind::NORMAL_FUNCTION, bool strict = true); 218 static JSHClass *GetOrCreateInitialJSHClass(JSThread *thread, const JSHandle<JSFunction> &fun); 219 static JSHandle<JSHClass> GetInstanceJSHClass(JSThread *thread, JSHandle<JSFunction> constructor, 220 JSHandle<JSTaggedValue> newTarget); 221 222 static constexpr size_t PROTO_OR_DYNCLASS_OFFSET = JSFunctionBase::SIZE; 223 ACCESSORS(ProtoOrDynClass, PROTO_OR_DYNCLASS_OFFSET, LEXICAL_ENV_OFFSET) 224 ACCESSORS(LexicalEnv, LEXICAL_ENV_OFFSET, HOME_OBJECT_OFFSET) 225 ACCESSORS(HomeObject, HOME_OBJECT_OFFSET, FUNCTION_EXTRA_INFO_OFFSET) 226 ACCESSORS(FunctionExtraInfo, FUNCTION_EXTRA_INFO_OFFSET, CONSTANT_POOL_OFFSET) 227 ACCESSORS(ConstantPool, CONSTANT_POOL_OFFSET, PROFILE_TYPE_INFO_OFFSET) 228 ACCESSORS(ProfileTypeInfo, PROFILE_TYPE_INFO_OFFSET, BIT_FIELD_OFFSET) 229 ACCESSORS_BIT_FIELD(BitField, BIT_FIELD_OFFSET, LAST_OFFSET) 230 DEFINE_ALIGN_SIZE(LAST_OFFSET); 231 232 // define BitField 233 static constexpr uint32_t FUNCTION_KIND_BITS = 4; 234 static constexpr uint32_t STRICT_BITS = 1; 235 static constexpr uint32_t RESOLVED_BITS = 1; 236 static constexpr uint32_t THIS_MODE_BITS = 2; 237 FIRST_BIT_FIELD(BitField, FunctionKind, FunctionKind, FUNCTION_KIND_BITS) 238 NEXT_BIT_FIELD(BitField, Strict, bool, STRICT_BITS, FunctionKind) 239 NEXT_BIT_FIELD(BitField, Resolved, bool, RESOLVED_BITS, Strict) 240 NEXT_BIT_FIELD(BitField, ThisMode, FunctionMode, THIS_MODE_BITS, Resolved) 241 242 DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunctionBase, PROTO_OR_DYNCLASS_OFFSET, BIT_FIELD_OFFSET) 243 DECL_DUMP() 244 245 private: 246 static JSHandle<JSHClass> GetOrCreateDerivedJSHClass(JSThread *thread, JSHandle<JSFunction> derived, 247 JSHandle<JSFunction> constructor, 248 JSHandle<JSHClass> ctorInitialDynClass); 249 }; 250 251 class JSGeneratorFunction : public JSFunction { 252 public: 253 CAST_CHECK(JSGeneratorFunction, IsGeneratorFunction); 254 255 static constexpr size_t SIZE = JSFunction::SIZE; 256 257 DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, SIZE, SIZE) 258 259 DECL_DUMP() 260 }; 261 262 class JSBoundFunction : public JSFunctionBase { 263 public: 264 CAST_CHECK(JSBoundFunction, IsBoundFunction); 265 266 // 9.4.1.1[[Call]](thisArgument, argumentsList) 267 static JSTaggedValue CallInternal(JSThread *thread, const JSHandle<JSBoundFunction> &func); 268 269 // 9.4.1.2[[Construct]](argumentsList, newTarget) 270 static JSTaggedValue ConstructInternal(JSThread *thread, const JSHandle<JSBoundFunction> &func, 271 const JSHandle<JSTaggedValue> &newTarget); 272 273 static constexpr size_t BOUND_TARGET_OFFSET = JSFunctionBase::SIZE; 274 ACCESSORS(BoundTarget, BOUND_TARGET_OFFSET, BOUND_THIS_OFFSET); 275 ACCESSORS(BoundThis, BOUND_THIS_OFFSET, BOUND_ARGUMENTS_OFFSET); 276 ACCESSORS(BoundArguments, BOUND_ARGUMENTS_OFFSET, SIZE); 277 278 DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunctionBase, BOUND_TARGET_OFFSET, SIZE) 279 280 DECL_DUMP() 281 }; 282 283 class JSProxyRevocFunction : public JSFunction { 284 public: 285 CAST_CHECK(JSProxyRevocFunction, IsProxyRevocFunction); 286 287 static void ProxyRevocFunctions(const JSThread *thread, const JSHandle<JSProxyRevocFunction> &revoker); 288 289 static constexpr size_t REVOCABLE_PROXY_OFFSET = JSFunction::SIZE; 290 ACCESSORS(RevocableProxy, REVOCABLE_PROXY_OFFSET, SIZE); 291 292 DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, REVOCABLE_PROXY_OFFSET, SIZE) 293 294 DECL_DUMP() 295 }; 296 297 // ResolveFunction/RejectFunction 298 class JSPromiseReactionsFunction : public JSFunction { 299 public: 300 CAST_CHECK(JSPromiseReactionsFunction, IsJSPromiseReactionFunction); 301 302 static constexpr size_t PROMISE_OFFSET = JSFunction::SIZE; 303 ACCESSORS(Promise, PROMISE_OFFSET, ALREADY_RESOLVED_OFFSET); 304 ACCESSORS(AlreadyResolved, ALREADY_RESOLVED_OFFSET, SIZE); 305 306 DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, PROMISE_OFFSET, SIZE) 307 308 DECL_DUMP() 309 }; 310 311 // ExecutorFunction 312 class JSPromiseExecutorFunction : public JSFunction { 313 public: 314 CAST_CHECK(JSPromiseExecutorFunction, IsJSPromiseExecutorFunction); 315 316 static constexpr size_t CAPABILITY_OFFSET = JSFunction::SIZE; 317 ACCESSORS(Capability, CAPABILITY_OFFSET, SIZE); 318 319 DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, CAPABILITY_OFFSET, SIZE) 320 321 DECL_DUMP() 322 }; 323 324 class JSPromiseAllResolveElementFunction : public JSFunction { 325 public: 326 CAST_CHECK(JSPromiseAllResolveElementFunction, IsJSPromiseAllResolveElementFunction); 327 328 static constexpr size_t INDEX_OFFSET = JSFunction::SIZE; 329 ACCESSORS(Index, INDEX_OFFSET, VALUES_OFFSET); 330 ACCESSORS(Values, VALUES_OFFSET, CAPABILITIES_OFFSET); 331 ACCESSORS(Capabilities, CAPABILITIES_OFFSET, REMAINING_ELEMENTS_OFFSET); 332 ACCESSORS(RemainingElements, REMAINING_ELEMENTS_OFFSET, ALREADY_CALLED_OFFSET); 333 ACCESSORS(AlreadyCalled, ALREADY_CALLED_OFFSET, SIZE); 334 335 DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, INDEX_OFFSET, SIZE) 336 337 DECL_DUMP() 338 }; 339 340 class JSIntlBoundFunction : public JSFunction { 341 public: 342 CAST_CHECK(JSIntlBoundFunction, IsJSIntlBoundFunction); 343 344 static JSTaggedValue IntlNameGetter(JSThread *thread, const JSHandle<JSObject> &self); 345 346 static constexpr size_t NUMBER_FORMAT_OFFSET = JSFunction::SIZE; 347 348 ACCESSORS(NumberFormat, NUMBER_FORMAT_OFFSET, DATETIME_FORMAT_OFFSET); 349 ACCESSORS(DateTimeFormat, DATETIME_FORMAT_OFFSET, COLLATOR_OFFSET); 350 ACCESSORS(Collator, COLLATOR_OFFSET, SIZE); 351 352 DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, NUMBER_FORMAT_OFFSET, SIZE) 353 DECL_DUMP() 354 }; 355 } // namespace panda::ecmascript 356 357 #endif // ECMASCRIPT_JSFUCNTION_H 358