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