diff options
author | David Srbecky <dsrbecky@google.com> | 2015-04-07 20:29:48 +0100 |
---|---|---|
committer | David Srbecky <dsrbecky@google.com> | 2015-04-08 16:36:27 +0100 |
commit | dd97393aca1a3ff2abec4dc4f78d7724300971bc (patch) | |
tree | eed7360a80b7543ec7962b47feb7df0d1a8d438e /compiler/utils | |
parent | 1109fb3cacc8bb667979780c2b4b12ce5bb64549 (diff) | |
download | art-dd97393aca1a3ff2abec4dc4f78d7724300971bc.zip art-dd97393aca1a3ff2abec4dc4f78d7724300971bc.tar.gz art-dd97393aca1a3ff2abec4dc4f78d7724300971bc.tar.bz2 |
Implement CFI for JNI.
CFI is necessary for stack unwinding in gdb, lldb, and libunwind.
Change-Id: I37eb7973f99a6975034cf0e699e138c3a9aba10f
Diffstat (limited to 'compiler/utils')
-rw-r--r-- | compiler/utils/arm/assembler_arm.cc | 84 | ||||
-rw-r--r-- | compiler/utils/arm/managed_register_arm.h | 1 | ||||
-rw-r--r-- | compiler/utils/arm64/assembler_arm64.cc | 121 | ||||
-rw-r--r-- | compiler/utils/arm64/managed_register_arm64.h | 1 | ||||
-rw-r--r-- | compiler/utils/assembler.cc | 3 | ||||
-rw-r--r-- | compiler/utils/assembler.h | 28 | ||||
-rw-r--r-- | compiler/utils/mips/assembler_mips.cc | 15 | ||||
-rw-r--r-- | compiler/utils/mips/managed_register_mips.h | 1 | ||||
-rw-r--r-- | compiler/utils/mips64/assembler_mips64.cc | 15 | ||||
-rw-r--r-- | compiler/utils/mips64/managed_register_mips64.h | 1 | ||||
-rw-r--r-- | compiler/utils/x86/assembler_x86.cc | 24 | ||||
-rw-r--r-- | compiler/utils/x86/managed_register_x86.h | 1 | ||||
-rw-r--r-- | compiler/utils/x86_64/assembler_x86_64.cc | 25 | ||||
-rw-r--r-- | compiler/utils/x86_64/managed_register_x86_64.h | 1 |
14 files changed, 199 insertions, 122 deletions
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc index 8059289..c410660 100644 --- a/compiler/utils/arm/assembler_arm.cc +++ b/compiler/utils/arm/assembler_arm.cc @@ -370,40 +370,46 @@ void ArmAssembler::Pad(uint32_t bytes) { } } +static dwarf::Reg DWARFReg(Register reg) { + return dwarf::Reg::ArmCore(static_cast<int>(reg)); +} + +static dwarf::Reg DWARFReg(SRegister reg) { + return dwarf::Reg::ArmFp(static_cast<int>(reg)); +} + constexpr size_t kFramePointerSize = 4; void ArmAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, const std::vector<ManagedRegister>& callee_save_regs, const ManagedRegisterEntrySpills& entry_spills) { + CHECK_EQ(buffer_.Size(), 0U); // Nothing emitted yet CHECK_ALIGNED(frame_size, kStackAlignment); CHECK_EQ(R0, method_reg.AsArm().AsCoreRegister()); // Push callee saves and link register. - RegList push_list = 1 << LR; - size_t pushed_values = 1; - int32_t min_s = kNumberOfSRegisters; - int32_t max_s = -1; - for (size_t i = 0; i < callee_save_regs.size(); i++) { - if (callee_save_regs.at(i).AsArm().IsCoreRegister()) { - Register reg = callee_save_regs.at(i).AsArm().AsCoreRegister(); - push_list |= 1 << reg; - pushed_values++; + RegList core_spill_mask = 1 << LR; + uint32_t fp_spill_mask = 0; + for (const ManagedRegister& reg : callee_save_regs) { + if (reg.AsArm().IsCoreRegister()) { + core_spill_mask |= 1 << reg.AsArm().AsCoreRegister(); } else { - CHECK(callee_save_regs.at(i).AsArm().IsSRegister()); - min_s = std::min(static_cast<int>(callee_save_regs.at(i).AsArm().AsSRegister()), min_s); - max_s = std::max(static_cast<int>(callee_save_regs.at(i).AsArm().AsSRegister()), max_s); + fp_spill_mask |= 1 << reg.AsArm().AsSRegister(); } } - PushList(push_list); - if (max_s != -1) { - pushed_values += 1 + max_s - min_s; - vpushs(static_cast<SRegister>(min_s), 1 + max_s - min_s); + PushList(core_spill_mask); + cfi_.AdjustCFAOffset(POPCOUNT(core_spill_mask) * kFramePointerSize); + cfi_.RelOffsetForMany(DWARFReg(Register(0)), 0, core_spill_mask, kFramePointerSize); + if (fp_spill_mask != 0) { + vpushs(SRegister(CTZ(fp_spill_mask)), POPCOUNT(fp_spill_mask)); + cfi_.AdjustCFAOffset(POPCOUNT(fp_spill_mask) * kFramePointerSize); + cfi_.RelOffsetForMany(DWARFReg(SRegister(0)), 0, fp_spill_mask, kFramePointerSize); } // Increase frame to required size. + int pushed_values = POPCOUNT(core_spill_mask) + POPCOUNT(fp_spill_mask); CHECK_GT(frame_size, pushed_values * kFramePointerSize); // Must at least have space for Method*. - size_t adjust = frame_size - (pushed_values * kFramePointerSize); - IncreaseFrameSize(adjust); + IncreaseFrameSize(frame_size - pushed_values * kFramePointerSize); // handles CFI as well. // Write out Method*. StoreToOffset(kStoreWord, R0, SP, 0); @@ -432,46 +438,46 @@ void ArmAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, void ArmAssembler::RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs) { CHECK_ALIGNED(frame_size, kStackAlignment); + cfi_.RememberState(); + // Compute callee saves to pop and PC. - RegList pop_list = 1 << PC; - size_t pop_values = 1; - int32_t min_s = kNumberOfSRegisters; - int32_t max_s = -1; - for (size_t i = 0; i < callee_save_regs.size(); i++) { - if (callee_save_regs.at(i).AsArm().IsCoreRegister()) { - Register reg = callee_save_regs.at(i).AsArm().AsCoreRegister(); - pop_list |= 1 << reg; - pop_values++; + RegList core_spill_mask = 1 << PC; + uint32_t fp_spill_mask = 0; + for (const ManagedRegister& reg : callee_save_regs) { + if (reg.AsArm().IsCoreRegister()) { + core_spill_mask |= 1 << reg.AsArm().AsCoreRegister(); } else { - CHECK(callee_save_regs.at(i).AsArm().IsSRegister()); - min_s = std::min(static_cast<int>(callee_save_regs.at(i).AsArm().AsSRegister()), min_s); - max_s = std::max(static_cast<int>(callee_save_regs.at(i).AsArm().AsSRegister()), max_s); + fp_spill_mask |= 1 << reg.AsArm().AsSRegister(); } } - if (max_s != -1) { - pop_values += 1 + max_s - min_s; - } - // Decrease frame to start of callee saves. + int pop_values = POPCOUNT(core_spill_mask) + POPCOUNT(fp_spill_mask); CHECK_GT(frame_size, pop_values * kFramePointerSize); - size_t adjust = frame_size - (pop_values * kFramePointerSize); - DecreaseFrameSize(adjust); + DecreaseFrameSize(frame_size - (pop_values * kFramePointerSize)); // handles CFI as well. - if (max_s != -1) { - vpops(static_cast<SRegister>(min_s), 1 + max_s - min_s); + if (fp_spill_mask != 0) { + vpops(SRegister(CTZ(fp_spill_mask)), POPCOUNT(fp_spill_mask)); + cfi_.AdjustCFAOffset(-kFramePointerSize * POPCOUNT(fp_spill_mask)); + cfi_.RestoreMany(DWARFReg(SRegister(0)), fp_spill_mask); } // Pop callee saves and PC. - PopList(pop_list); + PopList(core_spill_mask); + + // The CFI should be restored for any code that follows the exit block. + cfi_.RestoreState(); + cfi_.DefCFAOffset(frame_size); } void ArmAssembler::IncreaseFrameSize(size_t adjust) { AddConstant(SP, -adjust); + cfi_.AdjustCFAOffset(adjust); } void ArmAssembler::DecreaseFrameSize(size_t adjust) { AddConstant(SP, adjust); + cfi_.AdjustCFAOffset(-adjust); } void ArmAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { diff --git a/compiler/utils/arm/managed_register_arm.h b/compiler/utils/arm/managed_register_arm.h index a496c87..5fde9e8 100644 --- a/compiler/utils/arm/managed_register_arm.h +++ b/compiler/utils/arm/managed_register_arm.h @@ -19,6 +19,7 @@ #include "base/logging.h" #include "constants_arm.h" +#include "dwarf/register.h" #include "utils/managed_register.h" namespace art { diff --git a/compiler/utils/arm64/assembler_arm64.cc b/compiler/utils/arm64/assembler_arm64.cc index 58c7367..fbd0411 100644 --- a/compiler/utils/arm64/assembler_arm64.cc +++ b/compiler/utils/arm64/assembler_arm64.cc @@ -63,12 +63,14 @@ void Arm64Assembler::GetCurrentThread(FrameOffset offset, ManagedRegister /* scr void Arm64Assembler::IncreaseFrameSize(size_t adjust) { CHECK_ALIGNED(adjust, kStackAlignment); AddConstant(SP, -adjust); + cfi().AdjustCFAOffset(adjust); } // See Arm64 PCS Section 5.2.2.1. void Arm64Assembler::DecreaseFrameSize(size_t adjust) { CHECK_ALIGNED(adjust, kStackAlignment); AddConstant(SP, adjust); + cfi().AdjustCFAOffset(-adjust); } void Arm64Assembler::AddConstant(XRegister rd, int32_t value, Condition cond) { @@ -638,6 +640,14 @@ void Arm64Assembler::EmitExceptionPoll(Arm64Exception *exception) { ___ Brk(); } +static dwarf::Reg DWARFReg(XRegister reg) { + return dwarf::Reg::Arm64Core(static_cast<int>(reg)); +} + +static dwarf::Reg DWARFReg(DRegister reg) { + return dwarf::Reg::Arm64Fp(static_cast<int>(reg)); +} + constexpr size_t kFramePointerSize = 8; constexpr unsigned int kJniRefSpillRegsSize = 11 + 8; @@ -660,45 +670,20 @@ void Arm64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, // TUNING: Use stp. // Note: Must match Arm64JniCallingConvention::CoreSpillMask(). size_t reg_offset = frame_size; - reg_offset -= 8; - StoreToOffset(LR, SP, reg_offset); - reg_offset -= 8; - StoreToOffset(X29, SP, reg_offset); - reg_offset -= 8; - StoreToOffset(X28, SP, reg_offset); - reg_offset -= 8; - StoreToOffset(X27, SP, reg_offset); - reg_offset -= 8; - StoreToOffset(X26, SP, reg_offset); - reg_offset -= 8; - StoreToOffset(X25, SP, reg_offset); - reg_offset -= 8; - StoreToOffset(X24, SP, reg_offset); - reg_offset -= 8; - StoreToOffset(X23, SP, reg_offset); - reg_offset -= 8; - StoreToOffset(X22, SP, reg_offset); - reg_offset -= 8; - StoreToOffset(X21, SP, reg_offset); - reg_offset -= 8; - StoreToOffset(X20, SP, reg_offset); - - reg_offset -= 8; - StoreDToOffset(D15, SP, reg_offset); - reg_offset -= 8; - StoreDToOffset(D14, SP, reg_offset); - reg_offset -= 8; - StoreDToOffset(D13, SP, reg_offset); - reg_offset -= 8; - StoreDToOffset(D12, SP, reg_offset); - reg_offset -= 8; - StoreDToOffset(D11, SP, reg_offset); - reg_offset -= 8; - StoreDToOffset(D10, SP, reg_offset); - reg_offset -= 8; - StoreDToOffset(D9, SP, reg_offset); - reg_offset -= 8; - StoreDToOffset(D8, SP, reg_offset); + static constexpr XRegister x_spills[] = { + LR, X29, X28, X27, X26, X25, X24, X23, X22, X21, X20 }; + for (size_t i = 0; i < arraysize(x_spills); i++) { + XRegister reg = x_spills[i]; + reg_offset -= 8; + StoreToOffset(reg, SP, reg_offset); + cfi_.RelOffset(DWARFReg(reg), reg_offset); + } + for (int d = 15; d >= 8; d--) { + DRegister reg = static_cast<DRegister>(d); + reg_offset -= 8; + StoreDToOffset(reg, SP, reg_offset); + cfi_.RelOffset(DWARFReg(reg), reg_offset); + } // Move TR(Caller saved) to ETR(Callee saved). The original (ETR)X21 has been saved on stack. // This way we make sure that TR is not trashed by native code. @@ -734,6 +719,7 @@ void Arm64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, void Arm64Assembler::RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs) { CHECK_ALIGNED(frame_size, kStackAlignment); + cfi_.RememberState(); // For now we only check that the size of the frame is greater than the spill size. CHECK_EQ(callee_save_regs.size(), kJniRefSpillRegsSize); @@ -748,51 +734,30 @@ void Arm64Assembler::RemoveFrame(size_t frame_size, const std::vector<ManagedReg // TUNING: Use ldp. // Note: Must match Arm64JniCallingConvention::CoreSpillMask(). size_t reg_offset = frame_size; - reg_offset -= 8; - LoadFromOffset(LR, SP, reg_offset); - reg_offset -= 8; - LoadFromOffset(X29, SP, reg_offset); - reg_offset -= 8; - LoadFromOffset(X28, SP, reg_offset); - reg_offset -= 8; - LoadFromOffset(X27, SP, reg_offset); - reg_offset -= 8; - LoadFromOffset(X26, SP, reg_offset); - reg_offset -= 8; - LoadFromOffset(X25, SP, reg_offset); - reg_offset -= 8; - LoadFromOffset(X24, SP, reg_offset); - reg_offset -= 8; - LoadFromOffset(X23, SP, reg_offset); - reg_offset -= 8; - LoadFromOffset(X22, SP, reg_offset); - reg_offset -= 8; - LoadFromOffset(X21, SP, reg_offset); - reg_offset -= 8; - LoadFromOffset(X20, SP, reg_offset); - - reg_offset -= 8; - LoadDFromOffset(D15, SP, reg_offset); - reg_offset -= 8; - LoadDFromOffset(D14, SP, reg_offset); - reg_offset -= 8; - LoadDFromOffset(D13, SP, reg_offset); - reg_offset -= 8; - LoadDFromOffset(D12, SP, reg_offset); - reg_offset -= 8; - LoadDFromOffset(D11, SP, reg_offset); - reg_offset -= 8; - LoadDFromOffset(D10, SP, reg_offset); - reg_offset -= 8; - LoadDFromOffset(D9, SP, reg_offset); - reg_offset -= 8; - LoadDFromOffset(D8, SP, reg_offset); + static constexpr XRegister x_spills[] = { + LR, X29, X28, X27, X26, X25, X24, X23, X22, X21, X20 }; + for (size_t i = 0; i < arraysize(x_spills); i++) { + XRegister reg = x_spills[i]; + reg_offset -= 8; + LoadFromOffset(reg, SP, reg_offset); + cfi_.Restore(DWARFReg(reg)); + } + for (int d = 15; d >= 8; d--) { + DRegister reg = static_cast<DRegister>(d); + reg_offset -= 8; + LoadDFromOffset(reg, SP, reg_offset); + cfi_.Restore(DWARFReg(reg)); + } // Decrease frame size to start of callee saved regs. DecreaseFrameSize(frame_size); // Pop callee saved and return to LR. ___ Ret(); + + // The CFI should be restored for any code that follows the exit block. + cfi_.RestoreState(); + cfi_.DefCFAOffset(frame_size); } } // namespace arm64 diff --git a/compiler/utils/arm64/managed_register_arm64.h b/compiler/utils/arm64/managed_register_arm64.h index e1d6f31..62c1d4d 100644 --- a/compiler/utils/arm64/managed_register_arm64.h +++ b/compiler/utils/arm64/managed_register_arm64.h @@ -19,6 +19,7 @@ #include "base/logging.h" #include "constants_arm64.h" +#include "dwarf/register.h" #include "utils/managed_register.h" namespace art { diff --git a/compiler/utils/assembler.cc b/compiler/utils/assembler.cc index 5340dd3..36342c6 100644 --- a/compiler/utils/assembler.cc +++ b/compiler/utils/assembler.cc @@ -105,6 +105,9 @@ void AssemblerBuffer::ExtendCapacity() { CHECK_EQ(Size(), old_size); } +void DebugFrameOpCodeWriterForAssembler::ImplicitlyAdvancePC() { + this->AdvancePC(assembler_->CodeSize()); +} Assembler* Assembler::Create(InstructionSet instruction_set) { switch (instruction_set) { diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h index 323f93c..ebafd3d 100644 --- a/compiler/utils/assembler.h +++ b/compiler/utils/assembler.h @@ -29,6 +29,7 @@ #include "offsets.h" #include "x86/constants_x86.h" #include "x86_64/constants_x86_64.h" +#include "dwarf/debug_frame_opcode_writer.h" namespace art { @@ -354,6 +355,23 @@ class AssemblerBuffer { friend class AssemblerFixup; }; +// The purpose of this class is to ensure that we do not have to explicitly +// call the AdvancePC method (which is good for convenience and correctness). +class DebugFrameOpCodeWriterForAssembler FINAL + : public dwarf::DebugFrameOpCodeWriter<> { + public: + // This method is called the by the opcode writers. + virtual void ImplicitlyAdvancePC() FINAL; + + explicit DebugFrameOpCodeWriterForAssembler(Assembler* buffer) + : dwarf::DebugFrameOpCodeWriter<>(), + assembler_(buffer) { + } + + private: + Assembler* assembler_; +}; + class Assembler { public: static Assembler* Create(InstructionSet instruction_set); @@ -506,10 +524,18 @@ class Assembler { virtual ~Assembler() {} + /** + * @brief Buffer of DWARF's Call Frame Information opcodes. + * @details It is used by debuggers and other tools to unwind the call stack. + */ + DebugFrameOpCodeWriterForAssembler& cfi() { return cfi_; } + protected: - Assembler() : buffer_() {} + Assembler() : buffer_(), cfi_(this) {} AssemblerBuffer buffer_; + + DebugFrameOpCodeWriterForAssembler cfi_; }; } // namespace art diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc index b5437b0..709a911 100644 --- a/compiler/utils/mips/assembler_mips.cc +++ b/compiler/utils/mips/assembler_mips.cc @@ -536,6 +536,10 @@ void MipsAssembler::StoreDToOffset(DRegister reg, Register base, int32_t offset) Sdc1(reg, base, offset); } +static dwarf::Reg DWARFReg(Register reg) { + return dwarf::Reg::MipsCore(static_cast<int>(reg)); +} + constexpr size_t kFramePointerSize = 4; void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, @@ -549,10 +553,12 @@ void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, // Push callee saves and return address int stack_offset = frame_size - kFramePointerSize; StoreToOffset(kStoreWord, RA, SP, stack_offset); + cfi_.RelOffset(DWARFReg(RA), stack_offset); for (int i = callee_save_regs.size() - 1; i >= 0; --i) { stack_offset -= kFramePointerSize; Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister(); StoreToOffset(kStoreWord, reg, SP, stack_offset); + cfi_.RelOffset(DWARFReg(reg), stack_offset); } // Write out Method*. @@ -568,31 +574,40 @@ void MipsAssembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, void MipsAssembler::RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs) { CHECK_ALIGNED(frame_size, kStackAlignment); + cfi_.RememberState(); // Pop callee saves and return address int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize; for (size_t i = 0; i < callee_save_regs.size(); ++i) { Register reg = callee_save_regs.at(i).AsMips().AsCoreRegister(); LoadFromOffset(kLoadWord, reg, SP, stack_offset); + cfi_.Restore(DWARFReg(reg)); stack_offset += kFramePointerSize; } LoadFromOffset(kLoadWord, RA, SP, stack_offset); + cfi_.Restore(DWARFReg(RA)); // Decrease frame to required size. DecreaseFrameSize(frame_size); // Then jump to the return address. Jr(RA); + + // The CFI should be restored for any code that follows the exit block. + cfi_.RestoreState(); + cfi_.DefCFAOffset(frame_size); } void MipsAssembler::IncreaseFrameSize(size_t adjust) { CHECK_ALIGNED(adjust, kStackAlignment); AddConstant(SP, SP, -adjust); + cfi_.AdjustCFAOffset(adjust); } void MipsAssembler::DecreaseFrameSize(size_t adjust) { CHECK_ALIGNED(adjust, kStackAlignment); AddConstant(SP, SP, adjust); + cfi_.AdjustCFAOffset(-adjust); } void MipsAssembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { diff --git a/compiler/utils/mips/managed_register_mips.h b/compiler/utils/mips/managed_register_mips.h index dd55cc4..40d39e3 100644 --- a/compiler/utils/mips/managed_register_mips.h +++ b/compiler/utils/mips/managed_register_mips.h @@ -18,6 +18,7 @@ #define ART_COMPILER_UTILS_MIPS_MANAGED_REGISTER_MIPS_H_ #include "constants_mips.h" +#include "dwarf/register.h" #include "utils/managed_register.h" namespace art { diff --git a/compiler/utils/mips64/assembler_mips64.cc b/compiler/utils/mips64/assembler_mips64.cc index 388d274..282ab96 100644 --- a/compiler/utils/mips64/assembler_mips64.cc +++ b/compiler/utils/mips64/assembler_mips64.cc @@ -568,6 +568,10 @@ void Mips64Assembler::StoreFpuToOffset(StoreOperandType type, FpuRegister reg, G } } +static dwarf::Reg DWARFReg(GpuRegister reg) { + return dwarf::Reg::Mips64Core(static_cast<int>(reg)); +} + constexpr size_t kFramePointerSize = 8; void Mips64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, @@ -581,10 +585,12 @@ void Mips64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, // Push callee saves and return address int stack_offset = frame_size - kFramePointerSize; StoreToOffset(kStoreDoubleword, RA, SP, stack_offset); + cfi_.RelOffset(DWARFReg(RA), stack_offset); for (int i = callee_save_regs.size() - 1; i >= 0; --i) { stack_offset -= kFramePointerSize; GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister(); StoreToOffset(kStoreDoubleword, reg, SP, stack_offset); + cfi_.RelOffset(DWARFReg(reg), stack_offset); } // Write out Method*. @@ -612,31 +618,40 @@ void Mips64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, void Mips64Assembler::RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& callee_save_regs) { CHECK_ALIGNED(frame_size, kStackAlignment); + cfi_.RememberState(); // Pop callee saves and return address int stack_offset = frame_size - (callee_save_regs.size() * kFramePointerSize) - kFramePointerSize; for (size_t i = 0; i < callee_save_regs.size(); ++i) { GpuRegister reg = callee_save_regs.at(i).AsMips64().AsGpuRegister(); LoadFromOffset(kLoadDoubleword, reg, SP, stack_offset); + cfi_.Restore(DWARFReg(reg)); stack_offset += kFramePointerSize; } LoadFromOffset(kLoadDoubleword, RA, SP, stack_offset); + cfi_.Restore(DWARFReg(RA)); // Decrease frame to required size. DecreaseFrameSize(frame_size); // Then jump to the return address. Jr(RA); + + // The CFI should be restored for any code that follows the exit block. + cfi_.RestoreState(); + cfi_.DefCFAOffset(frame_size); } void Mips64Assembler::IncreaseFrameSize(size_t adjust) { CHECK_ALIGNED(adjust, kStackAlignment); AddConstant64(SP, SP, -adjust); + cfi_.AdjustCFAOffset(adjust); } void Mips64Assembler::DecreaseFrameSize(size_t adjust) { CHECK_ALIGNED(adjust, kStackAlignment); AddConstant64(SP, SP, adjust); + cfi_.AdjustCFAOffset(-adjust); } void Mips64Assembler::Store(FrameOffset dest, ManagedRegister msrc, size_t size) { diff --git a/compiler/utils/mips64/managed_register_mips64.h b/compiler/utils/mips64/managed_register_mips64.h index 924a928..4c4705b 100644 --- a/compiler/utils/mips64/managed_register_mips64.h +++ b/compiler/utils/mips64/managed_register_mips64.h @@ -18,6 +18,7 @@ #define ART_COMPILER_UTILS_MIPS64_MANAGED_REGISTER_MIPS64_H_ #include "constants_mips64.h" +#include "dwarf/register.h" #include "utils/managed_register.h" namespace art { diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc index 4b71412..8ce9375 100644 --- a/compiler/utils/x86/assembler_x86.cc +++ b/compiler/utils/x86/assembler_x86.cc @@ -1630,18 +1630,25 @@ void X86Assembler::EmitGenericShift(int reg_or_opcode, EmitOperand(reg_or_opcode, Operand(operand)); } +static dwarf::Reg DWARFReg(Register reg) { + return dwarf::Reg::X86Core(static_cast<int>(reg)); +} + constexpr size_t kFramePointerSize = 4; void X86Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, const std::vector<ManagedRegister>& spill_regs, const ManagedRegisterEntrySpills& entry_spills) { DCHECK_EQ(buffer_.Size(), 0U); // Nothing emitted yet. + cfi_.SetCurrentCFAOffset(4); // Return address on stack. CHECK_ALIGNED(frame_size, kStackAlignment); int gpr_count = 0; for (int i = spill_regs.size() - 1; i >= 0; --i) { Register spill = spill_regs.at(i).AsX86().AsCpuRegister(); pushl(spill); gpr_count++; + cfi_.AdjustCFAOffset(kFramePointerSize); + cfi_.RelOffset(DWARFReg(spill), 0); } // return address then method on stack. @@ -1649,7 +1656,10 @@ void X86Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, sizeof(StackReference<mirror::ArtMethod>) /*method*/ - kFramePointerSize /*return address*/; addl(ESP, Immediate(-adjust)); + cfi_.AdjustCFAOffset(adjust); pushl(method_reg.AsX86().AsCpuRegister()); + cfi_.AdjustCFAOffset(kFramePointerSize); + DCHECK_EQ(static_cast<size_t>(cfi_.GetCurrentCFAOffset()), frame_size); for (size_t i = 0; i < entry_spills.size(); ++i) { ManagedRegisterSpill spill = entry_spills.at(i); @@ -1671,25 +1681,33 @@ void X86Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, void X86Assembler::RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& spill_regs) { CHECK_ALIGNED(frame_size, kStackAlignment); + cfi_.RememberState(); int adjust = frame_size - (spill_regs.size() * kFramePointerSize) - sizeof(StackReference<mirror::ArtMethod>); addl(ESP, Immediate(adjust)); + cfi_.AdjustCFAOffset(-adjust); for (size_t i = 0; i < spill_regs.size(); ++i) { - x86::X86ManagedRegister spill = spill_regs.at(i).AsX86(); - DCHECK(spill.IsCpuRegister()); - popl(spill.AsCpuRegister()); + Register spill = spill_regs.at(i).AsX86().AsCpuRegister(); + popl(spill); + cfi_.AdjustCFAOffset(-static_cast<int>(kFramePointerSize)); + cfi_.Restore(DWARFReg(spill)); } ret(); + // The CFI should be restored for any code that follows the exit block. + cfi_.RestoreState(); + cfi_.DefCFAOffset(frame_size); } void X86Assembler::IncreaseFrameSize(size_t adjust) { CHECK_ALIGNED(adjust, kStackAlignment); addl(ESP, Immediate(-adjust)); + cfi_.AdjustCFAOffset(adjust); } void X86Assembler::DecreaseFrameSize(size_t adjust) { CHECK_ALIGNED(adjust, kStackAlignment); addl(ESP, Immediate(adjust)); + cfi_.AdjustCFAOffset(-adjust); } void X86Assembler::Store(FrameOffset offs, ManagedRegister msrc, size_t size) { diff --git a/compiler/utils/x86/managed_register_x86.h b/compiler/utils/x86/managed_register_x86.h index 09d2b49..4e8c41e 100644 --- a/compiler/utils/x86/managed_register_x86.h +++ b/compiler/utils/x86/managed_register_x86.h @@ -18,6 +18,7 @@ #define ART_COMPILER_UTILS_X86_MANAGED_REGISTER_X86_H_ #include "constants_x86.h" +#include "dwarf/register.h" #include "utils/managed_register.h" namespace art { diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc index 25d24fb..780c1b4 100644 --- a/compiler/utils/x86_64/assembler_x86_64.cc +++ b/compiler/utils/x86_64/assembler_x86_64.cc @@ -2167,12 +2167,20 @@ void X86_64Assembler::EmitOptionalByteRegNormalizingRex32(CpuRegister dst, const } } +static dwarf::Reg DWARFReg(Register reg) { + return dwarf::Reg::X86_64Core(static_cast<int>(reg)); +} +static dwarf::Reg DWARFReg(FloatRegister reg) { + return dwarf::Reg::X86_64Fp(static_cast<int>(reg)); +} + constexpr size_t kFramePointerSize = 8; void X86_64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, const std::vector<ManagedRegister>& spill_regs, const ManagedRegisterEntrySpills& entry_spills) { DCHECK_EQ(buffer_.Size(), 0U); // Nothing emitted yet. + cfi_.SetCurrentCFAOffset(8); // Return address on stack. CHECK_ALIGNED(frame_size, kStackAlignment); int gpr_count = 0; for (int i = spill_regs.size() - 1; i >= 0; --i) { @@ -2180,6 +2188,8 @@ void X86_64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, if (spill.IsCpuRegister()) { pushq(spill.AsCpuRegister()); gpr_count++; + cfi_.AdjustCFAOffset(kFramePointerSize); + cfi_.RelOffset(DWARFReg(spill.AsCpuRegister().AsRegister()), 0); } } // return address then method on stack. @@ -2187,6 +2197,7 @@ void X86_64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, - (gpr_count * kFramePointerSize) - kFramePointerSize /*return address*/; subq(CpuRegister(RSP), Immediate(rest_of_frame)); + cfi_.AdjustCFAOffset(rest_of_frame); // spill xmms int64_t offset = rest_of_frame; @@ -2195,6 +2206,7 @@ void X86_64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, if (spill.IsXmmRegister()) { offset -= sizeof(double); movsd(Address(CpuRegister(RSP), offset), spill.AsXmmRegister()); + cfi_.RelOffset(DWARFReg(spill.AsXmmRegister().AsFloatRegister()), offset); } } @@ -2226,6 +2238,7 @@ void X86_64Assembler::BuildFrame(size_t frame_size, ManagedRegister method_reg, void X86_64Assembler::RemoveFrame(size_t frame_size, const std::vector<ManagedRegister>& spill_regs) { CHECK_ALIGNED(frame_size, kStackAlignment); + cfi_.RememberState(); int gpr_count = 0; // unspill xmms int64_t offset = static_cast<int64_t>(frame_size) - (spill_regs.size() * kFramePointerSize) - 2 * kFramePointerSize; @@ -2234,28 +2247,38 @@ void X86_64Assembler::RemoveFrame(size_t frame_size, if (spill.IsXmmRegister()) { offset += sizeof(double); movsd(spill.AsXmmRegister(), Address(CpuRegister(RSP), offset)); + cfi_.Restore(DWARFReg(spill.AsXmmRegister().AsFloatRegister())); } else { gpr_count++; } } - addq(CpuRegister(RSP), Immediate(static_cast<int64_t>(frame_size) - (gpr_count * kFramePointerSize) - kFramePointerSize)); + int adjust = static_cast<int>(frame_size) - (gpr_count * kFramePointerSize) - kFramePointerSize; + addq(CpuRegister(RSP), Immediate(adjust)); + cfi_.AdjustCFAOffset(-adjust); for (size_t i = 0; i < spill_regs.size(); ++i) { x86_64::X86_64ManagedRegister spill = spill_regs.at(i).AsX86_64(); if (spill.IsCpuRegister()) { popq(spill.AsCpuRegister()); + cfi_.AdjustCFAOffset(-static_cast<int>(kFramePointerSize)); + cfi_.Restore(DWARFReg(spill.AsCpuRegister().AsRegister())); } } ret(); + // The CFI should be restored for any code that follows the exit block. + cfi_.RestoreState(); + cfi_.DefCFAOffset(frame_size); } void X86_64Assembler::IncreaseFrameSize(size_t adjust) { CHECK_ALIGNED(adjust, kStackAlignment); addq(CpuRegister(RSP), Immediate(-static_cast<int64_t>(adjust))); + cfi_.AdjustCFAOffset(adjust); } void X86_64Assembler::DecreaseFrameSize(size_t adjust) { CHECK_ALIGNED(adjust, kStackAlignment); addq(CpuRegister(RSP), Immediate(adjust)); + cfi_.AdjustCFAOffset(-adjust); } void X86_64Assembler::Store(FrameOffset offs, ManagedRegister msrc, size_t size) { diff --git a/compiler/utils/x86_64/managed_register_x86_64.h b/compiler/utils/x86_64/managed_register_x86_64.h index 822659f..47bbb44 100644 --- a/compiler/utils/x86_64/managed_register_x86_64.h +++ b/compiler/utils/x86_64/managed_register_x86_64.h @@ -18,6 +18,7 @@ #define ART_COMPILER_UTILS_X86_64_MANAGED_REGISTER_X86_64_H_ #include "constants_x86_64.h" +#include "dwarf/register.h" #include "utils/managed_register.h" namespace art { |