• 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 SPILL 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 * frameData)88     explicit CFrame(void *frameData) : fp_(reinterpret_cast<SlotType *>(frameData)) {}
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     PANDA_PUBLIC_API 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 * prevFrame)138     void SetPrevFrame(void *prevFrame)
139     {
140         *GetPtr<SlotType>(CFrameLayout::PrevFrameSlot::Start()) = bit_cast<SlotType>(prevFrame);
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 & codeInfo,SlotType ** calleeStack,RegRef && reg)174     inline void GetVRegValue(const VRegInfo &vreg, const compiler::CodeInfo &codeInfo, SlotType **calleeStack,
175                              RegRef &&reg)
176     {
177         auto val = GetVRegValue<false>(vreg, codeInfo, calleeStack).GetValue();
178         if (vreg.IsObject()) {
179             reg.SetReference(reinterpret_cast<ObjectHeader *>(static_cast<ObjectPointerType>(val)));
180         } else {
181             reg.SetPrimitive(val);
182         }
183     }
184 
185     template <typename RegRef>
GetPackVRegValue(const VRegInfo & vreg,const compiler::CodeInfo & codeInfo,SlotType ** calleeStack,RegRef && reg)186     inline void GetPackVRegValue(const VRegInfo &vreg, const compiler::CodeInfo &codeInfo, SlotType **calleeStack,
187                                  RegRef &&reg)
188     {
189         auto val = GetVRegValue<true>(vreg, codeInfo, calleeStack).GetValue();
190         reg.SetPrimitive(val);
191     }
192 
193     template <bool NEED_PACK = false>
194     void SetVRegValue(const VRegInfo &vreg, uint64_t value, SlotType **calleeStack);
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 
GetStackArgsStart()230     SlotType *GetStackArgsStart()
231     {
232         return GetPtr<SlotType>(CFrameLayout::STACK_ARGS_START);
233     }
234 
GetStackArgsStart()235     const SlotType *GetStackArgsStart() const
236     {
237         return GetPtr<const SlotType>(CFrameLayout::STACK_ARGS_START);
238     }
239 
GetFrameStart()240     SlotType *GetFrameStart()
241     {
242         return GetPtr<SlotType>(CFrameLayout::FRAME_START_SLOT);
243     }
244 
GetFrameStart()245     const SlotType *GetFrameStart() const
246     {
247         return GetPtr<const SlotType>(CFrameLayout::FRAME_START_SLOT);
248     }
249 
GetValueFromSlot(int slot)250     SlotType GetValueFromSlot(int slot) const
251     {
252         return *GetValuePtrFromSlot(slot);
253     }
254 
GetValuePtrFromSlot(int slot)255     const SlotType *GetValuePtrFromSlot(int slot) const
256     {
257         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
258         return reinterpret_cast<const SlotType *>(GetStackOrigin()) - slot;
259     }
260 
SetValueToSlot(int slot,SlotType value)261     void SetValueToSlot(int slot, SlotType value)
262     {
263         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
264         *(reinterpret_cast<SlotType *>(GetStackOrigin()) - slot) = value;
265     }
266 
267     void Dump(const CodeInfo &codeInfo, std::ostream &os);
268 
269     void Dump(std::ostream &os, uint32_t maxSlot = 0);
270 
271     template <bool NEED_PACK>
272     PANDA_PUBLIC_API interpreter::VRegister GetVRegValue(const VRegInfo &vreg, const compiler::CodeInfo &codeInfo,
273                                                          SlotType **calleeStack) const;
274 
275 private:
ReadCalleeSavedRegister(size_t reg,bool isFp,SlotType ** calleeStack)276     SlotType ReadCalleeSavedRegister(size_t reg, bool isFp, SlotType **calleeStack) const
277     {
278         ASSERT(reg >= GetFirstCalleeReg(ARCH, isFp));
279         ASSERT(reg <= GetLastCalleeReg(ARCH, isFp));
280         ASSERT(GetCalleeRegsCount(ARCH, isFp) != 0);
281         size_t startSlot = GetCalleeRegsMask(ARCH, isFp).GetDistanceFromTail(reg);
282         if (isFp) {
283             startSlot += GetCalleeRegsCount(ARCH, false);
284         }
285         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
286         ASSERT(calleeStack[startSlot] != nullptr);
287         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
288         return *calleeStack[startSlot];
289     }
290 
WriteCalleeSavedRegister(size_t reg,SlotType value,bool isFp,SlotType ** calleeStack)291     void WriteCalleeSavedRegister(size_t reg, SlotType value, bool isFp, SlotType **calleeStack) const
292     {
293         ASSERT(reg >= GetFirstCalleeReg(ARCH, isFp));
294         ASSERT(reg <= GetLastCalleeReg(ARCH, isFp));
295         ASSERT(GetCalleeRegsCount(ARCH, isFp) != 0);
296         size_t startSlot = reg - GetFirstCalleeReg(ARCH, isFp);
297         if (isFp) {
298             startSlot += GetCalleeRegsCount(ARCH, false);
299         }
300         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
301         ASSERT(calleeStack[startSlot] != nullptr);
302         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
303         *calleeStack[startSlot] = value;
304     }
305 
306     template <typename T>
GetPtr(ptrdiff_t slot)307     T *GetPtr(ptrdiff_t slot)
308     {
309         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
310         return reinterpret_cast<T *>(GetFrameOrigin() - slot);
311     }
312     template <typename T>
GetPtr(ptrdiff_t slot)313     const T *GetPtr(ptrdiff_t slot) const
314     {
315         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
316         return reinterpret_cast<const T *>(GetFrameOrigin() - slot);
317     }
318 
319     template <bool NEED_PACK>
320     interpreter::VRegister GetVRegValueSlot(const VRegInfo &vreg) const;
321     template <bool NEED_PACK>
322     interpreter::VRegister GetVRegValueRegister(const VRegInfo &vreg, SlotType **calleeStack) const;
323     template <bool NEED_PACK>
324     interpreter::VRegister GetVRegValueConstant(const VRegInfo &vreg, const compiler::CodeInfo &codeInfo) const;
325 
326     uint64_t GetPackValue(VRegInfo::Type type, uint64_t val) const;
327 
328     using MemPrinter = void (*)(std::ostream &, void *, std::string_view, uintptr_t);
329     void DumpCalleeRegs(std::ostream &os, MemPrinter printMem, PandaString *dscr, size_t *slot);
330     void DumpCalleeFPRegs(std::ostream &os, MemPrinter printMem, PandaString *dscr, size_t *slot);
331     void DumpCallerRegs(std::ostream &os, MemPrinter printMem, PandaString *dscr, size_t *slot);
332     void DumpCallerFPRegs(std::ostream &os, MemPrinter printMem, PandaString *dscr, size_t *slot);
333     void DumpLocals(std::ostream &os, MemPrinter printMem, PandaString *dscr, size_t *slot, int32_t maxSlot);
334 
335 private:
336     SlotType *fp_ {nullptr};
337 };
338 
339 }  // namespace panda
340 
341 #endif  // PANDA_CFRAME_H
342