1/*
2 * Copyright (c) 2023 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_FRAMES_H
17#define ECMASCRIPT_FRAMES_H
18
19#include "ecmascript/base/aligned_struct.h"
20#include "ecmascript/js_tagged_value.h"
21#include "ecmascript/mem/visitor.h"
22#include "ecmascript/method.h"
23#include "ecmascript/stackmap/ark_stackmap.h"
24#include "ecmascript/stackmap/llvm/llvm_stackmap_type.h"
25
26namespace panda::ecmascript {
27class JSThread;
28class EcmaVM;
29class FrameIterator;
30namespace kungfu {
31    class ArkStackMapParser;
32};
33
34static constexpr int64_t BASELINEJIT_PC_FLAG = static_cast<int64_t>(std::numeric_limits<uint64_t>::max());
35
36// Here list all scenarios of calling between Runtime/CInterpreter/ASMInterpreter/AOTCompiler/CBuiltin/ASMBuitlin.
37// Please note that the "[]" means a must frame while "<>" means an optional frame. Each case is from top to down.
38//
39// * Runtime (C++) => CInterpreter:
40//          1) [INTERPRETER_FRAME]
41//
42// * Runtime (C++) -> AOTCompiler:
43//          1) [OPTIMIZED_ENTRY_FRAME]
44//             <OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME>
45//             <OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME>
46//             [OPTIMIZED_JS_FUNCTION_FRAME]
47//
48// * Runtime (C++) => ASMInterpreter:
49//          1) [INTERPRETER_ENTRY_FRAME][ASM_INTERPRETER_FRAME]
50//
51// * Runtime (C++) => CBuiltin:
52//          1) [not supported]
53//
54// * Runtime (C++) => ASMBuiltin:
55//          1) [not supported]
56//
57// * CInterpreter => CInterpreter:
58//          1) [INTERPRETER_FRAME]
59//
60// * CInterpreter => Runtime (C++):
61//          1) [INTERPRETER_FAST_NEW_FRAME]
62//          2) [INTERPRETER_CONSTRUCTOR_FRAME]
63//
64// * CInterpreter => AOTCompiler:
65//          1) [not supported]
66//
67// * CInterperter => CBuiltin:
68//          1) [INTERPRETER_BUILTIN_FRAME]
69//
70// * CInterpreter => ASMBuiltin:
71//          1) [not supported]
72//
73// * ASMInterpreter => Runtime (C++):
74//          1) [LEAVE_FRAME]
75//          2) [LEAVE_FRAME_WITH_ARGV]
76//
77// * ASMInterpreter => AOTCompiler:
78//          1) [OPTIMIZED_ENTRY_FRAME]
79//             <OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME>
80//             <OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME>
81//             [OPTIMIZED_JS_FUNCTION_FRAME]
82//
83// * ASMInterpreter => ASMInterpreter:
84//          1) [ASM_INTERPRETER_FRAME]
85//
86// * ASMInterpreter => AsmBuiltin:
87//          1) [BUILTIN_ENTRY_FRAME]
88//             [BUILTIN_FRAME]
89//          2) [BUILTIN_ENTRY_FRAME]
90//             [BUILTIN_FRAME_WITH_ARGV]
91//
92// * ASMInterpreter => CBuiltin:
93//          1) [LEAVE_FRAME]
94//          2) [LEAVE_FRAME_WITH_ARGV]
95//
96// * AOTCompiler => Runtime (C++):
97//          1) [LEAVE_FRAME]
98//          2) [LEAVE_FRAME_WITH_ARGV]
99//
100// * AOTCompiler => ASMInterpreter:
101//          1) [ASM_INTERPRETER_BRIDGE_FRAME]
102//          2) [ASM_INTERPRETER_FRAME]
103//
104// * AOTCompiler => CBuiltin:
105//          1) [LEAVE_FRAME]
106//          2) [LEAVE_FRAME_WITH_ARGV]
107//
108// * AOTCompiler => ASMBuiltin:
109//          1) [BUILTIN_ENTRY_FRAME]
110//             [BUILTIN_FRAME]
111//          2) [BUILTIN_ENTRY_FRAME]
112//             [BUILTIN_FRAME_WITH_ARGV]
113
114
115enum class FrameType: uintptr_t {
116    OPTIMIZED_FRAME = 0,
117    OPTIMIZED_ENTRY_FRAME,
118    OPTIMIZED_JS_FUNCTION_FRAME,
119    OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME,
120    FASTJIT_FUNCTION_FRAME,
121    FASTJIT_FAST_CALL_FUNCTION_FRAME,
122    ASM_BRIDGE_FRAME,
123    LEAVE_FRAME,
124    LEAVE_FRAME_WITH_ARGV,
125    BUILTIN_CALL_LEAVE_FRAME,
126    INTERPRETER_FRAME,
127    ASM_INTERPRETER_FRAME,
128    INTERPRETER_CONSTRUCTOR_FRAME,
129    BUILTIN_FRAME,
130    BUILTIN_FRAME_WITH_ARGV,
131    BUILTIN_ENTRY_FRAME,
132    INTERPRETER_BUILTIN_FRAME,
133    INTERPRETER_FAST_NEW_FRAME,
134    INTERPRETER_ENTRY_FRAME,
135    ASM_INTERPRETER_ENTRY_FRAME,
136    ASM_INTERPRETER_BRIDGE_FRAME,
137    OPTIMIZED_JS_FUNCTION_ARGS_CONFIG_FRAME,
138    OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME,
139    BUILTIN_FRAME_WITH_ARGV_STACK_OVER_FLOW_FRAME,
140    BASELINE_BUILTIN_FRAME,
141
142    FRAME_TYPE_FIRST = OPTIMIZED_FRAME,
143    FRAME_TYPE_LAST = OPTIMIZED_JS_FUNCTION_UNFOLD_ARGV_FRAME,
144    INTERPRETER_FIRST = INTERPRETER_FRAME,
145    INTERPRETER_LAST = INTERPRETER_FAST_NEW_FRAME,
146    BUILTIN_FIRST = BUILTIN_FRAME,
147    BUILTIN_LAST = BUILTIN_ENTRY_FRAME,
148};
149
150enum class JSCallMode : uintptr_t {
151    CALL_ARG0 = 0,
152    CALL_ARG1,
153    CALL_ARG2,
154    CALL_ARG3,
155    CALL_THIS_ARG0,
156    CALL_THIS_ARG1,
157    CALL_THIS_ARG2,
158    CALL_THIS_ARG3,
159    CALL_WITH_ARGV,
160    CALL_THIS_WITH_ARGV,
161    CALL_CONSTRUCTOR_WITH_ARGV,
162    SUPER_CALL_WITH_ARGV,
163    SUPER_CALL_SPREAD_WITH_ARGV,
164    DEPRECATED_CALL_ARG0,
165    DEPRECATED_CALL_ARG1,
166    DEPRECATED_CALL_ARG2,
167    DEPRECATED_CALL_ARG3,
168    DEPRECATED_CALL_WITH_ARGV,
169    DEPRECATED_CALL_THIS_WITH_ARGV,
170    DEPRECATED_CALL_CONSTRUCTOR_WITH_ARGV,
171    CALL_GETTER,
172    CALL_SETTER,
173    CALL_THIS_ARG2_WITH_RETURN,
174    CALL_THIS_ARG3_WITH_RETURN,
175    CALL_THIS_ARGV_WITH_RETURN,
176    CALL_ENTRY,
177    CALL_GENERATOR,
178    CALL_FROM_AOT,
179};
180
181// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
182struct OptimizedFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
183                                                   base::AlignedPointer,
184                                                   base::AlignedPointer,
185                                                   base::AlignedPointer> {
186public:
187    void GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
188        const RootBaseAndDerivedVisitor &derivedVisitor) const;
189
190    static size_t GetTypeOffset(bool isArch32 = false)
191    {
192        return GetOffset<static_cast<size_t>(Index::TypeIndex)>(isArch32);
193    }
194
195    static size_t GetPrevOffset(bool isArch32 = false)
196    {
197        return GetOffset<static_cast<size_t>(Index::PrevFpIndex)>(isArch32);
198    }
199
200    static size_t GetReturnAddrOffset(bool isArch32 = false)
201    {
202        return GetOffset<static_cast<size_t>(Index::ReturnAddrIndex)>(isArch32);
203    }
204
205    static size_t ComputeReservedSize(size_t slotSize)
206    {
207        size_t slotOffset = static_cast<size_t>(Index::PrevFpIndex) - static_cast<size_t>(Index::TypeIndex);
208        return slotSize * slotOffset;
209    }
210
211    FrameType GetType() const
212    {
213        return type;
214    }
215
216private:
217    enum class Index : size_t {
218        TypeIndex = 0,
219        PrevFpIndex,
220        ReturnAddrIndex,
221        NumOfMembers
222    };
223    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
224
225    static OptimizedFrame* GetFrameFromSp(const JSTaggedType *sp)
226    {
227        return reinterpret_cast<OptimizedFrame *>(reinterpret_cast<uintptr_t>(sp) -
228            MEMBER_OFFSET(OptimizedFrame, prevFp));
229    }
230    inline JSTaggedType* GetPrevFrameFp()
231    {
232        return prevFp;
233    }
234    uintptr_t GetReturnAddr() const
235    {
236        return returnAddr;
237    }
238
239    alignas(EAS) FrameType type {0};
240    alignas(EAS) JSTaggedType *prevFp {nullptr};
241    alignas(EAS) uintptr_t returnAddr {0};
242    friend class FrameIterator;
243};
244STATIC_ASSERT_EQ_ARCH(sizeof(OptimizedFrame), OptimizedFrame::SizeArch32, OptimizedFrame::SizeArch64);
245
246// * BaselineBuiltinFrame layout as the following:
247//               +--------------------------+ ---------
248//               |       . . . . .          |         ^
249// callerSP ---> |--------------------------|         |
250//               |       returnAddr         |         |
251//               |--------------------------|   BuiltinBuiltinFrame
252//               |       callsiteFp         |         |
253//       fp ---> |--------------------------|         |
254//               |       frameType          |         v
255//               +--------------------------+ ---------
256//               |        . . . .           |
257// calleeSP ---> +--------------------------+
258//
259// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
260struct BaselineBuiltinFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
261                                                         base::AlignedPointer,
262                                                         base::AlignedPointer,
263                                                         base::AlignedPointer> {
264public:
265    void GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
266        const RootBaseAndDerivedVisitor &derivedVisitor) const;
267
268    static size_t GetTypeOffset(bool isArch32 = false)
269    {
270        return GetOffset<static_cast<size_t>(Index::TypeIndex)>(isArch32);
271    }
272
273    static size_t GetPrevOffset(bool isArch32 = false)
274    {
275        return GetOffset<static_cast<size_t>(Index::PrevFpIndex)>(isArch32);
276    }
277
278    static size_t GetReturnAddrOffset(bool isArch32 = false)
279    {
280        return GetOffset<static_cast<size_t>(Index::ReturnAddrIndex)>(isArch32);
281    }
282
283    static size_t ComputeReservedSize(size_t slotSize)
284    {
285        size_t slotOffset = static_cast<size_t>(Index::PrevFpIndex) - static_cast<size_t>(Index::TypeIndex);
286        return slotSize * slotOffset;
287    }
288
289    FrameType GetType() const
290    {
291        return type;
292    }
293
294    uintptr_t GetReturnAddr() const
295    {
296        return returnAddr;
297    }
298
299private:
300    enum class Index : size_t {
301        TypeIndex = 0,
302        PrevFpIndex,
303        ReturnAddrIndex,
304        NumOfMembers
305    };
306    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
307
308    static BaselineBuiltinFrame* GetFrameFromSp(const JSTaggedType *sp)
309    {
310        return reinterpret_cast<BaselineBuiltinFrame *>(reinterpret_cast<uintptr_t>(sp) -
311            MEMBER_OFFSET(BaselineBuiltinFrame, prevFp));
312    }
313    inline JSTaggedType* GetPrevFrameFp()
314    {
315        return prevFp;
316    }
317
318    alignas(EAS) FrameType type {0};
319    alignas(EAS) JSTaggedType *prevFp {nullptr};
320    alignas(EAS) uintptr_t returnAddr {0};
321    friend class FrameIterator;
322};
323STATIC_ASSERT_EQ_ARCH(sizeof(BaselineBuiltinFrame), BaselineBuiltinFrame::SizeArch32, BaselineBuiltinFrame::SizeArch64);
324
325struct AsmBridgeFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
326                                                   base::AlignedPointer,
327                                                   base::AlignedPointer,
328                                                   base::AlignedPointer> {
329public:
330    static size_t GetTypeOffset(bool isArch32 = false)
331    {
332        return GetOffset<static_cast<size_t>(Index::TypeIndex)>(isArch32);
333    }
334
335    static size_t GetPrevOffset(bool isArch32 = false)
336    {
337        return GetOffset<static_cast<size_t>(Index::PrevFpIndex)>(isArch32);
338    }
339
340    static size_t GetReturnAddrOffset(bool isArch32 = false)
341    {
342        return GetOffset<static_cast<size_t>(Index::ReturnAddrIndex)>(isArch32);
343    }
344
345    uintptr_t GetCallSiteSp() const
346    {
347        return ToUintPtr(this) + sizeof(AsmBridgeFrame);
348    }
349
350    FrameType GetType() const
351    {
352        return type;
353    }
354
355private:
356    enum class Index : size_t {
357        TypeIndex = 0,
358        PrevFpIndex,
359        ReturnAddrIndex,
360        NumOfMembers
361    };
362    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
363
364    static AsmBridgeFrame* GetFrameFromSp(const JSTaggedType *sp)
365    {
366        return reinterpret_cast<AsmBridgeFrame *>(reinterpret_cast<uintptr_t>(sp) -
367            MEMBER_OFFSET(AsmBridgeFrame, prevFp));
368    }
369    inline JSTaggedType* GetPrevFrameFp()
370    {
371        return prevFp;
372    }
373    uintptr_t GetReturnAddr() const
374    {
375        return returnAddr;
376    }
377    alignas(EAS) FrameType type {0};
378    alignas(EAS) JSTaggedType *prevFp {nullptr};
379    alignas(EAS) uintptr_t returnAddr {0};
380    friend class FrameIterator;
381};
382STATIC_ASSERT_EQ_ARCH(sizeof(AsmBridgeFrame), AsmBridgeFrame::SizeArch32, AsmBridgeFrame::SizeArch64);
383
384// * OptimizedUnfoldArgVFrame layout description as the following:
385// callerSP ---> |--------------------------| ---------------
386//               |       returnAddr         |               ^
387//               |--------------------------|               |
388//               |       prevFp             |               |
389//       fp ---> |--------------------------|   OptimizedUnfoldArgVFrame
390//               |       frameType          |               |
391//               |--------------------------|               |
392//               |       currentFp          |               v
393// calleESP ---> +--------------------------+ ---------------
394//
395// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
396struct OptimizedJSFunctionUnfoldArgVFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
397                                                                       base::AlignedPointer,
398                                                                       base::AlignedPointer,
399                                                                       base::AlignedPointer,
400                                                                       base::AlignedPointer> {
401public:
402    static size_t GetTypeOffset(bool isArch32 = false)
403    {
404        return GetOffset<static_cast<size_t>(Index::TypeIndex)>(isArch32);
405    }
406
407    static size_t GetPrevOffset(bool isArch32 = false)
408    {
409        return GetOffset<static_cast<size_t>(Index::PrevFpIndex)>(isArch32);
410    }
411
412    static size_t GetReturnAddrOffset(bool isArch32 = false)
413    {
414        return GetOffset<static_cast<size_t>(Index::ReturnAddrIndex)>(isArch32);
415    }
416
417    FrameType GetType() const
418    {
419        return type;
420    }
421
422private:
423    enum class Index : size_t {
424        CallSiteSpIndex = 0,
425        TypeIndex,
426        PrevFpIndex,
427        ReturnAddrIndex,
428        NumOfMembers
429    };
430    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
431
432    static OptimizedJSFunctionUnfoldArgVFrame* GetFrameFromSp(const JSTaggedType *sp)
433    {
434        return reinterpret_cast<OptimizedJSFunctionUnfoldArgVFrame *>(reinterpret_cast<uintptr_t>(sp) -
435            MEMBER_OFFSET(OptimizedJSFunctionUnfoldArgVFrame, prevFp));
436    }
437    inline JSTaggedType* GetPrevFrameFp() const
438    {
439        return prevFp;
440    }
441    uintptr_t GetReturnAddr() const
442    {
443        return returnAddr;
444    }
445    uintptr_t GetPrevFrameSp() const
446    {
447        return callSiteSp;
448    }
449    alignas(EAS) uintptr_t callSiteSp {0};
450    alignas(EAS) FrameType type {0};
451    alignas(EAS) JSTaggedType *prevFp {nullptr};
452    alignas(EAS) uintptr_t returnAddr {0};
453    friend class FrameIterator;
454};
455STATIC_ASSERT_EQ_ARCH(sizeof(OptimizedJSFunctionUnfoldArgVFrame),
456    OptimizedJSFunctionUnfoldArgVFrame::SizeArch32, OptimizedJSFunctionUnfoldArgVFrame::SizeArch64);
457
458// * The OptimizedJSFunctionArgsConfig Frame's structure is illustrated as the following:
459//          +--------------------------+
460//          |         arg[N-1]         |
461//          +--------------------------+
462//          |         . . . .          |
463//          +--------------------------+
464//          |         arg[0]           |
465//          +--------------------------+
466//          |         argC             |
467//  sp ---> +--------------------------+ -----------------
468//          |                          |                 ^
469//          |        prevFP            |                 |
470//  fp ---> |--------------------------|    OptimizedJSFunctionArgsConfigFrame
471//          |       frameType          |                 |
472//          |                          |                 V
473//          +--------------------------+ -----------------
474//
475// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
476struct OptimizedJSFunctionArgConfigFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
477                                                                      base::AlignedPointer,
478                                                                      base::AlignedPointer> {
479public:
480    static size_t GetTypeOffset(bool isArch32 = false)
481    {
482        return GetOffset<static_cast<size_t>(Index::TypeIndex)>(isArch32);
483    }
484
485    static size_t GetPrevOffset(bool isArch32 = false)
486    {
487        return GetOffset<static_cast<size_t>(Index::PrevFpIndex)>(isArch32);
488    }
489
490    FrameType GetType() const
491    {
492        return type;
493    }
494
495private:
496    enum class Index : size_t {
497        TypeIndex = 0,
498        PrevFpIndex,
499        NumOfMembers
500    };
501    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
502
503    static OptimizedJSFunctionArgConfigFrame* GetFrameFromSp(const JSTaggedType *sp)
504    {
505        return reinterpret_cast<OptimizedJSFunctionArgConfigFrame *>(reinterpret_cast<uintptr_t>(sp) -
506            MEMBER_OFFSET(OptimizedJSFunctionArgConfigFrame, prevFp));
507    }
508    inline JSTaggedType* GetPrevFrameFp()
509    {
510        return prevFp;
511    }
512
513    alignas(EAS) FrameType type {0};
514    alignas(EAS) JSTaggedType *prevFp {nullptr};
515    friend class FrameIterator;
516};
517STATIC_ASSERT_EQ_ARCH(sizeof(OptimizedJSFunctionArgConfigFrame),
518                      OptimizedJSFunctionArgConfigFrame::SizeArch32,
519                      OptimizedJSFunctionArgConfigFrame::SizeArch64);
520
521// * OptimizedJSFunctionFrame layout description as the following:
522//                 +----------------------------------------+
523//                 |     arg[N-1]                           |
524//                 +----------------------------------------+
525//                 |     ...                                |
526//                 +----------------------------------------+
527//                 |     arg[1]                             |
528//                 +----------------------------------------+
529//                 |     arg[0]                             |
530//                 +----------------------------------------+
531//                 |     this                               |
532//                 +----------------------------------------+
533//                 |     new-target [not exist in fastcall] |
534//                 +----------------------------------------+
535//                 |     call-target                        |
536//       argv ---> +----------------------------------------+
537//                 |     argv   [not exist in fastcall]     |
538//                 |----------------------------------------|
539//                 |     argc   [not exist in fastcall]     |
540//   callerSp ---> |----------------------------------------|----------------
541//                 |     returnAddr                         |               ^
542//                 |----------------------------------------|               |
543//                 |     callsiteFp                         |               |
544//         fp ---> |----------------------------------------|   OptimizedJSFunctionFrame
545//                 |     frameType                          |               |
546//                 |----------------------------------------|               |
547//                 |     call-target                        |               v
548//   calleeSP ---> +----------------------------------------+----------------
549//
550// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
551struct OptimizedJSFunctionFrame : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
552                                                             JSTaggedValue,
553                                                             base::AlignedPointer,
554                                                             base::AlignedPointer,
555                                                             base::AlignedPointer> {
556public:
557    using ConstInfo = kungfu::LLVMStackMapType::ConstInfo;
558    enum class Index : size_t {
559        JSFuncIndex = 0,
560        TypeIndex,
561        PrevFpIndex,
562        ReturnAddrIndex,
563        NumOfMembers
564    };
565    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
566
567    static constexpr size_t GetFunctionDeltaReturnAddr()
568    {
569        return static_cast<size_t>(Index::ReturnAddrIndex) - static_cast<size_t>(Index::JSFuncIndex);
570    }
571
572    inline JSTaggedType* GetPrevFrameFp()
573    {
574        return prevFp;
575    }
576
577    JSTaggedType* GetArgv(uintptr_t *preFrameSp) const
578    {
579        const size_t offset = 2;    // 2: skip argc and argv.
580        return reinterpret_cast<JSTaggedType *>(preFrameSp + offset * sizeof(uint64_t) / sizeof(uintptr_t));
581    }
582
583    size_t GetArgc(uintptr_t *preFrameSp) const
584    {
585        return *preFrameSp;
586    }
587
588    JSTaggedType* GetArgv(const FrameIterator &it) const;
589
590    uintptr_t GetReturnAddr() const
591    {
592        return returnAddr;
593    }
594
595    void GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
596        const RootBaseAndDerivedVisitor &derivedVisitor, FrameType frameType) const;
597    void CollectPcOffsetInfo(const FrameIterator &it, ConstInfo &info) const;
598
599    inline JSTaggedValue GetFunction() const
600    {
601        return jsFunc;
602    }
603
604    static uintptr_t ComputeArgsConfigFrameSp(JSTaggedType *fp)
605    {
606        const size_t offset = 2;  // 2: skip prevFp and return address.
607        return reinterpret_cast<uintptr_t>(fp) + offset * sizeof(uintptr_t);
608    }
609
610    static size_t GetTypeOffset(bool isArch32 = false)
611    {
612        return GetOffset<static_cast<size_t>(Index::TypeIndex)>(isArch32);
613    }
614
615    static size_t GetPrevOffset(bool isArch32 = false)
616    {
617        return GetOffset<static_cast<size_t>(Index::PrevFpIndex)>(isArch32);
618    }
619
620    static size_t GetFunctionOffset(bool isArch32 = false)
621    {
622        return GetOffset<static_cast<size_t>(Index::JSFuncIndex)>(isArch32);
623    }
624
625    static size_t GetReturnAddrOffset(bool isArch32 = false)
626    {
627        return GetOffset<static_cast<size_t>(Index::ReturnAddrIndex)>(isArch32);
628    }
629
630    static size_t ComputeReservedJSFuncOffset(size_t slotSize)
631    {
632        size_t slotOffset = static_cast<size_t>(Index::PrevFpIndex) - static_cast<size_t>(Index::JSFuncIndex);
633        return slotSize * slotOffset;
634    }
635
636    static int GetFrmaeTypeToFpDelta()
637    {
638        return -(int)sizeof(uintptr_t);
639    }
640
641    static int GetFunctionToFpDelta()
642    {
643        int slotOffset = static_cast<int>(Index::JSFuncIndex) - static_cast<int>(Index::TypeIndex);
644        return slotOffset * JSTaggedValue::TaggedTypeSize() + GetFrmaeTypeToFpDelta();
645    }
646
647    FrameType GetType() const
648    {
649        return type;
650    }
651
652    friend class FrameIterator;
653    friend class FrameHandler;
654    void GetDeoptBundleInfo(const FrameIterator &it, std::vector<kungfu::ARKDeopt>& deopts) const;
655    void GetFuncCalleeRegAndOffset(
656        const FrameIterator &it, kungfu::CalleeRegAndOffsetVec &ret) const;
657    uintptr_t* ComputePrevFrameSp(const FrameIterator &it) const;
658
659private:
660    static OptimizedJSFunctionFrame* GetFrameFromSp(const JSTaggedType *sp)
661    {
662        return reinterpret_cast<OptimizedJSFunctionFrame *>(reinterpret_cast<uintptr_t>(sp) -
663            MEMBER_OFFSET(OptimizedJSFunctionFrame, prevFp));
664    }
665
666    // dynamic callee saveregisters for x86-64
667    alignas(EAS) JSTaggedValue jsFunc {JSTaggedValue::Undefined()};
668    alignas(EAS) FrameType type {0};
669    alignas(EAS) JSTaggedType *prevFp {nullptr};
670    alignas(EAS) uintptr_t returnAddr {0};
671    // dynamic callee saveregisters for arm64
672};
673STATIC_ASSERT_EQ_ARCH(sizeof(OptimizedJSFunctionFrame),
674                      OptimizedJSFunctionFrame::SizeArch32,
675                      OptimizedJSFunctionFrame::SizeArch64);
676// 2: return addr & prevFp, type and js function should be pairs to update type and js function at the same time.
677static_assert((OptimizedJSFunctionFrame::GetFunctionDeltaReturnAddr() % 2) == 1);
678
679// * The JSFunctionEntry Frame's structure is illustrated as the following:
680//              +--------------------------+
681//              |      . . . . . .         |
682// callerSP --> +--------------------------+ -----------------
683//              |        prevFP            |                 ^
684//       fp --> |--------------------------|                 |
685//              |       frameType          |      JSFunctionEntryFrame
686//              |--------------------------|                 |
687//              |    preLeaveFrameFp       |                 v
688// calleeSP --> +--------------------------+ -----------------
689
690struct OptimizedEntryFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
691                                                        base::AlignedPointer,
692                                                        base::AlignedPointer,
693                                                        base::AlignedPointer> {
694public:
695    enum class CallType : size_t {
696        CALL_FUNC = 0,
697        CALL_NEW,
698    };
699
700    enum class Index : size_t {
701        PreLeaveFrameFpIndex = 0,
702        TypeIndex,
703        PrevFpIndex,
704        NumOfMembers
705    };
706
707    static size_t GetTypeOffset(bool isArch32 = false)
708    {
709        return GetOffset<static_cast<size_t>(Index::TypeIndex)>(isArch32);
710    }
711
712    static size_t GetLeaveFrameFpOffset(bool isArch32 = false)
713    {
714        return GetOffset<static_cast<size_t>(Index::PreLeaveFrameFpIndex)>(isArch32);
715    }
716
717    inline JSTaggedType* GetPrevFrameFp()
718    {
719        return preLeaveFrameFp;
720    }
721
722    static size_t ComputeReservedSize(size_t slotSize)
723    {
724        size_t slotOffset = static_cast<size_t>(Index::PrevFpIndex) - static_cast<size_t>(Index::PreLeaveFrameFpIndex);
725        return slotSize * slotOffset;
726    }
727
728    FrameType GetType() const
729    {
730        return type;
731    }
732    friend class FrameIterator;
733
734private:
735    static OptimizedEntryFrame* GetFrameFromSp(const JSTaggedType *sp)
736    {
737        return reinterpret_cast<OptimizedEntryFrame *>(reinterpret_cast<uintptr_t>(sp) -
738                                                       MEMBER_OFFSET(OptimizedEntryFrame, prevFp));
739    }
740
741    JSTaggedType* GetLeaveFp() const
742    {
743        return preLeaveFrameFp;
744    }
745
746    JSTaggedType* GetPrevFp() const
747    {
748        return prevFp;
749    }
750
751    alignas(EAS) JSTaggedType *preLeaveFrameFp {nullptr};
752    alignas(EAS) FrameType type {0};
753    alignas(EAS) JSTaggedType *prevFp {nullptr};
754};
755STATIC_ASSERT_EQ_ARCH(sizeof(OptimizedEntryFrame), OptimizedEntryFrame::SizeArch32, OptimizedEntryFrame::SizeArch64);
756
757// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
758struct InterpretedFrameBase : public base::AlignedStruct<base::AlignedPointer::Size(),
759                                                         base::AlignedPointer,
760                                                         base::AlignedSize> {
761    enum class Index : size_t {
762        PrevIndex = 0,
763        TypeIndex,
764        NumOfMembers
765    };
766    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
767
768    inline JSTaggedType* GetPrevFrameFp()
769    {
770        return prev;
771    }
772
773    static InterpretedFrameBase* GetFrameFromSp(const JSTaggedType *sp)
774    {
775        return reinterpret_cast<InterpretedFrameBase *>(const_cast<JSTaggedType *>(sp)) - 1;
776    }
777
778    static size_t GetPrevOffset(bool isArch32 = false)
779    {
780        return GetOffset<static_cast<size_t>(Index::PrevIndex)>(isArch32);
781    }
782
783    static size_t GetTypeOffset(bool isArch32 = false)
784    {
785        return GetOffset<static_cast<size_t>(Index::TypeIndex)>(isArch32);
786    }
787
788    static constexpr size_t GetSize(bool isArch32)
789    {
790        return isArch32 ? InterpretedFrameBase::SizeArch32 : InterpretedFrameBase::SizeArch64;
791    }
792
793    alignas(EAS) JSTaggedType *prev {nullptr}; // for llvm :c-fp ; for interrupt: thread-fp for gc
794    alignas(EAS) FrameType type {FrameType::OPTIMIZED_FRAME}; // 0
795};
796STATIC_ASSERT_EQ_ARCH(sizeof(InterpretedFrameBase),
797                      InterpretedFrameBase::SizeArch32,
798                      InterpretedFrameBase::SizeArch64);
799
800// Interpreter Frame Layout as the following:
801//   +----------------------------------+
802//   |    argv[n-1]                     |
803//   |----------------------------------|
804//   |    ......                        |
805//   |----------------------------------|
806//   |    thisArg [maybe not exist]     |
807//   |----------------------------------|
808//   |    newTarget [maybe not exist]   |
809//   |----------------------------------|
810//   |    ......                        |
811//   |----------------------------------|
812//   |    Vregs [not exist in native]   |
813//   +----------------------------------+--------+
814//   |    base.frameType                |        ^
815//   |----------------------------------|        |
816//   |    base.prev(prev stack pointer) |        |
817//   |----------------------------------|        |
818//   |    pc(bytecode addr)             |        |
819//   |----------------------------------|        |
820//   |    sp(current stack pointer)     |        |
821//   |----------------------------------|        |
822//   |    env                           |        |
823//   |----------------------------------|        |
824//   |    acc                           |        |
825//   |----------------------------------|   InterpretedFrame
826//   |    profileTypeInfo               |        |
827//   |----------------------------------|        |
828//   |    thisObj                       |        |
829//   |----------------------------------|        |
830//   |    function                      |        |
831//   |----------------------------------|        |
832//   |    constpool                     |        v
833//   +----------------------------------+--------+
834//
835// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
836struct InterpretedFrame : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
837                                                     JSTaggedValue,
838                                                     JSTaggedValue,
839                                                     JSTaggedValue,
840                                                     JSTaggedValue,
841                                                     JSTaggedValue,
842                                                     JSTaggedValue,
843                                                     base::AlignedPointer,
844                                                     InterpretedFrameBase> {
845public:
846    enum class Index : size_t {
847        ConstPoolIndex = 0,
848        FunctionIndex,
849        ThisObjIndex,
850        ProFileTypeInfoIndex,
851        AccIndex,
852        EnvIndex,
853        PcIndex,
854        BaseIndex,
855        NumOfMembers
856    };
857    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
858
859    inline JSTaggedType* GetPrevFrameFp() const
860    {
861        return base.prev;
862    }
863
864    static InterpretedFrame* GetFrameFromSp(const JSTaggedType *sp)
865    {
866        return reinterpret_cast<InterpretedFrame *>(const_cast<JSTaggedType *>(sp)) - 1;
867    }
868
869    inline const uint8_t *GetPc() const
870    {
871        return pc;
872    }
873
874    inline JSTaggedValue GetEnv() const
875    {
876        return env;
877    }
878
879    static uint32_t NumOfMembers()
880    {
881        return sizeof(InterpretedFrame) / JSTaggedValue::TaggedTypeSize();
882    }
883
884    static size_t GetPcOffset(bool isArch32)
885    {
886        return GetOffset<static_cast<size_t>(Index::PcIndex)>(isArch32);
887    }
888
889    static size_t GetTypeOffset(bool isArch32 = false)
890    {
891        return GetOffset<static_cast<size_t>(Index::BaseIndex)>(isArch32) +
892            InterpretedFrameBase::GetTypeOffset(isArch32);
893    }
894
895    static size_t GetPrevOffset(bool isArch32 = false)
896    {
897        return GetOffset<static_cast<size_t>(Index::BaseIndex)>(isArch32) +
898            InterpretedFrameBase::GetPrevOffset(isArch32);
899    }
900
901    static size_t GetFunctionOffset(bool isArch32 = false)
902    {
903        return GetOffset<static_cast<size_t>(Index::FunctionIndex)>(isArch32);
904    }
905
906    void GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const;
907
908    alignas(EAS) JSTaggedValue constpool {JSTaggedValue::Hole()};
909    alignas(EAS) JSTaggedValue function {JSTaggedValue::Hole()};
910    alignas(EAS) JSTaggedValue thisObj {JSTaggedValue::Hole()};
911    alignas(EAS) JSTaggedValue profileTypeInfo {JSTaggedValue::Hole()};
912    alignas(EAS) JSTaggedValue acc {JSTaggedValue::Hole()};
913    alignas(EAS) JSTaggedValue env {JSTaggedValue::Hole()};
914    alignas(EAS) const uint8_t *pc {nullptr};
915    alignas(EAS) InterpretedFrameBase base;
916    friend class FrameIterator;
917};
918STATIC_ASSERT_EQ_ARCH(sizeof(InterpretedFrame), InterpretedFrame::SizeArch32, InterpretedFrame::SizeArch64);
919
920// * InterpretedBuiltinFrame layout description as the following:
921//               |--------------------------| ---------------
922//               |         . . . . .        |               ^
923//               |    InterpretedFrameBase  |               |
924//               |         . . . . .        |               |
925//               |--------------------------|    InterpretedBuiltinFrame
926//               |       bytecode-PC        |               |
927//               |--------------------------|               |
928//               |       call-target        |               v
929//               +--------------------------+ ---------------
930//
931// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
932struct InterpretedBuiltinFrame : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
933                                                            JSTaggedValue,
934                                                            base::AlignedPointer,
935                                                            InterpretedFrameBase> {
936    enum class Index : size_t {
937        FunctionIndex = 0,
938        PcIndex,
939        BaseIndex,
940        NumOfMembers
941    };
942    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
943
944    inline JSTaggedType* GetPrevFrameFp()
945    {
946        return base.prev;
947    }
948
949    static InterpretedBuiltinFrame* GetFrameFromSp(const JSTaggedType *sp)
950    {
951        return reinterpret_cast<InterpretedBuiltinFrame *>(const_cast<JSTaggedType *>(sp)) - 1;
952    }
953
954    static uint32_t NumOfMembers()
955    {
956        return sizeof(InterpretedBuiltinFrame) / JSTaggedValue::TaggedTypeSize();
957    }
958
959    static size_t GetTypeOffset(bool isArch32 = false)
960    {
961        return GetOffset<static_cast<size_t>(Index::BaseIndex)>(isArch32) +
962            InterpretedFrameBase::GetTypeOffset(isArch32);
963    }
964
965    static size_t GetPrevOffset(bool isArch32 = false)
966    {
967        return GetOffset<static_cast<size_t>(Index::BaseIndex)>(isArch32) +
968            InterpretedFrameBase::GetPrevOffset(isArch32);
969    }
970
971    static size_t GetFunctionOffset(bool isArch32 = false)
972    {
973        return GetOffset<static_cast<size_t>(Index::FunctionIndex)>(isArch32);
974    }
975
976    void GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const;
977
978    alignas(EAS) JSTaggedValue function {JSTaggedValue::Hole()};
979    alignas(EAS) const uint8_t *pc {nullptr};
980    alignas(EAS) InterpretedFrameBase base;
981};
982STATIC_ASSERT_EQ_ARCH(sizeof(InterpretedBuiltinFrame),
983                      InterpretedBuiltinFrame::SizeArch32,
984                      InterpretedBuiltinFrame::SizeArch64);
985
986// AsmInterpretedFrame Layout as the following:
987//   +----------------------------------+
988//   |    argv[n-1]                     |
989//   |----------------------------------|
990//   |    ......                        |
991//   |----------------------------------|
992//   |    thisArg [maybe not exist]     |
993//   |----------------------------------|
994//   |    newTarget [maybe not exist]   |
995//   |----------------------------------|
996//   |    ......                        |
997//   |----------------------------------|
998//   |    Vregs [not exist in native]   |
999//   +----------------------------------+--------+
1000//   |        .  .  .   .               |        ^
1001//   |     InterpretedFrameBase         |        |
1002//   |        .  .  .   .               |        |
1003//   |----------------------------------|        |
1004//   |    pc(bytecode addr)             |        |
1005//   |----------------------------------|        |
1006//   |    sp(current stack pointer)     |        |
1007//   |----------------------------------|   AsmInterpretedFrame
1008//   |    callSize                      |        |
1009//   |----------------------------------|        |
1010//   |    env                           |        |
1011//   |----------------------------------|        |
1012//   |    acc                           |        |
1013//   |----------------------------------|        |
1014//   |    thisObj                       |        |
1015//   |----------------------------------|        |
1016//   |    call-target                   |        v
1017//   +----------------------------------+--------+
1018//
1019// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
1020struct AsmInterpretedFrame : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
1021                                                        JSTaggedValue,
1022                                                        JSTaggedValue,
1023                                                        JSTaggedValue,
1024                                                        JSTaggedValue,
1025                                                        base::AlignedPointer,
1026                                                        base::AlignedPointer,
1027                                                        base::AlignedPointer,
1028                                                        InterpretedFrameBase> {
1029    enum class Index : size_t {
1030        FunctionIndex = 0,
1031        ThisObjIndex,
1032        AccIndex,
1033        EnvIndex,
1034        CallSizeIndex,
1035        FpIndex,
1036        PcIndex,
1037        BaseIndex,
1038        NumOfMembers
1039    };
1040
1041    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
1042
1043    inline JSTaggedType* GetCurrentFramePointer()
1044    {
1045        return fp;
1046    }
1047
1048    inline JSTaggedType* GetPrevFrameFp()
1049    {
1050        return base.prev;
1051    }
1052
1053    static AsmInterpretedFrame* GetFrameFromSp(const JSTaggedType *sp)
1054    {
1055        return reinterpret_cast<AsmInterpretedFrame *>(const_cast<JSTaggedType *>(sp)) - 1;
1056    }
1057
1058    static size_t GetFpOffset(bool isArch32)
1059    {
1060        return GetOffset<static_cast<size_t>(Index::FpIndex)>(isArch32);
1061    }
1062
1063    static size_t GetCallSizeOffset(bool isArch32)
1064    {
1065        return GetOffset<static_cast<size_t>(Index::CallSizeIndex)>(isArch32);
1066    }
1067
1068    static size_t GetFunctionOffset(bool isArch32)
1069    {
1070        return GetOffset<static_cast<size_t>(Index::FunctionIndex)>(isArch32);
1071    }
1072
1073    static size_t GetThisOffset(bool isArch32)
1074    {
1075        return GetOffset<static_cast<size_t>(Index::ThisObjIndex)>(isArch32);
1076    }
1077
1078    static size_t GetAccOffset(bool isArch32)
1079    {
1080        return GetOffset<static_cast<size_t>(Index::AccIndex)>(isArch32);
1081    }
1082
1083    static size_t GetEnvOffset(bool isArch32)
1084    {
1085        return GetOffset<static_cast<size_t>(Index::EnvIndex)>(isArch32);
1086    }
1087
1088    static size_t GetBaseOffset(bool isArch32)
1089    {
1090        return GetOffset<static_cast<size_t>(Index::BaseIndex)>(isArch32);
1091    }
1092
1093    static size_t GetPcOffset(bool isArch32)
1094    {
1095        return GetOffset<static_cast<size_t>(Index::PcIndex)>(isArch32);
1096    }
1097
1098    static constexpr size_t GetSize(bool isArch32)
1099    {
1100        return isArch32 ? AsmInterpretedFrame::SizeArch32 : AsmInterpretedFrame::SizeArch64;
1101    }
1102
1103    static intptr_t GetFpOffsetAsIntptr(bool isArch32)
1104    {
1105        return static_cast<intptr_t>(GetFpOffset(isArch32));
1106    }
1107
1108    static intptr_t GetFunctionOffsetAsIntptr(bool isArch32)
1109    {
1110        return static_cast<intptr_t>(GetFunctionOffset(isArch32));
1111    }
1112
1113    static intptr_t GetSizeAsIntptr(bool isArch32)
1114    {
1115        return static_cast<intptr_t>(GetSize(isArch32));
1116    }
1117
1118    static uint32_t NumOfMembers()
1119    {
1120        return sizeof(AsmInterpretedFrame) / JSTaggedValue::TaggedTypeSize();
1121    }
1122    void GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
1123        const RootBaseAndDerivedVisitor &derivedVisitor, bool isBaselineFrame) const;
1124
1125    JSTaggedValue GetEnv() const
1126    {
1127        return env;
1128    }
1129
1130    const uint8_t *GetPc() const
1131    {
1132        return pc;
1133    }
1134
1135    static size_t GetTypeOffset()
1136    {
1137        return MEMBER_OFFSET(AsmInterpretedFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, type);
1138    }
1139
1140    static size_t GetPrevOffset()
1141    {
1142        return MEMBER_OFFSET(AsmInterpretedFrame, base) + MEMBER_OFFSET(InterpretedFrameBase, prev);
1143    }
1144
1145    alignas(EAS) JSTaggedValue function {JSTaggedValue::Hole()};
1146    alignas(EAS) JSTaggedValue thisObj {JSTaggedValue::Hole()};
1147    alignas(EAS) JSTaggedValue acc {JSTaggedValue::Hole()};
1148    alignas(EAS) JSTaggedValue env {JSTaggedValue::Hole()};
1149    alignas(EAS) uintptr_t callSize {0};
1150    alignas(EAS) JSTaggedType *fp {nullptr};
1151    alignas(EAS) const uint8_t *pc {nullptr};
1152    alignas(EAS) InterpretedFrameBase base;
1153    // vregs, not exist in native
1154    // args, may be truncated if not extra
1155};
1156STATIC_ASSERT_EQ_ARCH(sizeof(AsmInterpretedFrame), AsmInterpretedFrame::SizeArch32, AsmInterpretedFrame::SizeArch64);
1157
1158// InterpretedEntryFrame Layout as the following:
1159//   +----------------------------------+---------------
1160//   |        .  .  .   .               |              ^
1161//   |     InterpretedFrameBase         |              |
1162//   |        .  .  .   .               |    InterpretedEntryFrame
1163//   |----------------------------------|              |
1164//   |    pc(bytecode addr)             |              v
1165//   |----------------------------------|---------------
1166//
1167// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
1168struct InterpretedEntryFrame : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
1169                                                          base::AlignedPointer,
1170                                                          InterpretedFrameBase> {
1171    enum class Index : size_t {
1172        PcIndex = 0,
1173        BaseIndex,
1174        NumOfMembers
1175    };
1176    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
1177
1178    inline JSTaggedType* GetPrevFrameFp()
1179    {
1180        return base.prev;
1181    }
1182
1183    static InterpretedEntryFrame* GetFrameFromSp(const JSTaggedType *sp)
1184    {
1185        return reinterpret_cast<InterpretedEntryFrame *>(const_cast<JSTaggedType *>(sp)) - 1;
1186    }
1187
1188    static uint32_t NumOfMembers()
1189    {
1190        return sizeof(InterpretedEntryFrame) / JSTaggedValue::TaggedTypeSize();
1191    }
1192
1193    static size_t GetTypeOffset(bool isArch32 = false)
1194    {
1195        return GetOffset<static_cast<size_t>(Index::BaseIndex)>(isArch32) +
1196            InterpretedFrameBase::GetTypeOffset(isArch32);
1197    }
1198
1199    static size_t GetPrevOffset(bool isArch32 = false)
1200    {
1201        return GetOffset<static_cast<size_t>(Index::BaseIndex)>(isArch32) +
1202            InterpretedFrameBase::GetPrevOffset(isArch32);
1203    }
1204
1205    void GCIterate(const FrameIterator &it, const RootVisitor &visitor,
1206        const RootRangeVisitor &rangeVisitor) const;
1207    alignas(EAS) const uint8_t *pc {nullptr};
1208    alignas(EAS) InterpretedFrameBase base;
1209};
1210STATIC_ASSERT_EQ_ARCH(sizeof(InterpretedEntryFrame),
1211                      InterpretedEntryFrame::SizeArch32,
1212                      InterpretedEntryFrame::SizeArch64);
1213
1214
1215// AsmInterpretedEntryFrame Layout as the following:
1216//   +----------------------------------+---------------
1217//   |        .  .  .   .               |              ^
1218//   |     InterpretedFrameBase         |              |
1219//   |        .  .  .   .               |    AsmInterpretedEntryFrame
1220//   |----------------------------------|              |
1221//   |    pc(bytecode addr)             |              v
1222//   |----------------------------------|---------------
1223//
1224// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
1225struct AsmInterpretedEntryFrame : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
1226                                                             base::AlignedPointer,
1227                                                             InterpretedFrameBase> {
1228    enum class Index : size_t {
1229        PcIndex = 0,
1230        BaseIndex,
1231        NumOfMembers
1232    };
1233    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
1234
1235    inline JSTaggedType* GetPrevFrameFp()
1236    {
1237        return base.prev;
1238    }
1239
1240    static size_t GetBaseOffset(bool isArch32)
1241    {
1242        return GetOffset<static_cast<size_t>(Index::BaseIndex)>(isArch32);
1243    }
1244
1245    static AsmInterpretedEntryFrame* GetFrameFromSp(const JSTaggedType *sp)
1246    {
1247        return reinterpret_cast<AsmInterpretedEntryFrame *>(const_cast<JSTaggedType *>(sp)) - 1;
1248    }
1249
1250    static size_t GetTypeOffset(bool isArch32 = false)
1251    {
1252        return GetOffset<static_cast<size_t>(Index::BaseIndex)>(isArch32) +
1253            InterpretedFrameBase::GetTypeOffset(isArch32);
1254    }
1255
1256    static size_t GetPrevOffset(bool isArch32 = false)
1257    {
1258        return GetOffset<static_cast<size_t>(Index::BaseIndex)>(isArch32) +
1259            InterpretedFrameBase::GetPrevOffset(isArch32);
1260    }
1261
1262    alignas(EAS) const uint8_t *pc {nullptr};
1263    alignas(EAS) InterpretedFrameBase base;
1264};
1265
1266// AsmInterpretedBridgeFrame Layout as the following:
1267//   +----------------------------------+---------------
1268//   |      ret-address                 |              ^
1269//   |----------------------------------|              |
1270//   |        .  .  .   .               |     AsmInterpretedBridgeFrame
1271//   |     AsmInterpretedEntryFrame     |              |
1272//   |        .  .  .   .               |              v
1273//   |----------------------------------|---------------
1274//
1275// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
1276struct AsmInterpretedBridgeFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
1277                                                              AsmInterpretedEntryFrame,
1278                                                              base::AlignedPointer> {
1279    enum class Index : size_t {
1280        EntryIndex = 0,
1281        ReturnAddrIndex,
1282        NumOfMembers
1283    };
1284    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
1285
1286    static AsmInterpretedBridgeFrame* GetFrameFromSp(const JSTaggedType *sp)
1287    {
1288        return reinterpret_cast<AsmInterpretedBridgeFrame *>(reinterpret_cast<uintptr_t>(sp) -
1289            MEMBER_OFFSET(AsmInterpretedBridgeFrame, returnAddr));
1290    }
1291    uintptr_t GetCallSiteSp() const
1292    {
1293        return ToUintPtr(this) + sizeof(AsmInterpretedBridgeFrame);
1294    }
1295    inline JSTaggedType* GetPrevFrameFp()
1296    {
1297        return entry.base.prev;
1298    }
1299
1300    static size_t GetReturnAddrOffset(bool isArch32)
1301    {
1302        return GetOffset<static_cast<size_t>(Index::ReturnAddrIndex)>(isArch32);
1303    }
1304
1305    static constexpr size_t GetSize(bool isArch32)
1306    {
1307        return isArch32 ? AsmInterpretedBridgeFrame::SizeArch32 : AsmInterpretedBridgeFrame::SizeArch64;
1308    }
1309
1310    static size_t GetTypeOffset(bool isArch32 = false)
1311    {
1312        return GetOffset<static_cast<size_t>(Index::EntryIndex)>(isArch32) +
1313            AsmInterpretedEntryFrame::GetBaseOffset(isArch32) +
1314            InterpretedFrameBase::GetTypeOffset(isArch32);
1315    }
1316    static size_t GetPrevOffset(bool isArch32 = false)
1317    {
1318        return GetOffset<static_cast<size_t>(Index::EntryIndex)>(isArch32) +
1319            AsmInterpretedEntryFrame::GetBaseOffset(isArch32) +
1320            InterpretedFrameBase::GetPrevOffset(isArch32);
1321    }
1322
1323    uintptr_t GetReturnAddr() const
1324    {
1325        return returnAddr;
1326    }
1327
1328    AsmInterpretedEntryFrame entry;
1329    alignas(EAS) uintptr_t returnAddr;
1330};
1331
1332// * Optimized-leaved-frame layout as the following:
1333//               +--------------------------+
1334//               |       argv[N-1]          |
1335//               |--------------------------|
1336//               |       . . . . .          |
1337//               |--------------------------|
1338//               |       argv[0]            |
1339//               +--------------------------+-------------
1340//               |       argc               |            ^
1341//               |--------------------------|            |
1342//               |       RuntimeId          |            |
1343//  callerSP --> |--------------------------|   OptimizedLeaveFrame
1344//               |       ret-addr           |            |
1345//               |--------------------------|            |
1346//               |       prevFp             |            |
1347//        fp --> |--------------------------|            |
1348//               |       frameType          |            v
1349//  calleeSP --> +--------------------------+-------------
1350//
1351// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
1352struct OptimizedLeaveFrame {
1353    FrameType type;
1354    uintptr_t callsiteFp; // thread sp set here
1355    uintptr_t returnAddr;
1356    uint64_t argRuntimeId;
1357    uint64_t argc;
1358
1359    // argv[0]...argv[argc-1] dynamic according to agc
1360    static OptimizedLeaveFrame* GetFrameFromSp(const JSTaggedType *sp)
1361    {
1362        return reinterpret_cast<OptimizedLeaveFrame *>(reinterpret_cast<uintptr_t>(sp) -
1363            MEMBER_OFFSET(OptimizedLeaveFrame, callsiteFp));
1364    }
1365
1366    uintptr_t GetCallSiteSp() const
1367    {
1368        return ToUintPtr(this) + MEMBER_OFFSET(OptimizedLeaveFrame, argRuntimeId);
1369    }
1370
1371    inline JSTaggedType* GetPrevFrameFp() const
1372    {
1373        return reinterpret_cast<JSTaggedType*>(callsiteFp);
1374    }
1375
1376    uintptr_t GetReturnAddr() const
1377    {
1378        return returnAddr;
1379    }
1380
1381    static size_t GetTypeOffset()
1382    {
1383        return MEMBER_OFFSET(OptimizedLeaveFrame, type);
1384    }
1385
1386    static size_t GetPrevOffset()
1387    {
1388        return MEMBER_OFFSET(OptimizedLeaveFrame, callsiteFp);
1389    }
1390
1391    static size_t GetReturnAddrOffset()
1392    {
1393        return MEMBER_OFFSET(OptimizedLeaveFrame, returnAddr);
1394    }
1395
1396    void GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const;
1397};
1398
1399// * Optimized-leaved-frame-with-argv layout as the following:
1400//               +--------------------------+
1401//               |       argv[]             |
1402//               +--------------------------+-------------
1403//               |       argc               |            ^
1404//               |--------------------------|            |
1405//               |       RuntimeId          |   OptimizedWithArgvLeaveFrame
1406//  callerSP --> |--------------------------|            |
1407//               |       returnAddr         |            |
1408//               |--------------------------|            |
1409//               |       callsiteFp         |            |
1410//        fp --> |--------------------------|            |
1411//               |       frameType          |            v
1412//  calleeSP --> +--------------------------+-------------
1413
1414struct OptimizedWithArgvLeaveFrame {
1415    FrameType type;
1416    uintptr_t callsiteFp; // thread sp set here
1417    uintptr_t returnAddr;
1418    uint64_t argRuntimeId;
1419    uint64_t argc;
1420
1421    static OptimizedWithArgvLeaveFrame* GetFrameFromSp(const JSTaggedType *sp)
1422    {
1423        return reinterpret_cast<OptimizedWithArgvLeaveFrame *>(reinterpret_cast<uintptr_t>(sp) -
1424            MEMBER_OFFSET(OptimizedWithArgvLeaveFrame, callsiteFp));
1425    }
1426
1427    uintptr_t GetCallSiteSp() const
1428    {
1429        return ToUintPtr(this) + MEMBER_OFFSET(OptimizedWithArgvLeaveFrame, argRuntimeId);
1430    }
1431
1432    inline JSTaggedType* GetPrevFrameFp()
1433    {
1434        return reinterpret_cast<JSTaggedType*>(callsiteFp);
1435    }
1436
1437    uintptr_t GetReturnAddr() const
1438    {
1439        return returnAddr;
1440    }
1441
1442    static size_t GetTypeOffset()
1443    {
1444        return MEMBER_OFFSET(OptimizedWithArgvLeaveFrame, type);
1445    }
1446
1447    static size_t GetPrevOffset()
1448    {
1449        return MEMBER_OFFSET(OptimizedWithArgvLeaveFrame, callsiteFp);
1450    }
1451
1452    static size_t GetReturnAddrOffset()
1453    {
1454        return MEMBER_OFFSET(OptimizedWithArgvLeaveFrame, returnAddr);
1455    }
1456
1457    void GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const;
1458};
1459
1460// * OptimizedBuiltinLeaveFrame layout as the following:
1461//               +--------------------------+
1462//               |       argv[N-1]          |
1463//               |--------------------------|
1464//               |       . . . . .          |
1465//               |--------------------------|
1466//               |       argv[0]            |
1467//               +--------------------------+-------------
1468//               |       argc               |            ^
1469//               |--------------------------|            |
1470//               |       thread             |            |
1471//  callerSP --> +--------------------------+            |
1472//               |       ret-addr           |            |
1473//               |--------------------------|   OptimizedBuiltinLeaveFrame
1474//               |       prevFp             |            |
1475//        fp --> |--------------------------|            |
1476//               |       frameType          |            |
1477//               |--------------------------|            |
1478//               |       align byte         |            v
1479//  calleeSP --> +--------------------------+-------------
1480//
1481// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
1482struct OptimizedBuiltinLeaveFrame {
1483public:
1484    static OptimizedBuiltinLeaveFrame* GetFrameFromSp(const JSTaggedType *sp)
1485    {
1486        return reinterpret_cast<OptimizedBuiltinLeaveFrame *>(reinterpret_cast<uintptr_t>(sp) -
1487            MEMBER_OFFSET(OptimizedBuiltinLeaveFrame, callsiteFp));
1488    }
1489
1490    uintptr_t GetCallSiteSp() const
1491    {
1492        return ToUintPtr(this) + MEMBER_OFFSET(OptimizedBuiltinLeaveFrame, thread);
1493    }
1494
1495    inline JSTaggedType* GetPrevFrameFp() const
1496    {
1497        return reinterpret_cast<JSTaggedType*>(callsiteFp);
1498    }
1499
1500    uintptr_t GetReturnAddr() const
1501    {
1502        return returnAddr;
1503    }
1504
1505    void GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const;
1506
1507    static size_t GetTypeOffset()
1508    {
1509        return MEMBER_OFFSET(OptimizedBuiltinLeaveFrame, type);
1510    }
1511
1512    static size_t GetPrevOffset()
1513    {
1514        return MEMBER_OFFSET(OptimizedBuiltinLeaveFrame, callsiteFp);
1515    }
1516
1517    static size_t GetReturnAddrOffset()
1518    {
1519        return MEMBER_OFFSET(OptimizedBuiltinLeaveFrame, returnAddr);
1520    }
1521
1522    static size_t GetFunctionOffset()
1523    {
1524        return MEMBER_OFFSET(OptimizedBuiltinLeaveFrame, argc) + 1;
1525    }
1526
1527    const JSTaggedType* GetArgv() const
1528    {
1529        return reinterpret_cast<const JSTaggedType *>(&argc + 1);
1530    }
1531
1532    FrameType GetType() const
1533    {
1534        return type;
1535    }
1536
1537private:
1538    FrameType type;
1539    uintptr_t callsiteFp; // thread sp set here
1540    uintptr_t returnAddr;
1541    JSTaggedValue thread;
1542    uint64_t argc;
1543    // argv[0]...argv[argc-1] dynamic according to agc
1544};
1545
1546// * BuiltinFrame layout as the following:
1547//               +--------------------------+
1548//               |     argV[N - 1]          |
1549//               |--------------------------|
1550//               |       . . . .            |
1551//               |--------------------------+
1552//               |     argV[2]=this         |
1553//               +--------------------------+
1554//               |     argV[1]=new-target   |
1555//               +--------------------------+
1556//               |     argV[0]=call-target  |
1557//               +--------------------------+ ---------
1558//               |       argc               |         ^
1559//               |--------------------------|         |
1560//               |       thread             |         |
1561//  callerSP --> |--------------------------|         |
1562//               |       returnAddr         |     BuiltinFrame
1563//               |--------------------------|         |
1564//               |       callsiteFp         |         |
1565//        fp --> |--------------------------|         |
1566//               |       frameType          |         v
1567//  calleeSP --> +--------------------------+ ---------
1568//
1569// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
1570struct BuiltinFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
1571                                                 base::AlignedSize,
1572                                                 base::AlignedPointer,
1573                                                 base::AlignedPointer,
1574                                                 base::AlignedPointer,
1575                                                 base::AlignedPointer,
1576                                                 base::AlignedPointer> {
1577    enum class Index : size_t {
1578        TypeIndex = 0,
1579        PrevFpIndex,
1580        ReturnAddrIndex,
1581        ThreadIndex,
1582        NumArgsIndex,
1583        StackArgsIndex,
1584        NumOfMembers
1585    };
1586    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
1587
1588    static BuiltinFrame* GetFrameFromSp(const JSTaggedType *sp)
1589    {
1590        return reinterpret_cast<BuiltinFrame *>(reinterpret_cast<uintptr_t>(sp) -
1591            MEMBER_OFFSET(BuiltinFrame, prevFp));
1592    }
1593
1594    inline JSTaggedType* GetPrevFrameFp()
1595    {
1596        return prevFp;
1597    }
1598
1599    uintptr_t GetCallSiteSp() const
1600    {
1601        return ToUintPtr(this) + MEMBER_OFFSET(BuiltinFrame, thread);
1602    }
1603
1604    static size_t GetPreFpOffset(bool isArch32)
1605    {
1606        return GetOffset<static_cast<size_t>(Index::PrevFpIndex)>(isArch32);
1607    }
1608
1609    static size_t GetNumArgsToFpDelta(bool isArch32)
1610    {
1611        auto offset = GetOffset<static_cast<size_t>(Index::NumArgsIndex)>(isArch32);
1612        return offset - GetPreFpOffset(isArch32);
1613    }
1614
1615    static size_t GetStackArgsToFpDelta(bool isArch32)
1616    {
1617        auto offset = GetOffset<static_cast<size_t>(Index::StackArgsIndex)>(isArch32);
1618        return offset - GetPreFpOffset(isArch32);
1619    }
1620
1621    uintptr_t GetStackArgsAddress()
1622    {
1623        return reinterpret_cast<uintptr_t>(&stackArgs);
1624    }
1625
1626    JSTaggedValue GetFunction()
1627    {
1628        auto functionAddress = reinterpret_cast<JSTaggedType *>(GetStackArgsAddress());
1629        return JSTaggedValue(*functionAddress);
1630    }
1631
1632    uint32_t GetNumArgs()
1633    {
1634        return numArgs;
1635    }
1636
1637    uintptr_t GetReturnAddr() const
1638    {
1639        return returnAddr;
1640    }
1641
1642    static size_t GetStackArgsOffset(bool isArch32 = false)
1643    {
1644        return GetOffset<static_cast<size_t>(Index::StackArgsIndex)>(isArch32);
1645    }
1646
1647    static size_t GetTypeOffset(bool isArch32 = false)
1648    {
1649        return GetOffset<static_cast<size_t>(Index::TypeIndex)>(isArch32);
1650    }
1651
1652    static size_t GetPrevOffset(bool isArch32 = false)
1653    {
1654        return GetOffset<static_cast<size_t>(Index::PrevFpIndex)>(isArch32);
1655    }
1656
1657    static size_t GetReturnAddrOffset(bool isArch32 = false)
1658    {
1659        return GetOffset<static_cast<size_t>(Index::ReturnAddrIndex)>(isArch32);
1660    }
1661
1662    void GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const;
1663
1664    alignas(EAS) FrameType type;
1665    alignas(EAS) JSTaggedType *prevFp;
1666    alignas(EAS) uintptr_t returnAddr;
1667    alignas(EAS) uintptr_t thread;
1668    alignas(EAS) uint32_t numArgs;
1669    alignas(EAS) uintptr_t stackArgs;
1670};
1671
1672// * BuiltinWithArgvFrame layout as the following:
1673//               +--------------------------+ ---------
1674//               |       . . . . .          |         ^
1675//  callerSP --> |--------------------------|         |
1676//               |       returnAddr         |         |
1677//               |--------------------------|         |
1678//               |       callsiteFp         |   BuiltinWithArgvFrame
1679//        fp --> |--------------------------|         |
1680//               |       frameType          |         |
1681//               +--------------------------+         |
1682//               |        argc              |         v
1683//               +--------------------------+ ---------
1684//               |        argV[0]           |
1685//               +--------------------------+
1686//               |        argV[1]           |
1687//               +--------------------------+
1688//               |        . . . .           |
1689//  calleeSP --> +--------------------------+
1690//
1691// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
1692struct BuiltinWithArgvFrame : public base::AlignedStruct<base::AlignedPointer::Size(),
1693                                                         base::AlignedSize,
1694                                                         base::AlignedPointer,
1695                                                         base::AlignedPointer> {
1696    enum class Index : int {
1697        StackArgsTopIndex = -1,
1698        NumArgsIndex = -1,
1699        TypeIndex = 0,
1700        PrevFpIndex,
1701        ReturnAddrIndex,
1702        NumOfMembers
1703    };
1704    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
1705
1706    static BuiltinWithArgvFrame* GetFrameFromSp(const JSTaggedType *sp)
1707    {
1708        return reinterpret_cast<BuiltinWithArgvFrame *>(reinterpret_cast<uintptr_t>(sp) -
1709            MEMBER_OFFSET(BuiltinFrame, prevFp));
1710    }
1711
1712    inline JSTaggedType* GetPrevFrameFp()
1713    {
1714        return prevFp;
1715    }
1716
1717    uintptr_t GetCallSiteSp() const
1718    {
1719        return ToUintPtr(this) + sizeof(BuiltinWithArgvFrame);
1720    }
1721
1722    uintptr_t GetStackArgsAddress()
1723    {
1724        auto topAddress = ToUintPtr(this) +
1725            (static_cast<int>(Index::StackArgsTopIndex) * sizeof(uintptr_t));
1726        auto numberArgs = GetNumArgs() + NUM_MANDATORY_JSFUNC_ARGS;
1727        return topAddress - static_cast<uint32_t>(numberArgs) * sizeof(uintptr_t);
1728    }
1729
1730    JSTaggedValue GetFunction()
1731    {
1732        auto functionAddress = reinterpret_cast<JSTaggedType *>(GetStackArgsAddress());
1733        return JSTaggedValue(*functionAddress);
1734    }
1735
1736    int32_t GetNumArgs()
1737    {
1738        auto argcAddress = reinterpret_cast<int32_t *>(
1739            ToUintPtr(this) + (static_cast<int>(Index::NumArgsIndex) * sizeof(uintptr_t)));
1740        return *argcAddress;
1741    }
1742
1743    uintptr_t GetReturnAddr() const
1744    {
1745        return returnAddr;
1746    }
1747
1748    static size_t GetTypeOffset(bool isArch32 = false)
1749    {
1750        return GetOffset<static_cast<size_t>(Index::TypeIndex)>(isArch32);
1751    }
1752
1753    static size_t GetPrevOffset(bool isArch32 = false)
1754    {
1755        return GetOffset<static_cast<size_t>(Index::PrevFpIndex)>(isArch32);
1756    }
1757
1758    static size_t GetReturnAddrOffset(bool isArch32 = false)
1759    {
1760        return GetOffset<static_cast<size_t>(Index::ReturnAddrIndex)>(isArch32);
1761    }
1762
1763    void GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor) const;
1764    // argv(... this, new.target, function)
1765    // numargs
1766    alignas(EAS) FrameType type;
1767    alignas(EAS) JSTaggedType *prevFp;
1768    alignas(EAS) uintptr_t returnAddr;
1769};
1770
1771// * FASTJITFunctionFrame layout description as the following:
1772//               +--------------------------+
1773//               |        arg[N-1]          |
1774//               +--------------------------+
1775//               |       ...                |
1776//               +--------------------------+
1777//               |       arg[1]             |
1778//               +--------------------------+
1779//               |       arg[0]             |
1780//               +--------------------------+
1781//               |       this               |
1782//               +--------------------------+
1783//               |       new-target         |
1784//               +--------------------------+
1785//               |       call-target        |
1786//               |--------------------------|
1787//               |       argc               |
1788// callerSp ---> |--------------------------| ---------------
1789//               |       returnAddr         |               ^
1790//               |--------------------------|               |
1791//               |       callsiteFp         |               |
1792//               |--------------------------|               |
1793//               |       frameType          |    FASTJITFunctionFrame
1794//               |--------------------------|               |
1795//               |       call-target        |               |
1796//               |--------------------------|               |
1797//               |       pc(bytecode pc)    |               v
1798// calleeSP ---> +--------------------------+ ---------------
1799//
1800// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
1801struct FASTJITFunctionFrame : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
1802                                                             JSTaggedValue,
1803                                                             JSTaggedValue,
1804                                                             base::AlignedPointer,
1805                                                             base::AlignedPointer,
1806                                                             base::AlignedPointer> {
1807public:
1808    using ConstInfo = kungfu::LLVMStackMapType::ConstInfo;
1809    enum class Index : size_t {
1810        PcIndex = 0,
1811        JSFuncIndex,
1812        TypeIndex,
1813        PrevFpIndex,
1814        ReturnAddrIndex,
1815        NumOfMembers
1816    };
1817    static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
1818
1819    static constexpr size_t GetFunctionDeltaReturnAddr()
1820    {
1821        return static_cast<size_t>(Index::ReturnAddrIndex) - static_cast<size_t>(Index::JSFuncIndex);
1822    }
1823
1824    inline JSTaggedType* GetPrevFrameFp()
1825    {
1826        return prevFp;
1827    }
1828
1829    JSTaggedType* GetArgv(uintptr_t *preFrameSp) const
1830    {
1831        const size_t offset = 2;    // 2: skip argc and argv.
1832        return reinterpret_cast<JSTaggedType *>(preFrameSp + offset * sizeof(uint64_t) / sizeof(uintptr_t));
1833    }
1834
1835    size_t GetArgc(uintptr_t *preFrameSp) const
1836    {
1837        return *preFrameSp;
1838    }
1839
1840    JSTaggedType* GetArgv(const FrameIterator &it) const;
1841
1842    uintptr_t GetReturnAddr() const
1843    {
1844        return returnAddr;
1845    }
1846
1847    void GCIterate(const FrameIterator &it, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
1848        const RootBaseAndDerivedVisitor &derivedVisitor, FrameType frameType) const;
1849    void CollectPcOffsetInfo(const FrameIterator &it, ConstInfo &info) const;
1850
1851    inline JSTaggedValue GetFunction() const
1852    {
1853        return jsFunc;
1854    }
1855
1856    static uintptr_t ComputeArgsConfigFrameSp(JSTaggedType *fp)
1857    {
1858        const size_t offset = 2;  // 2: skip prevFp and return address.
1859        return reinterpret_cast<uintptr_t>(fp) + offset * sizeof(uintptr_t);
1860    }
1861
1862    static size_t GetTypeOffset(bool isArch32 = false)
1863    {
1864        return GetOffset<static_cast<size_t>(Index::TypeIndex)>(isArch32);
1865    }
1866
1867    static size_t GetPcOffset(bool isArch32 = false)
1868    {
1869        return GetOffset<static_cast<size_t>(Index::PcIndex)>(isArch32);
1870    }
1871
1872    static size_t GetPrevOffset(bool isArch32 = false)
1873    {
1874        return GetOffset<static_cast<size_t>(Index::PrevFpIndex)>(isArch32);
1875    }
1876
1877    static size_t GetFunctionOffset(bool isArch32 = false)
1878    {
1879        return GetOffset<static_cast<size_t>(Index::JSFuncIndex)>(isArch32);
1880    }
1881
1882    static size_t ComputeReservedJSFuncOffset(size_t slotSize)
1883    {
1884        size_t slotOffset = static_cast<size_t>(Index::PrevFpIndex) - static_cast<size_t>(Index::JSFuncIndex);
1885        return slotSize * slotOffset;
1886    }
1887
1888    static size_t ComputeReservedPcOffset(size_t slotSize)
1889    {
1890        size_t slotOffset = static_cast<size_t>(Index::PrevFpIndex) - static_cast<size_t>(Index::PcIndex);
1891        return slotSize * slotOffset;
1892    }
1893
1894    static int GetFrmaeTypeToFpDelta()
1895    {
1896        return -(int)sizeof(uintptr_t);
1897    }
1898
1899    static int GetFunctionToFpDelta()
1900    {
1901        int slotOffset = static_cast<int>(Index::JSFuncIndex) - static_cast<int>(Index::TypeIndex);
1902        return slotOffset * JSTaggedValue::TaggedTypeSize() + GetFrmaeTypeToFpDelta();
1903    }
1904
1905    FrameType GetType() const
1906    {
1907        return type;
1908    }
1909
1910    inline const uint8_t *GetPc() const
1911    {
1912        return pc;
1913    }
1914
1915    friend class FrameIterator;
1916    friend class FrameHandler;
1917    void GetDeoptBundleInfo(const FrameIterator &it, std::vector<kungfu::ARKDeopt>& deopts) const;
1918    void GetFuncCalleeRegAndOffset(
1919        const FrameIterator &it, kungfu::CalleeRegAndOffsetVec &ret) const;
1920    uintptr_t* ComputePrevFrameSp(const FrameIterator &it) const;
1921
1922private:
1923    static FASTJITFunctionFrame* GetFrameFromSp(const JSTaggedType *sp)
1924    {
1925        return reinterpret_cast<FASTJITFunctionFrame *>(reinterpret_cast<uintptr_t>(sp) -
1926            MEMBER_OFFSET(FASTJITFunctionFrame, prevFp));
1927    }
1928
1929    static uintptr_t GetFuncAddrFromSp(const JSTaggedType *sp)
1930    {
1931        return reinterpret_cast<uintptr_t>(sp) - MEMBER_OFFSET(FASTJITFunctionFrame, type);
1932    }
1933
1934    // dynamic callee saveregisters for x86-64
1935    alignas(EAS) const uint8_t *pc {nullptr};
1936    alignas(EAS) JSTaggedValue jsFunc {JSTaggedValue::Undefined()};
1937    alignas(EAS) FrameType type {0};
1938    alignas(EAS) JSTaggedType *prevFp {nullptr};
1939    alignas(EAS) uintptr_t returnAddr {0};
1940    // dynamic callee saveregisters for arm64
1941};
1942
1943enum class GCVisitedFlag : uint8_t {
1944    VISITED = 0,
1945    IGNORED,
1946    HYBRID_STACK,
1947    DEOPT,
1948};
1949
1950class FrameIterator {
1951public:
1952    using ConstInfo = kungfu::LLVMStackMapType::ConstInfo;
1953    using CallSiteInfo = std::tuple<uint64_t, uint8_t *, int, kungfu::CalleeRegAndOffsetVec>;
1954    explicit FrameIterator(JSTaggedType *sp, const JSThread *thread = nullptr);
1955    FrameType GetFrameType() const
1956    {
1957        ASSERT(current_ != nullptr);
1958        FrameType *typeAddr = reinterpret_cast<FrameType *>(
1959            reinterpret_cast<uintptr_t>(current_) - sizeof(FrameType));
1960        return *typeAddr;
1961    }
1962
1963    template<class T>
1964    T* GetFrame()
1965    {
1966        return T::GetFrameFromSp(current_);
1967    }
1968
1969    template<class T>
1970    const T* GetFrame() const
1971    {
1972        return T::GetFrameFromSp(current_);
1973    }
1974
1975    bool Done() const
1976    {
1977        return current_ == nullptr;
1978    }
1979    JSTaggedType *GetSp() const
1980    {
1981        return current_;
1982    }
1983    JSTaggedType *GetSp()
1984    {
1985        return current_;
1986    }
1987    void GetCalleeRegAndOffsetVec(kungfu::CalleeRegAndOffsetVec &ret) const
1988    {
1989        ret = calleeRegInfo_;
1990    }
1991    int ComputeDelta(const Method *method = nullptr) const;
1992    template <GCVisitedFlag GCVisit = GCVisitedFlag::IGNORED>
1993    void Advance();
1994    std::map<uint32_t, uint32_t> GetInlinedMethodInfo();
1995    uint32_t GetBytecodeOffset() const;
1996    uintptr_t GetPrevFrameCallSiteSp() const;
1997    uintptr_t GetPrevFrame() const;
1998    uintptr_t GetCallSiteSp() const
1999    {
2000        return optimizedCallSiteSp_;
2001    }
2002    uintptr_t GetOptimizedReturnAddr() const
2003    {
2004        return optimizedReturnAddr_;
2005    }
2006    const JSThread *GetThread() const
2007    {
2008        return thread_;
2009    }
2010    bool IteratorStackMap(const RootVisitor &visitor, const RootBaseAndDerivedVisitor &derivedVisitor) const;
2011    void CollectPcOffsetInfo(ConstInfo &info) const;
2012    void CollectMethodOffsetInfo(std::map<uint32_t, uint32_t> &info) const;
2013    void CollectArkDeopt(std::vector<kungfu::ARKDeopt>& deopts) const;
2014    std::pair<CallSiteInfo, bool> CalCallSiteInfo(uintptr_t retAddr, bool isDeopt) const;
2015    CallSiteInfo TryCalCallSiteInfoFromMachineCode(uintptr_t retAddr) const;
2016
2017    Method *CheckAndGetMethod() const;
2018    JSTaggedValue GetFunction() const;
2019
2020    bool IsLeaveFrame() const
2021    {
2022        FrameType type = GetFrameType();
2023        return (type == FrameType::LEAVE_FRAME) || (type == FrameType::LEAVE_FRAME_WITH_ARGV);
2024    }
2025
2026    bool IsOptimizedFrame() const
2027    {
2028        FrameType type = GetFrameType();
2029        return (type == FrameType::OPTIMIZED_FRAME);
2030    }
2031
2032    bool IsInterpretedFrame(FrameType type) const
2033    {
2034        return (type >= FrameType::INTERPRETER_FIRST) && (type <= FrameType::INTERPRETER_LAST);
2035    }
2036
2037    bool IsJSFrame() const
2038    {
2039        FrameType type = GetFrameType();
2040        return IsInterpretedFrame(type) || IsOptimizedJSFunctionFrame(type) || IsFastJitFunctionFrame(type);
2041    }
2042
2043    bool IsOptimizedJSFunctionFrame(FrameType type) const
2044    {
2045        return type == FrameType::OPTIMIZED_JS_FUNCTION_FRAME ||
2046            type == FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME;
2047    }
2048
2049    bool IsOptimizedJSFunctionFrame() const
2050    {
2051        FrameType type = GetFrameType();
2052        return IsOptimizedJSFunctionFrame(type);
2053    }
2054
2055    bool IsFastJitFunctionFrame(FrameType type) const
2056    {
2057        return type == FrameType::FASTJIT_FUNCTION_FRAME ||
2058            type == FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME;
2059    }
2060
2061    bool IsFastJitFunctionFrame() const
2062    {
2063        FrameType type = GetFrameType();
2064        return IsFastJitFunctionFrame(type);
2065    }
2066
2067    bool IsAotOrJitFunctionFrame() const
2068    {
2069        return IsOptimizedJSFunctionFrame() || IsFastJitFunctionFrame();
2070    }
2071
2072    JSTaggedType *GetMachineCodeSlot() const
2073    {
2074        return const_cast<JSTaggedType*>(&machineCode_);
2075    }
2076
2077private:
2078    JSTaggedType *current_ {nullptr};
2079    const JSThread *thread_ {nullptr};
2080    const kungfu::ArkStackMapParser *arkStackMapParser_ {nullptr};
2081    uintptr_t optimizedCallSiteSp_ {0};
2082    uintptr_t optimizedReturnAddr_ {0};
2083    uint8_t *stackMapAddr_ {nullptr};
2084    kungfu::CalleeRegAndOffsetVec calleeRegInfo_;
2085
2086    // in jit, delta on method is not set, get it from iterator
2087    bool isJITFrame_ {false};
2088    int fpDeltaPrevFrameSp_ {0};
2089
2090    // cache current machine code, it's nonmovable
2091    JSTaggedType machineCode_ {JSTaggedValue::VALUE_UNDEFINED};
2092};
2093}  // namespace panda::ecmascript
2094#endif // ECMASCRIPT_FRAMES_H
2095