/** * Copyright (c) 2021-2022 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. */ #include "runtime/include/cframe.h" #include "compiler/code_info/code_info.h" #include "runtime/include/runtime.h" #include "runtime/include/stack_walker.h" #include "utils/regmask.h" namespace panda { bool CFrame::IsNativeMethod() const { return GetMethod()->IsNative(); } template <bool need_pack> interpreter::VRegister CFrame::GetVRegValueInternal(const VRegInfo &vreg, const compiler::CodeInfo &code_info, SlotType **callee_stack) const { switch (vreg.GetLocation()) { case VRegInfo::Location::SLOT: return GetVRegValueSlot<need_pack>(vreg); case VRegInfo::Location::REGISTER: case VRegInfo::Location::FP_REGISTER: return GetVRegValueRegister<need_pack>(vreg, callee_stack); case VRegInfo::Location::CONSTANT: return GetVRegValueConstant<need_pack>(vreg, code_info); default: return interpreter::VRegister {}; } } template interpreter::VRegister CFrame::GetVRegValueInternal<true>(const VRegInfo &vreg, const compiler::CodeInfo &code_info, SlotType **callee_stack) const; template interpreter::VRegister CFrame::GetVRegValueInternal<false>(const VRegInfo &vreg, const compiler::CodeInfo &code_info, SlotType **callee_stack) const; template void CFrame::SetVRegValue<true>(const VRegInfo &vreg, uint64_t value, SlotType **callee_stack); template void CFrame::SetVRegValue<false>(const VRegInfo &vreg, uint64_t value, SlotType **callee_stack); uint64_t CFrame::GetPackValue(VRegInfo::Type type, uint64_t val) const { if (type == VRegInfo::Type::ANY) { return val; } if (type == VRegInfo::Type::FLOAT64) { return coretypes::TaggedValue::GetDoubleTaggedValue(val); } if (type == VRegInfo::Type::INT32) { return coretypes::TaggedValue::GetIntTaggedValue(val); } if (type == VRegInfo::Type::BOOL) { return coretypes::TaggedValue::GetBoolTaggedValue(val); } if (type == VRegInfo::Type::OBJECT) { return coretypes::TaggedValue::GetObjectTaggedValue(val); } UNREACHABLE(); return val; } template <bool need_pack> interpreter::VRegister CFrame::GetVRegValueSlot(const VRegInfo &vreg) const { interpreter::VRegister res_reg; uint64_t val = GetValueFromSlot(vreg.GetValue()); // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements) if constexpr (!ArchTraits<ARCH>::IS_64_BITS) { if (vreg.Has64BitValue()) { ASSERT(!vreg.IsObject()); val |= static_cast<uint64_t>(GetValueFromSlot(helpers::ToSigned(vreg.GetValue()) - 1)) << BITS_PER_UINT32; } } // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements) if constexpr (need_pack) { val = GetPackValue(vreg.GetType(), val); } res_reg.Set(val); return res_reg; } template <bool need_pack> interpreter::VRegister CFrame::GetVRegValueRegister(const VRegInfo &vreg, SlotType **callee_stack) const { interpreter::VRegister res_reg; bool is_fp = vreg.GetLocation() == VRegInfo::Location::FP_REGISTER; if ((GetCallerRegsMask(ARCH, is_fp) & (1U << vreg.GetValue())).Any()) { CFrameLayout fl(ARCH, 0); RegMask mask(GetCallerRegsMask(RUNTIME_ARCH, is_fp)); auto reg_num = mask.GetDistanceFromTail(vreg.GetValue()); reg_num = fl.GetCallerLastSlot(is_fp) - reg_num; uint64_t val = GetValueFromSlot(reg_num); // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-magic-numbers,readability-braces-around-statements) if constexpr (!ArchTraits<ARCH>::IS_64_BITS) { if (vreg.Has64BitValue()) { ASSERT(!vreg.IsObject()); val |= static_cast<uint64_t>(GetValueFromSlot(static_cast<int>(reg_num) - 1)) << BITS_PER_UINT32; } } // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements) if constexpr (need_pack) { val = GetPackValue(vreg.GetType(), val); } res_reg.Set(val); return res_reg; } uint64_t val = ReadCalleeSavedRegister(vreg.GetValue(), is_fp, callee_stack); if (!ArchTraits<ARCH>::IS_64_BITS && vreg.Has64BitValue()) { val |= static_cast<uint64_t>(ReadCalleeSavedRegister(vreg.GetValue() + 1, is_fp, callee_stack)) << BITS_PER_UINT32; } // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements) if constexpr (need_pack) { val = GetPackValue(vreg.GetType(), val); } if (is_fp) { res_reg.Set(val); if (vreg.Has64BitValue()) { res_reg.Set(bit_cast<double>(val)); return res_reg; } res_reg.Set(bit_cast<float>(static_cast<uint32_t>(val))); return res_reg; } res_reg.Set(val); return res_reg; } template <bool need_pack> interpreter::VRegister CFrame::GetVRegValueConstant(const VRegInfo &vreg, const compiler::CodeInfo &code_info) const { interpreter::VRegister res_reg; auto val = code_info.GetConstant(vreg); // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements) if constexpr (need_pack) { val = GetPackValue(vreg.GetType(), val); } res_reg.Set(val); return res_reg; } template <bool need_pack> void CFrame::SetVRegValue(const VRegInfo &vreg, uint64_t value, SlotType **callee_stack) { auto location_value = static_cast<int>(vreg.GetValue()); // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements) if constexpr (need_pack) { value = GetPackValue(vreg.GetType(), value); } switch (vreg.GetLocation()) { case VRegInfo::Location::SLOT: { SetValueToSlot(location_value, value); if (!ArchTraits<ARCH>::IS_64_BITS && vreg.Has64BitValue()) { SetValueToSlot(location_value - 1, value >> BITS_PER_UINT32); } break; } case VRegInfo::Location::REGISTER: case VRegInfo::Location::FP_REGISTER: { bool is_fp = vreg.GetLocation() == VRegInfo::Location::FP_REGISTER; if ((GetCallerRegsMask(ARCH, is_fp) & (1U << vreg.GetValue())).Any()) { CFrameLayout fl(ARCH, 0); auto reg_num = location_value - GetFirstCallerReg(ARCH, is_fp); reg_num = fl.GetCallerLastSlot(is_fp) - reg_num; SetValueToSlot(reg_num, value); if (!ArchTraits<ARCH>::IS_64_BITS && vreg.Has64BitValue()) { SetValueToSlot(static_cast<int>(reg_num) - 1, value >> BITS_PER_UINT32); } break; } WriteCalleeSavedRegister(location_value, value, is_fp, callee_stack); // NOLINTNEXTLINE(bugprone-suspicious-semicolon,readability-braces-around-statements) if constexpr (!ArchTraits<ARCH>::IS_64_BITS) { if (vreg.Has64BitValue()) { WriteCalleeSavedRegister(location_value + 1, value >> BITS_PER_UINT32, is_fp, callee_stack); } break; } break; } case VRegInfo::Location::CONSTANT: ASSERT(false && "Modifying constants is not permitted"); // NOLINT(misc-static-assert) break; default: UNREACHABLE(); } } void CFrame::Dump(const CodeInfo &code_info, std::ostream &os) { auto max_slot = code_info.GetHeader().GetFrameSize(); Dump(os, max_slot); } void CFrame::Dump(std::ostream &os, uint32_t max_slot) { if (IsNative()) { os << "NATIVE CFRAME: fp=" << fp_ << std::endl; return; } auto spill_start_slot = GetCalleeRegsCount(ARCH, false) + GetCalleeRegsCount(ARCH, true) + GetCallerRegsCount(ARCH, false) + GetCallerRegsCount(ARCH, true); max_slot = (max_slot > spill_start_slot) ? (max_slot - spill_start_slot) : 0; auto print_mem = [](std::ostream &stream, void *addr, std::string_view dscr, uintptr_t value) { constexpr size_t WIDTH = 16; stream << ' ' << addr << ": " << std::setw(WIDTH) << std::setfill(' ') << dscr << " 0x" << std::hex << value << std::dec << std::endl; }; os << "****************************************\n"; os << "* CFRAME: fp=" << fp_ << ", max_spill_slot=" << max_slot << '\n'; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) print_mem(os, fp_ - CFrameLayout::LrSlot::Start(), "lr", GetLr()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) print_mem(os, fp_ - CFrameLayout::PrevFrameSlot::Start(), "prev", reinterpret_cast<uintptr_t>(GetPrevFrame())); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) print_mem(os, fp_ - CFrameLayout::MethodSlot::Start(), "method", reinterpret_cast<uintptr_t>(GetMethod())); PandaString dscr; size_t slot = 0; DumpCalleeRegs(os, print_mem, &dscr, &slot); DumpCalleeFPRegs(os, print_mem, &dscr, &slot); DumpCallerRegs(os, print_mem, &dscr, &slot); DumpCallerFPRegs(os, print_mem, &dscr, &slot); DumpLocals(os, print_mem, &dscr, &slot, max_slot); os << "* CFRAME END\n"; os << "****************************************\n"; } void CFrame::DumpCalleeRegs(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot) { os << " [Callee saved registers]\n"; for (auto i = panda::helpers::ToSigned(GetLastCalleeReg(ARCH, false)); i >= panda::helpers::ToSigned(GetFirstCalleeReg(ARCH, false)); i--, (*slot)++) { *dscr = "x" + ToPandaString(i) + ":" + ToPandaString(*slot); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) print_mem(os, fp_ - CFrameLayout::STACK_START_SLOT - *slot, *dscr, GetValueFromSlot(*slot)); } } void CFrame::DumpCalleeFPRegs(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot) { os << " [Callee saved FP registers]\n"; for (auto i = panda::helpers::ToSigned(GetLastCalleeReg(ARCH, true)); i >= panda::helpers::ToSigned(GetFirstCalleeReg(ARCH, true)); i--, (*slot)++) { *dscr = "d" + ToPandaString(i) + ":" + ToPandaString(*slot); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) print_mem(os, fp_ - CFrameLayout::STACK_START_SLOT - *slot, *dscr, GetValueFromSlot(*slot)); } } void CFrame::DumpCallerRegs(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot) { os << " [Caller saved registers] " << GetLastCallerReg(ARCH, false) << " " << GetFirstCallerReg(ARCH, false) << "\n"; for (auto i = panda::helpers::ToSigned(GetLastCallerReg(ARCH, false)); i >= panda::helpers::ToSigned(GetFirstCallerReg(ARCH, false)); i--, (*slot)++) { *dscr = "x" + ToPandaString(i) + ":" + ToPandaString(*slot); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) print_mem(os, fp_ - CFrameLayout::STACK_START_SLOT - *slot, *dscr, GetValueFromSlot(*slot)); } } void CFrame::DumpCallerFPRegs(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot) { os << " [Caller saved FP registers]\n"; for (auto i = panda::helpers::ToSigned(GetLastCallerReg(ARCH, true)); i >= panda::helpers::ToSigned(GetFirstCallerReg(ARCH, true)); i--, (*slot)++) { *dscr = "d" + ToPandaString(i) + ":" + ToPandaString(*slot); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) print_mem(os, fp_ - CFrameLayout::STACK_START_SLOT - *slot, *dscr, GetValueFromSlot(*slot)); } } void CFrame::DumpLocals(std::ostream &os, MemPrinter print_mem, PandaString *dscr, size_t *slot, int32_t max_slot) { os << " [Locals]\n"; for (auto i = 0; i <= max_slot; i++, (*slot)++) { *dscr = "s" + ToPandaString(i) + ":" + ToPandaString(*slot); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) print_mem(os, fp_ - CFrameLayout::STACK_START_SLOT - *slot, *dscr, GetValueFromSlot(*slot)); } } } // namespace panda