• 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_LIBPANDABASE_UTILS_CFRAME_LAYOUT_H_
17 #define PANDA_LIBPANDABASE_UTILS_CFRAME_LAYOUT_H_
18 
19 #include "arch.h"
20 
21 namespace panda {
22 
23 enum FrameBridgeKind {
24     INTERPRETER_TO_COMPILED_CODE = 1,
25     COMPILED_CODE_TO_INTERPRETER = 2,
26     BYPASS = 3,
27 };
28 
29 template <ssize_t START, ssize_t SIZE>
30 class StackRegion {
31 public:
32     static_assert(SIZE >= 0);
33     template <size_t SZ>
34     using NextStackRegion = StackRegion<START + SIZE, SZ>;
35 
36     using NextStackSlot = StackRegion<START + SIZE, 1>;
37 
Start()38     static constexpr ssize_t Start()
39     {
40         return START;
41     }
42 
End()43     static constexpr ssize_t End()
44     {
45         return Start() + GetSize();
46     }
47 
GetSize()48     static constexpr ssize_t GetSize()
49     {
50         return SIZE;
51     }
52 
53     template <class CFrameLayoutT>
GetOffsetFromSpInSlots(const CFrameLayoutT & fl)54     static constexpr ssize_t GetOffsetFromSpInSlots(const CFrameLayoutT &fl)
55     {
56         // CODECHECK-NOLINTNEXTLINE(C_RULE_ID_HORIZON_SPACE)
57         return fl.template GetFrameSize<CFrameLayoutT::SLOTS>() - START - 2U;
58     }
59 
60     template <class CFrameLayoutT>
GetOffsetFromSpInBytes(const CFrameLayoutT & fl)61     static constexpr ssize_t GetOffsetFromSpInBytes(const CFrameLayoutT &fl)
62     {
63         return GetOffsetFromSpInSlots(fl) * fl.GetSlotSize();
64     }
65 
66 private:
67 };
68 
69 class CFrameLayout {
70 public:
CFrameLayout(Arch arch,size_t spills_count)71     constexpr CFrameLayout(Arch arch, size_t spills_count)
72         : arch_(arch), spills_count_(AlignSpillCount(arch, spills_count))
73     {
74     }
75     ~CFrameLayout() = default;
76     DEFAULT_COPY_SEMANTIC(CFrameLayout);
77     DEFAULT_MOVE_SEMANTIC(CFrameLayout);
78 
79     enum OffsetOrigin { SP, FP };
80     enum OffsetUnit { BYTES, SLOTS };
81 
82     using StackArgSlot = StackRegion<-2, 1>;               // -2 slot
83     using LrSlot = StackArgSlot::NextStackSlot;            // -1 slot
84     using PrevFrameSlot = LrSlot::NextStackSlot;           //  0 slot
85     using MethodSlot = PrevFrameSlot::NextStackSlot;       //  1 slot
86     using FlagsSlot = MethodSlot::NextStackSlot;           //  2 slot
87     using DataRegion = FlagsSlot::NextStackRegion<2>;      // [3..4] slots
88     using LocalsRegion = DataRegion::NextStackRegion<4>;   // [5..8] slots
89     using SlotsRegion = LocalsRegion::NextStackRegion<0>;  // [9...] slots
90     using RegsRegion = SlotsRegion;
91 
92     static constexpr ssize_t HEADER_SIZE = FlagsSlot::End() - LrSlot::Start();
93 
94     // Current usage of the locals:
95     //  [0..1] slots: internal spill slots for codegen
96     //  [2..3] slots: fp and lr in osr mode
97     static constexpr size_t LOCALS_START_SLOT = 5;
98     static constexpr size_t STACK_START_SLOT = 9;
99     static constexpr size_t CALLEE_REGS_START_SLOT = STACK_START_SLOT;
100 
101     // NB! This 4 static constants are for cframe_test and stack_walker_test
102     // Use getters below in other code.
103     static constexpr size_t CALLEE_FP_REGS_START_SLOT =
104         CALLEE_REGS_START_SLOT + GetCalleeRegsCount(RUNTIME_ARCH, false);
105     static constexpr size_t CALLER_REGS_START_SLOT = CALLEE_FP_REGS_START_SLOT + GetCalleeRegsCount(RUNTIME_ARCH, true);
106     static constexpr size_t CALLER_FP_REGS_START_SLOT =
107         CALLER_REGS_START_SLOT + GetCallerRegsCount(RUNTIME_ARCH, false);
108     static constexpr size_t SPILLS_START_SLOT = CALLER_FP_REGS_START_SLOT + GetCallerRegsCount(RUNTIME_ARCH, true);
109 
110     // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
GetCalleeRegsStartSlot()111     constexpr size_t GetCalleeRegsStartSlot() const
112     {
113         return STACK_START_SLOT;
114     }
115 
GetCalleeFpRegsStartSlot()116     constexpr size_t GetCalleeFpRegsStartSlot() const
117     {
118         return GetCalleeRegsStartSlot() + ::panda::GetCalleeRegsCount(GetArch(), false);
119     }
120 
GetCallerRegsStartSlot()121     constexpr size_t GetCallerRegsStartSlot() const
122     {
123         return GetCalleeFpRegsStartSlot() + ::panda::GetCalleeRegsCount(GetArch(), true);
124     }
125 
GetCallerFpRegsStartSlot()126     constexpr size_t GetCallerFpRegsStartSlot() const
127     {
128         return GetCallerRegsStartSlot() + ::panda::GetCallerRegsCount(GetArch(), false);
129     }
130 
GetSpillsStartSlot()131     constexpr size_t GetSpillsStartSlot() const
132     {
133         return GetCallerFpRegsStartSlot() + ::panda::GetCallerRegsCount(GetArch(), true);
134     }
135 
136     // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
GetStackArgsStartSlot()137     constexpr ptrdiff_t GetStackArgsStartSlot() const
138     {
139         return StackArgSlot::Start();
140     }
141 
GetArch()142     constexpr Arch GetArch() const
143     {
144         return arch_;
145     }
146 
147     template <OffsetUnit unit>
GetFrameSize()148     constexpr size_t GetFrameSize() const
149     {
150         // +1 for LR slot
151         size_t size_in_slots = STACK_START_SLOT + GetFirstSpillSlot() + spills_count_ + 1U;
152         return unit == BYTES ? size_in_slots * GetSlotSize() : size_in_slots;
153     }
154 
155     template <OffsetOrigin origin, OffsetUnit unit>
GetMethodOffset()156     constexpr ssize_t GetMethodOffset() const
157     {
158         return GetOffset<origin, unit>(MethodSlot::Start());
159     }
160 
161     template <OffsetOrigin origin, OffsetUnit unit>
GetReturnAddressOffset()162     constexpr ssize_t GetReturnAddressOffset() const
163     {
164         return GetOffset<origin, unit>(LrSlot::Start());
165     }
166 
167     template <OffsetOrigin origin, OffsetUnit unit>
GetFreeSlotOffset()168     constexpr ssize_t GetFreeSlotOffset() const
169     {
170         return GetOffset<origin, unit>(LOCALS_START_SLOT);
171     }
172 
173     template <OffsetOrigin origin, OffsetUnit unit>
GetSpillOffset(size_t spill_slot)174     constexpr ssize_t GetSpillOffset(size_t spill_slot) const
175     {
176         size_t shift = Is64BitsArch(arch_) ? 0 : 1;  // in arm32 one slot is 2 word and shifted by 1
177         return GetOffset<origin, unit>(STACK_START_SLOT + GetFirstSpillSlot() + (spill_slot << shift) + shift);
178     }
179 
GetSpillOffsetFromSpInBytes(size_t spill_slot)180     constexpr ssize_t GetSpillOffsetFromSpInBytes(size_t spill_slot) const
181     {
182         return GetSpillOffset<CFrameLayout::SP, CFrameLayout::BYTES>(spill_slot);
183     }
184 
185     template <OffsetOrigin origin, OffsetUnit unit>
GetOffset(ssize_t slot)186     constexpr ssize_t GetOffset(ssize_t slot) const
187     {
188         if constexpr (origin == SP) {  // NOLINT(readability-braces-around-statements)
189             const auto OFFSET = GetFrameSize<SLOTS>() - slot - 2U;
190             if constexpr (unit == BYTES) {  // NOLINT
191                 return OFFSET * GetSlotSize();
192             }
193             return OFFSET;
194         } else {                            // NOLINT
195             if constexpr (unit == BYTES) {  // NOLINT
196                 return slot * PointerSize(arch_);
197             }
198             return slot;
199         }
200     }
201 
GetBytesOffsetSp(ssize_t slot)202     constexpr ssize_t GetBytesOffsetSp(ssize_t slot) const
203     {
204         return GetOffset<SP, BYTES>(slot);
205     }
206 
207     // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
GetStackStartSlot()208     constexpr ssize_t GetStackStartSlot() const
209     {
210         return STACK_START_SLOT;
211     }
212 
GetFirstSpillSlot()213     constexpr size_t GetFirstSpillSlot() const
214     {
215         return GetCalleeRegistersCount(false) + GetCalleeRegistersCount(true) + GetCallerRegistersCount(false) +
216                GetCallerRegistersCount(true);
217     }
GetLastSpillSlot()218     constexpr size_t GetLastSpillSlot() const
219     {
220         return GetFirstSpillSlot() + spills_count_ - 1;
221     }
222 
GetCalleeFirstSlot(bool is_fp)223     constexpr size_t GetCalleeFirstSlot(bool is_fp) const
224     {
225         return is_fp ? GetCalleeRegistersCount(false) : 0;
226     }
227 
GetCalleeLastSlot(bool is_fp)228     constexpr size_t GetCalleeLastSlot(bool is_fp) const
229     {
230         return GetCalleeFirstSlot(is_fp) + GetCalleeRegistersCount(is_fp) - 1;
231     }
232 
GetCallerFirstSlot(bool is_fp)233     constexpr size_t GetCallerFirstSlot(bool is_fp) const
234     {
235         return GetCalleeLastSlot(true) + 1 + (is_fp ? GetCallerRegistersCount(false) : 0);
236     }
237 
GetCallerLastSlot(bool is_fp)238     constexpr size_t GetCallerLastSlot(bool is_fp) const
239     {
240         return GetCallerFirstSlot(is_fp) + GetCallerRegistersCount(is_fp) - 1;
241     }
242 
GetCalleeRegistersCount(bool is_fp)243     constexpr size_t GetCalleeRegistersCount(bool is_fp) const
244     {
245         return panda::GetCalleeRegsCount(arch_, is_fp);
246     }
247 
GetCallerRegistersCount(bool is_fp)248     constexpr size_t GetCallerRegistersCount(bool is_fp) const
249     {
250         return panda::GetCallerRegsCount(arch_, is_fp);
251     }
252 
GetSlotSize()253     constexpr size_t GetSlotSize() const
254     {
255         return PointerSize(arch_);
256     }
257 
GetSlotsCount()258     constexpr size_t GetSlotsCount() const
259     {
260         return spills_count_;
261     }
262 
GetLocalsCount()263     static constexpr size_t GetLocalsCount()
264     {
265         return STACK_START_SLOT - LOCALS_START_SLOT;
266     }
267 
268 private:
AlignSpillCount(Arch arch,size_t spills_count)269     constexpr size_t AlignSpillCount(Arch arch, size_t spills_count)
270     {
271         // Align by odd-number, because GetSpillsStartSlot begins from fp (+1 slot for lr)
272         if (arch == Arch::AARCH64 || arch == Arch::X86_64) {
273             if (((GetSpillsStartSlot() + spills_count) % 2) == 0) {
274                 spills_count++;
275             }
276         } else if (arch == Arch::AARCH32) {
277             // Additional slot for spill/fill <-> sf-registers ldrd miscorp
278             spills_count = (spills_count + 1) * 2;
279             if (((GetSpillsStartSlot() + spills_count) % 2) == 0) {
280                 spills_count++;
281             }
282         }
283         return spills_count;
284     }
285 
286 private:
287     Arch arch_;
288     size_t spills_count_ {0};
289 };
290 
291 using CFrameReturnAddr = CFrameLayout::LrSlot;
292 using CFramePrevFrame = CFrameLayout::PrevFrameSlot;
293 using CFrameMethod = CFrameLayout::MethodSlot;
294 using CFrameFlags = CFrameLayout::FlagsSlot;
295 using CFrameData = CFrameLayout::DataRegion;
296 using CFrameLocals = CFrameLayout::LocalsRegion;
297 using CFrameSlots = CFrameLayout::SlotsRegion;
298 
299 }  // namespace panda
300 
301 #endif  // PANDA_LIBPANDABASE_UTILS_CFRAME_LAYOUT_H_
302