summaryrefslogtreecommitdiffstats
path: root/compiler/dex/quick/x86/target_x86.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/dex/quick/x86/target_x86.cc')
-rw-r--r--compiler/dex/quick/x86/target_x86.cc165
1 files changed, 164 insertions, 1 deletions
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index eea7191..7bb866d 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -539,7 +539,8 @@ X86Mir2Lir::X86Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator*
: Mir2Lir(cu, mir_graph, arena),
method_address_insns_(arena, 100, kGrowableArrayMisc),
class_type_address_insns_(arena, 100, kGrowableArrayMisc),
- call_method_insns_(arena, 100, kGrowableArrayMisc) {
+ call_method_insns_(arena, 100, kGrowableArrayMisc),
+ stack_decrement_(nullptr), stack_increment_(nullptr) {
store_method_addr_used_ = false;
for (int i = 0; i < kX86Last; i++) {
if (X86Mir2Lir::EncodingMap[i].opcode != i) {
@@ -1118,4 +1119,166 @@ bool X86Mir2Lir::GenInlinedIndexOf(CallInfo* info, bool zero_based) {
return true;
}
+/*
+ * @brief Enter a 32 bit quantity into the FDE buffer
+ * @param buf FDE buffer.
+ * @param data Data value.
+ */
+static void PushWord(std::vector<uint8_t>&buf, int data) {
+ buf.push_back(data & 0xff);
+ buf.push_back((data >> 8) & 0xff);
+ buf.push_back((data >> 16) & 0xff);
+ buf.push_back((data >> 24) & 0xff);
+}
+
+/*
+ * @brief Enter an 'advance LOC' into the FDE buffer
+ * @param buf FDE buffer.
+ * @param increment Amount by which to increase the current location.
+ */
+static void AdvanceLoc(std::vector<uint8_t>&buf, uint32_t increment) {
+ if (increment < 64) {
+ // Encoding in opcode.
+ buf.push_back(0x1 << 6 | increment);
+ } else if (increment < 256) {
+ // Single byte delta.
+ buf.push_back(0x02);
+ buf.push_back(increment);
+ } else if (increment < 256 * 256) {
+ // Two byte delta.
+ buf.push_back(0x03);
+ buf.push_back(increment & 0xff);
+ buf.push_back((increment >> 8) & 0xff);
+ } else {
+ // Four byte delta.
+ buf.push_back(0x04);
+ PushWord(buf, increment);
+ }
+}
+
+
+std::vector<uint8_t>* X86CFIInitialization() {
+ return X86Mir2Lir::ReturnCommonCallFrameInformation();
+}
+
+std::vector<uint8_t>* X86Mir2Lir::ReturnCommonCallFrameInformation() {
+ std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+
+ // Length of the CIE (except for this field).
+ PushWord(*cfi_info, 16);
+
+ // CIE id.
+ PushWord(*cfi_info, 0xFFFFFFFFU);
+
+ // Version: 3.
+ cfi_info->push_back(0x03);
+
+ // Augmentation: empty string.
+ cfi_info->push_back(0x0);
+
+ // Code alignment: 1.
+ cfi_info->push_back(0x01);
+
+ // Data alignment: -4.
+ cfi_info->push_back(0x7C);
+
+ // Return address register (R8).
+ cfi_info->push_back(0x08);
+
+ // Initial return PC is 4(ESP): DW_CFA_def_cfa R4 4.
+ cfi_info->push_back(0x0C);
+ cfi_info->push_back(0x04);
+ cfi_info->push_back(0x04);
+
+ // Return address location: 0(SP): DW_CFA_offset R8 1 (* -4);.
+ cfi_info->push_back(0x2 << 6 | 0x08);
+ cfi_info->push_back(0x01);
+
+ // And 2 Noops to align to 4 byte boundary.
+ cfi_info->push_back(0x0);
+ cfi_info->push_back(0x0);
+
+ DCHECK_EQ(cfi_info->size() & 3, 0U);
+ return cfi_info;
+}
+
+static void EncodeUnsignedLeb128(std::vector<uint8_t>& buf, uint32_t value) {
+ uint8_t buffer[12];
+ uint8_t *ptr = EncodeUnsignedLeb128(buffer, value);
+ for (uint8_t *p = buffer; p < ptr; p++) {
+ buf.push_back(*p);
+ }
+}
+
+std::vector<uint8_t>* X86Mir2Lir::ReturnCallFrameInformation() {
+ std::vector<uint8_t>*cfi_info = new std::vector<uint8_t>;
+
+ // Generate the FDE for the method.
+ DCHECK_NE(data_offset_, 0U);
+
+ // Length (will be filled in later in this routine).
+ PushWord(*cfi_info, 0);
+
+ // CIE_pointer (can be filled in by linker); might be left at 0 if there is only
+ // one CIE for the whole debug_frame section.
+ PushWord(*cfi_info, 0);
+
+ // 'initial_location' (filled in by linker).
+ PushWord(*cfi_info, 0);
+
+ // 'address_range' (number of bytes in the method).
+ PushWord(*cfi_info, data_offset_);
+
+ // The instructions in the FDE.
+ if (stack_decrement_ != nullptr) {
+ // Advance LOC to just past the stack decrement.
+ uint32_t pc = NEXT_LIR(stack_decrement_)->offset;
+ AdvanceLoc(*cfi_info, pc);
+
+ // Now update the offset to the call frame: DW_CFA_def_cfa_offset frame_size.
+ cfi_info->push_back(0x0e);
+ EncodeUnsignedLeb128(*cfi_info, frame_size_);
+
+ // We continue with that stack until the epilogue.
+ if (stack_increment_ != nullptr) {
+ uint32_t new_pc = NEXT_LIR(stack_increment_)->offset;
+ AdvanceLoc(*cfi_info, new_pc - pc);
+
+ // We probably have code snippets after the epilogue, so save the
+ // current state: DW_CFA_remember_state.
+ cfi_info->push_back(0x0a);
+
+ // We have now popped the stack: DW_CFA_def_cfa_offset 4. There is only the return
+ // PC on the stack now.
+ cfi_info->push_back(0x0e);
+ EncodeUnsignedLeb128(*cfi_info, 4);
+
+ // Everything after that is the same as before the epilogue.
+ // Stack bump was followed by RET instruction.
+ LIR *post_ret_insn = NEXT_LIR(NEXT_LIR(stack_increment_));
+ if (post_ret_insn != nullptr) {
+ pc = new_pc;
+ new_pc = post_ret_insn->offset;
+ AdvanceLoc(*cfi_info, new_pc - pc);
+ // Restore the state: DW_CFA_restore_state.
+ cfi_info->push_back(0x0b);
+ }
+ }
+ }
+
+ // Padding to a multiple of 4
+ while ((cfi_info->size() & 3) != 0) {
+ // DW_CFA_nop is encoded as 0.
+ cfi_info->push_back(0);
+ }
+
+ // Set the length of the FDE inside the generated bytes.
+ uint32_t length = cfi_info->size() - 4;
+ (*cfi_info)[0] = length;
+ (*cfi_info)[1] = length >> 8;
+ (*cfi_info)[2] = length >> 16;
+ (*cfi_info)[3] = length >> 24;
+ return cfi_info;
+}
+
} // namespace art