• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_JSPANDAFILE_METHOD_LITERAL_H
17 #define ECMASCRIPT_JSPANDAFILE_METHOD_LITERAL_H
18 
19 #include <set>
20 
21 #include "ecmascript/base/aligned_struct.h"
22 #include "ecmascript/js_function_kind.h"
23 #include "ecmascript/js_tagged_value.h"
24 #include "ecmascript/mem/c_string.h"
25 #include "libpandafile/file.h"
26 
27 static constexpr uint32_t CALL_TYPE_MASK = 0xF;  // 0xF: the last 4 bits are used as callType
28 
29 namespace panda::ecmascript {
30 class JSPandaFile;
31 using EntityId = panda_file::File::EntityId;
32 using StringData = panda_file::File::StringData;
33 struct PUBLIC_API MethodLiteral : public base::AlignedStruct<sizeof(uint64_t),
34                                                         base::AlignedUint64,
35                                                         base::AlignedPointer,
36                                                         base::AlignedUint64,
37                                                         base::AlignedUint64> {
38 public:
39     static constexpr uint8_t INVALID_IC_SLOT = 0xFFU;
40     static constexpr uint16_t MAX_SLOT_SIZE = 0xFFFFU;
41     static constexpr size_t EXTEND_SLOT_SIZE = 2;
42 
43     PUBLIC_API explicit MethodLiteral(EntityId methodId);
44     MethodLiteral() = delete;
45     ~MethodLiteral() = default;
46 
47     NO_COPY_SEMANTIC(MethodLiteral);
48     NO_MOVE_SEMANTIC(MethodLiteral);
49 
50     static constexpr size_t VREGS_ARGS_NUM_BITS = 28; // 28: maximum 268,435,455
51     using HaveThisBit = BitField<bool, 0, 1>;  // offset 0
52     using HaveNewTargetBit = HaveThisBit::NextFlag;  // offset 1
53     using HaveExtraBit = HaveNewTargetBit::NextFlag;  // offset 2
54     using HaveFuncBit = HaveExtraBit::NextFlag;  // offset 3
55     using NumVregsBits = HaveFuncBit::NextField<uint32_t, VREGS_ARGS_NUM_BITS>;  // offset 4-31
56     using NumArgsBits = NumVregsBits::NextField<uint32_t, VREGS_ARGS_NUM_BITS>;  // offset 32-59
57     using IsNativeBit = NumArgsBits::NextFlag;  // offset 60
58     using IsAotCodeBit = IsNativeBit::NextFlag; // offset 61
59     using IsFastBuiltinBit = IsAotCodeBit::NextFlag; // offset 62
60     using IsFastCallBit = IsFastBuiltinBit::NextFlag; // offset 63
61 
GetCallFieldMethodLiteral62     uint64_t GetCallField() const
63     {
64         return callField_;
65     }
66 
SetNativeBitMethodLiteral67     void SetNativeBit(bool isNative)
68     {
69         callField_ = IsNativeBit::Update(callField_, isNative);
70     }
71 
SetAotCodeBitMethodLiteral72     void SetAotCodeBit(bool isCompiled)
73     {
74         callField_ = IsAotCodeBit::Update(callField_, isCompiled);
75     }
76 
77     void PUBLIC_API Initialize(const JSPandaFile *jsPandaFile, const JSThread *thread = nullptr,
78                                const uint32_t offset = 0);
79 
HaveThisWithCallFieldMethodLiteral80     bool HaveThisWithCallField() const
81     {
82         return HaveThisWithCallField(callField_);
83     }
84 
HaveNewTargetWithCallFieldMethodLiteral85     bool HaveNewTargetWithCallField() const
86     {
87         return HaveNewTargetWithCallField(callField_);
88     }
89 
HaveExtraWithCallFieldMethodLiteral90     bool HaveExtraWithCallField() const
91     {
92         return HaveExtraWithCallField(callField_);
93     }
94 
HaveFuncWithCallFieldMethodLiteral95     bool HaveFuncWithCallField() const
96     {
97         return HaveFuncWithCallField(callField_);
98     }
99 
IsNativeWithCallFieldMethodLiteral100     bool IsNativeWithCallField() const
101     {
102         return IsNativeWithCallField(callField_);
103     }
104 
GetNumArgsWithCallFieldMethodLiteral105     uint32_t GetNumArgsWithCallField() const
106     {
107         return GetNumArgsWithCallField(callField_);
108     }
109 
GetNumArgsMethodLiteral110     uint32_t GetNumArgs() const
111     {
112         return GetNumArgsWithCallField() + HaveFuncWithCallField() +
113             HaveNewTargetWithCallField() + HaveThisWithCallField();
114     }
115 
GetNumberVRegsMethodLiteral116     uint32_t GetNumberVRegs() const
117     {
118         return GetNumVregsWithCallField() + GetNumArgs();
119     }
120 
GetNewTargetVregIndexMethodLiteral121     uint32_t GetNewTargetVregIndex() const
122     {
123         if (!HaveNewTargetWithCallField()) {
124             return 0;
125         }
126         uint32_t numVregs = GetNumVregsWithCallField();
127         return HaveFuncWithCallField() ? (numVregs + 1) : numVregs;
128     }
129 
SetNativeBitMethodLiteral130     static uint64_t SetNativeBit(uint64_t callField, bool isNative)
131     {
132         return IsNativeBit::Update(callField, isNative);
133     }
134 
SetAotCodeBitMethodLiteral135     static uint64_t SetAotCodeBit(uint64_t callField, bool isCompiled)
136     {
137         return IsAotCodeBit::Update(callField, isCompiled);
138     }
139 
HaveThisWithCallFieldMethodLiteral140     static bool HaveThisWithCallField(uint64_t callField)
141     {
142         return HaveThisBit::Decode(callField);
143     }
144 
HaveNewTargetWithCallFieldMethodLiteral145     static bool HaveNewTargetWithCallField(uint64_t callField)
146     {
147         return HaveNewTargetBit::Decode(callField);
148     }
149 
HaveExtraWithCallFieldMethodLiteral150     static bool HaveExtraWithCallField(uint64_t callField)
151     {
152         return HaveExtraBit::Decode(callField);
153     }
154 
HaveFuncWithCallFieldMethodLiteral155     static bool HaveFuncWithCallField(uint64_t callField)
156     {
157         return HaveFuncBit::Decode(callField);
158     }
159 
IsNativeWithCallFieldMethodLiteral160     static bool IsNativeWithCallField(uint64_t callField)
161     {
162         return IsNativeBit::Decode(callField);
163     }
164 
IsAotWithCallFieldMethodLiteral165     static bool IsAotWithCallField(uint64_t callField)
166     {
167         return IsAotCodeBit::Decode(callField);
168     }
169 
OnlyHaveThisWithCallFieldMethodLiteral170     static bool OnlyHaveThisWithCallField(uint64_t callField)
171     {
172         return (callField & CALL_TYPE_MASK) == 1;  // 1: the first bit of callFiled is HaveThisBit
173     }
174 
OnlyHaveNewTagetAndThisWithCallFieldMethodLiteral175     static bool OnlyHaveNewTagetAndThisWithCallField(uint64_t callField)
176     {
177         return (callField & CALL_TYPE_MASK) == 0b11;  // the first two bit of callFiled is `This` and `NewTarget`
178     }
179 
GetNumVregsWithCallFieldMethodLiteral180     static uint32_t GetNumVregsWithCallField(uint64_t callField)
181     {
182         return NumVregsBits::Decode(callField);
183     }
184 
GetNumVregsWithCallFieldMethodLiteral185     uint32_t GetNumVregsWithCallField() const
186     {
187         return NumVregsBits::Decode(callField_);
188     }
189 
GetNumArgsWithCallFieldMethodLiteral190     static uint32_t GetNumArgsWithCallField(uint64_t callField)
191     {
192         return NumArgsBits::Decode(callField);
193     }
194 
SetIsFastCallMethodLiteral195     static uint64_t SetIsFastCall(uint64_t callField, bool isFastCall)
196     {
197         return IsFastCallBit::Update(callField, isFastCall);
198     }
199 
SetIsFastCallMethodLiteral200     void SetIsFastCall(bool isFastCall)
201     {
202         callField_ = IsFastCallBit::Update(callField_, isFastCall);
203     }
204 
IsFastCallMethodLiteral205     static bool IsFastCall(uint64_t callField)
206     {
207         return IsFastCallBit::Decode(callField);
208     }
209 
IsFastCallMethodLiteral210     bool IsFastCall() const
211     {
212         return IsFastCallBit::Decode(callField_);
213     }
214 
215     static constexpr size_t METHOD_ARGS_NUM_BITS = 16;
216     static constexpr size_t METHOD_ARGS_METHODID_BITS = 32;
217     static constexpr size_t METHOD_SLOT_SIZE_BITS = 16;
218     using HotnessCounterBits = BitField<int16_t, 0, METHOD_ARGS_NUM_BITS>; // offset 0-15
219     using MethodIdBits = HotnessCounterBits::NextField<uint32_t, METHOD_ARGS_METHODID_BITS>; // offset 16-47
220     using SlotSizeBits = MethodIdBits::NextField<uint16_t, METHOD_SLOT_SIZE_BITS>; // offset 48-63
221 
222     static constexpr size_t BUILTINID_NUM_BITS = 8;
223     static constexpr size_t FUNCTION_KIND_NUM_BITS = 4;
224     static constexpr size_t EMPTY_BITS = 16;
225     using BuiltinIdBits = BitField<uint8_t, 0, BUILTINID_NUM_BITS>; // offset 0-7
226     using FunctionKindBits = BuiltinIdBits::NextField<FunctionKind, FUNCTION_KIND_NUM_BITS>; // offset 8-11
227     using IsNoGCBit = FunctionKindBits::NextFlag; // offset 12
228     using HasDebuggerStmtBit = IsNoGCBit::NextFlag; // offset 13
229     using EmptyBit = HasDebuggerStmtBit::NextField<uint8_t, EMPTY_BITS>; // offset 14-29
230     using IsSharedBit = EmptyBit::NextFlag; // offset 30
231     using CanTypedCall = IsSharedBit::NextFlag; // offset 31
232 
SetHotnessCounterMethodLiteral233     inline NO_THREAD_SANITIZE void SetHotnessCounter(int16_t counter)
234     {
235         literalInfo_ = HotnessCounterBits::Update(literalInfo_, counter);
236     }
237 
GetMethodIdMethodLiteral238     EntityId GetMethodId() const
239     {
240         return EntityId(MethodIdBits::Decode(literalInfo_));
241     }
242 
GetSlotSizeMethodLiteral243     uint32_t GetSlotSize() const
244     {
245         auto size = SlotSizeBits::Decode(literalInfo_);
246         return size == MAX_SLOT_SIZE ? MAX_SLOT_SIZE + EXTEND_SLOT_SIZE : size;
247     }
248 
UpdateSlotSizeWith8BitMethodLiteral249     uint8_t UpdateSlotSizeWith8Bit(uint16_t size)
250     {
251         uint16_t start = SlotSizeBits::Decode(literalInfo_);
252         uint32_t end = start + size;
253         // ic overflow
254         if (end >= INVALID_IC_SLOT) {
255             if (start < INVALID_IC_SLOT + 1) {
256                 literalInfo_ = SlotSizeBits::Update(literalInfo_, INVALID_IC_SLOT + 1);
257             }
258             return INVALID_IC_SLOT;
259         }
260         literalInfo_ = SlotSizeBits::Update(literalInfo_, static_cast<uint8_t>(end));
261         return start;
262     }
263 
SetFunctionKindMethodLiteral264     void SetFunctionKind(FunctionKind kind)
265     {
266         extraLiteralInfo_ = FunctionKindBits::Update(extraLiteralInfo_, kind);
267     }
268 
SetNoGCBitMethodLiteral269     void SetNoGCBit(bool isNoGC)
270     {
271         extraLiteralInfo_ = IsNoGCBit::Update(extraLiteralInfo_, isNoGC);
272     }
273 
IsNoGCMethodLiteral274     bool IsNoGC() const
275     {
276         return IsNoGCBit::Decode(extraLiteralInfo_);
277     }
278 
SetHasDebuggerStmtBitMethodLiteral279     void SetHasDebuggerStmtBit(bool isDebuggerStmt)
280     {
281         extraLiteralInfo_ = HasDebuggerStmtBit::Update(extraLiteralInfo_, isDebuggerStmt);
282     }
283 
HasDebuggerStmtMethodLiteral284     bool HasDebuggerStmt() const
285     {
286         return HasDebuggerStmtBit::Decode(extraLiteralInfo_);
287     }
288 
SetIsSharedMethodLiteral289     void SetIsShared(bool isShared)
290     {
291         extraLiteralInfo_ = IsSharedBit::Update(extraLiteralInfo_, isShared);
292     }
293 
IsSharedMethodLiteral294     bool IsShared() const
295     {
296         return IsSharedBit::Decode(extraLiteralInfo_);
297     }
298 
SetCanTypedCallMethodLiteral299     void SetCanTypedCall(bool isTypedCall)
300     {
301         extraLiteralInfo_ = CanTypedCall::Update(extraLiteralInfo_, isTypedCall);
302     }
303 
IsTypedCallMethodLiteral304     bool IsTypedCall() const
305     {
306         return CanTypedCall::Decode(extraLiteralInfo_);
307     }
308 
GetFunctionKindMethodLiteral309     FunctionKind GetFunctionKind() const
310     {
311         return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo_));
312     }
313 
IsClassConstructorMethodLiteral314     inline bool IsClassConstructor() const
315     {
316         return GetFunctionKind() == FunctionKind::CLASS_CONSTRUCTOR;
317     }
318 
GetHotnessCounterMethodLiteral319     static inline int16_t GetHotnessCounter(uint64_t literalInfo)
320     {
321         return HotnessCounterBits::Decode(literalInfo);
322     }
323 
SetHotnessCounterMethodLiteral324     static uint64_t SetHotnessCounter(uint64_t literalInfo, int16_t counter)
325     {
326         return HotnessCounterBits::Update(literalInfo, counter);
327     }
328 
SetFunctionKindMethodLiteral329     static uint64_t SetFunctionKind(uint64_t extraLiteralInfo, FunctionKind kind)
330     {
331         return FunctionKindBits::Update(extraLiteralInfo, kind);
332     }
333 
GetFunctionKindMethodLiteral334     static FunctionKind GetFunctionKind(uint64_t extraLiteralInfo)
335     {
336         return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo));
337     }
338 
GetMethodIdMethodLiteral339     static EntityId GetMethodId(uint64_t literalInfo)
340     {
341         return EntityId(MethodIdBits::Decode(literalInfo));
342     }
343 
GetSlotSizeMethodLiteral344     static uint32_t GetSlotSize(uint64_t literalInfo)
345     {
346         auto size = SlotSizeBits::Decode(literalInfo);
347         return size == MAX_SLOT_SIZE ? MAX_SLOT_SIZE + EXTEND_SLOT_SIZE : size;
348     }
349 
350     static const char PUBLIC_API *GetMethodName(const JSPandaFile *jsPandaFile, EntityId methodId,
351                                                 bool cpuProfiler = false);
352     static std::string PUBLIC_API ParseFunctionName(const JSPandaFile *jsPandaFile, EntityId methodId);
353     static std::pair<std::string_view, bool> PUBLIC_API ParseFunctionNameView(const JSPandaFile* jsPandaFile,
354                                                                               EntityId methodId);
355     static CString PUBLIC_API ParseFunctionNameToCString(const JSPandaFile *jsPandaFile, EntityId methodId);
356 
357     static uint32_t PUBLIC_API GetCodeSize(const JSPandaFile *jsPandaFile, EntityId methodId);
358     static CString PUBLIC_API GetRecordName(const JSPandaFile *jsPandaFile, EntityId methodId);
359     static const char PUBLIC_API *GetRecordNameWithSymbol(const JSPandaFile *jsPandaFile, EntityId methodId);
360 
GetBytecodeArrayMethodLiteral361     const uint8_t *GetBytecodeArray() const
362     {
363         return reinterpret_cast<const uint8_t *>(nativePointerOrBytecodeArray_);
364     }
365 
GetNativePointerMethodLiteral366     const void* GetNativePointer() const
367     {
368         return nativePointerOrBytecodeArray_;
369     }
370 
GetLiteralInfoMethodLiteral371     uint64_t GetLiteralInfo() const
372     {
373         return literalInfo_;
374     }
375 
GetExtraLiteralInfoMethodLiteral376     uint64_t GetExtraLiteralInfo() const
377     {
378         return extraLiteralInfo_;
379     }
380 
381     std::optional<std::set<uint32_t>> GetConcurrentRequestedModules(const JSPandaFile *jsPandaFile) const;
382 
383 private:
384     enum class Index : size_t {
385         CALL_FIELD_INDEX = 0,
386         NATIVE_POINTER_OR_BYTECODE_ARRAY_INDEX,
387         LITERAL_INFO_INDEX,
388         EXTRA_LITERAL_INFO_INDEX,
389         NUM_OF_MEMBERS
390     };
391     static_assert(static_cast<size_t>(Index::NUM_OF_MEMBERS) == NumOfTypes);
392 
393     static std::pair<std::string_view, bool> GetMethodNameView(const JSPandaFile* jsPandaFile, EntityId methodId,
394                                                                bool cpuProfiler = false);
395 
SetMethodIdMethodLiteral396     void SetMethodId(EntityId methodId)
397     {
398         literalInfo_ = MethodIdBits::Update(literalInfo_, methodId.GetOffset());
399     }
400 
SetSlotSizeMethodLiteral401     void SetSlotSize(uint32_t size)
402     {
403         if (size > MAX_SLOT_SIZE) {
404             size = MAX_SLOT_SIZE;
405         } else if (size + EXTEND_SLOT_SIZE > INVALID_IC_SLOT && size <= INVALID_IC_SLOT) {
406             // for compatibility: ensure there's always 0xff slot in this situation
407             size = INVALID_IC_SLOT + 1;
408         }
409         literalInfo_ = SlotSizeBits::Update(literalInfo_, size);
410     }
411 
412     alignas(EAS) uint64_t callField_ {0ULL};
413     // Native method decides this filed is NativePointer or BytecodeArray pointer.
414     alignas(EAS) const void *nativePointerOrBytecodeArray_ {nullptr};
415     // hotnessCounter, methodId and slotSize are encoded in literalInfo_.
416     alignas(EAS) uint64_t literalInfo_ {0ULL};
417     // BuiltinId, FunctionKind are encoded in extraLiteralInfo_.
418     alignas(EAS) uint64_t extraLiteralInfo_ {0ULL};
419 };
420 STATIC_ASSERT_EQ_ARCH(sizeof(MethodLiteral), MethodLiteral::SizeArch32, MethodLiteral::SizeArch64);
421 }  // namespace panda::ecmascript
422 
423 #endif  // ECMASCRIPT_JSPANDAFILE_METHOD_LITERAL_H
424