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