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 using StringData = panda_file::File::StringData; 32 struct PUBLIC_API MethodLiteral : public base::AlignedStruct<sizeof(uint64_t), 33 base::AlignedUint64, 34 base::AlignedPointer, 35 base::AlignedUint64, 36 base::AlignedUint64> { 37 public: 38 static constexpr uint8_t INVALID_IC_SLOT = 0xFFU; 39 static constexpr uint16_t MAX_SLOT_SIZE = 0xFFFFU; 40 41 explicit MethodLiteral(EntityId methodId); 42 MethodLiteral() = delete; 43 ~MethodLiteral() = default; 44 45 NO_COPY_SEMANTIC(MethodLiteral); 46 NO_MOVE_SEMANTIC(MethodLiteral); 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 IsFastCallBit = 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); 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 SetIsFastCallMethodLiteral188 static uint64_t SetIsFastCall(uint64_t callField, bool isFastCall) 189 { 190 return IsFastCallBit::Update(callField, isFastCall); 191 } 192 SetIsFastCallMethodLiteral193 void SetIsFastCall(bool isFastCall) 194 { 195 callField_ = IsFastCallBit::Update(callField_, isFastCall); 196 } 197 IsFastCallMethodLiteral198 static bool IsFastCall(uint64_t callField) 199 { 200 return IsFastCallBit::Decode(callField); 201 } 202 IsFastCallMethodLiteral203 bool IsFastCall() const 204 { 205 return IsFastCallBit::Decode(callField_); 206 } 207 208 static constexpr size_t METHOD_ARGS_NUM_BITS = 16; 209 static constexpr size_t METHOD_ARGS_METHODID_BITS = 32; 210 static constexpr size_t METHOD_SLOT_SIZE_BITS = 16; 211 using HotnessCounterBits = BitField<int16_t, 0, METHOD_ARGS_NUM_BITS>; // offset 0-15 212 using MethodIdBits = HotnessCounterBits::NextField<uint32_t, METHOD_ARGS_METHODID_BITS>; // offset 16-47 213 using SlotSizeBits = MethodIdBits::NextField<uint16_t, METHOD_SLOT_SIZE_BITS>; // offset 48-63 214 215 static constexpr size_t BUILTINID_NUM_BITS = 8; 216 static constexpr size_t FUNCTION_KIND_NUM_BITS = 4; 217 using BuiltinIdBits = BitField<uint8_t, 0, BUILTINID_NUM_BITS>; // offset 0-7 218 using FunctionKindBits = BuiltinIdBits::NextField<FunctionKind, FUNCTION_KIND_NUM_BITS>; // offset 8-11 219 using IsNoGCBit = FunctionKindBits::NextFlag; // offset 12 220 SetHotnessCounterMethodLiteral221 inline NO_THREAD_SANITIZE void SetHotnessCounter(int16_t counter) 222 { 223 literalInfo_ = HotnessCounterBits::Update(literalInfo_, counter); 224 } 225 GetMethodIdMethodLiteral226 EntityId GetMethodId() const 227 { 228 return EntityId(MethodIdBits::Decode(literalInfo_)); 229 } 230 GetSlotSizeMethodLiteral231 uint32_t GetSlotSize() const 232 { 233 auto size = SlotSizeBits::Decode(literalInfo_); 234 return size == MAX_SLOT_SIZE ? MAX_SLOT_SIZE + 2 : size; // 2: last maybe two slot 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 SetNoGCBitMethodLiteral257 void SetNoGCBit(bool isNoGC) 258 { 259 extraLiteralInfo_ = IsNoGCBit::Update(extraLiteralInfo_, isNoGC); 260 } 261 IsNoGCMethodLiteral262 bool IsNoGC() const 263 { 264 return IsNoGCBit::Decode(extraLiteralInfo_); 265 } 266 GetFunctionKindMethodLiteral267 FunctionKind GetFunctionKind() const 268 { 269 return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo_)); 270 } 271 IsClassConstructorMethodLiteral272 inline bool IsClassConstructor() const 273 { 274 return GetFunctionKind() == FunctionKind::CLASS_CONSTRUCTOR; 275 } 276 GetHotnessCounterMethodLiteral277 static inline int16_t GetHotnessCounter(uint64_t literalInfo) 278 { 279 return HotnessCounterBits::Decode(literalInfo); 280 } 281 SetHotnessCounterMethodLiteral282 static uint64_t SetHotnessCounter(uint64_t literalInfo, int16_t counter) 283 { 284 return HotnessCounterBits::Update(literalInfo, counter); 285 } 286 SetFunctionKindMethodLiteral287 static uint64_t SetFunctionKind(uint64_t extraLiteralInfo, FunctionKind kind) 288 { 289 return FunctionKindBits::Update(extraLiteralInfo, kind); 290 } 291 GetFunctionKindMethodLiteral292 static FunctionKind GetFunctionKind(uint64_t extraLiteralInfo) 293 { 294 return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo)); 295 } 296 GetMethodIdMethodLiteral297 static EntityId GetMethodId(uint64_t literalInfo) 298 { 299 return EntityId(MethodIdBits::Decode(literalInfo)); 300 } 301 GetSlotSizeMethodLiteral302 static uint16_t GetSlotSize(uint64_t literalInfo) 303 { 304 return SlotSizeBits::Decode(literalInfo); 305 } 306 307 static const char PUBLIC_API *GetMethodName(const JSPandaFile *jsPandaFile, EntityId methodId); 308 static std::string PUBLIC_API ParseFunctionName(const JSPandaFile *jsPandaFile, EntityId methodId); 309 static uint32_t GetCodeSize(const JSPandaFile *jsPandaFile, EntityId methodId); 310 static CString GetRecordName(const JSPandaFile *jsPandaFile, EntityId methodId); 311 static const char PUBLIC_API *GetRecordNameWithSymbol(const JSPandaFile *jsPandaFile, EntityId methodId); 312 GetBytecodeArrayMethodLiteral313 const uint8_t *GetBytecodeArray() const 314 { 315 return reinterpret_cast<const uint8_t *>(nativePointerOrBytecodeArray_); 316 } 317 GetNativePointerMethodLiteral318 const void* GetNativePointer() const 319 { 320 return nativePointerOrBytecodeArray_; 321 } 322 GetLiteralInfoMethodLiteral323 uint64_t GetLiteralInfo() const 324 { 325 return literalInfo_; 326 } 327 GetExtraLiteralInfoMethodLiteral328 uint64_t GetExtraLiteralInfo() const 329 { 330 return extraLiteralInfo_; 331 } 332 333 private: 334 enum class Index : size_t { 335 CALL_FIELD_INDEX = 0, 336 NATIVE_POINTER_OR_BYTECODE_ARRAY_INDEX, 337 LITERAL_INFO_INDEX, 338 EXTRA_LITERAL_INFO_INDEX, 339 NUM_OF_MEMBERS 340 }; 341 static_assert(static_cast<size_t>(Index::NUM_OF_MEMBERS) == NumOfTypes); 342 SetMethodIdMethodLiteral343 void SetMethodId(EntityId methodId) 344 { 345 literalInfo_ = MethodIdBits::Update(literalInfo_, methodId.GetOffset()); 346 } 347 SetSlotSizeMethodLiteral348 void SetSlotSize(uint32_t size) 349 { 350 size = size > MAX_SLOT_SIZE ? MAX_SLOT_SIZE : size; 351 literalInfo_ = SlotSizeBits::Update(literalInfo_, size); 352 } 353 354 alignas(EAS) uint64_t callField_ {0ULL}; 355 // Native method decides this filed is NativePointer or BytecodeArray pointer. 356 alignas(EAS) const void *nativePointerOrBytecodeArray_ {nullptr}; 357 // hotnessCounter, methodId and slotSize are encoded in literalInfo_. 358 alignas(EAS) uint64_t literalInfo_ {0ULL}; 359 // BuiltinId, FunctionKind are encoded in extraLiteralInfo_. 360 alignas(EAS) uint64_t extraLiteralInfo_ {0ULL}; 361 }; 362 STATIC_ASSERT_EQ_ARCH(sizeof(MethodLiteral), MethodLiteral::SizeArch32, MethodLiteral::SizeArch64); 363 } // namespace panda::ecmascript 364 365 #endif // ECMASCRIPT_JSPANDAFILE_METHOD_LITERAL_H 366