• 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 LIBPANDABASE_UTILS_CFRAME_LAYOUT_H
17 #define 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     }
End()42     static constexpr ssize_t End()
43     {
44         return Start() + GetSize();
45     }
GetSize()46     static constexpr ssize_t GetSize()
47     {
48         return SIZE;
49     }
50     template <class CFrameLayoutT>
GetOffsetFromSpInSlots(const CFrameLayoutT & fl)51     static constexpr ssize_t GetOffsetFromSpInSlots(const CFrameLayoutT &fl)
52     {
53         return fl.template GetFrameSize<CFrameLayoutT::SLOTS>() - START - 2U;
54     }
55     template <class CFrameLayoutT>
GetOffsetFromSpInBytes(const CFrameLayoutT & fl)56     static constexpr ssize_t GetOffsetFromSpInBytes(const CFrameLayoutT &fl)
57     {
58         return GetOffsetFromSpInSlots(fl) * fl.GetSlotSize();
59     }
60 
61 private:
62 };
63 
64 class CFrameLayout {
65 public:
CFrameLayout(Arch arch,size_t spills_count)66     constexpr CFrameLayout(Arch arch, size_t spills_count)
67         : arch_(arch), spills_count_(AlignSpillCount(arch, spills_count))
68     {
69     }
70     ~CFrameLayout() = default;
71     DEFAULT_COPY_SEMANTIC(CFrameLayout);
72     DEFAULT_MOVE_SEMANTIC(CFrameLayout);
73 
74     enum OffsetOrigin { SP, FP };
75     enum OffsetUnit { BYTES, SLOTS };
76 
77     using StackArgSlot = StackRegion<-2, 1>;               // -2 slot
78     using LrSlot = StackArgSlot::NextStackSlot;            // -1 slot
79     using PrevFrameSlot = LrSlot::NextStackSlot;           //  0 slot
80     using MethodSlot = PrevFrameSlot::NextStackSlot;       //  1 slot
81     using FlagsSlot = MethodSlot::NextStackSlot;           //  2 slot
82     using DataRegion = FlagsSlot::NextStackRegion<2>;      // [3..4] slots
83     using LocalsRegion = DataRegion::NextStackRegion<4>;   // [5..8] slots
84     using SlotsRegion = LocalsRegion::NextStackRegion<0>;  // [9...] slots
85     using RegsRegion = SlotsRegion;
86 
87     static constexpr ssize_t HEADER_SIZE = FlagsSlot::End() - LrSlot::Start();
88 
89     enum class FrameKind : uint8_t { DEFAULT = 0, OSR = 1, NATIVE = 2, LAST = NATIVE };
90 
91     using ShouldDeoptimizeFlag = BitField<bool, 0, 1>;
92     using HasFloatRegsFlag = ShouldDeoptimizeFlag::NextFlag;
93     using FrameKindField = HasFloatRegsFlag::NextField<FrameKind, MinimumBitsToStore(FrameKind::LAST)>;
94 
95     // Current usage of the locals:
96     //  [0..1] slots: internal spill slots for codegen
97     //  [2..3] slots: fp and lr in osr mode
98     // TODO(msherstennikov): need to make flexible machinery to handle locals
99     static constexpr size_t LOCALS_START_SLOT = 5;
100     static constexpr size_t STACK_START_SLOT = 9;
101     static constexpr size_t CALLEE_REGS_START_SLOT = STACK_START_SLOT;
102 
103     // NB! This 4 static constants are for cframe_test and stack_walker_test
104     // Use getters below in other code.
105     static constexpr size_t CALLEE_FP_REGS_START_SLOT =
106         CALLEE_REGS_START_SLOT + GetCalleeRegsCount(RUNTIME_ARCH, false);
107     static constexpr size_t CALLER_REGS_START_SLOT = CALLEE_FP_REGS_START_SLOT + GetCalleeRegsCount(RUNTIME_ARCH, true);
108     static constexpr size_t CALLER_FP_REGS_START_SLOT =
109         CALLER_REGS_START_SLOT + GetCallerRegsCount(RUNTIME_ARCH, false);
110     static constexpr size_t SPILLS_START_SLOT = CALLER_FP_REGS_START_SLOT + GetCallerRegsCount(RUNTIME_ARCH, true);
111 
112     // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
GetCalleeRegsStartSlot()113     constexpr size_t GetCalleeRegsStartSlot() const
114     {
115         return STACK_START_SLOT;
116     }
117 
GetCalleeFpRegsStartSlot()118     constexpr size_t GetCalleeFpRegsStartSlot() const
119     {
120         return GetCalleeRegsStartSlot() + ::panda::GetCalleeRegsCount(GetArch(), false);
121     }
122 
GetCallerRegsStartSlot()123     constexpr size_t GetCallerRegsStartSlot() const
124     {
125         return GetCalleeFpRegsStartSlot() + ::panda::GetCalleeRegsCount(GetArch(), true);
126     }
127 
GetCallerFpRegsStartSlot()128     constexpr size_t GetCallerFpRegsStartSlot() const
129     {
130         return GetCallerRegsStartSlot() + ::panda::GetCallerRegsCount(GetArch(), false);
131     }
132 
GetSpillsStartSlot()133     constexpr size_t GetSpillsStartSlot() const
134     {
135         return GetCallerFpRegsStartSlot() + ::panda::GetCallerRegsCount(GetArch(), true);
136     }
137 
138     // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
GetStackArgsStartSlot()139     constexpr ptrdiff_t GetStackArgsStartSlot() const
140     {
141         return StackArgSlot::Start();
142     }
143 
GetArch()144     constexpr Arch GetArch() const
145     {
146         return arch_;
147     }
148 
149     template <OffsetUnit unit>
GetFrameSize()150     constexpr size_t GetFrameSize() const
151     {
152         // +1 for LR slot
153         size_t size_in_slots = STACK_START_SLOT + GetFirstSpillSlot() + spills_count_ + 1U;
154         return unit == BYTES ? (size_in_slots * GetSlotSize()) : size_in_slots;
155     }
156 
157     template <OffsetOrigin origin, OffsetUnit unit>
GetOffset(ssize_t slot)158     constexpr ssize_t GetOffset(ssize_t slot) const
159     {
160         if constexpr (origin == SP) {  // NOLINT(readability-braces-around-statements)
161             const auto OFFSET = GetFrameSize<SLOTS>() - slot - 2U;
162             if constexpr (unit == BYTES) {  // NOLINT
163                 return OFFSET * GetSlotSize();
164             }
165             return OFFSET;
166         } else {                            // NOLINT
167             if constexpr (unit == BYTES) {  // NOLINT
168                 return slot * PointerSize(arch_);
169             }
170             return slot;
171         }
172     }
173 
174     template <OffsetOrigin origin, OffsetUnit unit>
GetMethodOffset()175     constexpr ssize_t GetMethodOffset() const
176     {
177         return GetOffset<origin, unit>(MethodSlot::Start());
178     }
179 
180     template <OffsetOrigin origin, OffsetUnit unit>
GetReturnAddressOffset()181     constexpr ssize_t GetReturnAddressOffset() const
182     {
183         return GetOffset<origin, unit>(LrSlot::Start());
184     }
185 
186     template <OffsetOrigin origin, OffsetUnit unit>
GetFreeSlotOffset()187     constexpr ssize_t GetFreeSlotOffset() const
188     {
189         return GetOffset<origin, unit>(LOCALS_START_SLOT);
190     }
191 
192     template <OffsetOrigin origin, OffsetUnit unit>
GetSpillOffset(size_t spill_slot)193     constexpr ssize_t GetSpillOffset(size_t spill_slot) const
194     {
195         size_t shift = Is64BitsArch(arch_) ? 0 : 1;  // in arm32 one slot is 2 word and shifted by 1
196         return GetOffset<origin, unit>(STACK_START_SLOT + GetFirstSpillSlot() + (spill_slot << shift) + shift);
197     }
198 
GetSpillOffsetFromSpInBytes(size_t spill_slot)199     constexpr ssize_t GetSpillOffsetFromSpInBytes(size_t spill_slot) const
200     {
201         return GetSpillOffset<CFrameLayout::SP, CFrameLayout::BYTES>(spill_slot);
202     }
203 
204     // NOLINTNEXTLINE(readability-convert-member-functions-to-static)
GetStackStartSlot()205     static constexpr ssize_t GetStackStartSlot()
206     {
207         return STACK_START_SLOT;
208     }
209 
GetCalleeSlotsCount()210     constexpr size_t GetCalleeSlotsCount() const
211     {
212         return GetCalleeRegistersCount(false) + GetCalleeRegistersCount(true);
213     }
214 
GetCallerSlotsCount()215     constexpr size_t GetCallerSlotsCount() const
216     {
217         return GetCallerRegistersCount(false) + GetCallerRegistersCount(true);
218     }
219 
GetFirstSpillSlot()220     constexpr size_t GetFirstSpillSlot() const
221     {
222         return GetCalleeSlotsCount() + GetCallerSlotsCount();
223     }
GetLastSpillSlot()224     constexpr size_t GetLastSpillSlot() const
225     {
226         return GetFirstSpillSlot() + spills_count_ - 1;
227     }
228 
GetCalleeFirstSlot(bool is_fp)229     constexpr size_t GetCalleeFirstSlot(bool is_fp) const
230     {
231         return is_fp ? GetCalleeRegistersCount(false) : 0;
232     }
233 
GetCalleeLastSlot(bool is_fp)234     constexpr size_t GetCalleeLastSlot(bool is_fp) const
235     {
236         return GetCalleeFirstSlot(is_fp) + GetCalleeRegistersCount(is_fp) - 1;
237     }
238 
GetCallerFirstSlot(bool is_fp)239     constexpr size_t GetCallerFirstSlot(bool is_fp) const
240     {
241         return GetCalleeLastSlot(true) + 1 + (is_fp ? GetCallerRegistersCount(false) : 0);
242     }
243 
GetCallerLastSlot(bool is_fp)244     constexpr size_t GetCallerLastSlot(bool is_fp) const
245     {
246         return GetCallerFirstSlot(is_fp) + GetCallerRegistersCount(is_fp) - 1;
247     }
248 
GetCalleeRegistersCount(bool is_fp)249     constexpr size_t GetCalleeRegistersCount(bool is_fp) const
250     {
251         return panda::GetCalleeRegsCount(arch_, is_fp);
252     }
253 
GetCallerRegistersCount(bool is_fp)254     constexpr size_t GetCallerRegistersCount(bool is_fp) const
255     {
256         return panda::GetCallerRegsCount(arch_, is_fp);
257     }
258 
GetSlotSize()259     constexpr size_t GetSlotSize() const
260     {
261         return PointerSize(arch_);
262     }
263 
GetSpillsCount()264     constexpr size_t GetSpillsCount() const
265     {
266         return spills_count_;
267     }
268 
GetRegsSlotsCount()269     constexpr size_t GetRegsSlotsCount() const
270     {
271         return GetCalleeSlotsCount() + GetCallerSlotsCount() + GetSpillsCount();
272     }
273 
GetLocalsCount()274     static constexpr size_t GetLocalsCount()
275     {
276         return STACK_START_SLOT - LOCALS_START_SLOT;
277     }
278 
GetOsrFpLrSlot()279     static constexpr ssize_t GetOsrFpLrSlot()
280     {
281         return LocalsRegion::Start() + static_cast<ssize_t>(GetLocalsCount()) - 1;
282     }
283 
GetOsrFpLrOffset()284     constexpr ssize_t GetOsrFpLrOffset() const
285     {
286         return GetOffset<CFrameLayout::FP, CFrameLayout::BYTES>(GetOsrFpLrSlot());
287     }
288 
GetFpLrSlotsCount()289     static constexpr size_t GetFpLrSlotsCount()
290     {
291         static_assert(MethodSlot::Start() > LrSlot::Start());
292         return MethodSlot::Start() - LrSlot::Start();
293     }
294 
GetTopToRegsSlotsCount()295     static constexpr size_t GetTopToRegsSlotsCount()
296     {
297         static_assert(SlotsRegion::Start() > LrSlot::Start());
298         return SlotsRegion::Start() - LrSlot::Start();
299     }
300 
301 private:
AlignSpillCount(Arch arch,size_t spills_count)302     constexpr size_t AlignSpillCount(Arch arch, size_t spills_count)
303     {
304         // Allign by odd-number, because GetSpillsStartSlot begins from fp (+1 slot for lr)
305         if (arch == Arch::AARCH64 || arch == Arch::X86_64) {
306             if (((GetSpillsStartSlot() + spills_count) % 2) == 0) {
307                 spills_count++;
308             }
309         } else if (arch == Arch::AARCH32) {
310             // Additional slot for spill/fill <-> sf-registers ldrd miscorp
311             spills_count = (spills_count + 1) * 2;
312             if (((GetSpillsStartSlot() + spills_count) % 2) == 0) {
313                 spills_count++;
314             }
315         }
316         return spills_count;
317     }
318 
319 private:
320     Arch arch_;
321     size_t spills_count_ {0};
322 };
323 
324 static_assert(CFrameLayout::GetLocalsCount() >= 2U);
325 static_assert(CFrameLayout::GetFpLrSlotsCount() == 2U);
326 
327 enum class FrameKind { NONE, INTERPRETER, COMPILER };
328 
329 template <FrameKind kind>
330 struct BoundaryFrame;
331 
332 template <>
333 struct BoundaryFrame<FrameKind::INTERPRETER> {
334     static constexpr ssize_t METHOD_OFFSET = 1;
335     static constexpr ssize_t FP_OFFSET = 0;
336     static constexpr ssize_t RETURN_OFFSET = 2;
337     static constexpr ssize_t CALLEES_OFFSET = -1;
338 };
339 
340 template <>
341 struct BoundaryFrame<FrameKind::COMPILER> {
342     static constexpr ssize_t METHOD_OFFSET = -1;
343     static constexpr ssize_t FP_OFFSET = 0;
344     static constexpr ssize_t RETURN_OFFSET = 1;
345     static constexpr ssize_t CALLEES_OFFSET = -2;
346 };
347 
348 using CFrameReturnAddr = CFrameLayout::LrSlot;
349 using CFramePrevFrame = CFrameLayout::PrevFrameSlot;
350 using CFrameMethod = CFrameLayout::MethodSlot;
351 using CFrameFlags = CFrameLayout::FlagsSlot;
352 using CFrameData = CFrameLayout::DataRegion;
353 using CFrameLocals = CFrameLayout::LocalsRegion;
354 using CFrameSlots = CFrameLayout::SlotsRegion;
355 using CFrameRegs = CFrameLayout::RegsRegion;
356 
357 }  // namespace panda
358 
359 #endif  // LIBPANDABASE_UTILS_CFRAME_LAYOUT_H
360