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