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