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_METHOD_H
17 #define ECMASCRIPT_METHOD_H
18 
19 #include "ecmascript/compiler/deopt_type.h"
20 #include "ecmascript/ecma_macros.h"
21 #include "ecmascript/jspandafile/method_literal.h"
22 #include "ecmascript/js_tagged_value.h"
23 #include "ecmascript/mem/barriers.h"
24 #include "ecmascript/mem/c_string.h"
25 #include "ecmascript/mem/visitor.h"
26 
27 #include "libpandafile/file.h"
28 
29 namespace panda::ecmascript {
30 class JSPandaFile;
31 struct Reference;
32 using EntityId = panda_file::File::EntityId;
33 class Method : public TaggedObject {
34 public:
35     CAST_CHECK(Method, IsMethod);
36 
SetNumArgsWithCallField(uint64_t callField, uint32_t numargs)37     uint64_t SetNumArgsWithCallField(uint64_t callField, uint32_t numargs)
38     {
39         return NumArgsBits::Update(callField, numargs);
40     }
41 
SetNativeBit(uint64_t callField, bool isNative)42     uint64_t SetNativeBit(uint64_t callField, bool isNative)
43     {
44         return IsNativeBit::Update(callField, isNative);
45     }
46 
SetAotCodeBit(uint64_t callField, bool isCompiled)47     uint64_t SetAotCodeBit(uint64_t callField, bool isCompiled)
48     {
49         return IsAotCodeBit::Update(callField, isCompiled);
50     }
51 
SetFastBuiltinBit(uint64_t callField, bool isFastBuiltin)52     uint64_t SetFastBuiltinBit(uint64_t callField, bool isFastBuiltin)
53     {
54         return IsFastBuiltinBit::Update(callField, isFastBuiltin);
55     }
56 
HaveThisWithCallField(uint64_t callField)57     static bool HaveThisWithCallField(uint64_t callField)
58     {
59         return HaveThisBit::Decode(callField);
60     }
61 
HaveNewTargetWithCallField(uint64_t callField)62     static bool HaveNewTargetWithCallField(uint64_t callField)
63     {
64         return HaveNewTargetBit::Decode(callField);
65     }
66 
HaveExtraWithCallField(uint64_t callField)67     bool HaveExtraWithCallField(uint64_t callField)
68     {
69         return HaveExtraBit::Decode(callField);
70     }
71 
HaveFuncWithCallField(uint64_t callField)72     static bool HaveFuncWithCallField(uint64_t callField)
73     {
74         return HaveFuncBit::Decode(callField);
75     }
76 
IsNativeWithCallField(uint64_t callField) const77     bool IsNativeWithCallField(uint64_t callField) const
78     {
79         return IsNativeBit::Decode(callField);
80     }
81 
OnlyHaveThisWithCallField(uint64_t callField) const82     bool OnlyHaveThisWithCallField(uint64_t callField) const
83     {
84         return (callField & CALL_TYPE_MASK) == 1;  // 1: the first bit of callFiled is HaveThisBit
85     }
86 
OnlyHaveNewTagetAndThisWithCallField(uint64_t callField) const87     bool OnlyHaveNewTagetAndThisWithCallField(uint64_t callField) const
88     {
89         return (callField & CALL_TYPE_MASK) == 0b11;  // the first two bit of callFiled is `This` and `NewTarget`
90     }
91 
GetNumArgsWithCallField(uint64_t callField)92     static uint32_t GetNumArgsWithCallField(uint64_t callField)
93     {
94         return NumArgsBits::Decode(callField);
95     }
96 
SetCallNapi(uint64_t extraLiteralInfo, bool isCallNapi)97     static uint64_t SetCallNapi(uint64_t extraLiteralInfo, bool isCallNapi)
98     {
99         return IsCallNapiBit::Update(extraLiteralInfo, isCallNapi);
100     }
101 
IsCallNapi(uint64_t extraLiteralInfo)102     static bool IsCallNapi(uint64_t extraLiteralInfo)
103     {
104         return IsCallNapiBit::Decode(extraLiteralInfo);
105     }
106 
SetIsFastCall(uint64_t callField, bool isFastCall)107     static uint64_t SetIsFastCall(uint64_t callField, bool isFastCall)
108     {
109         return IsFastCallBit::Update(callField, isFastCall);
110     }
111 
IsFastCall(uint64_t callField)112     static bool IsFastCall(uint64_t callField)
113     {
114         return IsFastCallBit::Decode(callField);
115     }
116 
SetNumArgsWithCallField(uint32_t numargs)117     void SetNumArgsWithCallField(uint32_t numargs)
118     {
119         uint64_t callField = GetCallField();
120         uint64_t newValue = SetNumArgsWithCallField(callField, numargs);
121         SetCallField(newValue);
122     }
123 
SetNativeBit(bool isNative)124     void SetNativeBit(bool isNative)
125     {
126         uint64_t callField = GetCallField();
127         uint64_t newValue = SetNativeBit(callField, isNative);
128         SetCallField(newValue);
129     }
130 
SetAotCodeBit(bool isCompiled)131     void SetAotCodeBit(bool isCompiled)
132     {
133         uint64_t callField = AtomicGetCallField();
134         uint64_t newValue = SetAotCodeBit(callField, isCompiled);
135         AtomicSetCallField(newValue);
136     }
137 
SetFastBuiltinBit(bool isFastBuiltin)138     void SetFastBuiltinBit(bool isFastBuiltin)
139     {
140         uint64_t callField = GetCallField();
141         uint64_t newValue = SetFastBuiltinBit(callField, isFastBuiltin);
142         SetCallField(newValue);
143     }
144 
HaveThisWithCallField() const145     bool HaveThisWithCallField() const
146     {
147         uint64_t callField = GetCallField();
148         return HaveThisWithCallField(callField);
149     }
150 
HaveNewTargetWithCallField() const151     bool HaveNewTargetWithCallField() const
152     {
153         uint64_t callField = GetCallField();
154         return HaveNewTargetWithCallField(callField);
155     }
156 
HaveExtraWithCallField()157     bool HaveExtraWithCallField()
158     {
159         uint64_t callField = GetCallField();
160         return HaveExtraWithCallField(callField);
161     }
162 
HaveFuncWithCallField() const163     bool HaveFuncWithCallField() const
164     {
165         uint64_t callField = GetCallField();
166         return HaveFuncWithCallField(callField);
167     }
168 
IsNativeWithCallField() const169     bool IsNativeWithCallField() const
170     {
171         uint64_t callField = GetCallField();
172         return IsNativeWithCallField(callField);
173     }
174 
IsAotWithCallField() const175     bool IsAotWithCallField() const
176     {
177         uint64_t callField = AtomicGetCallField();
178         return MethodLiteral::IsAotWithCallField(callField);
179     }
180 
181     bool IsDeoptimized() const;
182 
OnlyHaveThisWithCallField() const183     bool OnlyHaveThisWithCallField() const
184     {
185         uint64_t callField = GetCallField();
186         return MethodLiteral::OnlyHaveThisWithCallField(callField);
187     }
188 
OnlyHaveNewTagetAndThisWithCallField() const189     bool OnlyHaveNewTagetAndThisWithCallField() const
190     {
191         uint64_t callField = GetCallField();
192         return MethodLiteral::OnlyHaveNewTagetAndThisWithCallField(callField);
193     }
194 
GetNumVregsWithCallField(uint64_t callField)195     static uint32_t GetNumVregsWithCallField(uint64_t callField)
196     {
197         return NumVregsBits::Decode(callField);
198     }
199 
GetNumVregsWithCallField() const200     uint32_t GetNumVregsWithCallField() const
201     {
202         uint64_t callField = GetCallField();
203         return GetNumVregsWithCallField(callField);
204     }
205 
GetNumArgsWithCallField() const206     uint32_t GetNumArgsWithCallField() const
207     {
208         uint64_t callField = GetCallField();
209         return MethodLiteral::GetNumArgsWithCallField(callField);
210     }
211 
GetNumArgs() const212     uint32_t GetNumArgs() const
213     {
214         return GetNumArgsWithCallField() + GetNumRevervedArgs();
215     }
216 
GetNumRevervedArgs() const217     uint32_t GetNumRevervedArgs() const
218     {
219         return HaveFuncWithCallField() +
220             HaveNewTargetWithCallField() + HaveThisWithCallField();
221     }
222 
GetNumberVRegs() const223     uint32_t GetNumberVRegs() const
224     {
225         return GetNumVregsWithCallField() + GetNumArgs();
226     }
227 
GetHotnessCounter() const228     inline int16_t GetHotnessCounter() const
229     {
230         uint64_t literalInfo = GetLiteralInfo();
231         return MethodLiteral::GetHotnessCounter(literalInfo);
232     }
233 
SetHotnessCounter(int16_t counter)234     inline NO_THREAD_SANITIZE void SetHotnessCounter(int16_t counter)
235     {
236         uint64_t literalInfo = GetLiteralInfo();
237         uint64_t newValue = MethodLiteral::SetHotnessCounter(literalInfo, counter);
238         SetLiteralInfo(newValue);
239     }
240 
GetMethodId() const241     EntityId GetMethodId() const
242     {
243         uint64_t literalInfo = GetLiteralInfo();
244         return MethodLiteral::GetMethodId(literalInfo);
245     }
246 
GetSlotSize() const247     uint32_t GetSlotSize() const
248     {
249         uint64_t literalInfo = GetLiteralInfo();
250         return MethodLiteral::GetSlotSize(literalInfo);
251     }
252 
GetBuiltinId(uint64_t literalInfo) const253     uint8_t GetBuiltinId(uint64_t literalInfo) const
254     {
255         return BuiltinIdBits::Decode(literalInfo);
256     }
257 
SetBuiltinId(uint64_t literalInfo, uint8_t id)258     uint64_t SetBuiltinId(uint64_t literalInfo, uint8_t id)
259     {
260         return BuiltinIdBits::Update(literalInfo, id);
261     }
262 
SetFunctionKind(uint64_t extraLiteralInfo, FunctionKind kind)263     uint64_t SetFunctionKind(uint64_t extraLiteralInfo, FunctionKind kind)
264     {
265         return FunctionKindBits::Update(extraLiteralInfo, kind);
266     }
267 
GetFunctionKind(uint64_t extraLiteralInfo) const268     FunctionKind GetFunctionKind(uint64_t extraLiteralInfo) const
269     {
270         return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo));
271     }
272 
SetDeoptThreshold(uint64_t literalInfo, uint8_t count)273     uint64_t SetDeoptThreshold(uint64_t literalInfo, uint8_t count)
274     {
275         return DeoptCountBits::Update(literalInfo, count);
276     }
277 
GetDeoptThreshold(uint64_t literalInfo) const278     uint16_t GetDeoptThreshold(uint64_t literalInfo) const
279     {
280         return DeoptCountBits::Decode(literalInfo);
281     }
282 
SetDeoptType(uint64_t extraLiteralInfo, kungfu::DeoptType type)283     uint64_t SetDeoptType(uint64_t extraLiteralInfo, kungfu::DeoptType type)
284     {
285         return DeoptTypeBits::Update(extraLiteralInfo, type);
286     }
287 
SetIsSendable(uint64_t extraLiteralInfo, bool isSendable)288     uint64_t SetIsSendable(uint64_t extraLiteralInfo, bool isSendable)
289     {
290         return IsSharedBit::Update(extraLiteralInfo, isSendable);
291     }
292 
SetFpDelta(uint64_t extraLitearalInfo, int32_t delta)293     uint64_t SetFpDelta(uint64_t extraLitearalInfo, int32_t delta)
294     {
295         return FpDeltaBits::Update(extraLitearalInfo, delta);
296     }
297 
GetFpDelta(uint64_t extraLiteralInfo) const298     int32_t GetFpDelta(uint64_t extraLiteralInfo) const
299     {
300         return static_cast<int32_t>(FpDeltaBits::Decode(extraLiteralInfo));
301     }
302 
SetDeoptType(kungfu::DeoptType type)303     void SetDeoptType(kungfu::DeoptType type)
304     {
305         uint64_t extraLiteralInfo = GetExtraLiteralInfo();
306         uint64_t newValue = SetDeoptType(extraLiteralInfo, type);
307         SetExtraLiteralInfo(newValue);
308     }
309 
GetDeoptType(uint64_t extraLiteralInfo) const310     kungfu::DeoptType GetDeoptType(uint64_t extraLiteralInfo) const
311     {
312         return static_cast<kungfu::DeoptType>(DeoptTypeBits::Decode(extraLiteralInfo));
313     }
314 
GetDeoptType() const315     kungfu::DeoptType GetDeoptType() const
316     {
317         uint64_t extraLiteralInfo = GetExtraLiteralInfo();
318         return GetDeoptType(extraLiteralInfo);
319     }
320 
SetFunctionKind(FunctionKind kind)321     void SetFunctionKind(FunctionKind kind)
322     {
323         uint64_t extraLiteralInfo = AtomicGetExtraLiteralInfo();
324         uint64_t newValue = SetFunctionKind(extraLiteralInfo, kind);
325         AtomicSetExtraLiteralInfo(newValue);
326     }
327 
GetFunctionKind() const328     FunctionKind GetFunctionKind() const
329     {
330         uint64_t extraLiteralInfo = AtomicGetExtraLiteralInfo();
331         return GetFunctionKind(extraLiteralInfo);
332     }
333 
GetBuiltinId() const334     uint8_t GetBuiltinId() const
335     {
336         uint64_t extraLiteralInfo = GetExtraLiteralInfo();
337         return GetBuiltinId(extraLiteralInfo);
338     }
339 
SetIsFastCall(bool isFastCall)340     void SetIsFastCall(bool isFastCall)
341     {
342         uint64_t callFiled = GetCallField();
343         uint64_t newValue = SetIsFastCall(callFiled, isFastCall);
344         SetCallField(newValue);
345     }
346 
IsFastCall() const347     bool IsFastCall() const
348     {
349         uint64_t callFiled = GetCallField();
350         return IsFastCall(callFiled);
351     }
352 
SetCallNapi(bool isCallNapi)353     void SetCallNapi(bool isCallNapi)
354     {
355         uint64_t extraLiteralInfo = GetExtraLiteralInfo();
356         uint64_t newValue = SetCallNapi(extraLiteralInfo, isCallNapi);
357         SetExtraLiteralInfo(newValue);
358     }
359 
IsCallNapi() const360     bool IsCallNapi() const
361     {
362         uint64_t extraLiteralInfo = GetExtraLiteralInfo();
363         return IsCallNapi(extraLiteralInfo);
364     }
365 
SetBuiltinId(uint8_t id)366     void SetBuiltinId(uint8_t id)
367     {
368         uint64_t extraLiteralInfo = GetExtraLiteralInfo();
369         uint64_t newValue = SetBuiltinId(extraLiteralInfo, id);
370         SetExtraLiteralInfo(newValue);
371     }
372 
SetDeoptThreshold(uint8_t count)373     void SetDeoptThreshold(uint8_t count)
374     {
375         uint64_t extraLiteralInfo = GetExtraLiteralInfo();
376         uint64_t newValue = SetDeoptThreshold(extraLiteralInfo, count);
377         SetExtraLiteralInfo(newValue);
378     }
379 
GetDeoptThreshold() const380     uint16_t GetDeoptThreshold() const
381     {
382         uint64_t extraLiteralInfo = GetExtraLiteralInfo();
383         return GetDeoptThreshold(extraLiteralInfo);
384     }
385 
SetFpDelta(int32_t delta)386     void SetFpDelta(int32_t delta)
387     {
388         uint64_t extraLiteralInfo = GetExtraLiteralInfo();
389         uint64_t newValue = SetFpDelta(extraLiteralInfo, delta);
390         SetExtraLiteralInfo(newValue);
391     }
392 
GetFpDelta() const393     int32_t GetFpDelta() const
394     {
395         uint64_t extraLiteralInfo = GetExtraLiteralInfo();
396         return GetFpDelta(extraLiteralInfo);
397     }
398 
GetNativePointer() const399     const void* GetNativePointer() const
400     {
401         return GetNativePointerOrBytecodeArray();
402     }
403 
SetNativePointer(void *nativePointer)404     void SetNativePointer(void *nativePointer)
405     {
406         SetNativePointerOrBytecodeArray(nativePointer);
407     }
408 
GetBytecodeArray() const409     const uint8_t *GetBytecodeArray() const
410     {
411         return reinterpret_cast<const uint8_t *>(GetNativePointerOrBytecodeArray());
412     }
413 
IsSendableMethod() const414     bool IsSendableMethod() const
415     {
416         uint64_t extraLiteralInfo = GetExtraLiteralInfo();
417         return IsSharedBit::Decode(extraLiteralInfo);
418     }
419 
SetIsSendable(bool isSendable)420     void SetIsSendable(bool isSendable)
421     {
422         uint64_t extraLiteralInfo = GetExtraLiteralInfo();
423         uint64_t newValue = SetIsSendable(extraLiteralInfo, isSendable);
424         SetExtraLiteralInfo(newValue);
425     }
426 
427     // add for AOT
428     void SetCodeEntryAndMarkAOTWhenBinding(uintptr_t codeEntry);
429 
430     void ClearAOTStatusWhenDeopt(uintptr_t entry);
431 
432     void ClearAOTFlagsWhenInit();
433 
434     void InitInterpreterStatusForCompiledMethod(const JSThread *thread);
435 
436     void SetCompiledFuncEntry(uintptr_t codeEntry, bool isFastCall);
437 
Size()438     static constexpr size_t Size()
439     {
440         return sizeof(Method);
441     }
442 
443     const JSPandaFile *PUBLIC_API GetJSPandaFile() const;
444     uint32_t PUBLIC_API GetCodeSize() const;
445     MethodLiteral *PUBLIC_API GetMethodLiteral() const;
446 
447     const char *PUBLIC_API GetMethodName() const;
448     const char *PUBLIC_API GetMethodName(const JSPandaFile *file) const;
449     std::string PUBLIC_API ParseFunctionName() const;
450     std::pair<std::string_view, bool> PUBLIC_API ParseFunctionNameView() const;
451     const CString PUBLIC_API GetRecordNameStr() const;
452 
453     uint32_t FindCatchBlock(uint32_t pc) const;
454     bool HasCatchBlock() const;
455 
456     /* callfield */
457     static constexpr size_t VREGS_ARGS_NUM_BITS = 28; // 28: maximum 268,435,455
458     static constexpr uint64_t AOT_FASTCALL_BITS = 0x5; // 0x5LU: aot and fastcall bit field
459     using HaveThisBit = BitField<bool, 0, 1>;  // offset 0
460     using HaveNewTargetBit = HaveThisBit::NextFlag;  // offset 1
461     using HaveExtraBit = HaveNewTargetBit::NextFlag;  // offset 2
462     using HaveFuncBit = HaveExtraBit::NextFlag;  // offset 3
463     using NumVregsBits = HaveFuncBit::NextField<uint32_t, VREGS_ARGS_NUM_BITS>;  // offset 4-31
464     using NumArgsBits = NumVregsBits::NextField<uint32_t, VREGS_ARGS_NUM_BITS>;  // offset 32-59
465     using IsNativeBit = NumArgsBits::NextFlag;  // offset 60
466     using IsAotCodeBit = IsNativeBit::NextFlag; // offset 61
467     using IsFastBuiltinBit = IsAotCodeBit::NextFlag; // offset 62
468     using IsFastCallBit = IsFastBuiltinBit::NextFlag; // offset 63
469 
470     /*  ExtraLiteralInfo */
471     static constexpr size_t BUILTINID_NUM_BITS = 8;
472     static constexpr size_t FUNCTION_KIND_NUM_BITS = 4;
473     static constexpr size_t DEOPT_THRESHOLD_BITS = 8;
474     static constexpr size_t DEOPTTYPE_NUM_BITS = 8;
475     static constexpr size_t FP_DELTA_BITS = 32;
476     using BuiltinIdBits = BitField<uint8_t, 0, BUILTINID_NUM_BITS>; // offset 0-7
477     using FunctionKindBits = BuiltinIdBits::NextField<FunctionKind, FUNCTION_KIND_NUM_BITS>; // offset 8-11
478     using DeoptCountBits = FunctionKindBits::NextField<uint8_t, DEOPT_THRESHOLD_BITS>; // offset 12-19
479     using DeoptTypeBits = DeoptCountBits::NextField<kungfu::DeoptType, DEOPTTYPE_NUM_BITS>; // offset 20-27
480     using IsCallNapiBit = DeoptTypeBits::NextFlag; // offset 28
481     using IsJitCompiledCodeBit = IsCallNapiBit::NextFlag; // offset 29
482     using IsSharedBit = IsJitCompiledCodeBit::NextFlag; // offset 30
483     using FpDeltaBits = IsSharedBit::NextField<int32_t, FP_DELTA_BITS>; // offset 31-62
484 
485     static constexpr size_t CONSTANT_POOL_OFFSET = TaggedObjectSize();
486     ACCESSORS(ConstantPool, CONSTANT_POOL_OFFSET, CALL_FIELD_OFFSET)
487     ACCESSORS_PRIMITIVE_FIELD_HAS_ATOMIC_INTERFACE(CallField, uint64_t, CALL_FIELD_OFFSET,
488                                                     NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET)
489     // Native method decides this filed is NativePointer or BytecodeArray pointer.
490     ACCESSORS_NATIVE_FIELD(
491         NativePointerOrBytecodeArray, void, NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET, CODEENTRY_LITERAL_OFFSET)
492     ACCESSORS_PRIMITIVE_FIELD(CodeEntryOrLiteral, uintptr_t, CODEENTRY_LITERAL_OFFSET, LITERAL_INFO_OFFSET)
493     // hotness counter is encoded in a js method field, the first uint16_t in a uint64_t.
494     ACCESSORS_PRIMITIVE_FIELD(LiteralInfo, uint64_t, LITERAL_INFO_OFFSET, EXTRA_LITERAL_INFO_OFFSET)
495     ACCESSORS_PRIMITIVE_FIELD_HAS_ATOMIC_INTERFACE(ExtraLiteralInfo, uint64_t, EXTRA_LITERAL_INFO_OFFSET, LAST_OFFSET)
496     DEFINE_ALIGN_SIZE(LAST_OFFSET);
497 
498     DECL_VISIT_OBJECT(CONSTANT_POOL_OFFSET, CALL_FIELD_OFFSET);
499 
500     DECL_DUMP()
501 
502 private:
503     static JSHandle<Method> Create(JSThread *thread, const JSPandaFile *jsPandaFile, MethodLiteral *methodLiteral);
504 
505     friend class ObjectFactory;
506 };
507 }  // namespace panda::ecmascript
508 
509 #endif  // ECMASCRIPT_METHOD_H
510