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