/** * Copyright (c) 2021-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef PANDA_CFRAME_H #define PANDA_CFRAME_H #include #include "compiler/code_info/code_info.h" #include "libpandabase/utils/cframe_layout.h" #include "runtime/interpreter/frame.h" #include "libpandabase/macros.h" namespace ark { namespace compiler { class CodeInfo; } // namespace compiler class Method; struct alignas(2U * alignof(uintptr_t)) C2IBridge { std::array v; // 4: means array length }; /** * CFrame layout (in descending order): * * ----------------- * LR * PREV_FRAME <-- `fp_` points here * METHOD * PROPERTIES: [0]: Should deoptimize (1 - deoptimize) * [1..2]: Frame type - NATIVE, OSR or DEFAULT * ----------------- * LOCALS several slots used for internal needs * ----------------- * R_N = CALLEE SAVED REGS <--- `callee_stack_` of the caller's frame points here * ... * R_0 * ----------------- * VR_N = CALLEE SAVED FP REGS * ... * VR_0 * ----------------- * R_N = CALLER SAVED REGS * ... * R_0 * ----------------- * VR_N = CALLER SAVED FP REGS * ... * VR_0 * ----------------- * SLOT_N = REGALLOC SPILL/FILLS * ... * SLOT_0 * ----------------- * SLOT_M = LANGUAGE EXTENSION SPILL SLOTS * ... * SLOT_0 * ----------------- * SLOT_P = PARAMETERS SLOTS * ... * SLOT_0 * ----------------- */ class CFrame final { public: static constexpr Arch ARCH = RUNTIME_ARCH; using SlotType = std::conditional_t::IS_64_BITS, uint64_t, uint32_t>; using CodeInfo = compiler::CodeInfo; using VRegInfo = compiler::VRegInfo; using StackMap = compiler::StackMap; public: explicit CFrame(void *frameData) : fp_(reinterpret_cast(frameData)) {} ~CFrame() = default; DEFAULT_COPY_SEMANTIC(CFrame); DEFAULT_NOEXCEPT_MOVE_SEMANTIC(CFrame); bool IsOsr() const { return CFrameLayout::FrameKindField::Get(*GetPtr(CFrameLayout::FlagsSlot::Start())) == CFrameLayout::FrameKind::OSR; } bool IsNative() const { return CFrameLayout::FrameKindField::Get(*GetPtr(CFrameLayout::FlagsSlot::Start())) == CFrameLayout::FrameKind::NATIVE; } void SetFrameKind(CFrameLayout::FrameKind kind) { CFrameLayout::FrameKindField::Set(kind, GetPtr(CFrameLayout::FlagsSlot::Start())); } PANDA_PUBLIC_API bool IsNativeMethod() const; bool ShouldDeoptimize() const { return CFrameLayout::ShouldDeoptimizeFlag::Get(*GetPtr(CFrameLayout::FlagsSlot::Start())); } void SetShouldDeoptimize(bool v) { CFrameLayout::ShouldDeoptimizeFlag::Set(v, GetPtr(CFrameLayout::FlagsSlot::Start())); } void SetHasFloatRegs(bool has) { CFrameLayout::HasFloatRegsFlag::Set(has, GetPtr(CFrameLayout::FlagsSlot::Start())); } SlotType *GetPrevFrame() { return *GetPtr(CFrameLayout::PrevFrameSlot::Start()); } const SlotType *GetPrevFrame() const { return *GetPtr(CFrameLayout::PrevFrameSlot::Start()); } void SetPrevFrame(void *prevFrame) { *GetPtr(CFrameLayout::PrevFrameSlot::Start()) = bit_cast(prevFrame); } Method *GetMethod() { return *GetPtr(CFrameLayout::MethodSlot::Start()); } const Method *GetMethod() const { return const_cast(this)->GetMethod(); } void SetMethod(Method *method) { *GetPtr(CFrameLayout::MethodSlot::Start()) = bit_cast(method); } void *GetDeoptCodeEntry() const { return *GetPtr(CFrameData::Start()); } /** * When method is deoptimizated due to it speculation fatal failure, its code entry is reset. * Therefore already executing methods will can't get proper code entry for stack walker, * thus we create this backup code entry. */ void SetDeoptCodeEntry(const void *value) { *GetPtr(CFrameData::Start()) = value; } template inline void GetVRegValue(const VRegInfo &vreg, const compiler::CodeInfo &codeInfo, SlotType **calleeStack, RegRef &®) { auto val = GetVRegValue(vreg, codeInfo, calleeStack).GetValue(); if (vreg.IsObject()) { reg.SetReference(reinterpret_cast(static_cast(val))); } else { reg.SetPrimitive(val); } } template inline void GetPackVRegValue(const VRegInfo &vreg, const compiler::CodeInfo &codeInfo, SlotType **calleeStack, RegRef &®) { auto val = GetVRegValue(vreg, codeInfo, calleeStack).GetValue(); reg.SetPrimitive(val); } template void SetVRegValue(const VRegInfo &vreg, uint64_t value, SlotType **calleeStack); uintptr_t GetLr() const { return *GetPtr(CFrameLayout::LrSlot::Start()); } SlotType *GetStackOrigin() { return GetPtr(CFrameLayout::STACK_START_SLOT); } const SlotType *GetStackOrigin() const { return GetPtr(CFrameLayout::STACK_START_SLOT); } SlotType *GetCalleeSaveStack() { return GetPtr(CFrameLayout::CALLEE_REGS_START_SLOT - 1); } SlotType *GetCallerSaveStack() { return GetPtr(CFrameLayout::CALLER_REGS_START_SLOT - 1); } SlotType *GetFrameOrigin() { return fp_; } const SlotType *GetFrameOrigin() const { return fp_; } SlotType *GetStackArgsStart() { return GetPtr(CFrameLayout::STACK_ARGS_START); } const SlotType *GetStackArgsStart() const { return GetPtr(CFrameLayout::STACK_ARGS_START); } SlotType *GetFrameStart() { return GetPtr(CFrameLayout::FRAME_START_SLOT); } const SlotType *GetFrameStart() const { return GetPtr(CFrameLayout::FRAME_START_SLOT); } SlotType GetValueFromSlot(int slot) const { return *GetValuePtrFromSlot(slot); } const SlotType *GetValuePtrFromSlot(int slot) const { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) return reinterpret_cast(GetStackOrigin()) - slot; } void SetValueToSlot(int slot, SlotType value) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) *(reinterpret_cast(GetStackOrigin()) - slot) = value; } void Dump(const CodeInfo &codeInfo, std::ostream &os); void Dump(std::ostream &os, uint32_t maxSlot = 0); template PANDA_PUBLIC_API interpreter::VRegister GetVRegValue(const VRegInfo &vreg, const compiler::CodeInfo &codeInfo, SlotType **calleeStack) const; private: SlotType ReadCalleeSavedRegister(size_t reg, bool isFp, SlotType **calleeStack) const { ASSERT(reg >= GetFirstCalleeReg(ARCH, isFp)); ASSERT(reg <= GetLastCalleeReg(ARCH, isFp)); ASSERT(GetCalleeRegsCount(ARCH, isFp) != 0); size_t startSlot = GetCalleeRegsMask(ARCH, isFp).GetDistanceFromTail(reg); if (isFp) { startSlot += GetCalleeRegsCount(ARCH, false); } // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) ASSERT(calleeStack[startSlot] != nullptr); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) return *calleeStack[startSlot]; } void WriteCalleeSavedRegister(size_t reg, SlotType value, bool isFp, SlotType **calleeStack) const { ASSERT(reg >= GetFirstCalleeReg(ARCH, isFp)); ASSERT(reg <= GetLastCalleeReg(ARCH, isFp)); ASSERT(GetCalleeRegsCount(ARCH, isFp) != 0); size_t startSlot = reg - GetFirstCalleeReg(ARCH, isFp); if (isFp) { startSlot += GetCalleeRegsCount(ARCH, false); } // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) ASSERT(calleeStack[startSlot] != nullptr); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) *calleeStack[startSlot] = value; } template T *GetPtr(ptrdiff_t slot) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) return reinterpret_cast(GetFrameOrigin() - slot); } template const T *GetPtr(ptrdiff_t slot) const { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) return reinterpret_cast(GetFrameOrigin() - slot); } template interpreter::VRegister GetVRegValueSlot(const VRegInfo &vreg) const; template interpreter::VRegister GetVRegValueRegister(const VRegInfo &vreg, SlotType **calleeStack) const; template interpreter::VRegister GetVRegValueConstant(const VRegInfo &vreg, const compiler::CodeInfo &codeInfo) const; uint64_t GetPackValue(VRegInfo::Type type, uint64_t val) const; using MemPrinter = void (*)(std::ostream &, void *, std::string_view, uintptr_t); void DumpCalleeRegs(std::ostream &os, MemPrinter printMem, PandaString *dscr, size_t *slot); void DumpCalleeFPRegs(std::ostream &os, MemPrinter printMem, PandaString *dscr, size_t *slot); void DumpCallerRegs(std::ostream &os, MemPrinter printMem, PandaString *dscr, size_t *slot); void DumpCallerFPRegs(std::ostream &os, MemPrinter printMem, PandaString *dscr, size_t *slot); void DumpLocals(std::ostream &os, MemPrinter printMem, PandaString *dscr, size_t *slot, int32_t maxSlot); private: SlotType *fp_ {nullptr}; }; } // namespace ark #endif // PANDA_CFRAME_H