• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/share_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     using HasDebuggerStmtBit = IsNoGCBit::NextFlag; // offset 13
221 
SetHotnessCounterMethodLiteral222     inline NO_THREAD_SANITIZE void SetHotnessCounter(int16_t counter)
223     {
224         literalInfo_ = HotnessCounterBits::Update(literalInfo_, counter);
225     }
226 
GetMethodIdMethodLiteral227     EntityId GetMethodId() const
228     {
229         return EntityId(MethodIdBits::Decode(literalInfo_));
230     }
231 
GetSlotSizeMethodLiteral232     uint32_t GetSlotSize() const
233     {
234         auto size = SlotSizeBits::Decode(literalInfo_);
235         return size == MAX_SLOT_SIZE ? MAX_SLOT_SIZE + 2 : size;  // 2: last maybe two slot
236     }
237 
UpdateSlotSizeWith8BitMethodLiteral238     uint8_t UpdateSlotSizeWith8Bit(uint16_t size)
239     {
240         uint16_t start = SlotSizeBits::Decode(literalInfo_);
241         uint32_t end = start + size;
242         // ic overflow
243         if (end >= INVALID_IC_SLOT) {
244             if (start < INVALID_IC_SLOT + 1) {
245                 literalInfo_ = SlotSizeBits::Update(literalInfo_, INVALID_IC_SLOT + 1);
246             }
247             return INVALID_IC_SLOT;
248         }
249         literalInfo_ = SlotSizeBits::Update(literalInfo_, static_cast<uint8_t>(end));
250         return start;
251     }
252 
SetFunctionKindMethodLiteral253     void SetFunctionKind(FunctionKind kind)
254     {
255         extraLiteralInfo_ = FunctionKindBits::Update(extraLiteralInfo_, kind);
256     }
257 
SetNoGCBitMethodLiteral258     void SetNoGCBit(bool isNoGC)
259     {
260         extraLiteralInfo_ = IsNoGCBit::Update(extraLiteralInfo_, isNoGC);
261     }
262 
IsNoGCMethodLiteral263     bool IsNoGC() const
264     {
265         return IsNoGCBit::Decode(extraLiteralInfo_);
266     }
267 
SetHasDebuggerStmtBitMethodLiteral268     void SetHasDebuggerStmtBit(bool isDebuggerStmt)
269     {
270         extraLiteralInfo_ = HasDebuggerStmtBit::Update(extraLiteralInfo_, isDebuggerStmt);
271     }
272 
HasDebuggerStmtMethodLiteral273     bool HasDebuggerStmt() const
274     {
275         return HasDebuggerStmtBit::Decode(extraLiteralInfo_);
276     }
277 
GetFunctionKindMethodLiteral278     FunctionKind GetFunctionKind() const
279     {
280         return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo_));
281     }
282 
IsClassConstructorMethodLiteral283     inline bool IsClassConstructor() const
284     {
285         return GetFunctionKind() == FunctionKind::CLASS_CONSTRUCTOR;
286     }
287 
GetHotnessCounterMethodLiteral288     static inline int16_t GetHotnessCounter(uint64_t literalInfo)
289     {
290         return HotnessCounterBits::Decode(literalInfo);
291     }
292 
SetHotnessCounterMethodLiteral293     static uint64_t SetHotnessCounter(uint64_t literalInfo, int16_t counter)
294     {
295         return HotnessCounterBits::Update(literalInfo, counter);
296     }
297 
SetFunctionKindMethodLiteral298     static uint64_t SetFunctionKind(uint64_t extraLiteralInfo, FunctionKind kind)
299     {
300         return FunctionKindBits::Update(extraLiteralInfo, kind);
301     }
302 
GetFunctionKindMethodLiteral303     static FunctionKind GetFunctionKind(uint64_t extraLiteralInfo)
304     {
305         return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo));
306     }
307 
GetMethodIdMethodLiteral308     static EntityId GetMethodId(uint64_t literalInfo)
309     {
310         return EntityId(MethodIdBits::Decode(literalInfo));
311     }
312 
GetSlotSizeMethodLiteral313     static uint16_t GetSlotSize(uint64_t literalInfo)
314     {
315         return SlotSizeBits::Decode(literalInfo);
316     }
317 
318     static const char PUBLIC_API *GetMethodName(const JSPandaFile *jsPandaFile, EntityId methodId,
319                                                 bool cpuProfiler = false);
320     static std::string PUBLIC_API ParseFunctionName(const JSPandaFile *jsPandaFile, EntityId methodId);
321     static CString PUBLIC_API ParseFunctionNameToCString(const JSPandaFile *jsPandaFile, EntityId methodId);
322 
323     static uint32_t GetCodeSize(const JSPandaFile *jsPandaFile, EntityId methodId);
324     static CString GetRecordName(const JSPandaFile *jsPandaFile, EntityId methodId);
325     static const char PUBLIC_API *GetRecordNameWithSymbol(const JSPandaFile *jsPandaFile, EntityId methodId);
326 
GetBytecodeArrayMethodLiteral327     const uint8_t *GetBytecodeArray() const
328     {
329         return reinterpret_cast<const uint8_t *>(nativePointerOrBytecodeArray_);
330     }
331 
GetNativePointerMethodLiteral332     const void* GetNativePointer() const
333     {
334         return nativePointerOrBytecodeArray_;
335     }
336 
GetLiteralInfoMethodLiteral337     uint64_t GetLiteralInfo() const
338     {
339         return literalInfo_;
340     }
341 
GetExtraLiteralInfoMethodLiteral342     uint64_t GetExtraLiteralInfo() const
343     {
344         return extraLiteralInfo_;
345     }
346 
347     std::optional<std::set<uint32_t>> GetConcurrentRequestedModules(const JSPandaFile *jsPandaFile) const;
348 
349 private:
350     enum class Index : size_t {
351         CALL_FIELD_INDEX = 0,
352         NATIVE_POINTER_OR_BYTECODE_ARRAY_INDEX,
353         LITERAL_INFO_INDEX,
354         EXTRA_LITERAL_INFO_INDEX,
355         NUM_OF_MEMBERS
356     };
357     static_assert(static_cast<size_t>(Index::NUM_OF_MEMBERS) == NumOfTypes);
358 
SetMethodIdMethodLiteral359     void SetMethodId(EntityId methodId)
360     {
361         literalInfo_ = MethodIdBits::Update(literalInfo_, methodId.GetOffset());
362     }
363 
SetSlotSizeMethodLiteral364     void SetSlotSize(uint32_t size)
365     {
366         size = size > MAX_SLOT_SIZE ? MAX_SLOT_SIZE : size;
367         literalInfo_ = SlotSizeBits::Update(literalInfo_, size);
368     }
369 
370     alignas(EAS) uint64_t callField_ {0ULL};
371     // Native method decides this filed is NativePointer or BytecodeArray pointer.
372     alignas(EAS) const void *nativePointerOrBytecodeArray_ {nullptr};
373     // hotnessCounter, methodId and slotSize are encoded in literalInfo_.
374     alignas(EAS) uint64_t literalInfo_ {0ULL};
375     // BuiltinId, FunctionKind are encoded in extraLiteralInfo_.
376     alignas(EAS) uint64_t extraLiteralInfo_ {0ULL};
377 };
378 STATIC_ASSERT_EQ_ARCH(sizeof(MethodLiteral), MethodLiteral::SizeArch32, MethodLiteral::SizeArch64);
379 }  // namespace panda::ecmascript
380 
381 #endif  // ECMASCRIPT_JSPANDAFILE_METHOD_LITERAL_H
382