diff options
author | Ian Rogers <irogers@google.com> | 2014-03-02 20:09:10 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2014-03-02 20:09:10 +0000 |
commit | 1179b7b770c096e93442b9c6afea4730283256f0 (patch) | |
tree | e5f70dc307945fd510660ebde1fd259aecdf66a1 /compiler/dex | |
parent | 9fab32265f35c808b216210a8d5bebd931279041 (diff) | |
parent | ae9fd93c39a341e2dffe15c61cc7d9e841fa92c4 (diff) | |
download | android_art-1179b7b770c096e93442b9c6afea4730283256f0.tar.gz android_art-1179b7b770c096e93442b9c6afea4730283256f0.tar.bz2 android_art-1179b7b770c096e93442b9c6afea4730283256f0.zip |
Merge "Tell GDB about Quick ART generated code"
Diffstat (limited to 'compiler/dex')
-rw-r--r-- | compiler/dex/quick/codegen_util.cc | 9 | ||||
-rw-r--r-- | compiler/dex/quick/mir_to_lir.h | 5 | ||||
-rw-r--r-- | compiler/dex/quick/x86/call_x86.cc | 4 | ||||
-rw-r--r-- | compiler/dex/quick/x86/codegen_x86.h | 18 | ||||
-rw-r--r-- | compiler/dex/quick/x86/target_x86.cc | 165 |
5 files changed, 197 insertions, 4 deletions
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc index 31854496ab..b0b8d1ea15 100644 --- a/compiler/dex/quick/codegen_util.cc +++ b/compiler/dex/quick/codegen_util.cc @@ -1070,10 +1070,12 @@ CompiledMethod* Mir2Lir::GetCompiledMethod() { DCHECK_EQ(fp_vmap_table_.size(), 0u); vmap_encoder.PushBackUnsigned(0u); // Size is 0. } + + UniquePtr<std::vector<uint8_t> > cfi_info(ReturnCallFrameInformation()); CompiledMethod* result = new CompiledMethod(*cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_, core_spill_mask_, fp_spill_mask_, encoded_mapping_table_, - vmap_encoder.GetData(), native_gc_map_); + vmap_encoder.GetData(), native_gc_map_, cfi_info.get()); return result; } @@ -1216,4 +1218,9 @@ void Mir2Lir::LoadClassType(uint32_t type_idx, SpecialTargetRegister symbolic_re AppendLIR(load_pc_rel); } +std::vector<uint8_t>* Mir2Lir::ReturnCallFrameInformation() { + // Default case is to do nothing. + return nullptr; +} + } // namespace art diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h index b74052c117..8f199f8c85 100644 --- a/compiler/dex/quick/mir_to_lir.h +++ b/compiler/dex/quick/mir_to_lir.h @@ -1089,6 +1089,11 @@ class Mir2Lir : public Backend { bool can_assume_type_is_in_dex_cache, uint32_t type_idx, RegLocation rl_dest, RegLocation rl_src); + /* + * @brief Generate the debug_frame FDE information if possible. + * @returns pointer to vector containg CFE information, or NULL. + */ + virtual std::vector<uint8_t>* ReturnCallFrameInformation(); /** * @brief Used to insert marker that can be used to associate MIR with LIR. diff --git a/compiler/dex/quick/x86/call_x86.cc b/compiler/dex/quick/x86/call_x86.cc index 0613cdff7a..399001c397 100644 --- a/compiler/dex/quick/x86/call_x86.cc +++ b/compiler/dex/quick/x86/call_x86.cc @@ -198,7 +198,7 @@ void X86Mir2Lir::GenEntrySequence(RegLocation* ArgLocs, RegLocation rl_method) { LockTemp(rX86_ARG2); /* Build frame, return address already on stack */ - OpRegImm(kOpSub, rX86_SP, frame_size_ - 4); + stack_decrement_ = OpRegImm(kOpSub, rX86_SP, frame_size_ - 4); /* * We can safely skip the stack overflow check if we're @@ -246,7 +246,7 @@ void X86Mir2Lir::GenExitSequence() { NewLIR0(kPseudoMethodExit); UnSpillCoreRegs(); /* Remove frame except for return address */ - OpRegImm(kOpAdd, rX86_SP, frame_size_ - 4); + stack_increment_ = OpRegImm(kOpAdd, rX86_SP, frame_size_ - 4); NewLIR0(kX86Ret); } diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h index 421d51e4fd..c97d0e6f4d 100644 --- a/compiler/dex/quick/x86/codegen_x86.h +++ b/compiler/dex/quick/x86/codegen_x86.h @@ -302,6 +302,18 @@ class X86Mir2Lir : public Mir2Lir { */ void InstallLiteralPools(); + /* + * @brief Generate the debug_frame CFI information. + * @returns pointer to vector containing CFE information + */ + static std::vector<uint8_t>* ReturnCommonCallFrameInformation(); + + /* + * @brief Generate the debug_frame FDE information. + * @returns pointer to vector containing CFE information + */ + std::vector<uint8_t>* ReturnCallFrameInformation(); + private: void EmitPrefix(const X86EncodingMap* entry); void EmitOpcode(const X86EncodingMap* entry); @@ -549,6 +561,12 @@ class X86Mir2Lir : public Mir2Lir { // Instructions needing patching with PC relative code addresses. GrowableArray<LIR*> call_method_insns_; + + // Prologue decrement of stack pointer. + LIR* stack_decrement_; + + // Epilogue increment of stack pointer. + LIR* stack_increment_; }; } // namespace art diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc index eea7191c3b..7bb866d4aa 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 |