• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 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 PANDA_CFRAME_H
17 #define PANDA_CFRAME_H
18 #include <array>
19 
20 #include "compiler/code_info/code_info.h"
21 #include "libpandabase/utils/cframe_layout.h"
22 #include "runtime/interpreter/frame.h"
23 #include "libpandabase/macros.h"
24 namespace panda {
25 
26 namespace compiler {
27 class CodeInfo;
28 }  // namespace compiler
29 
30 class Method;
31 
32 struct alignas(2U * alignof(uintptr_t)) C2IBridge {
33     std::array<uintptr_t, 4> v_;  // 4: means array length
34 };
35 
36 /**
37  * CFrame layout (in descending order):
38  *
39  * -----------------
40  *    LR
41  *    PREV_FRAME   <-- `fp_` points here
42  *    METHOD
43  *    PROPERTIES: [0]: Should deoptimize (1 - deoptimize)
44  *                [1..2]: Frame type - NATIVE, OSR or DEFAULT
45  * -----------------
46  *   LOCALS     several slots used for internal needs
47  * -----------------
48  *    R_N       = CALLEE SAVED REGS <--- `callee_stack_` of the caller's frame points here
49  *    ...
50  *    R_0
51  * -----------------
52  *    VR_N      = CALLEE SAVED FP REGS
53  *    ...
54  *    VR_0
55  * -----------------
56  *    R_N       = CALLER SAVED REGS
57  *    ...
58  *    R_0
59  * -----------------
60  *    VR_N      = CALLER SAVED FP REGS
61  *    ...
62  *    VR_0
63  * -----------------
64  *    SLOT_N    = REGALLOC SPILL/FILLS
65  *    ...
66  *    SLOT_0
67  * -----------------
68  *    SLOT_M    = LANGUAGE EXTENSION SPLILL SLOTS
69  *    ...
70  *    SLOT_0
71  * -----------------
72  *    SLOT_P    = PARAMETERS SLOTS
73  *    ...
74  *    SLOT_0
75  * -----------------
76  */
77 class CFrame final {
78 public:
79     static constexpr Arch ARCH = RUNTIME_ARCH;
80 
81     using SlotType = std::conditional_t<ArchTraits<ARCH>::IS_64_BITS, uint64_t, uint32_t>;
82 
83     using CodeInfo = compiler::CodeInfo;
84     using VRegInfo = compiler::VRegInfo;
85     using StackMap = compiler::StackMap;
86 
87 public:
CFrame(void * frame_data)88     explicit CFrame(void *frame_data) : fp_(reinterpret_cast<SlotType *>(frame_data)) {}
89     ~CFrame() = default;
90 
91     DEFAULT_COPY_SEMANTIC(CFrame);
92     DEFAULT_NOEXCEPT_MOVE_SEMANTIC(CFrame);
93 
IsOsr()94     bool IsOsr() const
95     {
96         return CFrameLayout::FrameKindField::Get(*GetPtr<SlotType>(CFrameLayout::FlagsSlot::Start())) ==
97                CFrameLayout::FrameKind::OSR;
98     }
99 
IsNative()100     bool IsNative() const
101     {
102         return CFrameLayout::FrameKindField::Get(*GetPtr<SlotType>(CFrameLayout::FlagsSlot::Start())) ==
103                CFrameLayout::FrameKind::NATIVE;
104     }
105 
SetFrameKind(CFrameLayout::FrameKind kind)106     void SetFrameKind(CFrameLayout::FrameKind kind)
107     {
108         CFrameLayout::FrameKindField::Set(kind, GetPtr<SlotType>(CFrameLayout::FlagsSlot::Start()));
109     }
110 
111     bool IsNativeMethod() const;
112 
ShouldDeoptimize()113     bool ShouldDeoptimize() const
114     {
115         return CFrameLayout::ShouldDeoptimizeFlag::Get(*GetPtr<SlotType>(CFrameLayout::FlagsSlot::Start()));
116     }
117 
SetShouldDeoptimize(bool v)118     void SetShouldDeoptimize(bool v)
119     {
120         CFrameLayout::ShouldDeoptimizeFlag::Set(v, GetPtr<SlotType>(CFrameLayout::FlagsSlot::Start()));
121     }
122 
SetHasFloatRegs(bool has)123     void SetHasFloatRegs(bool has)
124     {
125         CFrameLayout::HasFloatRegsFlag::Set(has, GetPtr<SlotType>(CFrameLayout::FlagsSlot::Start()));
126     }
127 
GetPrevFrame()128     SlotType *GetPrevFrame()
129     {
130         return *GetPtr<SlotType *>(CFrameLayout::PrevFrameSlot::Start());
131     }
132 
GetPrevFrame()133     const SlotType *GetPrevFrame() const
134     {
135         return *GetPtr<SlotType *>(CFrameLayout::PrevFrameSlot::Start());
136     }
137 
SetPrevFrame(void * prev_frame)138     void SetPrevFrame(void *prev_frame)
139     {
140         *GetPtr<SlotType>(CFrameLayout::PrevFrameSlot::Start()) = bit_cast<SlotType>(prev_frame);
141     }
142 
GetMethod()143     Method *GetMethod()
144     {
145         return *GetPtr<Method *>(CFrameLayout::MethodSlot::Start());
146     }
147 
GetMethod()148     const Method *GetMethod() const
149     {
150         return const_cast<CFrame *>(this)->GetMethod();
151     }
152 
SetMethod(Method * method)153     void SetMethod(Method *method)
154     {
155         *GetPtr<SlotType>(CFrameLayout::MethodSlot::Start()) = bit_cast<SlotType>(method);
156     }
157 
GetDeoptCodeEntry()158     void *GetDeoptCodeEntry() const
159     {
160         return *GetPtr<void *>(CFrameData::Start());
161     }
162 
163     /**
164      * When method is deoptimizated due to it speculation fatal failure, its code entry is reset.
165      * Therefore already executing methods will can't get proper code entry for stack walker,
166      * thus we create this backup code entry.
167      */
SetDeoptCodeEntry(const void * value)168     void SetDeoptCodeEntry(const void *value)
169     {
170         *GetPtr<const void *>(CFrameData::Start()) = value;
171     }
172 
173     template <typename RegRef>
GetVRegValue(const VRegInfo & vreg,const compiler::CodeInfo & code_info,SlotType ** callee_stack,RegRef && reg)174     inline void GetVRegValue(const VRegInfo &vreg, const compiler::CodeInfo &code_info, SlotType **callee_stack,
175                              RegRef &&reg)
176     {
177         auto val = GetVRegValueInternal<false>(vreg, code_info, callee_stack).GetValue();
178         if (vreg.IsObject()) {
179             reg.SetReference(reinterpret_cast<ObjectHeader *>(static_cast<object_pointer_type>(val)));
180         } else {
181             reg.SetPrimitive(val);
182         }
183     }
184 
185     template <typename RegRef>
GetPackVRegValue(const VRegInfo & vreg,const compiler::CodeInfo & code_info,SlotType ** callee_stack,RegRef && reg)186     inline void GetPackVRegValue(const VRegInfo &vreg, const compiler::CodeInfo &code_info, SlotType **callee_stack,
187                                  RegRef &&reg)
188     {
189         auto val = GetVRegValueInternal<true>(vreg, code_info, callee_stack).GetValue();
190         reg.SetPrimitive(val);
191     }
192 
193     template <bool need_pack = false>
194     void SetVRegValue(const VRegInfo &vreg, uint64_t value, SlotType **callee_stack);
195 
GetLr()196     uintptr_t GetLr() const
197     {
198         return *GetPtr<uintptr_t>(CFrameLayout::LrSlot::Start());
199     }
200 
GetStackOrigin()201     SlotType *GetStackOrigin()
202     {
203         return GetPtr<SlotType>(CFrameLayout::STACK_START_SLOT);
204     }
GetStackOrigin()205     const SlotType *GetStackOrigin() const
206     {
207         return GetPtr<const SlotType>(CFrameLayout::STACK_START_SLOT);
208     }
209 
GetCalleeSaveStack()210     SlotType *GetCalleeSaveStack()
211     {
212         return GetPtr<SlotType>(CFrameLayout::CALLEE_REGS_START_SLOT - 1);
213     }
214 
GetCallerSaveStack()215     SlotType *GetCallerSaveStack()
216     {
217         return GetPtr<SlotType>(CFrameLayout::CALLER_REGS_START_SLOT - 1);
218     }
219 
GetFrameOrigin()220     SlotType *GetFrameOrigin()
221     {
222         return fp_;
223     }
224 
GetFrameOrigin()225     const SlotType *GetFrameOrigin() const
226     {
227         return fp_;
228     }
229 
GetValueFromSlot(int slot)230     SlotType GetValueFromSlot(int slot) const
231     {
232         return *GetValuePtrFromSlot(slot);
233     }
234 
GetValuePtrFromSlot(int slot)235     const SlotType *GetValuePtrFromSlot(int slot) const
236     {
237         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
238         return reinterpret_cast<const SlotType *>(GetStackOrigin()) - slot;
239     }
240 
SetValueToSlot(int slot,SlotType value)241     void SetValueToSlot(int slot, SlotType value)
242     {
243         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
244         *(reinterpret_cast<SlotType *>(GetStackOrigin()) - slot) = value;
245     }
246 
247     void Dump(const CodeInfo &code_info, std::ostream &os);
248 
249     void Dump(std::ostream &os, uint32_t max_slot = 0);
250 
251 private:
ReadCalleeSavedRegister(size_t reg,bool is_fp,SlotType ** callee_stack)252     SlotType ReadCalleeSavedRegister(size_t reg, bool is_fp, SlotType **callee_stack) const
253     {
254         ASSERT(reg >= GetFirstCalleeReg(ARCH, is_fp));
255         ASSERT(reg <= GetLastCalleeReg(ARCH, is_fp));
256         ASSERT(GetCalleeRegsCount(ARCH, is_fp) != 0);
257         size_t start_slot = GetCalleeRegsMask(ARCH, is_fp).GetDistanceFromTail(reg);
258         if (is_fp) {
259             start_slot += GetCalleeRegsCount(ARCH, false);
260         }
261         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
262         ASSERT(callee_stack[start_slot] != nullptr);
263         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
264         return *callee_stack[start_slot];
265     }
266 
WriteCalleeSavedRegister(size_t reg,SlotType value,bool is_fp,SlotType ** callee_stack)267     void WriteCalleeSavedRegister(size_t reg, SlotType value, bool is_fp, SlotType **callee_stack) const
268     {
269         ASSERT(reg >= GetFirstCalleeReg(ARCH, is_fp));
270         ASSERT(reg <= GetLastCalleeReg(ARCH, is_fp));
271         ASSERT(GetCalleeRegsCount(ARCH, is_fp) != 0);
272         size_t start_slot = reg - GetFirstCalleeReg(ARCH, is_fp);
273         if (is_fp) {
274             start_slot += GetCalleeRegsCount(ARCH, false);
275         }
276         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
277         ASSERT(callee_stack[start_slot] != nullptr);
278         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
279         *callee_stack[start_slot] = value;
280     }
281 
282     template <typename T>
GetPtr(ptrdiff_t slot)283     T *GetPtr(ptrdiff_t slot)
284     {
285         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
286         return reinterpret_cast<T *>(GetFrameOrigin() - slot);
287     }
288     template <typename T>
GetPtr(ptrdiff_t slot)289     const T *GetPtr(ptrdiff_t slot) const
290     {
291         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
292         return reinterpret_cast<const T *>(GetFrameOrigin() - slot);
293     }
294 
295     template <bool need_pack>
296     interpreter::VRegister GetVRegValueInternal(const VRegInfo &vreg, const compiler::CodeInfo &code_info,
297                                                 SlotType **callee_stack) const;
298     template <bool need_pack>
299     interpreter::VRegister GetVRegValueSlot(const VRegInfo &vreg) const;
300     template <bool need_pack>
301     interpreter::VRegister GetVRegValueRegister(const VRegInfo &vreg, SlotType **callee_stack) const;
302     template <bool need_pack>
303     interpreter::VRegister GetVRegValueConstant(const VRegInfo &vreg, const compiler::CodeInfo &code_info) const;
304 
305     uint64_t GetPackValue(VRegInfo::Type type, uint64_t val) const;
306 
307     using MemPrinter = void (*)(std::ostream &, void *, std::string_view, uintptr_t);
308     void DumpCalleeRegs(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot);
309     void DumpCalleeFPRegs(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot);
310     void DumpCallerRegs(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot);
311     void DumpCallerFPRegs(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot);
312     void DumpLocals(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot, int32_t max_slot);
313 
314 private:
315     SlotType *fp_ {nullptr};
316 };
317 
318 }  // namespace panda
319 
320 #endif  // PANDA_CFRAME_H
321