• 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/compiler/builtins/builtins_call_signature.h"
23 #include "ecmascript/js_function_kind.h"
24 #include "ecmascript/js_tagged_value.h"
25 #include "ecmascript/mem/c_string.h"
26 #include "libpandafile/file.h"
27 
28 static constexpr uint32_t CALL_TYPE_MASK = 0xF;  // 0xF: the last 4 bits are used as callType
29 
30 namespace panda::ecmascript {
31 class JSPandaFile;
32 using EntityId = panda_file::File::EntityId;
33 using StringData = panda_file::File::StringData;
34 struct PUBLIC_API MethodLiteral : public base::AlignedStruct<sizeof(uint64_t),
35                                                         base::AlignedUint64,
36                                                         base::AlignedPointer,
37                                                         base::AlignedUint64,
38                                                         base::AlignedUint64> {
39 public:
40     static constexpr uint8_t INVALID_IC_SLOT = 0xFFU;
41     static constexpr uint16_t MAX_SLOT_SIZE = 0xFFFFU;
42     static constexpr uint32_t MAX_EXPECTED_PROPERTY_COUNT = 0xFFFFFFFFU;
43     static constexpr size_t EXTEND_SLOT_SIZE = 2;
44     static constexpr std::string_view KCALL_TYPE_ANNOTATION = "L_ESCallTypeAnnotation;";
45     static constexpr std::string_view KCALL_TYPE_NAME = "callType";
46     static constexpr std::string_view KSLOT_NUMBER_ANNOTATION = "L_ESSlotNumberAnnotation;";
47     static constexpr std::string_view KSLOT_NUMBER_NAME = "SlotNumber";
48     static constexpr std::string_view KEXPECTED_PROPERTY_COUNT_ANNOTATION = "L_ESExpectedPropertyCountAnnotation;";
49     static constexpr std::string_view KEXPECTED_PROPERTY_COUNT_NAME = "ExpectedPropertyCount";
50 
51     PUBLIC_API explicit MethodLiteral(EntityId methodId);
52     MethodLiteral() = delete;
53     ~MethodLiteral() = default;
54 
55     NO_COPY_SEMANTIC(MethodLiteral);
56     NO_MOVE_SEMANTIC(MethodLiteral);
57 
58     static constexpr size_t VREGS_ARGS_NUM_BITS = 28; // 28: maximum 268,435,455
59     using HaveThisBit = BitField<bool, 0, 1>;  // offset 0
60     using HaveNewTargetBit = HaveThisBit::NextFlag;  // offset 1
61     using HaveExtraBit = HaveNewTargetBit::NextFlag;  // offset 2
62     using HaveFuncBit = HaveExtraBit::NextFlag;  // offset 3
63     using NumVregsBits = HaveFuncBit::NextField<uint32_t, VREGS_ARGS_NUM_BITS>;  // offset 4-31
64     using NumArgsBits = NumVregsBits::NextField<uint32_t, VREGS_ARGS_NUM_BITS>;  // offset 32-59
65     using IsNativeBit = NumArgsBits::NextFlag;  // offset 60
66     using IsAotCodeBit = IsNativeBit::NextFlag; // offset 61
67     using IsFastBuiltinBit = IsAotCodeBit::NextFlag; // offset 62
68     using IsFastCallBit = IsFastBuiltinBit::NextFlag; // offset 63
69 
GetCallFieldMethodLiteral70     uint64_t GetCallField() const
71     {
72         return callField_;
73     }
74 
SetNativeBitMethodLiteral75     void SetNativeBit(bool isNative)
76     {
77         callField_ = IsNativeBit::Update(callField_, isNative);
78     }
79 
SetAotCodeBitMethodLiteral80     void SetAotCodeBit(bool isCompiled)
81     {
82         callField_ = IsAotCodeBit::Update(callField_, isCompiled);
83     }
84 
85     void PUBLIC_API Initialize(const JSPandaFile *jsPandaFile, const JSThread *thread = nullptr,
86                                const uint32_t offset = 0);
87 
HaveThisWithCallFieldMethodLiteral88     bool HaveThisWithCallField() const
89     {
90         return HaveThisWithCallField(callField_);
91     }
92 
HaveNewTargetWithCallFieldMethodLiteral93     bool HaveNewTargetWithCallField() const
94     {
95         return HaveNewTargetWithCallField(callField_);
96     }
97 
HaveExtraWithCallFieldMethodLiteral98     bool HaveExtraWithCallField() const
99     {
100         return HaveExtraWithCallField(callField_);
101     }
102 
HaveFuncWithCallFieldMethodLiteral103     bool HaveFuncWithCallField() const
104     {
105         return HaveFuncWithCallField(callField_);
106     }
107 
IsNativeWithCallFieldMethodLiteral108     bool IsNativeWithCallField() const
109     {
110         return IsNativeWithCallField(callField_);
111     }
112 
GetNumArgsWithCallFieldMethodLiteral113     uint32_t GetNumArgsWithCallField() const
114     {
115         return GetNumArgsWithCallField(callField_);
116     }
117 
GetNumArgsMethodLiteral118     uint32_t GetNumArgs() const
119     {
120         return GetNumArgsWithCallField() + HaveFuncWithCallField() +
121             HaveNewTargetWithCallField() + HaveThisWithCallField();
122     }
123 
GetNumberVRegsMethodLiteral124     uint32_t GetNumberVRegs() const
125     {
126         return GetNumVregsWithCallField() + GetNumArgs();
127     }
128 
GetNewTargetVregIndexMethodLiteral129     uint32_t GetNewTargetVregIndex() const
130     {
131         if (!HaveNewTargetWithCallField()) {
132             return 0;
133         }
134         uint32_t numVregs = GetNumVregsWithCallField();
135         return HaveFuncWithCallField() ? (numVregs + 1) : numVregs;
136     }
137 
SetNativeBitMethodLiteral138     static uint64_t SetNativeBit(uint64_t callField, bool isNative)
139     {
140         return IsNativeBit::Update(callField, isNative);
141     }
142 
SetAotCodeBitMethodLiteral143     static uint64_t SetAotCodeBit(uint64_t callField, bool isCompiled)
144     {
145         return IsAotCodeBit::Update(callField, isCompiled);
146     }
147 
HaveThisWithCallFieldMethodLiteral148     static bool HaveThisWithCallField(uint64_t callField)
149     {
150         return HaveThisBit::Decode(callField);
151     }
152 
HaveNewTargetWithCallFieldMethodLiteral153     static bool HaveNewTargetWithCallField(uint64_t callField)
154     {
155         return HaveNewTargetBit::Decode(callField);
156     }
157 
HaveExtraWithCallFieldMethodLiteral158     static bool HaveExtraWithCallField(uint64_t callField)
159     {
160         return HaveExtraBit::Decode(callField);
161     }
162 
HaveFuncWithCallFieldMethodLiteral163     static bool HaveFuncWithCallField(uint64_t callField)
164     {
165         return HaveFuncBit::Decode(callField);
166     }
167 
IsNativeWithCallFieldMethodLiteral168     static bool IsNativeWithCallField(uint64_t callField)
169     {
170         return IsNativeBit::Decode(callField);
171     }
172 
IsAotWithCallFieldMethodLiteral173     static bool IsAotWithCallField(uint64_t callField)
174     {
175         return IsAotCodeBit::Decode(callField);
176     }
177 
OnlyHaveThisWithCallFieldMethodLiteral178     static bool OnlyHaveThisWithCallField(uint64_t callField)
179     {
180         return (callField & CALL_TYPE_MASK) == 1;  // 1: the first bit of callFiled is HaveThisBit
181     }
182 
OnlyHaveNewTagetAndThisWithCallFieldMethodLiteral183     static bool OnlyHaveNewTagetAndThisWithCallField(uint64_t callField)
184     {
185         return (callField & CALL_TYPE_MASK) == 0b11;  // the first two bit of callFiled is `This` and `NewTarget`
186     }
187 
GetNumVregsWithCallFieldMethodLiteral188     static uint32_t GetNumVregsWithCallField(uint64_t callField)
189     {
190         return NumVregsBits::Decode(callField);
191     }
192 
GetNumVregsWithCallFieldMethodLiteral193     uint32_t GetNumVregsWithCallField() const
194     {
195         return NumVregsBits::Decode(callField_);
196     }
197 
GetNumArgsWithCallFieldMethodLiteral198     static uint32_t GetNumArgsWithCallField(uint64_t callField)
199     {
200         return NumArgsBits::Decode(callField);
201     }
202 
SetIsFastCallMethodLiteral203     static uint64_t SetIsFastCall(uint64_t callField, bool isFastCall)
204     {
205         return IsFastCallBit::Update(callField, isFastCall);
206     }
207 
SetIsFastCallMethodLiteral208     void SetIsFastCall(bool isFastCall)
209     {
210         callField_ = IsFastCallBit::Update(callField_, isFastCall);
211     }
212 
IsFastCallMethodLiteral213     static bool IsFastCall(uint64_t callField)
214     {
215         return IsFastCallBit::Decode(callField);
216     }
217 
IsFastCallMethodLiteral218     bool IsFastCall() const
219     {
220         return IsFastCallBit::Decode(callField_);
221     }
222 
223     static constexpr size_t METHOD_ARGS_NUM_BITS = 16;
224     static constexpr size_t METHOD_ARGS_METHODID_BITS = 32;
225     static constexpr size_t METHOD_EXPECTED_PROPERTY_COUNT_BITS = 32;
226     static constexpr size_t METHOD_SLOT_SIZE_BITS = 16;
227     using HotnessCounterBits = BitField<int16_t, 0, METHOD_ARGS_NUM_BITS>; // offset 0-15
228     using MethodIdBits = HotnessCounterBits::NextField<uint32_t, METHOD_ARGS_METHODID_BITS>; // offset 16-47
229     using SlotSizeBits = MethodIdBits::NextField<uint16_t, METHOD_SLOT_SIZE_BITS>; // offset 48-63
230 
231     static constexpr size_t BUILTINID_NUM_BITS = 8;
232     static constexpr size_t FUNCTION_KIND_NUM_BITS = 4;
233     static constexpr size_t EMPTY_BITS = 16;
234     using BuiltinIdBits = BitField<uint8_t, 0, BUILTINID_NUM_BITS>; // offset 0-7
235     using FunctionKindBits = BuiltinIdBits::NextField<FunctionKind, FUNCTION_KIND_NUM_BITS>; // offset 8-11
236     using IsNoGCBit = FunctionKindBits::NextFlag; // offset 12
237     using HasDebuggerStmtBit = IsNoGCBit::NextFlag; // offset 13
238     using EmptyBit = HasDebuggerStmtBit::NextField<uint8_t, EMPTY_BITS>; // offset 14-29
239     using IsSharedBit = EmptyBit::NextFlag; // offset 30
240     using CanTypedCall = IsSharedBit::NextFlag; // offset 31
241     using ExpectedPropertyCountBits =
242         CanTypedCall::NextField<uint32_t, METHOD_EXPECTED_PROPERTY_COUNT_BITS>; // offset 32-63
243 
244     // one placeholder 0xffff (INVALID) in kungfu::BuiltinsStubCSigns::ID
245     static_assert(static_cast<size_t>(kungfu::BuiltinsStubCSigns::ID::NUM_OF_BUILTINS_ID) < (1 << BUILTINID_NUM_BITS));
246     static_assert(static_cast<size_t>(FunctionKind::LAST_FUNCTION_KIND) <= (1 << FUNCTION_KIND_NUM_BITS));
247 
SetHotnessCounterMethodLiteral248     inline NO_THREAD_SANITIZE void SetHotnessCounter(int16_t counter)
249     {
250         literalInfo_ = HotnessCounterBits::Update(literalInfo_, counter);
251     }
252 
GetMethodIdMethodLiteral253     EntityId GetMethodId() const
254     {
255         return EntityId(MethodIdBits::Decode(literalInfo_));
256     }
257 
GetSlotSizeMethodLiteral258     uint32_t GetSlotSize() const
259     {
260         auto size = SlotSizeBits::Decode(literalInfo_);
261         return size == MAX_SLOT_SIZE ? MAX_SLOT_SIZE + EXTEND_SLOT_SIZE : size;
262     }
263 
UpdateSlotSizeWith8BitMethodLiteral264     uint8_t UpdateSlotSizeWith8Bit(uint16_t size)
265     {
266         uint16_t start = SlotSizeBits::Decode(literalInfo_);
267         uint32_t end = start + size;
268         // ic overflow
269         if (end >= INVALID_IC_SLOT) {
270             if (start < INVALID_IC_SLOT + 1) {
271                 literalInfo_ = SlotSizeBits::Update(literalInfo_, INVALID_IC_SLOT + 1);
272             }
273             return INVALID_IC_SLOT;
274         }
275         literalInfo_ = SlotSizeBits::Update(literalInfo_, static_cast<uint8_t>(end));
276         return start;
277     }
278 
SetFunctionKindMethodLiteral279     void SetFunctionKind(FunctionKind kind)
280     {
281         extraLiteralInfo_ = FunctionKindBits::Update(extraLiteralInfo_, kind);
282     }
283 
SetNoGCBitMethodLiteral284     void SetNoGCBit(bool isNoGC)
285     {
286         extraLiteralInfo_ = IsNoGCBit::Update(extraLiteralInfo_, isNoGC);
287     }
288 
IsNoGCMethodLiteral289     bool IsNoGC() const
290     {
291         return IsNoGCBit::Decode(extraLiteralInfo_);
292     }
293 
SetHasDebuggerStmtBitMethodLiteral294     void SetHasDebuggerStmtBit(bool isDebuggerStmt)
295     {
296         extraLiteralInfo_ = HasDebuggerStmtBit::Update(extraLiteralInfo_, isDebuggerStmt);
297     }
298 
HasDebuggerStmtMethodLiteral299     bool HasDebuggerStmt() const
300     {
301         return HasDebuggerStmtBit::Decode(extraLiteralInfo_);
302     }
303 
SetIsSharedMethodLiteral304     void SetIsShared(bool isShared)
305     {
306         extraLiteralInfo_ = IsSharedBit::Update(extraLiteralInfo_, isShared);
307     }
308 
IsSharedMethodLiteral309     bool IsShared() const
310     {
311         return IsSharedBit::Decode(extraLiteralInfo_);
312     }
313 
SetCanTypedCallMethodLiteral314     void SetCanTypedCall(bool isTypedCall)
315     {
316         extraLiteralInfo_ = CanTypedCall::Update(extraLiteralInfo_, isTypedCall);
317     }
318 
IsTypedCallMethodLiteral319     bool IsTypedCall() const
320     {
321         return CanTypedCall::Decode(extraLiteralInfo_);
322     }
323 
GetFunctionKindMethodLiteral324     FunctionKind GetFunctionKind() const
325     {
326         return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo_));
327     }
328 
GetExpectedPropertyCountMethodLiteral329     uint32_t GetExpectedPropertyCount() const
330     {
331         return ExpectedPropertyCountBits::Decode(extraLiteralInfo_);
332     }
333 
SetExpectedPropertyCountMethodLiteral334     void SetExpectedPropertyCount(uint32_t count)
335     {
336         extraLiteralInfo_ = ExpectedPropertyCountBits::Update(extraLiteralInfo_, count);
337     }
338 
IsClassConstructorMethodLiteral339     inline bool IsClassConstructor() const
340     {
341         return GetFunctionKind() == FunctionKind::CLASS_CONSTRUCTOR;
342     }
343 
GetHotnessCounterMethodLiteral344     static inline int16_t GetHotnessCounter(uint64_t literalInfo)
345     {
346         return HotnessCounterBits::Decode(literalInfo);
347     }
348 
SetHotnessCounterMethodLiteral349     static uint64_t SetHotnessCounter(uint64_t literalInfo, int16_t counter)
350     {
351         return HotnessCounterBits::Update(literalInfo, counter);
352     }
353 
SetFunctionKindMethodLiteral354     static uint64_t SetFunctionKind(uint64_t extraLiteralInfo, FunctionKind kind)
355     {
356         return FunctionKindBits::Update(extraLiteralInfo, kind);
357     }
358 
GetFunctionKindMethodLiteral359     static FunctionKind GetFunctionKind(uint64_t extraLiteralInfo)
360     {
361         return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo));
362     }
363 
GetMethodIdMethodLiteral364     static EntityId GetMethodId(uint64_t literalInfo)
365     {
366         return EntityId(MethodIdBits::Decode(literalInfo));
367     }
368 
GetSlotSizeMethodLiteral369     static uint32_t GetSlotSize(uint64_t literalInfo)
370     {
371         auto size = SlotSizeBits::Decode(literalInfo);
372         return size == MAX_SLOT_SIZE ? MAX_SLOT_SIZE + EXTEND_SLOT_SIZE : size;
373     }
374 
375     static const char PUBLIC_API *GetMethodName(const JSPandaFile *jsPandaFile, EntityId methodId,
376                                                 bool cpuProfiler = false);
377     static std::string PUBLIC_API ParseFunctionName(const JSPandaFile *jsPandaFile, EntityId methodId);
378     static std::pair<std::string_view, bool> PUBLIC_API ParseFunctionNameView(const JSPandaFile* jsPandaFile,
379                                                                               EntityId methodId);
380     static CString PUBLIC_API ParseFunctionNameToCString(const JSPandaFile *jsPandaFile, EntityId methodId);
381 
382     static uint32_t PUBLIC_API GetCodeSize(const JSPandaFile *jsPandaFile, EntityId methodId);
383     static CString PUBLIC_API GetRecordName(const JSPandaFile *jsPandaFile, EntityId methodId);
384     static const char PUBLIC_API *GetRecordNameWithSymbol(const JSPandaFile *jsPandaFile, EntityId methodId);
385 
GetBytecodeArrayMethodLiteral386     const uint8_t *GetBytecodeArray() const
387     {
388         return reinterpret_cast<const uint8_t *>(nativePointerOrBytecodeArray_);
389     }
390 
GetNativePointerMethodLiteral391     const void* GetNativePointer() const
392     {
393         return nativePointerOrBytecodeArray_;
394     }
395 
GetLiteralInfoMethodLiteral396     uint64_t GetLiteralInfo() const
397     {
398         return literalInfo_;
399     }
400 
GetExtraLiteralInfoMethodLiteral401     uint64_t GetExtraLiteralInfo() const
402     {
403         return extraLiteralInfo_;
404     }
405 
SetNativePointerMethodLiteral406     void SetNativePointer(void* nativePointer)
407     {
408         nativePointerOrBytecodeArray_ = nativePointer;
409     }
410 
411     std::optional<std::set<uint32_t>> GetConcurrentRequestedModules(const JSPandaFile *jsPandaFile) const;
412 
413 private:
414     enum class Index : size_t {
415         CALL_FIELD_INDEX = 0,
416         NATIVE_POINTER_OR_BYTECODE_ARRAY_INDEX,
417         LITERAL_INFO_INDEX,
418         EXTRA_LITERAL_INFO_INDEX,
419         NUM_OF_MEMBERS
420     };
421     static_assert(static_cast<size_t>(Index::NUM_OF_MEMBERS) == NumOfTypes);
422 
423     static std::pair<std::string_view, bool> GetMethodNameView(const JSPandaFile* jsPandaFile, EntityId methodId,
424                                                                bool cpuProfiler = false);
425 
SetMethodIdMethodLiteral426     void SetMethodId(EntityId methodId)
427     {
428         literalInfo_ = MethodIdBits::Update(literalInfo_, methodId.GetOffset());
429     }
430 
SetSlotSizeMethodLiteral431     void SetSlotSize(uint32_t size)
432     {
433         if (size > MAX_SLOT_SIZE) {
434             size = MAX_SLOT_SIZE;
435         } else if (size + EXTEND_SLOT_SIZE > INVALID_IC_SLOT && size <= INVALID_IC_SLOT) {
436             // for compatibility: ensure there's always 0xff slot in this situation
437             size = INVALID_IC_SLOT + 1;
438         }
439         literalInfo_ = SlotSizeBits::Update(literalInfo_, size);
440     }
441 
442     alignas(EAS) uint64_t callField_ {0ULL};
443     // Native method decides this filed is NativePointer or BytecodeArray pointer.
444     alignas(EAS) void *nativePointerOrBytecodeArray_ {nullptr};
445     // hotnessCounter, methodId and slotSize are encoded in literalInfo_.
446     alignas(EAS) uint64_t literalInfo_ {0ULL};
447     // BuiltinId, FunctionKind are encoded in extraLiteralInfo_.
448     alignas(EAS) uint64_t extraLiteralInfo_ {0ULL};
449 };
450 STATIC_ASSERT_EQ_ARCH(sizeof(MethodLiteral), MethodLiteral::SizeArch32, MethodLiteral::SizeArch64);
451 }  // namespace panda::ecmascript
452 
453 #endif  // ECMASCRIPT_JSPANDAFILE_METHOD_LITERAL_H
454