summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/dex/quick/codegen_util.cc2
-rw-r--r--compiler/driver/compiler_options.cc6
-rw-r--r--compiler/driver/compiler_options.h12
-rw-r--r--compiler/elf_builder.h17
-rw-r--r--compiler/elf_writer_debug.cc146
-rw-r--r--compiler/elf_writer_debug.h4
-rw-r--r--compiler/elf_writer_quick.cc9
-rw-r--r--compiler/jni/quick/jni_compiler.cc2
-rw-r--r--compiler/oat_writer.cc2
-rw-r--r--compiler/optimizing/optimizing_compiler.cc2
10 files changed, 177 insertions, 25 deletions
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index d68835a9cf..af6f91f21d 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -1076,7 +1076,7 @@ Mir2Lir::Mir2Lir(CompilationUnit* cu, MIRGraph* mir_graph, ArenaAllocator* arena
pc_rel_temp_(nullptr),
dex_cache_arrays_min_offset_(std::numeric_limits<uint32_t>::max()),
cfi_(&last_lir_insn_,
- cu->compiler_driver->GetCompilerOptions().GetGenerateDebugInfo(),
+ cu->compiler_driver->GetCompilerOptions().GenerateAnyDebugInfo(),
arena),
in_to_reg_storage_mapping_(arena) {
switch_tables_.reserve(4);
diff --git a/compiler/driver/compiler_options.cc b/compiler/driver/compiler_options.cc
index 4f6e922665..9285b8c927 100644
--- a/compiler/driver/compiler_options.cc
+++ b/compiler/driver/compiler_options.cc
@@ -37,6 +37,7 @@ CompilerOptions::CompilerOptions()
debuggable_(false),
native_debuggable_(kDefaultNativeDebuggable),
generate_debug_info_(kDefaultGenerateDebugInfo),
+ generate_mini_debug_info_(kDefaultGenerateMiniDebugInfo),
implicit_null_checks_(true),
implicit_so_checks_(true),
implicit_suspend_checks_(false),
@@ -91,6 +92,7 @@ CompilerOptions::CompilerOptions(CompilerFilter compiler_filter,
debuggable_(debuggable),
native_debuggable_(kDefaultNativeDebuggable),
generate_debug_info_(generate_debug_info),
+ generate_mini_debug_info_(kDefaultGenerateMiniDebugInfo),
implicit_null_checks_(implicit_null_checks),
implicit_so_checks_(implicit_so_checks),
implicit_suspend_checks_(implicit_suspend_checks),
@@ -215,6 +217,10 @@ bool CompilerOptions::ParseCompilerOption(const StringPiece& option, UsageFn Usa
generate_debug_info_ = true;
} else if (option == "--no-generate-debug-info") {
generate_debug_info_ = false;
+ } else if (option == "--generate-mini-debug-info") {
+ generate_mini_debug_info_ = true;
+ } else if (option == "--no-generate-mini-debug-info") {
+ generate_mini_debug_info_ = false;
} else if (option == "--debuggable") {
debuggable_ = true;
} else if (option == "--native-debuggable") {
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 9d51b750bf..6989bd5bae 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -51,6 +51,7 @@ class CompilerOptions FINAL {
static constexpr double kDefaultTopKProfileThreshold = 90.0;
static const bool kDefaultNativeDebuggable = false;
static const bool kDefaultGenerateDebugInfo = false;
+ static const bool kDefaultGenerateMiniDebugInfo = false;
static const bool kDefaultIncludePatchInformation = false;
static const size_t kDefaultInlineDepthLimit = 3;
static const size_t kDefaultInlineMaxCodeUnits = 32;
@@ -170,10 +171,20 @@ class CompilerOptions FINAL {
return native_debuggable_;
}
+ // This flag controls whether the compiler collects debugging information.
+ // The other flags control how the information is written to disk.
+ bool GenerateAnyDebugInfo() const {
+ return GetGenerateDebugInfo() || GetGenerateMiniDebugInfo();
+ }
+
bool GetGenerateDebugInfo() const {
return generate_debug_info_;
}
+ bool GetGenerateMiniDebugInfo() const {
+ return generate_mini_debug_info_;
+ }
+
bool GetImplicitNullChecks() const {
return implicit_null_checks_;
}
@@ -268,6 +279,7 @@ class CompilerOptions FINAL {
bool debuggable_;
bool native_debuggable_;
bool generate_debug_info_;
+ bool generate_mini_debug_info_;
bool implicit_null_checks_;
bool implicit_so_checks_;
bool implicit_suspend_checks_;
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 46484b1cd6..3d24d19919 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -165,10 +165,15 @@ class ElfBuilder FINAL {
}
}
- // Set desired allocation size for .bss section.
- void SetSize(Elf_Word size) {
- CHECK_EQ(header_.sh_type, (Elf_Word)SHT_NOBITS);
+ // Write this section as "NOBITS" section. (used for the .bss section)
+ // This means that the ELF file does not contain the initial data for this section
+ // and it will be zero-initialized when the ELF file is loaded in the running program.
+ void WriteNoBitsSection(Elf_Word size) {
+ DCHECK_NE(header_.sh_flags & SHF_ALLOC, 0u);
+ Start();
+ header_.sh_type = SHT_NOBITS;
header_.sh_size = size;
+ End();
}
// This function always succeeds to simplify code.
@@ -346,6 +351,12 @@ class ElfBuilder FINAL {
other_sections_.push_back(std::move(s));
}
+ // Set where the next section will be allocated in the virtual address space.
+ void SetVirtualAddress(Elf_Addr address) {
+ DCHECK_GE(address, virtual_address_);
+ virtual_address_ = address;
+ }
+
void Start() {
// Reserve space for ELF header and program headers.
// We do not know the number of headers until later, so
diff --git a/compiler/elf_writer_debug.cc b/compiler/elf_writer_debug.cc
index 73e6aa38f0..2e98b69c47 100644
--- a/compiler/elf_writer_debug.cc
+++ b/compiler/elf_writer_debug.cc
@@ -16,6 +16,7 @@
#include "elf_writer_debug.h"
+#include <algorithm>
#include <unordered_set>
#include <vector>
#include <cstdio>
@@ -40,6 +41,11 @@
#include "stack_map.h"
#include "utils.h"
+// liblzma.
+#include "XzEnc.h"
+#include "7zCrc.h"
+#include "XzCrc64.h"
+
namespace art {
namespace dwarf {
@@ -222,7 +228,8 @@ static void WriteCIE(InstructionSet isa,
template<typename ElfTypes>
void WriteCFISection(ElfBuilder<ElfTypes>* builder,
const ArrayRef<const MethodDebugInfo>& method_infos,
- CFIFormat format) {
+ CFIFormat format,
+ bool write_oat_patches) {
CHECK(format == DW_DEBUG_FRAME_FORMAT || format == DW_EH_FRAME_FORMAT);
typedef typename ElfTypes::Addr Elf_Addr;
@@ -238,6 +245,24 @@ void WriteCFISection(ElfBuilder<ElfTypes>* builder,
patch_locations.reserve(method_infos.size());
}
+ // The methods can be written any order.
+ // Let's therefore sort them in the lexicographical order of the opcodes.
+ // This has no effect on its own. However, if the final .debug_frame section is
+ // compressed it reduces the size since similar opcodes sequences are grouped.
+ std::vector<const MethodDebugInfo*> sorted_method_infos;
+ sorted_method_infos.reserve(method_infos.size());
+ for (size_t i = 0; i < method_infos.size(); i++) {
+ sorted_method_infos.push_back(&method_infos[i]);
+ }
+ std::sort(
+ sorted_method_infos.begin(),
+ sorted_method_infos.end(),
+ [](const MethodDebugInfo* lhs, const MethodDebugInfo* rhs) {
+ ArrayRef<const uint8_t> l = lhs->compiled_method_->GetCFIInfo();
+ ArrayRef<const uint8_t> r = rhs->compiled_method_->GetCFIInfo();
+ return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end());
+ });
+
// Write .eh_frame/.debug_frame section.
auto* cfi_section = (format == DW_DEBUG_FRAME_FORMAT
? builder->GetDebugFrame()
@@ -256,11 +281,11 @@ void WriteCFISection(ElfBuilder<ElfTypes>* builder,
cfi_section->WriteFully(buffer.data(), buffer.size());
buffer_address += buffer.size();
buffer.clear();
- for (const MethodDebugInfo& mi : method_infos) {
- if (!mi.deduped_) { // Only one FDE per unique address.
- ArrayRef<const uint8_t> opcodes = mi.compiled_method_->GetCFIInfo();
+ for (const MethodDebugInfo* mi : sorted_method_infos) {
+ if (!mi->deduped_) { // Only one FDE per unique address.
+ ArrayRef<const uint8_t> opcodes = mi->compiled_method_->GetCFIInfo();
if (!opcodes.empty()) {
- const Elf_Addr code_address = text_address + mi.low_pc_;
+ const Elf_Addr code_address = text_address + mi->low_pc_;
if (format == DW_EH_FRAME_FORMAT) {
binary_search_table.push_back(
dchecked_integral_cast<uint32_t>(code_address));
@@ -268,7 +293,7 @@ void WriteCFISection(ElfBuilder<ElfTypes>* builder,
dchecked_integral_cast<uint32_t>(buffer_address));
}
WriteFDE(is64bit, cfi_address, cie_address,
- code_address, mi.high_pc_ - mi.low_pc_,
+ code_address, mi->high_pc_ - mi->low_pc_,
opcodes, format, buffer_address, &buffer,
&patch_locations);
cfi_section->WriteFully(buffer.data(), buffer.size());
@@ -309,8 +334,10 @@ void WriteCFISection(ElfBuilder<ElfTypes>* builder,
header_section->WriteFully(binary_search_table.data(), binary_search_table.size());
header_section->End();
} else {
- builder->WritePatches(".debug_frame.oat_patches",
- ArrayRef<const uintptr_t>(patch_locations));
+ if (write_oat_patches) {
+ builder->WritePatches(".debug_frame.oat_patches",
+ ArrayRef<const uintptr_t>(patch_locations));
+ }
}
}
@@ -1338,8 +1365,9 @@ static void WriteDebugSections(ElfBuilder<ElfTypes>* builder,
}
template <typename ElfTypes>
-void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder,
- const ArrayRef<const MethodDebugInfo>& method_infos) {
+static void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder,
+ const ArrayRef<const MethodDebugInfo>& method_infos,
+ bool with_signature) {
bool generated_mapping_symbol = false;
auto* strtab = builder->GetStrTab();
auto* symtab = builder->GetSymTab();
@@ -1359,22 +1387,31 @@ void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder,
strtab->Start();
strtab->Write(""); // strtab should start with empty string.
+ std::string last_name;
+ size_t last_name_offset = 0;
for (const MethodDebugInfo& info : method_infos) {
if (info.deduped_) {
continue; // Add symbol only for the first instance.
}
- std::string name = PrettyMethod(info.dex_method_index_, *info.dex_file_, true);
+ std::string name = PrettyMethod(info.dex_method_index_, *info.dex_file_, with_signature);
if (deduped_addresses.find(info.low_pc_) != deduped_addresses.end()) {
name += " [DEDUPED]";
}
+ // If we write method names without signature, we might see the same name multiple times.
+ size_t name_offset = (name == last_name ? last_name_offset : strtab->Write(name));
const auto* text = builder->GetText()->Exists() ? builder->GetText() : nullptr;
const bool is_relative = (text != nullptr);
uint32_t low_pc = info.low_pc_;
// Add in code delta, e.g., thumb bit 0 for Thumb2 code.
low_pc += info.compiled_method_->CodeDelta();
- symtab->Add(strtab->Write(name), text, low_pc,
- is_relative, info.high_pc_ - info.low_pc_, STB_GLOBAL, STT_FUNC);
+ symtab->Add(name_offset,
+ text,
+ low_pc,
+ is_relative,
+ info.high_pc_ - info.low_pc_,
+ STB_GLOBAL,
+ STT_FUNC);
// Conforming to aaelf, add $t mapping symbol to indicate start of a sequence of thumb2
// instructions, so that disassembler tools can correctly disassemble.
@@ -1387,6 +1424,9 @@ void WriteDebugSymbols(ElfBuilder<ElfTypes>* builder,
generated_mapping_symbol = true;
}
}
+
+ last_name = std::move(name);
+ last_name_offset = name_offset;
}
strtab->End();
@@ -1402,13 +1442,83 @@ void WriteDebugInfo(ElfBuilder<ElfTypes>* builder,
const ArrayRef<const MethodDebugInfo>& method_infos,
CFIFormat cfi_format) {
// Add methods to .symtab.
- WriteDebugSymbols(builder, method_infos);
+ WriteDebugSymbols(builder, method_infos, true /* with_signature */);
// Generate CFI (stack unwinding information).
- WriteCFISection(builder, method_infos, cfi_format);
+ WriteCFISection(builder, method_infos, cfi_format, true /* write_oat_patches */);
// Write DWARF .debug_* sections.
WriteDebugSections(builder, method_infos);
}
+static void XzCompress(const std::vector<uint8_t>* src, std::vector<uint8_t>* dst) {
+ // Configure the compression library.
+ CrcGenerateTable();
+ Crc64GenerateTable();
+ CLzma2EncProps lzma2Props;
+ Lzma2EncProps_Init(&lzma2Props);
+ lzma2Props.lzmaProps.level = 1; // Fast compression.
+ Lzma2EncProps_Normalize(&lzma2Props);
+ CXzProps props;
+ XzProps_Init(&props);
+ props.lzma2Props = &lzma2Props;
+ // Implement the required interface for communication (written in C so no virtual methods).
+ struct XzCallbacks : public ISeqInStream, public ISeqOutStream, public ICompressProgress {
+ static SRes ReadImpl(void* p, void* buf, size_t* size) {
+ auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqInStream*>(p));
+ *size = std::min(*size, ctx->src_->size() - ctx->src_pos_);
+ memcpy(buf, ctx->src_->data() + ctx->src_pos_, *size);
+ ctx->src_pos_ += *size;
+ return SZ_OK;
+ }
+ static size_t WriteImpl(void* p, const void* buf, size_t size) {
+ auto* ctx = static_cast<XzCallbacks*>(reinterpret_cast<ISeqOutStream*>(p));
+ const uint8_t* buffer = reinterpret_cast<const uint8_t*>(buf);
+ ctx->dst_->insert(ctx->dst_->end(), buffer, buffer + size);
+ return size;
+ }
+ static SRes ProgressImpl(void* , UInt64, UInt64) {
+ return SZ_OK;
+ }
+ size_t src_pos_;
+ const std::vector<uint8_t>* src_;
+ std::vector<uint8_t>* dst_;
+ };
+ XzCallbacks callbacks;
+ callbacks.Read = XzCallbacks::ReadImpl;
+ callbacks.Write = XzCallbacks::WriteImpl;
+ callbacks.Progress = XzCallbacks::ProgressImpl;
+ callbacks.src_pos_ = 0;
+ callbacks.src_ = src;
+ callbacks.dst_ = dst;
+ // Compress.
+ SRes res = Xz_Encode(&callbacks, &callbacks, &props, &callbacks);
+ CHECK_EQ(res, SZ_OK);
+}
+
+template <typename ElfTypes>
+void WriteMiniDebugInfo(ElfBuilder<ElfTypes>* parent_builder,
+ const ArrayRef<const MethodDebugInfo>& method_infos) {
+ const InstructionSet isa = parent_builder->GetIsa();
+ std::vector<uint8_t> buffer;
+ buffer.reserve(KB);
+ VectorOutputStream out("Mini-debug-info ELF file", &buffer);
+ std::unique_ptr<ElfBuilder<ElfTypes>> builder(new ElfBuilder<ElfTypes>(isa, &out));
+ builder->Start();
+ // Write .rodata and .text as NOBITS sections.
+ // This allows tools to detect virtual address relocation of the parent ELF file.
+ builder->SetVirtualAddress(parent_builder->GetRoData()->GetAddress());
+ builder->GetRoData()->WriteNoBitsSection(parent_builder->GetRoData()->GetSize());
+ builder->SetVirtualAddress(parent_builder->GetText()->GetAddress());
+ builder->GetText()->WriteNoBitsSection(parent_builder->GetText()->GetSize());
+ WriteDebugSymbols(builder.get(), method_infos, false /* with_signature */);
+ WriteCFISection(builder.get(), method_infos, DW_DEBUG_FRAME_FORMAT, false /* write_oat_paches */);
+ builder->End();
+ CHECK(builder->Good());
+ std::vector<uint8_t> compressed_buffer;
+ compressed_buffer.reserve(buffer.size() / 4);
+ XzCompress(&buffer, &compressed_buffer);
+ parent_builder->WriteSection(".gnu_debugdata", &compressed_buffer);
+}
+
template <typename ElfTypes>
static ArrayRef<const uint8_t> WriteDebugElfFileForMethodInternal(
const dwarf::MethodDebugInfo& method_info) {
@@ -1481,6 +1591,12 @@ template void WriteDebugInfo<ElfTypes64>(
ElfBuilder<ElfTypes64>* builder,
const ArrayRef<const MethodDebugInfo>& method_infos,
CFIFormat cfi_format);
+template void WriteMiniDebugInfo<ElfTypes32>(
+ ElfBuilder<ElfTypes32>* builder,
+ const ArrayRef<const MethodDebugInfo>& method_infos);
+template void WriteMiniDebugInfo<ElfTypes64>(
+ ElfBuilder<ElfTypes64>* builder,
+ const ArrayRef<const MethodDebugInfo>& method_infos);
} // namespace dwarf
} // namespace art
diff --git a/compiler/elf_writer_debug.h b/compiler/elf_writer_debug.h
index e4bc856c5e..e19da088da 100644
--- a/compiler/elf_writer_debug.h
+++ b/compiler/elf_writer_debug.h
@@ -35,6 +35,10 @@ void WriteDebugInfo(ElfBuilder<ElfTypes>* builder,
const ArrayRef<const MethodDebugInfo>& method_infos,
CFIFormat cfi_format);
+template <typename ElfTypes>
+void WriteMiniDebugInfo(ElfBuilder<ElfTypes>* builder,
+ const ArrayRef<const MethodDebugInfo>& method_infos);
+
ArrayRef<const uint8_t> WriteDebugElfFileForMethod(const dwarf::MethodDebugInfo& method_info);
ArrayRef<const uint8_t> WriteDebugElfFileForClasses(const InstructionSet isa,
diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc
index 7b1bdd72e5..6bf080a083 100644
--- a/compiler/elf_writer_quick.cc
+++ b/compiler/elf_writer_quick.cc
@@ -137,9 +137,7 @@ template <typename ElfTypes>
void ElfWriterQuick<ElfTypes>::SetBssSize(size_t bss_size) {
auto* bss = builder_->GetBss();
if (bss_size != 0u) {
- bss->Start();
- bss->SetSize(bss_size);
- bss->End();
+ bss->WriteNoBitsSection(bss_size);
}
}
@@ -152,8 +150,13 @@ template <typename ElfTypes>
void ElfWriterQuick<ElfTypes>::WriteDebugInfo(
const ArrayRef<const dwarf::MethodDebugInfo>& method_infos) {
if (compiler_options_->GetGenerateDebugInfo()) {
+ // Generate all the debug information we can.
dwarf::WriteDebugInfo(builder_.get(), method_infos, kCFIFormat);
}
+ if (compiler_options_->GetGenerateMiniDebugInfo()) {
+ // Generate only some information and compress it.
+ dwarf::WriteMiniDebugInfo(builder_.get(), method_infos);
+ }
}
template <typename ElfTypes>
diff --git a/compiler/jni/quick/jni_compiler.cc b/compiler/jni/quick/jni_compiler.cc
index 52a238233b..e92046057c 100644
--- a/compiler/jni/quick/jni_compiler.cc
+++ b/compiler/jni/quick/jni_compiler.cc
@@ -95,7 +95,7 @@ CompiledMethod* ArtJniCompileMethodInternal(CompilerDriver* driver,
// Assembler that holds generated instructions
std::unique_ptr<Assembler> jni_asm(Assembler::Create(instruction_set, instruction_set_features));
- jni_asm->cfi().SetEnabled(driver->GetCompilerOptions().GetGenerateDebugInfo());
+ jni_asm->cfi().SetEnabled(driver->GetCompilerOptions().GenerateAnyDebugInfo());
// Offsets into data structures
// TODO: if cross compiling these offsets are for the host not the target
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index a5421622b7..569e0f4e19 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -806,7 +806,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor {
}
}
- if (writer_->compiler_driver_->GetCompilerOptions().GetGenerateDebugInfo()) {
+ if (writer_->compiler_driver_->GetCompilerOptions().GenerateAnyDebugInfo()) {
// Record debug information for this function if we are doing that.
const uint32_t quick_code_start = quick_code_offset -
writer_->oat_header_->GetExecutableOffset() - thumb_offset;
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index fffd00535c..3fac914017 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -676,7 +676,7 @@ CodeGenerator* OptimizingCompiler::TryCompile(ArenaAllocator* arena,
return nullptr;
}
codegen->GetAssembler()->cfi().SetEnabled(
- compiler_driver->GetCompilerOptions().GetGenerateDebugInfo());
+ compiler_driver->GetCompilerOptions().GenerateAnyDebugInfo());
PassObserver pass_observer(graph,
codegen.get(),