1 /* 2 * Copyright (c) 2022-2024 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_METHOD_H 17 #define ECMASCRIPT_METHOD_H 18 19 #include "ecmascript/compiler/deopt_type.h" 20 #include "ecmascript/ecma_macros.h" 21 #include "ecmascript/jspandafile/method_literal.h" 22 #include "ecmascript/js_tagged_value.h" 23 #include "ecmascript/mem/barriers.h" 24 #include "ecmascript/mem/c_string.h" 25 #include "ecmascript/mem/visitor.h" 26 27 #include "libpandafile/file.h" 28 29 namespace panda::ecmascript { 30 class JSPandaFile; 31 struct Reference; 32 using EntityId = panda_file::File::EntityId; 33 class Method : public TaggedObject { 34 public: 35 CAST_CHECK(Method, IsMethod); 36 SetNumArgsWithCallField(uint64_t callField, uint32_t numargs)37 uint64_t SetNumArgsWithCallField(uint64_t callField, uint32_t numargs) 38 { 39 return NumArgsBits::Update(callField, numargs); 40 } 41 SetNativeBit(uint64_t callField, bool isNative)42 uint64_t SetNativeBit(uint64_t callField, bool isNative) 43 { 44 return IsNativeBit::Update(callField, isNative); 45 } 46 SetAotCodeBit(uint64_t callField, bool isCompiled)47 uint64_t SetAotCodeBit(uint64_t callField, bool isCompiled) 48 { 49 return IsAotCodeBit::Update(callField, isCompiled); 50 } 51 SetFastBuiltinBit(uint64_t callField, bool isFastBuiltin)52 uint64_t SetFastBuiltinBit(uint64_t callField, bool isFastBuiltin) 53 { 54 return IsFastBuiltinBit::Update(callField, isFastBuiltin); 55 } 56 HaveThisWithCallField(uint64_t callField)57 static bool HaveThisWithCallField(uint64_t callField) 58 { 59 return HaveThisBit::Decode(callField); 60 } 61 HaveNewTargetWithCallField(uint64_t callField)62 static bool HaveNewTargetWithCallField(uint64_t callField) 63 { 64 return HaveNewTargetBit::Decode(callField); 65 } 66 HaveExtraWithCallField(uint64_t callField)67 bool HaveExtraWithCallField(uint64_t callField) 68 { 69 return HaveExtraBit::Decode(callField); 70 } 71 HaveFuncWithCallField(uint64_t callField)72 static bool HaveFuncWithCallField(uint64_t callField) 73 { 74 return HaveFuncBit::Decode(callField); 75 } 76 IsNativeWithCallField(uint64_t callField) const77 bool IsNativeWithCallField(uint64_t callField) const 78 { 79 return IsNativeBit::Decode(callField); 80 } 81 OnlyHaveThisWithCallField(uint64_t callField) const82 bool OnlyHaveThisWithCallField(uint64_t callField) const 83 { 84 return (callField & CALL_TYPE_MASK) == 1; // 1: the first bit of callFiled is HaveThisBit 85 } 86 OnlyHaveNewTagetAndThisWithCallField(uint64_t callField) const87 bool OnlyHaveNewTagetAndThisWithCallField(uint64_t callField) const 88 { 89 return (callField & CALL_TYPE_MASK) == 0b11; // the first two bit of callFiled is `This` and `NewTarget` 90 } 91 GetNumArgsWithCallField(uint64_t callField)92 static uint32_t GetNumArgsWithCallField(uint64_t callField) 93 { 94 return NumArgsBits::Decode(callField); 95 } 96 SetCallNapi(uint64_t extraLiteralInfo, bool isCallNapi)97 static uint64_t SetCallNapi(uint64_t extraLiteralInfo, bool isCallNapi) 98 { 99 return IsCallNapiBit::Update(extraLiteralInfo, isCallNapi); 100 } 101 IsCallNapi(uint64_t extraLiteralInfo)102 static bool IsCallNapi(uint64_t extraLiteralInfo) 103 { 104 return IsCallNapiBit::Decode(extraLiteralInfo); 105 } 106 SetIsFastCall(uint64_t callField, bool isFastCall)107 static uint64_t SetIsFastCall(uint64_t callField, bool isFastCall) 108 { 109 return IsFastCallBit::Update(callField, isFastCall); 110 } 111 IsFastCall(uint64_t callField)112 static bool IsFastCall(uint64_t callField) 113 { 114 return IsFastCallBit::Decode(callField); 115 } 116 SetNumArgsWithCallField(uint32_t numargs)117 void SetNumArgsWithCallField(uint32_t numargs) 118 { 119 uint64_t callField = GetCallField(); 120 uint64_t newValue = SetNumArgsWithCallField(callField, numargs); 121 SetCallField(newValue); 122 } 123 SetNativeBit(bool isNative)124 void SetNativeBit(bool isNative) 125 { 126 uint64_t callField = GetCallField(); 127 uint64_t newValue = SetNativeBit(callField, isNative); 128 SetCallField(newValue); 129 } 130 SetAotCodeBit(bool isCompiled)131 void SetAotCodeBit(bool isCompiled) 132 { 133 uint64_t callField = AtomicGetCallField(); 134 uint64_t newValue = SetAotCodeBit(callField, isCompiled); 135 AtomicSetCallField(newValue); 136 } 137 SetFastBuiltinBit(bool isFastBuiltin)138 void SetFastBuiltinBit(bool isFastBuiltin) 139 { 140 uint64_t callField = GetCallField(); 141 uint64_t newValue = SetFastBuiltinBit(callField, isFastBuiltin); 142 SetCallField(newValue); 143 } 144 HaveThisWithCallField() const145 bool HaveThisWithCallField() const 146 { 147 uint64_t callField = GetCallField(); 148 return HaveThisWithCallField(callField); 149 } 150 HaveNewTargetWithCallField() const151 bool HaveNewTargetWithCallField() const 152 { 153 uint64_t callField = GetCallField(); 154 return HaveNewTargetWithCallField(callField); 155 } 156 HaveExtraWithCallField()157 bool HaveExtraWithCallField() 158 { 159 uint64_t callField = GetCallField(); 160 return HaveExtraWithCallField(callField); 161 } 162 HaveFuncWithCallField() const163 bool HaveFuncWithCallField() const 164 { 165 uint64_t callField = GetCallField(); 166 return HaveFuncWithCallField(callField); 167 } 168 IsNativeWithCallField() const169 bool IsNativeWithCallField() const 170 { 171 uint64_t callField = GetCallField(); 172 return IsNativeWithCallField(callField); 173 } 174 IsAotWithCallField() const175 bool IsAotWithCallField() const 176 { 177 uint64_t callField = AtomicGetCallField(); 178 return MethodLiteral::IsAotWithCallField(callField); 179 } 180 181 bool IsDeoptimized() const; 182 OnlyHaveThisWithCallField() const183 bool OnlyHaveThisWithCallField() const 184 { 185 uint64_t callField = GetCallField(); 186 return MethodLiteral::OnlyHaveThisWithCallField(callField); 187 } 188 OnlyHaveNewTagetAndThisWithCallField() const189 bool OnlyHaveNewTagetAndThisWithCallField() const 190 { 191 uint64_t callField = GetCallField(); 192 return MethodLiteral::OnlyHaveNewTagetAndThisWithCallField(callField); 193 } 194 GetNumVregsWithCallField(uint64_t callField)195 static uint32_t GetNumVregsWithCallField(uint64_t callField) 196 { 197 return NumVregsBits::Decode(callField); 198 } 199 GetNumVregsWithCallField() const200 uint32_t GetNumVregsWithCallField() const 201 { 202 uint64_t callField = GetCallField(); 203 return GetNumVregsWithCallField(callField); 204 } 205 GetNumArgsWithCallField() const206 uint32_t GetNumArgsWithCallField() const 207 { 208 uint64_t callField = GetCallField(); 209 return MethodLiteral::GetNumArgsWithCallField(callField); 210 } 211 GetNumArgs() const212 uint32_t GetNumArgs() const 213 { 214 return GetNumArgsWithCallField() + GetNumRevervedArgs(); 215 } 216 GetNumRevervedArgs() const217 uint32_t GetNumRevervedArgs() const 218 { 219 return HaveFuncWithCallField() + 220 HaveNewTargetWithCallField() + HaveThisWithCallField(); 221 } 222 GetNumberVRegs() const223 uint32_t GetNumberVRegs() const 224 { 225 return GetNumVregsWithCallField() + GetNumArgs(); 226 } 227 GetHotnessCounter() const228 inline int16_t GetHotnessCounter() const 229 { 230 uint64_t literalInfo = GetLiteralInfo(); 231 return MethodLiteral::GetHotnessCounter(literalInfo); 232 } 233 SetHotnessCounter(int16_t counter)234 inline NO_THREAD_SANITIZE void SetHotnessCounter(int16_t counter) 235 { 236 uint64_t literalInfo = GetLiteralInfo(); 237 uint64_t newValue = MethodLiteral::SetHotnessCounter(literalInfo, counter); 238 SetLiteralInfo(newValue); 239 } 240 GetMethodId() const241 EntityId GetMethodId() const 242 { 243 uint64_t literalInfo = GetLiteralInfo(); 244 return MethodLiteral::GetMethodId(literalInfo); 245 } 246 GetSlotSize() const247 uint32_t GetSlotSize() const 248 { 249 uint64_t literalInfo = GetLiteralInfo(); 250 return MethodLiteral::GetSlotSize(literalInfo); 251 } 252 GetBuiltinId(uint64_t literalInfo) const253 uint8_t GetBuiltinId(uint64_t literalInfo) const 254 { 255 return BuiltinIdBits::Decode(literalInfo); 256 } 257 SetBuiltinId(uint64_t literalInfo, uint8_t id)258 uint64_t SetBuiltinId(uint64_t literalInfo, uint8_t id) 259 { 260 return BuiltinIdBits::Update(literalInfo, id); 261 } 262 SetFunctionKind(uint64_t extraLiteralInfo, FunctionKind kind)263 uint64_t SetFunctionKind(uint64_t extraLiteralInfo, FunctionKind kind) 264 { 265 return FunctionKindBits::Update(extraLiteralInfo, kind); 266 } 267 GetFunctionKind(uint64_t extraLiteralInfo) const268 FunctionKind GetFunctionKind(uint64_t extraLiteralInfo) const 269 { 270 return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo)); 271 } 272 SetDeoptThreshold(uint64_t literalInfo, uint8_t count)273 uint64_t SetDeoptThreshold(uint64_t literalInfo, uint8_t count) 274 { 275 return DeoptCountBits::Update(literalInfo, count); 276 } 277 GetDeoptThreshold(uint64_t literalInfo) const278 uint16_t GetDeoptThreshold(uint64_t literalInfo) const 279 { 280 return DeoptCountBits::Decode(literalInfo); 281 } 282 SetDeoptType(uint64_t extraLiteralInfo, kungfu::DeoptType type)283 uint64_t SetDeoptType(uint64_t extraLiteralInfo, kungfu::DeoptType type) 284 { 285 return DeoptTypeBits::Update(extraLiteralInfo, type); 286 } 287 SetIsSendable(uint64_t extraLiteralInfo, bool isSendable)288 uint64_t SetIsSendable(uint64_t extraLiteralInfo, bool isSendable) 289 { 290 return IsSharedBit::Update(extraLiteralInfo, isSendable); 291 } 292 SetFpDelta(uint64_t extraLitearalInfo, int32_t delta)293 uint64_t SetFpDelta(uint64_t extraLitearalInfo, int32_t delta) 294 { 295 return FpDeltaBits::Update(extraLitearalInfo, delta); 296 } 297 GetFpDelta(uint64_t extraLiteralInfo) const298 int32_t GetFpDelta(uint64_t extraLiteralInfo) const 299 { 300 return static_cast<int32_t>(FpDeltaBits::Decode(extraLiteralInfo)); 301 } 302 SetDeoptType(kungfu::DeoptType type)303 void SetDeoptType(kungfu::DeoptType type) 304 { 305 uint64_t extraLiteralInfo = GetExtraLiteralInfo(); 306 uint64_t newValue = SetDeoptType(extraLiteralInfo, type); 307 SetExtraLiteralInfo(newValue); 308 } 309 GetDeoptType(uint64_t extraLiteralInfo) const310 kungfu::DeoptType GetDeoptType(uint64_t extraLiteralInfo) const 311 { 312 return static_cast<kungfu::DeoptType>(DeoptTypeBits::Decode(extraLiteralInfo)); 313 } 314 GetDeoptType() const315 kungfu::DeoptType GetDeoptType() const 316 { 317 uint64_t extraLiteralInfo = GetExtraLiteralInfo(); 318 return GetDeoptType(extraLiteralInfo); 319 } 320 SetFunctionKind(FunctionKind kind)321 void SetFunctionKind(FunctionKind kind) 322 { 323 uint64_t extraLiteralInfo = AtomicGetExtraLiteralInfo(); 324 uint64_t newValue = SetFunctionKind(extraLiteralInfo, kind); 325 AtomicSetExtraLiteralInfo(newValue); 326 } 327 GetFunctionKind() const328 FunctionKind GetFunctionKind() const 329 { 330 uint64_t extraLiteralInfo = AtomicGetExtraLiteralInfo(); 331 return GetFunctionKind(extraLiteralInfo); 332 } 333 GetBuiltinId() const334 uint8_t GetBuiltinId() const 335 { 336 uint64_t extraLiteralInfo = GetExtraLiteralInfo(); 337 return GetBuiltinId(extraLiteralInfo); 338 } 339 SetIsFastCall(bool isFastCall)340 void SetIsFastCall(bool isFastCall) 341 { 342 uint64_t callFiled = GetCallField(); 343 uint64_t newValue = SetIsFastCall(callFiled, isFastCall); 344 SetCallField(newValue); 345 } 346 IsFastCall() const347 bool IsFastCall() const 348 { 349 uint64_t callFiled = GetCallField(); 350 return IsFastCall(callFiled); 351 } 352 SetCallNapi(bool isCallNapi)353 void SetCallNapi(bool isCallNapi) 354 { 355 uint64_t extraLiteralInfo = GetExtraLiteralInfo(); 356 uint64_t newValue = SetCallNapi(extraLiteralInfo, isCallNapi); 357 SetExtraLiteralInfo(newValue); 358 } 359 IsCallNapi() const360 bool IsCallNapi() const 361 { 362 uint64_t extraLiteralInfo = GetExtraLiteralInfo(); 363 return IsCallNapi(extraLiteralInfo); 364 } 365 SetBuiltinId(uint8_t id)366 void SetBuiltinId(uint8_t id) 367 { 368 uint64_t extraLiteralInfo = GetExtraLiteralInfo(); 369 uint64_t newValue = SetBuiltinId(extraLiteralInfo, id); 370 SetExtraLiteralInfo(newValue); 371 } 372 SetDeoptThreshold(uint8_t count)373 void SetDeoptThreshold(uint8_t count) 374 { 375 uint64_t extraLiteralInfo = GetExtraLiteralInfo(); 376 uint64_t newValue = SetDeoptThreshold(extraLiteralInfo, count); 377 SetExtraLiteralInfo(newValue); 378 } 379 GetDeoptThreshold() const380 uint16_t GetDeoptThreshold() const 381 { 382 uint64_t extraLiteralInfo = GetExtraLiteralInfo(); 383 return GetDeoptThreshold(extraLiteralInfo); 384 } 385 SetFpDelta(int32_t delta)386 void SetFpDelta(int32_t delta) 387 { 388 uint64_t extraLiteralInfo = GetExtraLiteralInfo(); 389 uint64_t newValue = SetFpDelta(extraLiteralInfo, delta); 390 SetExtraLiteralInfo(newValue); 391 } 392 GetFpDelta() const393 int32_t GetFpDelta() const 394 { 395 uint64_t extraLiteralInfo = GetExtraLiteralInfo(); 396 return GetFpDelta(extraLiteralInfo); 397 } 398 GetNativePointer() const399 const void* GetNativePointer() const 400 { 401 return GetNativePointerOrBytecodeArray(); 402 } 403 SetNativePointer(void *nativePointer)404 void SetNativePointer(void *nativePointer) 405 { 406 SetNativePointerOrBytecodeArray(nativePointer); 407 } 408 GetBytecodeArray() const409 const uint8_t *GetBytecodeArray() const 410 { 411 return reinterpret_cast<const uint8_t *>(GetNativePointerOrBytecodeArray()); 412 } 413 IsSendableMethod() const414 bool IsSendableMethod() const 415 { 416 uint64_t extraLiteralInfo = GetExtraLiteralInfo(); 417 return IsSharedBit::Decode(extraLiteralInfo); 418 } 419 SetIsSendable(bool isSendable)420 void SetIsSendable(bool isSendable) 421 { 422 uint64_t extraLiteralInfo = GetExtraLiteralInfo(); 423 uint64_t newValue = SetIsSendable(extraLiteralInfo, isSendable); 424 SetExtraLiteralInfo(newValue); 425 } 426 427 // add for AOT 428 void SetCodeEntryAndMarkAOTWhenBinding(uintptr_t codeEntry); 429 430 void ClearAOTStatusWhenDeopt(uintptr_t entry); 431 432 void ClearAOTFlagsWhenInit(); 433 434 void InitInterpreterStatusForCompiledMethod(const JSThread *thread); 435 436 void SetCompiledFuncEntry(uintptr_t codeEntry, bool isFastCall); 437 Size()438 static constexpr size_t Size() 439 { 440 return sizeof(Method); 441 } 442 443 const JSPandaFile *PUBLIC_API GetJSPandaFile() const; 444 uint32_t PUBLIC_API GetCodeSize() const; 445 MethodLiteral *PUBLIC_API GetMethodLiteral() const; 446 447 const char *PUBLIC_API GetMethodName() const; 448 const char *PUBLIC_API GetMethodName(const JSPandaFile *file) const; 449 std::string PUBLIC_API ParseFunctionName() const; 450 std::pair<std::string_view, bool> PUBLIC_API ParseFunctionNameView() const; 451 const CString PUBLIC_API GetRecordNameStr() const; 452 453 uint32_t FindCatchBlock(uint32_t pc) const; 454 bool HasCatchBlock() const; 455 456 /* callfield */ 457 static constexpr size_t VREGS_ARGS_NUM_BITS = 28; // 28: maximum 268,435,455 458 static constexpr uint64_t AOT_FASTCALL_BITS = 0x5; // 0x5LU: aot and fastcall bit field 459 using HaveThisBit = BitField<bool, 0, 1>; // offset 0 460 using HaveNewTargetBit = HaveThisBit::NextFlag; // offset 1 461 using HaveExtraBit = HaveNewTargetBit::NextFlag; // offset 2 462 using HaveFuncBit = HaveExtraBit::NextFlag; // offset 3 463 using NumVregsBits = HaveFuncBit::NextField<uint32_t, VREGS_ARGS_NUM_BITS>; // offset 4-31 464 using NumArgsBits = NumVregsBits::NextField<uint32_t, VREGS_ARGS_NUM_BITS>; // offset 32-59 465 using IsNativeBit = NumArgsBits::NextFlag; // offset 60 466 using IsAotCodeBit = IsNativeBit::NextFlag; // offset 61 467 using IsFastBuiltinBit = IsAotCodeBit::NextFlag; // offset 62 468 using IsFastCallBit = IsFastBuiltinBit::NextFlag; // offset 63 469 470 /* ExtraLiteralInfo */ 471 static constexpr size_t BUILTINID_NUM_BITS = 8; 472 static constexpr size_t FUNCTION_KIND_NUM_BITS = 4; 473 static constexpr size_t DEOPT_THRESHOLD_BITS = 8; 474 static constexpr size_t DEOPTTYPE_NUM_BITS = 8; 475 static constexpr size_t FP_DELTA_BITS = 32; 476 using BuiltinIdBits = BitField<uint8_t, 0, BUILTINID_NUM_BITS>; // offset 0-7 477 using FunctionKindBits = BuiltinIdBits::NextField<FunctionKind, FUNCTION_KIND_NUM_BITS>; // offset 8-11 478 using DeoptCountBits = FunctionKindBits::NextField<uint8_t, DEOPT_THRESHOLD_BITS>; // offset 12-19 479 using DeoptTypeBits = DeoptCountBits::NextField<kungfu::DeoptType, DEOPTTYPE_NUM_BITS>; // offset 20-27 480 using IsCallNapiBit = DeoptTypeBits::NextFlag; // offset 28 481 using IsJitCompiledCodeBit = IsCallNapiBit::NextFlag; // offset 29 482 using IsSharedBit = IsJitCompiledCodeBit::NextFlag; // offset 30 483 using FpDeltaBits = IsSharedBit::NextField<int32_t, FP_DELTA_BITS>; // offset 31-62 484 485 static constexpr size_t CONSTANT_POOL_OFFSET = TaggedObjectSize(); 486 ACCESSORS(ConstantPool, CONSTANT_POOL_OFFSET, CALL_FIELD_OFFSET) 487 ACCESSORS_PRIMITIVE_FIELD_HAS_ATOMIC_INTERFACE(CallField, uint64_t, CALL_FIELD_OFFSET, 488 NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET) 489 // Native method decides this filed is NativePointer or BytecodeArray pointer. 490 ACCESSORS_NATIVE_FIELD( 491 NativePointerOrBytecodeArray, void, NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET, CODEENTRY_LITERAL_OFFSET) 492 ACCESSORS_PRIMITIVE_FIELD(CodeEntryOrLiteral, uintptr_t, CODEENTRY_LITERAL_OFFSET, LITERAL_INFO_OFFSET) 493 // hotness counter is encoded in a js method field, the first uint16_t in a uint64_t. 494 ACCESSORS_PRIMITIVE_FIELD(LiteralInfo, uint64_t, LITERAL_INFO_OFFSET, EXTRA_LITERAL_INFO_OFFSET) 495 ACCESSORS_PRIMITIVE_FIELD_HAS_ATOMIC_INTERFACE(ExtraLiteralInfo, uint64_t, EXTRA_LITERAL_INFO_OFFSET, LAST_OFFSET) 496 DEFINE_ALIGN_SIZE(LAST_OFFSET); 497 498 DECL_VISIT_OBJECT(CONSTANT_POOL_OFFSET, CALL_FIELD_OFFSET); 499 500 DECL_DUMP() 501 502 private: 503 static JSHandle<Method> Create(JSThread *thread, const JSPandaFile *jsPandaFile, MethodLiteral *methodLiteral); 504 505 friend class ObjectFactory; 506 }; 507 } // namespace panda::ecmascript 508 509 #endif // ECMASCRIPT_METHOD_H 510