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