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