1/*
2 * Copyright (c) 2021-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_INTERPRETER_FRAME_HANDLER_H
17#define ECMASCRIPT_INTERPRETER_FRAME_HANDLER_H
18
19#include "ecmascript/frames.h"
20#include "ecmascript/js_tagged_value.h"
21#include "ecmascript/js_thread.h"
22#include "ecmascript/mem/heap.h"
23#include "ecmascript/mem/visitor.h"
24#include "ecmascript/method.h"
25
26namespace panda {
27namespace ecmascript {
28class JSThread;
29class ConstantPool;
30namespace kungfu {
31    class ArkStackMapParser;
32};
33
34class FrameHandler {
35public:
36    explicit FrameHandler(const JSThread *thread);
37
38    ~FrameHandler() = default;
39
40    DEFAULT_COPY_SEMANTIC(FrameHandler);
41    DEFAULT_MOVE_SEMANTIC(FrameHandler);
42
43    bool HasFrame() const
44    {
45        return sp_ != nullptr;
46    }
47
48    inline static FrameType GetFrameType(const JSTaggedType *sp)
49    {
50        ASSERT(sp != nullptr);
51        FrameType *typeAddr = reinterpret_cast<FrameType *>(reinterpret_cast<uintptr_t>(sp) - sizeof(FrameType));
52        return *typeAddr;
53    }
54
55    inline static bool IsEntryFrame(const uint8_t *pc)
56    {
57        return pc == nullptr;
58    }
59
60    bool IsEntryFrame() const
61    {
62        ASSERT(HasFrame());
63        // The structure of InterpretedFrame, AsmInterpretedFrame, InterpretedEntryFrame is the same, order is pc, base.
64        FrameType type = GetFrameType();
65        if (type == FrameType::BUILTIN_ENTRY_FRAME ||
66            type == FrameType::INTERPRETER_ENTRY_FRAME ||
67            type == FrameType::ASM_INTERPRETER_ENTRY_FRAME ||
68            type == FrameType::OPTIMIZED_ENTRY_FRAME) {
69                return true;
70        } else if (type == FrameType::ASM_INTERPRETER_BRIDGE_FRAME ||
71                   type == FrameType::INTERPRETER_FRAME) {
72            FrameIterator it(sp_);
73            InterpretedFrame *state = it.GetFrame<InterpretedFrame>();
74            return state->GetPc() == nullptr;
75        }
76        return false;
77    }
78
79    bool IsInterpretedFrame() const
80    {
81        FrameType type = GetFrameType();
82        return IsInterpretedFrame(type);
83    }
84
85    bool IsInterpretedFrame(FrameType type) const
86    {
87        return (type >= FrameType::INTERPRETER_FIRST) && (type <= FrameType::INTERPRETER_LAST);
88    }
89
90    bool IsJSFrame() const
91    {
92        FrameType type = GetFrameType();
93        return IsJSFrame(type);
94    }
95
96    bool IsOptimizedJSFunctionFrame() const
97    {
98        FrameType type = GetFrameType();
99        return type == FrameType::OPTIMIZED_JS_FUNCTION_FRAME ||
100            type == FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME;
101    }
102
103    bool IsJSFrame(FrameType type) const
104    {
105        return IsInterpretedFrame(type) || IsOptimizedJSFunctionFrame(type) || IsFastJitFunctionFrame(type);
106    }
107
108    bool IsOptimizedJSFunctionFrame(FrameType type) const
109    {
110        return type == FrameType::OPTIMIZED_JS_FUNCTION_FRAME ||
111            type == FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME;
112    }
113
114    bool IsFastJitFunctionFrame(FrameType type) const
115    {
116        return type == FrameType::FASTJIT_FUNCTION_FRAME ||
117            type == FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME;
118    }
119
120    bool IsAsmInterpretedFrame() const
121    {
122        FrameIterator it(sp_, thread_);
123        FrameType type = it.GetFrameType();
124        return (type == FrameType::ASM_INTERPRETER_FRAME) ||
125            (type == FrameType::INTERPRETER_CONSTRUCTOR_FRAME);
126    }
127
128    bool IsAsmInterpretedFrame(FrameType type) const
129    {
130        return (type == FrameType::ASM_INTERPRETER_FRAME) ||
131            (type == FrameType::INTERPRETER_CONSTRUCTOR_FRAME);
132    }
133    bool IsBuiltinFrame() const
134    {
135        FrameType type = GetFrameType();
136        return (type >= FrameType::BUILTIN_FIRST) && (type <= FrameType::BUILTIN_LAST);
137    }
138    bool IsBuiltinEntryFrame() const
139    {
140        return (GetFrameType() == FrameType::BUILTIN_ENTRY_FRAME);
141    }
142
143    bool IsInterpretedEntryFrame() const
144    {
145        if (thread_->IsAsmInterpreter()) {
146            FrameType type = GetFrameType();
147            return (type == FrameType::ASM_INTERPRETER_ENTRY_FRAME || type == FrameType::ASM_INTERPRETER_BRIDGE_FRAME);
148        }
149        return (GetFrameType() == FrameType::INTERPRETER_ENTRY_FRAME);
150    }
151
152    bool IsInterpretedEntryFrame(FrameType type) const
153    {
154        if (thread_->IsAsmInterpreter()) {
155            return (type == FrameType::ASM_INTERPRETER_ENTRY_FRAME || type == FrameType::ASM_INTERPRETER_BRIDGE_FRAME);
156        }
157        return (type == FrameType::INTERPRETER_ENTRY_FRAME);
158    }
159
160    bool IsAsmInterpretedEntryFrame() const
161    {
162        FrameType type = GetFrameType();
163        return IsAsmInterpretedEntryFrame(type);
164    }
165
166    bool IsAsmInterpretedEntryFrame(FrameType type) const
167    {
168        return (type == FrameType::ASM_INTERPRETER_ENTRY_FRAME || type == FrameType::ASM_INTERPRETER_BRIDGE_FRAME);
169    }
170
171    bool IsCInterpretedEntryFrame() const
172    {
173        return (GetFrameType() == FrameType::INTERPRETER_ENTRY_FRAME);
174    }
175
176    bool IsCInterpretedEntryFrame(FrameType type) const
177    {
178        return (type == FrameType::INTERPRETER_ENTRY_FRAME);
179    }
180
181    bool IsOptimizedEntryFrame(FrameType type) const
182    {
183        return type == FrameType::OPTIMIZED_ENTRY_FRAME;
184    }
185
186    bool IsJSEntryFrame(FrameType type) const
187    {
188        return IsAsmInterpretedEntryFrame(type) || IsOptimizedEntryFrame(type);
189    }
190
191    bool IsLeaveFrame() const
192    {
193        FrameType type = GetFrameType();
194        return (type == FrameType::LEAVE_FRAME) || (type == FrameType::LEAVE_FRAME_WITH_ARGV);
195    }
196
197    bool IsInterpreterBuiltinFrame() const
198    {
199        FrameType type = GetFrameType();
200        return type == FrameType::INTERPRETER_BUILTIN_FRAME;
201    }
202
203    bool IsBaselineBuiltinFrame(FrameType type) const
204    {
205        return (type == FrameType::BASELINE_BUILTIN_FRAME);
206    }
207
208    JSTaggedType *GetSp() const
209    {
210        return sp_;
211    }
212
213    JSTaggedType *GetFp() const
214    {
215        return fp_;
216    }
217
218    uintptr_t GetBaselineNativePc() const
219    {
220        return baselineNativePc_;
221    }
222
223    void PrevJSFrame();
224    JSTaggedType *GetPrevJSFrame();
225
226    // for InterpretedFrame.
227    JSTaggedValue GetVRegValue(size_t index) const;
228    void SetVRegValue(size_t index, JSTaggedValue value);
229
230    // for BaselineBuiltinFrame
231    void FindAndSetBaselineNativePc(FrameIterator it);
232
233    JSTaggedValue GetEnv() const;
234    JSTaggedValue GetAcc() const;
235    uint32_t GetNumberArgs();
236    uint32_t GetBytecodeOffset() const;
237    Method *GetMethod() const;
238    const JSPandaFile* GetJSPandaFile() const;
239    std::string GetFileName() const;
240    uint32_t GetAbcId() const;
241    uint32_t GetMethodId() const;
242    Method *CheckAndGetMethod() const;
243    JSTaggedValue GetThis() const;
244    JSTaggedValue GetFunction() const;
245    const uint8_t *GetPc() const;
246    ConstantPool *GetConstpool() const;
247
248    void DumpStack(std::ostream &os) const;
249    void DumpStack() const
250    {
251        DumpStack(std::cout);
252    }
253
254    void DumpPC(std::ostream &os, const uint8_t *pc) const;
255    void DumpPC(const uint8_t *pc) const
256    {
257        DumpPC(std::cout, pc);
258    }
259
260    // for Frame GC.
261    void Iterate(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
262        const RootBaseAndDerivedVisitor &derivedVisitor);
263    void IterateFrameChain(JSTaggedType *start, const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
264        const RootBaseAndDerivedVisitor &derivedVisitor) const;
265    void IterateAssembleStack(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor,
266        const RootBaseAndDerivedVisitor &derivedVisitor);
267    void IterateEcmaRuntimeCallInfo(const RootVisitor &visitor, const RootRangeVisitor &rangeVisitor);
268
269private:
270    FrameType GetFrameType() const
271    {
272        ASSERT(HasFrame());
273        FrameType *typeAddr = reinterpret_cast<FrameType *>(reinterpret_cast<uintptr_t>(sp_) - sizeof(FrameType));
274        return *typeAddr;
275    }
276
277    void AdvanceToJSFrame();
278    uintptr_t GetInterpretedFrameEnd(JSTaggedType *prevSp) const;
279private:
280    JSTaggedType *sp_ {nullptr};
281    JSTaggedType *fp_ {nullptr};
282    uintptr_t baselineNativePc_ {0}; // For baselineJit upFrame
283    const JSThread *thread_ {nullptr};
284    const kungfu::ArkStackMapParser *arkStackMapParser_ {nullptr};
285};
286
287class StackAssertScope {
288public:
289    explicit StackAssertScope(JSThread *thread) : thread_(thread), oldSp_(thread->GetCurrentSPFrame()) {}
290
291    ~StackAssertScope()
292    {
293        if (!thread_->HasPendingException()) {
294            DASSERT_PRINT(oldSp_ == thread_->GetCurrentSPFrame(),
295                          "StackAssertScope assert failed, sp did not restore as expeted");
296        }
297    }
298
299private:
300    JSThread *thread_ {nullptr};
301    const JSTaggedType *oldSp_ {nullptr};
302};
303}; // namespace ecmascript
304}  // namespace panda
305#endif  // ECMASCRIPT_INTERPRETER_FRAME_HANDLER_H
306