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_JSPANDAFILE_METHOD_LITERAL_H 17 #define ECMASCRIPT_JSPANDAFILE_METHOD_LITERAL_H 18 19 #include "ecmascript/base/aligned_struct.h" 20 #include "ecmascript/compiler/gate_meta_data.h" 21 #include "ecmascript/js_function_kind.h" 22 #include "ecmascript/js_tagged_value.h" 23 #include "ecmascript/mem/c_string.h" 24 #include "libpandafile/file.h" 25 26 static constexpr uint32_t CALL_TYPE_MASK = 0xF; // 0xF: the last 4 bits are used as callType 27 28 namespace panda::ecmascript { 29 class JSPandaFile; 30 using EntityId = panda_file::File::EntityId; 31 struct PUBLIC_API MethodLiteral : public base::AlignedStruct<sizeof(uint64_t), 32 base::AlignedUint64, 33 base::AlignedPointer, 34 base::AlignedUint64, 35 base::AlignedUint64> { 36 public: 37 static constexpr uint8_t INVALID_IC_SLOT = 0xFFU; 38 static constexpr uint16_t MAX_SLOT_SIZE = 0xFFFFU; 39 40 MethodLiteral(const JSPandaFile *jsPandaFile, EntityId methodId); 41 MethodLiteral() = delete; 42 ~MethodLiteral() = default; 43 MethodLiteral(const MethodLiteral &) = delete; 44 MethodLiteral(MethodLiteral &&) = delete; 45 MethodLiteral &operator=(const MethodLiteral &) = delete; 46 MethodLiteral &operator=(MethodLiteral &&) = delete; 47 48 static constexpr size_t VREGS_ARGS_NUM_BITS = 28; // 28: maximum 268,435,455 49 using HaveThisBit = BitField<bool, 0, 1>; // offset 0 50 using HaveNewTargetBit = HaveThisBit::NextFlag; // offset 1 51 using HaveExtraBit = HaveNewTargetBit::NextFlag; // offset 2 52 using HaveFuncBit = HaveExtraBit::NextFlag; // offset 3 53 using NumVregsBits = HaveFuncBit::NextField<uint32_t, VREGS_ARGS_NUM_BITS>; // offset 4-31 54 using NumArgsBits = NumVregsBits::NextField<uint32_t, VREGS_ARGS_NUM_BITS>; // offset 32-59 55 using IsNativeBit = NumArgsBits::NextFlag; // offset 60 56 using IsAotCodeBit = IsNativeBit::NextFlag; // offset 61 57 using IsFastBuiltinBit = IsAotCodeBit::NextFlag; // offset 62 58 using IsCallNapiBit = IsFastBuiltinBit::NextFlag; // offset 63 59 GetCallFieldMethodLiteral60 uint64_t GetCallField() const 61 { 62 return callField_; 63 } 64 SetNativeBitMethodLiteral65 void SetNativeBit(bool isNative) 66 { 67 callField_ = IsNativeBit::Update(callField_, isNative); 68 } 69 SetAotCodeBitMethodLiteral70 void SetAotCodeBit(bool isCompiled) 71 { 72 callField_ = IsAotCodeBit::Update(callField_, isCompiled); 73 } 74 75 void Initialize(const JSPandaFile *jsPandaFile, uint32_t numVregs, uint32_t numArgs); 76 HaveThisWithCallFieldMethodLiteral77 bool HaveThisWithCallField() const 78 { 79 return HaveThisWithCallField(callField_); 80 } 81 HaveNewTargetWithCallFieldMethodLiteral82 bool HaveNewTargetWithCallField() const 83 { 84 return HaveNewTargetWithCallField(callField_); 85 } 86 HaveExtraWithCallFieldMethodLiteral87 bool HaveExtraWithCallField() const 88 { 89 return HaveExtraWithCallField(callField_); 90 } 91 HaveFuncWithCallFieldMethodLiteral92 bool HaveFuncWithCallField() const 93 { 94 return HaveFuncWithCallField(callField_); 95 } 96 IsNativeWithCallFieldMethodLiteral97 bool IsNativeWithCallField() const 98 { 99 return IsNativeWithCallField(callField_); 100 } 101 IsAotWithCallFieldMethodLiteral102 bool IsAotWithCallField() const 103 { 104 return IsAotWithCallField(callField_); 105 } 106 GetNumArgsWithCallFieldMethodLiteral107 uint32_t GetNumArgsWithCallField() const 108 { 109 return GetNumArgsWithCallField(callField_); 110 } 111 GetNumArgsMethodLiteral112 uint32_t GetNumArgs() const 113 { 114 return GetNumArgsWithCallField() + HaveFuncWithCallField() + 115 HaveNewTargetWithCallField() + HaveThisWithCallField(); 116 } 117 GetNumberVRegsMethodLiteral118 uint32_t GetNumberVRegs() const 119 { 120 return GetNumVregsWithCallField() + GetNumArgs(); 121 } 122 SetNativeBitMethodLiteral123 static uint64_t SetNativeBit(uint64_t callField, bool isNative) 124 { 125 return IsNativeBit::Update(callField, isNative); 126 } 127 SetAotCodeBitMethodLiteral128 static uint64_t SetAotCodeBit(uint64_t callField, bool isCompiled) 129 { 130 return IsAotCodeBit::Update(callField, isCompiled); 131 } 132 HaveThisWithCallFieldMethodLiteral133 static bool HaveThisWithCallField(uint64_t callField) 134 { 135 return HaveThisBit::Decode(callField); 136 } 137 HaveNewTargetWithCallFieldMethodLiteral138 static bool HaveNewTargetWithCallField(uint64_t callField) 139 { 140 return HaveNewTargetBit::Decode(callField); 141 } 142 HaveExtraWithCallFieldMethodLiteral143 static bool HaveExtraWithCallField(uint64_t callField) 144 { 145 return HaveExtraBit::Decode(callField); 146 } 147 HaveFuncWithCallFieldMethodLiteral148 static bool HaveFuncWithCallField(uint64_t callField) 149 { 150 return HaveFuncBit::Decode(callField); 151 } 152 IsNativeWithCallFieldMethodLiteral153 static bool IsNativeWithCallField(uint64_t callField) 154 { 155 return IsNativeBit::Decode(callField); 156 } 157 IsAotWithCallFieldMethodLiteral158 static bool IsAotWithCallField(uint64_t callField) 159 { 160 return IsAotCodeBit::Decode(callField); 161 } 162 OnlyHaveThisWithCallFieldMethodLiteral163 static bool OnlyHaveThisWithCallField(uint64_t callField) 164 { 165 return (callField & CALL_TYPE_MASK) == 1; // 1: the first bit of callFiled is HaveThisBit 166 } 167 OnlyHaveNewTagetAndThisWithCallFieldMethodLiteral168 static bool OnlyHaveNewTagetAndThisWithCallField(uint64_t callField) 169 { 170 return (callField & CALL_TYPE_MASK) == 0b11; // the first two bit of callFiled is `This` and `NewTarget` 171 } 172 GetNumVregsWithCallFieldMethodLiteral173 static uint32_t GetNumVregsWithCallField(uint64_t callField) 174 { 175 return NumVregsBits::Decode(callField); 176 } 177 GetNumVregsWithCallFieldMethodLiteral178 uint32_t GetNumVregsWithCallField() const 179 { 180 return NumVregsBits::Decode(callField_); 181 } 182 GetNumArgsWithCallFieldMethodLiteral183 static uint32_t GetNumArgsWithCallField(uint64_t callField) 184 { 185 return NumArgsBits::Decode(callField); 186 } 187 SetCallNapiMethodLiteral188 static uint64_t SetCallNapi(uint64_t callField, bool isCallNapi) 189 { 190 return IsCallNapiBit::Update(callField, isCallNapi); 191 } 192 IsCallNapiMethodLiteral193 static bool IsCallNapi(uint64_t callField) 194 { 195 return IsCallNapiBit::Decode(callField); 196 } 197 198 static constexpr size_t METHOD_ARGS_NUM_BITS = 16; 199 static constexpr size_t METHOD_ARGS_METHODID_BITS = 32; 200 static constexpr size_t METHOD_SLOT_SIZE_BITS = 16; 201 using HotnessCounterBits = BitField<int16_t, 0, METHOD_ARGS_NUM_BITS>; // offset 0-15 202 using MethodIdBits = HotnessCounterBits::NextField<uint32_t, METHOD_ARGS_METHODID_BITS>; // offset 16-47 203 using SlotSizeBits = MethodIdBits::NextField<uint16_t, METHOD_SLOT_SIZE_BITS>; // offset 48-63 204 205 static constexpr size_t BUILTINID_NUM_BITS = 8; 206 static constexpr size_t FUNCTION_KIND_NUM_BITS = 4; 207 using BuiltinIdBits = BitField<uint8_t, 0, BUILTINID_NUM_BITS>; // offset 0-7 208 using FunctionKindBits = BuiltinIdBits::NextField<FunctionKind, FUNCTION_KIND_NUM_BITS>; // offset 8-11 209 SetHotnessCounterMethodLiteral210 inline NO_THREAD_SANITIZE void SetHotnessCounter(int16_t counter) 211 { 212 literalInfo_ = HotnessCounterBits::Update(literalInfo_, counter); 213 } 214 GetMethodIdMethodLiteral215 EntityId GetMethodId() const 216 { 217 return EntityId(MethodIdBits::Decode(literalInfo_)); 218 } 219 SetMethodIdMethodLiteral220 void SetMethodId(EntityId methodId) 221 { 222 literalInfo_ = MethodIdBits::Update(literalInfo_, methodId.GetOffset()); 223 } 224 GetSlotSizeMethodLiteral225 uint32_t GetSlotSize() const 226 { 227 auto size = SlotSizeBits::Decode(literalInfo_); 228 return size == MAX_SLOT_SIZE ? MAX_SLOT_SIZE + 2 : size; // 2: last maybe two slot 229 } 230 SetSlotSizeMethodLiteral231 void SetSlotSize(uint32_t size) 232 { 233 size = size > MAX_SLOT_SIZE ? MAX_SLOT_SIZE: size; 234 literalInfo_ = SlotSizeBits::Update(literalInfo_, size); 235 } 236 UpdateSlotSizeWith8BitMethodLiteral237 uint8_t UpdateSlotSizeWith8Bit(uint16_t size) 238 { 239 uint16_t start = SlotSizeBits::Decode(literalInfo_); 240 uint32_t end = start + size; 241 // ic overflow 242 if (end >= INVALID_IC_SLOT) { 243 if (start < INVALID_IC_SLOT + 1) { 244 literalInfo_ = SlotSizeBits::Update(literalInfo_, INVALID_IC_SLOT + 1); 245 } 246 return INVALID_IC_SLOT; 247 } 248 literalInfo_ = SlotSizeBits::Update(literalInfo_, static_cast<uint8_t>(end)); 249 return start; 250 } 251 SetFunctionKindMethodLiteral252 void SetFunctionKind(FunctionKind kind) 253 { 254 extraLiteralInfo_ = FunctionKindBits::Update(extraLiteralInfo_, kind); 255 } 256 GetFunctionKindMethodLiteral257 FunctionKind GetFunctionKind() const 258 { 259 return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo_)); 260 } 261 GetHotnessCounterMethodLiteral262 static inline int16_t GetHotnessCounter(uint64_t literalInfo) 263 { 264 return HotnessCounterBits::Decode(literalInfo); 265 } 266 SetHotnessCounterMethodLiteral267 static uint64_t SetHotnessCounter(uint64_t literalInfo, int16_t counter) 268 { 269 return HotnessCounterBits::Update(literalInfo, counter); 270 } 271 SetFunctionKindMethodLiteral272 static uint64_t SetFunctionKind(uint64_t extraLiteralInfo, FunctionKind kind) 273 { 274 return FunctionKindBits::Update(extraLiteralInfo, kind); 275 } 276 GetFunctionKindMethodLiteral277 static FunctionKind GetFunctionKind(uint64_t extraLiteralInfo) 278 { 279 return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo)); 280 } 281 GetMethodIdMethodLiteral282 static EntityId GetMethodId(uint64_t literalInfo) 283 { 284 return EntityId(MethodIdBits::Decode(literalInfo)); 285 } 286 GetSlotSizeMethodLiteral287 static uint16_t GetSlotSize(uint64_t literalInfo) 288 { 289 return SlotSizeBits::Decode(literalInfo); 290 } 291 292 static uint32_t PUBLIC_API GetNumVregs(const JSPandaFile *jsPandaFile, const MethodLiteral *methodLiteral); 293 static const char * PUBLIC_API GetMethodName(const JSPandaFile *jsPandaFile, EntityId methodId); 294 static std::string PUBLIC_API ParseFunctionName(const JSPandaFile *jsPandaFile, EntityId methodId); 295 static uint32_t GetCodeSize(const JSPandaFile *jsPandaFile, EntityId methodId); 296 static CString GetRecordName(const JSPandaFile *jsPandaFile, EntityId methodId); 297 GetBytecodeArrayMethodLiteral298 const uint8_t *GetBytecodeArray() const 299 { 300 return reinterpret_cast<const uint8_t *>(nativePointerOrBytecodeArray_); 301 } 302 GetNativePointerMethodLiteral303 const void* GetNativePointer() const 304 { 305 return nativePointerOrBytecodeArray_; 306 } 307 GetLiteralInfoMethodLiteral308 uint64_t GetLiteralInfo() const 309 { 310 return literalInfo_; 311 } 312 GetExtraLiteralInfoMethodLiteral313 uint64_t GetExtraLiteralInfo() const 314 { 315 return extraLiteralInfo_; 316 } 317 318 private: 319 enum class Index : size_t { 320 CALL_FIELD_INDEX = 0, 321 NATIVE_POINTER_OR_BYTECODE_ARRAY_INDEX, 322 LITERAL_INFO_INDEX, 323 EXTRA_LITERAL_INFO_INDEX, 324 NUM_OF_MEMBERS 325 }; 326 static_assert(static_cast<size_t>(Index::NUM_OF_MEMBERS) == NumOfTypes); 327 328 static panda_file::File::StringData GetName(const JSPandaFile *jsPandaFile, EntityId methodId); 329 330 alignas(EAS) uint64_t callField_ {0ULL}; 331 // Native method decides this filed is NativePointer or BytecodeArray pointer. 332 alignas(EAS) const void *nativePointerOrBytecodeArray_ {nullptr}; 333 // hotnessCounter, methodId and slotSize are encoded in literalInfo_. 334 alignas(EAS) uint64_t literalInfo_ {0ULL}; 335 // BuiltinId, FunctionKind are encoded in extraLiteralInfo_. 336 alignas(EAS) uint64_t extraLiteralInfo_ {0ULL}; 337 }; 338 STATIC_ASSERT_EQ_ARCH(sizeof(MethodLiteral), MethodLiteral::SizeArch32, MethodLiteral::SizeArch64); 339 } // namespace panda::ecmascript 340 341 #endif // ECMASCRIPT_JSPANDAFILE_METHOD_LITERAL_H 342