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 
26 namespace panda {
27 namespace ecmascript {
28 class JSThread;
29 class ConstantPool;
30 namespace kungfu {
31     class ArkStackMapParser;
32 };
33 
34 class FrameHandler {
35 public:
36     explicit FrameHandler(const JSThread *thread);
37 
38     ~FrameHandler() = default;
39 
40     DEFAULT_COPY_SEMANTIC(FrameHandler);
41     DEFAULT_MOVE_SEMANTIC(FrameHandler);
42 
HasFrame() const43     bool HasFrame() const
44     {
45         return sp_ != nullptr;
46     }
47 
GetFrameType(const JSTaggedType *sp)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 
IsEntryFrame(const uint8_t *pc)55     inline static bool IsEntryFrame(const uint8_t *pc)
56     {
57         return pc == nullptr;
58     }
59 
IsEntryFrame() const60     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 
IsInterpretedFrame() const79     bool IsInterpretedFrame() const
80     {
81         FrameType type = GetFrameType();
82         return IsInterpretedFrame(type);
83     }
84 
IsInterpretedFrame(FrameType type) const85     bool IsInterpretedFrame(FrameType type) const
86     {
87         return (type >= FrameType::INTERPRETER_FIRST) && (type <= FrameType::INTERPRETER_LAST);
88     }
89 
IsJSFrame() const90     bool IsJSFrame() const
91     {
92         FrameType type = GetFrameType();
93         return IsJSFrame(type);
94     }
95 
IsOptimizedJSFunctionFrame() const96     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 
IsJSFrame(FrameType type) const103     bool IsJSFrame(FrameType type) const
104     {
105         return IsInterpretedFrame(type) || IsOptimizedJSFunctionFrame(type) || IsFastJitFunctionFrame(type);
106     }
107 
IsOptimizedJSFunctionFrame(FrameType type) const108     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 
IsFastJitFunctionFrame(FrameType type) const114     bool IsFastJitFunctionFrame(FrameType type) const
115     {
116         return type == FrameType::FASTJIT_FUNCTION_FRAME ||
117             type == FrameType::FASTJIT_FAST_CALL_FUNCTION_FRAME;
118     }
119 
IsAsmInterpretedFrame() const120     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 
IsAsmInterpretedFrame(FrameType type) const128     bool IsAsmInterpretedFrame(FrameType type) const
129     {
130         return (type == FrameType::ASM_INTERPRETER_FRAME) ||
131             (type == FrameType::INTERPRETER_CONSTRUCTOR_FRAME);
132     }
IsBuiltinFrame() const133     bool IsBuiltinFrame() const
134     {
135         FrameType type = GetFrameType();
136         return (type >= FrameType::BUILTIN_FIRST) && (type <= FrameType::BUILTIN_LAST);
137     }
IsBuiltinEntryFrame() const138     bool IsBuiltinEntryFrame() const
139     {
140         return (GetFrameType() == FrameType::BUILTIN_ENTRY_FRAME);
141     }
142 
IsInterpretedEntryFrame() const143     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 
IsInterpretedEntryFrame(FrameType type) const152     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 
IsAsmInterpretedEntryFrame() const160     bool IsAsmInterpretedEntryFrame() const
161     {
162         FrameType type = GetFrameType();
163         return IsAsmInterpretedEntryFrame(type);
164     }
165 
IsAsmInterpretedEntryFrame(FrameType type) const166     bool IsAsmInterpretedEntryFrame(FrameType type) const
167     {
168         return (type == FrameType::ASM_INTERPRETER_ENTRY_FRAME || type == FrameType::ASM_INTERPRETER_BRIDGE_FRAME);
169     }
170 
IsCInterpretedEntryFrame() const171     bool IsCInterpretedEntryFrame() const
172     {
173         return (GetFrameType() == FrameType::INTERPRETER_ENTRY_FRAME);
174     }
175 
IsCInterpretedEntryFrame(FrameType type) const176     bool IsCInterpretedEntryFrame(FrameType type) const
177     {
178         return (type == FrameType::INTERPRETER_ENTRY_FRAME);
179     }
180 
IsOptimizedEntryFrame(FrameType type) const181     bool IsOptimizedEntryFrame(FrameType type) const
182     {
183         return type == FrameType::OPTIMIZED_ENTRY_FRAME;
184     }
185 
IsJSEntryFrame(FrameType type) const186     bool IsJSEntryFrame(FrameType type) const
187     {
188         return IsAsmInterpretedEntryFrame(type) || IsOptimizedEntryFrame(type);
189     }
190 
IsLeaveFrame() const191     bool IsLeaveFrame() const
192     {
193         FrameType type = GetFrameType();
194         return (type == FrameType::LEAVE_FRAME) || (type == FrameType::LEAVE_FRAME_WITH_ARGV);
195     }
196 
IsInterpreterBuiltinFrame() const197     bool IsInterpreterBuiltinFrame() const
198     {
199         FrameType type = GetFrameType();
200         return type == FrameType::INTERPRETER_BUILTIN_FRAME;
201     }
202 
IsBaselineBuiltinFrame(FrameType type) const203     bool IsBaselineBuiltinFrame(FrameType type) const
204     {
205         return (type == FrameType::BASELINE_BUILTIN_FRAME);
206     }
207 
GetSp() const208     JSTaggedType *GetSp() const
209     {
210         return sp_;
211     }
212 
GetFp() const213     JSTaggedType *GetFp() const
214     {
215         return fp_;
216     }
217 
GetBaselineNativePc() const218     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;
DumpStack() const249     void DumpStack() const
250     {
251         DumpStack(std::cout);
252     }
253 
254     void DumpPC(std::ostream &os, const uint8_t *pc) const;
DumpPC(const uint8_t *pc) const255     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 
269 private:
GetFrameType() const270     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;
279 private:
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 
287 class StackAssertScope {
288 public:
StackAssertScope(JSThread *thread)289     explicit StackAssertScope(JSThread *thread) : thread_(thread), oldSp_(thread->GetCurrentSPFrame()) {}
290 
~StackAssertScope()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 
299 private:
300     JSThread *thread_ {nullptr};
301     const JSTaggedType *oldSp_ {nullptr};
302 };
303 }; // namespace ecmascript
304 }  // namespace panda
305 #endif  // ECMASCRIPT_INTERPRETER_FRAME_HANDLER_H
306