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
29namespace panda::ecmascript {
30class JSPandaFile;
31struct Reference;
32using EntityId = panda_file::File::EntityId;
33class Method : public TaggedObject {
34public:
35    CAST_CHECK(Method, IsMethod);
36
37    uint64_t SetNumArgsWithCallField(uint64_t callField, uint32_t numargs)
38    {
39        return NumArgsBits::Update(callField, numargs);
40    }
41
42    uint64_t SetNativeBit(uint64_t callField, bool isNative)
43    {
44        return IsNativeBit::Update(callField, isNative);
45    }
46
47    uint64_t SetAotCodeBit(uint64_t callField, bool isCompiled)
48    {
49        return IsAotCodeBit::Update(callField, isCompiled);
50    }
51
52    uint64_t SetFastBuiltinBit(uint64_t callField, bool isFastBuiltin)
53    {
54        return IsFastBuiltinBit::Update(callField, isFastBuiltin);
55    }
56
57    static bool HaveThisWithCallField(uint64_t callField)
58    {
59        return HaveThisBit::Decode(callField);
60    }
61
62    static bool HaveNewTargetWithCallField(uint64_t callField)
63    {
64        return HaveNewTargetBit::Decode(callField);
65    }
66
67    bool HaveExtraWithCallField(uint64_t callField)
68    {
69        return HaveExtraBit::Decode(callField);
70    }
71
72    static bool HaveFuncWithCallField(uint64_t callField)
73    {
74        return HaveFuncBit::Decode(callField);
75    }
76
77    bool IsNativeWithCallField(uint64_t callField) const
78    {
79        return IsNativeBit::Decode(callField);
80    }
81
82    bool OnlyHaveThisWithCallField(uint64_t callField) const
83    {
84        return (callField & CALL_TYPE_MASK) == 1;  // 1: the first bit of callFiled is HaveThisBit
85    }
86
87    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
92    static uint32_t GetNumArgsWithCallField(uint64_t callField)
93    {
94        return NumArgsBits::Decode(callField);
95    }
96
97    static uint64_t SetCallNapi(uint64_t extraLiteralInfo, bool isCallNapi)
98    {
99        return IsCallNapiBit::Update(extraLiteralInfo, isCallNapi);
100    }
101
102    static bool IsCallNapi(uint64_t extraLiteralInfo)
103    {
104        return IsCallNapiBit::Decode(extraLiteralInfo);
105    }
106
107    static uint64_t SetIsFastCall(uint64_t callField, bool isFastCall)
108    {
109        return IsFastCallBit::Update(callField, isFastCall);
110    }
111
112    static bool IsFastCall(uint64_t callField)
113    {
114        return IsFastCallBit::Decode(callField);
115    }
116
117    void SetNumArgsWithCallField(uint32_t numargs)
118    {
119        uint64_t callField = GetCallField();
120        uint64_t newValue = SetNumArgsWithCallField(callField, numargs);
121        SetCallField(newValue);
122    }
123
124    void SetNativeBit(bool isNative)
125    {
126        uint64_t callField = GetCallField();
127        uint64_t newValue = SetNativeBit(callField, isNative);
128        SetCallField(newValue);
129    }
130
131    void SetAotCodeBit(bool isCompiled)
132    {
133        uint64_t callField = AtomicGetCallField();
134        uint64_t newValue = SetAotCodeBit(callField, isCompiled);
135        AtomicSetCallField(newValue);
136    }
137
138    void SetFastBuiltinBit(bool isFastBuiltin)
139    {
140        uint64_t callField = GetCallField();
141        uint64_t newValue = SetFastBuiltinBit(callField, isFastBuiltin);
142        SetCallField(newValue);
143    }
144
145    bool HaveThisWithCallField() const
146    {
147        uint64_t callField = GetCallField();
148        return HaveThisWithCallField(callField);
149    }
150
151    bool HaveNewTargetWithCallField() const
152    {
153        uint64_t callField = GetCallField();
154        return HaveNewTargetWithCallField(callField);
155    }
156
157    bool HaveExtraWithCallField()
158    {
159        uint64_t callField = GetCallField();
160        return HaveExtraWithCallField(callField);
161    }
162
163    bool HaveFuncWithCallField() const
164    {
165        uint64_t callField = GetCallField();
166        return HaveFuncWithCallField(callField);
167    }
168
169    bool IsNativeWithCallField() const
170    {
171        uint64_t callField = GetCallField();
172        return IsNativeWithCallField(callField);
173    }
174
175    bool IsAotWithCallField() const
176    {
177        uint64_t callField = AtomicGetCallField();
178        return MethodLiteral::IsAotWithCallField(callField);
179    }
180
181    bool IsDeoptimized() const;
182
183    bool OnlyHaveThisWithCallField() const
184    {
185        uint64_t callField = GetCallField();
186        return MethodLiteral::OnlyHaveThisWithCallField(callField);
187    }
188
189    bool OnlyHaveNewTagetAndThisWithCallField() const
190    {
191        uint64_t callField = GetCallField();
192        return MethodLiteral::OnlyHaveNewTagetAndThisWithCallField(callField);
193    }
194
195    static uint32_t GetNumVregsWithCallField(uint64_t callField)
196    {
197        return NumVregsBits::Decode(callField);
198    }
199
200    uint32_t GetNumVregsWithCallField() const
201    {
202        uint64_t callField = GetCallField();
203        return GetNumVregsWithCallField(callField);
204    }
205
206    uint32_t GetNumArgsWithCallField() const
207    {
208        uint64_t callField = GetCallField();
209        return MethodLiteral::GetNumArgsWithCallField(callField);
210    }
211
212    uint32_t GetNumArgs() const
213    {
214        return GetNumArgsWithCallField() + GetNumRevervedArgs();
215    }
216
217    uint32_t GetNumRevervedArgs() const
218    {
219        return HaveFuncWithCallField() +
220            HaveNewTargetWithCallField() + HaveThisWithCallField();
221    }
222
223    uint32_t GetNumberVRegs() const
224    {
225        return GetNumVregsWithCallField() + GetNumArgs();
226    }
227
228    inline int16_t GetHotnessCounter() const
229    {
230        uint64_t literalInfo = GetLiteralInfo();
231        return MethodLiteral::GetHotnessCounter(literalInfo);
232    }
233
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
241    EntityId GetMethodId() const
242    {
243        uint64_t literalInfo = GetLiteralInfo();
244        return MethodLiteral::GetMethodId(literalInfo);
245    }
246
247    uint32_t GetSlotSize() const
248    {
249        uint64_t literalInfo = GetLiteralInfo();
250        return MethodLiteral::GetSlotSize(literalInfo);
251    }
252
253    uint8_t GetBuiltinId(uint64_t literalInfo) const
254    {
255        return BuiltinIdBits::Decode(literalInfo);
256    }
257
258    uint64_t SetBuiltinId(uint64_t literalInfo, uint8_t id)
259    {
260        return BuiltinIdBits::Update(literalInfo, id);
261    }
262
263    uint64_t SetFunctionKind(uint64_t extraLiteralInfo, FunctionKind kind)
264    {
265        return FunctionKindBits::Update(extraLiteralInfo, kind);
266    }
267
268    FunctionKind GetFunctionKind(uint64_t extraLiteralInfo) const
269    {
270        return static_cast<FunctionKind>(FunctionKindBits::Decode(extraLiteralInfo));
271    }
272
273    uint64_t SetDeoptThreshold(uint64_t literalInfo, uint8_t count)
274    {
275        return DeoptCountBits::Update(literalInfo, count);
276    }
277
278    uint16_t GetDeoptThreshold(uint64_t literalInfo) const
279    {
280        return DeoptCountBits::Decode(literalInfo);
281    }
282
283    uint64_t SetDeoptType(uint64_t extraLiteralInfo, kungfu::DeoptType type)
284    {
285        return DeoptTypeBits::Update(extraLiteralInfo, type);
286    }
287
288    uint64_t SetIsSendable(uint64_t extraLiteralInfo, bool isSendable)
289    {
290        return IsSharedBit::Update(extraLiteralInfo, isSendable);
291    }
292
293    uint64_t SetFpDelta(uint64_t extraLitearalInfo, int32_t delta)
294    {
295        return FpDeltaBits::Update(extraLitearalInfo, delta);
296    }
297
298    int32_t GetFpDelta(uint64_t extraLiteralInfo) const
299    {
300        return static_cast<int32_t>(FpDeltaBits::Decode(extraLiteralInfo));
301    }
302
303    void SetDeoptType(kungfu::DeoptType type)
304    {
305        uint64_t extraLiteralInfo = GetExtraLiteralInfo();
306        uint64_t newValue = SetDeoptType(extraLiteralInfo, type);
307        SetExtraLiteralInfo(newValue);
308    }
309
310    kungfu::DeoptType GetDeoptType(uint64_t extraLiteralInfo) const
311    {
312        return static_cast<kungfu::DeoptType>(DeoptTypeBits::Decode(extraLiteralInfo));
313    }
314
315    kungfu::DeoptType GetDeoptType() const
316    {
317        uint64_t extraLiteralInfo = GetExtraLiteralInfo();
318        return GetDeoptType(extraLiteralInfo);
319    }
320
321    void SetFunctionKind(FunctionKind kind)
322    {
323        uint64_t extraLiteralInfo = AtomicGetExtraLiteralInfo();
324        uint64_t newValue = SetFunctionKind(extraLiteralInfo, kind);
325        AtomicSetExtraLiteralInfo(newValue);
326    }
327
328    FunctionKind GetFunctionKind() const
329    {
330        uint64_t extraLiteralInfo = AtomicGetExtraLiteralInfo();
331        return GetFunctionKind(extraLiteralInfo);
332    }
333
334    uint8_t GetBuiltinId() const
335    {
336        uint64_t extraLiteralInfo = GetExtraLiteralInfo();
337        return GetBuiltinId(extraLiteralInfo);
338    }
339
340    void SetIsFastCall(bool isFastCall)
341    {
342        uint64_t callFiled = GetCallField();
343        uint64_t newValue = SetIsFastCall(callFiled, isFastCall);
344        SetCallField(newValue);
345    }
346
347    bool IsFastCall() const
348    {
349        uint64_t callFiled = GetCallField();
350        return IsFastCall(callFiled);
351    }
352
353    void SetCallNapi(bool isCallNapi)
354    {
355        uint64_t extraLiteralInfo = GetExtraLiteralInfo();
356        uint64_t newValue = SetCallNapi(extraLiteralInfo, isCallNapi);
357        SetExtraLiteralInfo(newValue);
358    }
359
360    bool IsCallNapi() const
361    {
362        uint64_t extraLiteralInfo = GetExtraLiteralInfo();
363        return IsCallNapi(extraLiteralInfo);
364    }
365
366    void SetBuiltinId(uint8_t id)
367    {
368        uint64_t extraLiteralInfo = GetExtraLiteralInfo();
369        uint64_t newValue = SetBuiltinId(extraLiteralInfo, id);
370        SetExtraLiteralInfo(newValue);
371    }
372
373    void SetDeoptThreshold(uint8_t count)
374    {
375        uint64_t extraLiteralInfo = GetExtraLiteralInfo();
376        uint64_t newValue = SetDeoptThreshold(extraLiteralInfo, count);
377        SetExtraLiteralInfo(newValue);
378    }
379
380    uint16_t GetDeoptThreshold() const
381    {
382        uint64_t extraLiteralInfo = GetExtraLiteralInfo();
383        return GetDeoptThreshold(extraLiteralInfo);
384    }
385
386    void SetFpDelta(int32_t delta)
387    {
388        uint64_t extraLiteralInfo = GetExtraLiteralInfo();
389        uint64_t newValue = SetFpDelta(extraLiteralInfo, delta);
390        SetExtraLiteralInfo(newValue);
391    }
392
393    int32_t GetFpDelta() const
394    {
395        uint64_t extraLiteralInfo = GetExtraLiteralInfo();
396        return GetFpDelta(extraLiteralInfo);
397    }
398
399    const void* GetNativePointer() const
400    {
401        return GetNativePointerOrBytecodeArray();
402    }
403
404    void SetNativePointer(void *nativePointer)
405    {
406        SetNativePointerOrBytecodeArray(nativePointer);
407    }
408
409    const uint8_t *GetBytecodeArray() const
410    {
411        return reinterpret_cast<const uint8_t *>(GetNativePointerOrBytecodeArray());
412    }
413
414    bool IsSendableMethod() const
415    {
416        uint64_t extraLiteralInfo = GetExtraLiteralInfo();
417        return IsSharedBit::Decode(extraLiteralInfo);
418    }
419
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
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
502private:
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