Implement CFI for Quick.
CFI is necessary for stack unwinding in gdb, lldb, and libunwind.
Change-Id: Ic3b84c9dc91c4bae80e27cda02190f3274e95ae8
diff --git a/compiler/dex/quick/lazy_debug_frame_opcode_writer.h b/compiler/dex/quick/lazy_debug_frame_opcode_writer.h
new file mode 100644
index 0000000..d71a87d
--- /dev/null
+++ b/compiler/dex/quick/lazy_debug_frame_opcode_writer.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * 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 ART_COMPILER_DEX_QUICK_LAZY_DEBUG_FRAME_OPCODE_WRITER_H_
+#define ART_COMPILER_DEX_QUICK_LAZY_DEBUG_FRAME_OPCODE_WRITER_H_
+
+#include "base/arena_allocator.h"
+#include "base/arena_containers.h"
+#include "dwarf/debug_frame_opcode_writer.h"
+
+namespace art {
+struct LIR;
+namespace dwarf {
+
+// When we are generating the CFI code, we do not know the instuction offsets,
+// this class stores the LIR references and patches the instruction stream later.
+class LazyDebugFrameOpCodeWriter FINAL
+ : private DebugFrameOpCodeWriter<ArenaAllocatorAdapter<uint8_t>> {
+ typedef DebugFrameOpCodeWriter<ArenaAllocatorAdapter<uint8_t>> Base;
+ public:
+ // This method is implicitely called the by opcode writers.
+ virtual void ImplicitlyAdvancePC() OVERRIDE {
+ DCHECK_EQ(patched_, false);
+ DCHECK_EQ(this->current_pc_, 0);
+ advances_.push_back({this->data()->size(), *last_lir_insn_});
+ }
+
+ // The register was unspilled.
+ void Restore(Reg reg) {
+ if (enable_writes_) {
+ Base::Restore(reg);
+ }
+ }
+
+ // Custom alias - unspill many registers based on bitmask.
+ void RestoreMany(Reg reg_base, uint32_t reg_mask) {
+ if (enable_writes_) {
+ Base::RestoreMany(reg_base, reg_mask);
+ }
+ }
+
+ // Remember the state of register spills.
+ void RememberState() {
+ if (enable_writes_) {
+ Base::RememberState();
+ }
+ }
+
+ // Restore the state of register spills.
+ void RestoreState() {
+ if (enable_writes_) {
+ Base::RestoreState();
+ }
+ }
+
+ // Set the frame pointer (CFA) to (stack_pointer + offset).
+ void DefCFAOffset(int offset) {
+ if (enable_writes_) {
+ Base::DefCFAOffset(offset);
+ }
+ this->current_cfa_offset_ = offset;
+ }
+
+ // The stack size was increased by given delta.
+ void AdjustCFAOffset(int delta) {
+ DefCFAOffset(this->current_cfa_offset_ + delta);
+ }
+
+ // The register was spilled to (stack_pointer + offset).
+ void RelOffset(Reg reg, int offset) {
+ if (enable_writes_) {
+ Base::RelOffset(reg, offset);
+ }
+ }
+
+ // Custom alias - spill many registers based on bitmask.
+ void RelOffsetForMany(Reg reg_base, int offset, uint32_t reg_mask, int reg_size) {
+ if (enable_writes_) {
+ Base::RelOffsetForMany(reg_base, offset, reg_mask, reg_size);
+ }
+ }
+
+ using Base::GetCurrentCFAOffset;
+ using Base::SetCurrentCFAOffset;
+ using Base::GetCurrentPC;
+
+ const ArenaVector<uint8_t>* Patch(size_t code_size);
+
+ explicit LazyDebugFrameOpCodeWriter(LIR** last_lir_insn, bool enable_writes,
+ ArenaAllocator* allocator)
+ : Base(allocator->Adapter()),
+ last_lir_insn_(last_lir_insn),
+ enable_writes_(enable_writes),
+ advances_(allocator->Adapter()),
+ patched_(false) {
+ }
+
+ private:
+ typedef struct {
+ size_t pos;
+ LIR* last_lir_insn;
+ } Advance;
+
+ LIR** last_lir_insn_;
+ bool enable_writes_;
+ ArenaVector<Advance> advances_;
+ bool patched_;
+
+ DISALLOW_COPY_AND_ASSIGN(LazyDebugFrameOpCodeWriter);
+};
+
+} // namespace dwarf
+} // namespace art
+
+#endif // ART_COMPILER_DEX_QUICK_LAZY_DEBUG_FRAME_OPCODE_WRITER_H_