• 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/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