diff options
-rw-r--r-- | compiler/debug/elf_debug_writer.cc | 25 | ||||
-rw-r--r-- | compiler/debug/elf_debug_writer.h | 2 | ||||
-rw-r--r-- | compiler/debug/elf_symtab_writer.h | 4 | ||||
-rw-r--r-- | compiler/debug/method_debug_info.h | 2 | ||||
-rw-r--r-- | compiler/jit/jit_compiler.cc | 1 | ||||
-rw-r--r-- | compiler/linker/arm/relative_patcher_arm_base.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 42 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.cc | 4 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 4 | ||||
-rw-r--r-- | runtime/jit/debugger_interface.cc | 65 | ||||
-rw-r--r-- | runtime/jit/debugger_interface.h | 35 | ||||
-rw-r--r-- | runtime/jit/jit_code_cache.cc | 6 |
12 files changed, 112 insertions, 82 deletions
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc index bb2a214ecd..df5bb37358 100644 --- a/compiler/debug/elf_debug_writer.cc +++ b/compiler/debug/elf_debug_writer.cc @@ -137,10 +137,17 @@ static std::vector<uint8_t> MakeElfFileForJITInternal( InstructionSet isa, const InstructionSetFeatures* features, bool mini_debug_info, - const MethodDebugInfo& mi) { - CHECK_EQ(mi.is_code_address_text_relative, false); + ArrayRef<const MethodDebugInfo> method_infos) { + CHECK_GT(method_infos.size(), 0u); + uint64_t min_address = std::numeric_limits<uint64_t>::max(); + uint64_t max_address = 0; + for (const MethodDebugInfo& mi : method_infos) { + CHECK_EQ(mi.is_code_address_text_relative, false); + min_address = std::min(min_address, mi.code_address); + max_address = std::max(max_address, mi.code_address + mi.code_size); + } DebugInfo debug_info{}; - debug_info.compiled_methods = ArrayRef<const debug::MethodDebugInfo>(&mi, 1); + debug_info.compiled_methods = method_infos; std::vector<uint8_t> buffer; buffer.reserve(KB); linker::VectorOutputStream out("Debug ELF file", &buffer); @@ -151,14 +158,14 @@ static std::vector<uint8_t> MakeElfFileForJITInternal( if (mini_debug_info) { std::vector<uint8_t> mdi = MakeMiniDebugInfo(isa, features, - mi.code_address, - mi.code_size, + min_address, + max_address - min_address, /* dex_section_address */ 0, /* dex_section_size */ 0, debug_info); builder->WriteSection(".gnu_debugdata", &mdi); } else { - builder->GetText()->AllocateVirtualMemory(mi.code_address, mi.code_size); + builder->GetText()->AllocateVirtualMemory(min_address, max_address - min_address); WriteDebugInfo(builder.get(), debug_info, dwarf::DW_DEBUG_FRAME_FORMAT, @@ -173,11 +180,11 @@ std::vector<uint8_t> MakeElfFileForJIT( InstructionSet isa, const InstructionSetFeatures* features, bool mini_debug_info, - const MethodDebugInfo& method_info) { + ArrayRef<const MethodDebugInfo> method_infos) { if (Is64BitInstructionSet(isa)) { - return MakeElfFileForJITInternal<ElfTypes64>(isa, features, mini_debug_info, method_info); + return MakeElfFileForJITInternal<ElfTypes64>(isa, features, mini_debug_info, method_infos); } else { - return MakeElfFileForJITInternal<ElfTypes32>(isa, features, mini_debug_info, method_info); + return MakeElfFileForJITInternal<ElfTypes32>(isa, features, mini_debug_info, method_infos); } } diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h index 8ad0c4219a..e442e0016c 100644 --- a/compiler/debug/elf_debug_writer.h +++ b/compiler/debug/elf_debug_writer.h @@ -54,7 +54,7 @@ std::vector<uint8_t> MakeElfFileForJIT( InstructionSet isa, const InstructionSetFeatures* features, bool mini_debug_info, - const MethodDebugInfo& method_info); + ArrayRef<const MethodDebugInfo> method_infos); std::vector<uint8_t> WriteDebugElfFileForClasses( InstructionSet isa, diff --git a/compiler/debug/elf_symtab_writer.h b/compiler/debug/elf_symtab_writer.h index a853714d2b..9c9e8b35b8 100644 --- a/compiler/debug/elf_symtab_writer.h +++ b/compiler/debug/elf_symtab_writer.h @@ -72,8 +72,8 @@ static void WriteDebugSymbols(linker::ElfBuilder<ElfTypes>* builder, continue; // Add symbol only for the first instance. } size_t name_offset; - if (!info.trampoline_name.empty()) { - name_offset = strtab->Write(info.trampoline_name); + if (!info.custom_name.empty()) { + name_offset = strtab->Write(info.custom_name); } else { DCHECK(info.dex_file != nullptr); std::string name = info.dex_file->PrettyMethod(info.dex_method_index, !mini_debug_info); diff --git a/compiler/debug/method_debug_info.h b/compiler/debug/method_debug_info.h index 43c8de26aa..d0b03ec441 100644 --- a/compiler/debug/method_debug_info.h +++ b/compiler/debug/method_debug_info.h @@ -27,7 +27,7 @@ namespace art { namespace debug { struct MethodDebugInfo { - std::string trampoline_name; + std::string custom_name; const DexFile* dex_file; // Native methods (trampolines) do not reference dex file. size_t class_def_index; uint32_t dex_method_index; diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index 88e3e5b230..2c62095458 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -76,6 +76,7 @@ extern "C" void jit_types_loaded(void* handle, mirror::Class** types, size_t cou const ArrayRef<mirror::Class*> types_array(types, count); std::vector<uint8_t> elf_file = debug::WriteDebugElfFileForClasses( kRuntimeISA, jit_compiler->GetCompilerDriver()->GetInstructionSetFeatures(), types_array); + MutexLock mu(Thread::Current(), g_jit_debug_mutex); CreateJITCodeEntry(std::move(elf_file)); } } diff --git a/compiler/linker/arm/relative_patcher_arm_base.cc b/compiler/linker/arm/relative_patcher_arm_base.cc index cedbe5d97f..6e0286afac 100644 --- a/compiler/linker/arm/relative_patcher_arm_base.cc +++ b/compiler/linker/arm/relative_patcher_arm_base.cc @@ -250,12 +250,12 @@ std::vector<debug::MethodDebugInfo> ArmBaseRelativePatcher::GenerateThunkDebugIn for (size_t i = start, num = data.NumberOfThunks(); i != num; ++i) { debug::MethodDebugInfo info = {}; if (i == 0u) { - info.trampoline_name = base_name; + info.custom_name = base_name; } else { // Add a disambiguating tag for subsequent identical thunks. Since the `thunks_` // keeps records also for thunks in previous oat files, names based on the thunk // index shall be unique across the whole multi-oat output. - info.trampoline_name = base_name + "_" + std::to_string(i); + info.custom_name = base_name + "_" + std::to_string(i); } info.isa = instruction_set_; info.is_code_address_text_relative = true; diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index a3b1f0c5af..c35c490118 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -382,6 +382,8 @@ class OptimizingCompiler FINAL : public Compiler { PassObserver* pass_observer, VariableSizedHandleScope* handles) const; + void GenerateJitDebugInfo(debug::MethodDebugInfo method_debug_info); + std::unique_ptr<OptimizingCompilerStats> compilation_stats_; std::unique_ptr<std::ostream> visualizer_output_; @@ -1230,7 +1232,7 @@ bool OptimizingCompiler::JitCompile(Thread* self, const auto* method_header = reinterpret_cast<const OatQuickMethodHeader*>(code); const uintptr_t code_address = reinterpret_cast<uintptr_t>(method_header->GetCode()); debug::MethodDebugInfo info = {}; - DCHECK(info.trampoline_name.empty()); + DCHECK(info.custom_name.empty()); info.dex_file = dex_file; info.class_def_index = class_def_idx; info.dex_method_index = method_idx; @@ -1246,14 +1248,7 @@ bool OptimizingCompiler::JitCompile(Thread* self, info.frame_size_in_bytes = method_header->GetFrameSizeInBytes(); info.code_info = nullptr; info.cfi = jni_compiled_method.GetCfi(); - // If both flags are passed, generate full debug info. - const bool mini_debug_info = !compiler_options.GetGenerateDebugInfo(); - std::vector<uint8_t> elf_file = debug::MakeElfFileForJIT( - GetCompilerDriver()->GetInstructionSet(), - GetCompilerDriver()->GetInstructionSetFeatures(), - mini_debug_info, - info); - CreateJITCodeEntryForAddress(code_address, std::move(elf_file)); + GenerateJitDebugInfo(info); } Runtime::Current()->GetJit()->AddMemoryUsage(method, allocator.BytesUsed()); @@ -1361,7 +1356,7 @@ bool OptimizingCompiler::JitCompile(Thread* self, const auto* method_header = reinterpret_cast<const OatQuickMethodHeader*>(code); const uintptr_t code_address = reinterpret_cast<uintptr_t>(method_header->GetCode()); debug::MethodDebugInfo info = {}; - DCHECK(info.trampoline_name.empty()); + DCHECK(info.custom_name.empty()); info.dex_file = dex_file; info.class_def_index = class_def_idx; info.dex_method_index = method_idx; @@ -1377,14 +1372,7 @@ bool OptimizingCompiler::JitCompile(Thread* self, info.frame_size_in_bytes = method_header->GetFrameSizeInBytes(); info.code_info = stack_map_size == 0 ? nullptr : stack_map_data; info.cfi = ArrayRef<const uint8_t>(*codegen->GetAssembler()->cfi().data()); - // If both flags are passed, generate full debug info. - const bool mini_debug_info = !compiler_options.GetGenerateDebugInfo(); - std::vector<uint8_t> elf_file = debug::MakeElfFileForJIT( - GetCompilerDriver()->GetInstructionSet(), - GetCompilerDriver()->GetInstructionSetFeatures(), - mini_debug_info, - info); - CreateJITCodeEntryForAddress(code_address, std::move(elf_file)); + GenerateJitDebugInfo(info); } Runtime::Current()->GetJit()->AddMemoryUsage(method, allocator.BytesUsed()); @@ -1408,4 +1396,22 @@ bool OptimizingCompiler::JitCompile(Thread* self, return true; } +void OptimizingCompiler::GenerateJitDebugInfo(debug::MethodDebugInfo info) { + const CompilerOptions& compiler_options = GetCompilerDriver()->GetCompilerOptions(); + DCHECK(compiler_options.GenerateAnyDebugInfo()); + + // If both flags are passed, generate full debug info. + const bool mini_debug_info = !compiler_options.GetGenerateDebugInfo(); + + // Create entry for the single method that we just compiled. + std::vector<uint8_t> elf_file = debug::MakeElfFileForJIT( + GetCompilerDriver()->GetInstructionSet(), + GetCompilerDriver()->GetInstructionSetFeatures(), + mini_debug_info, + ArrayRef<const debug::MethodDebugInfo>(&info, 1)); + MutexLock mu(Thread::Current(), g_jit_debug_mutex); + JITCodeEntry* entry = CreateJITCodeEntry(elf_file); + IncrementJITCodeEntryRefcount(entry, info.code_address); +} + } // namespace art diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 849887c8ff..66041bbfad 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -1336,7 +1336,7 @@ class OatWriter::LayoutReserveOffsetCodeMethodVisitor : public OrderedMethodVisi bool has_code_info = method_header->IsOptimized(); // Record debug information for this function if we are doing that. debug::MethodDebugInfo& info = writer_->method_info_[debug_info_idx]; - DCHECK(info.trampoline_name.empty()); + DCHECK(info.custom_name.empty()); info.dex_file = method_ref.dex_file; info.class_def_index = class_def_index; info.dex_method_index = method_ref.index; @@ -2420,7 +2420,7 @@ size_t OatWriter::InitOatCode(size_t offset) { (field) = compiler_driver_->Create ## fn_name(); \ if (generate_debug_info) { \ debug::MethodDebugInfo info = {}; \ - info.trampoline_name = #fn_name; \ + info.custom_name = #fn_name; \ info.isa = instruction_set; \ info.is_code_address_text_relative = true; \ /* Use the code offset rather than the `adjusted_offset`. */ \ diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 2b90614b93..fcbf2f1c0a 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -180,7 +180,7 @@ class OatSymbolizer FINAL { #define DO_TRAMPOLINE(fn_name) \ if (oat_header.Get ## fn_name ## Offset() != 0) { \ debug::MethodDebugInfo info = {}; \ - info.trampoline_name = #fn_name; \ + info.custom_name = #fn_name; \ info.isa = oat_header.GetInstructionSet(); \ info.is_code_address_text_relative = true; \ size_t code_offset = oat_header.Get ## fn_name ## Offset(); \ @@ -308,7 +308,7 @@ class OatSymbolizer FINAL { const void* code_address = EntryPointToCodePointer(reinterpret_cast<void*>(entry_point)); debug::MethodDebugInfo info = {}; - DCHECK(info.trampoline_name.empty()); + DCHECK(info.custom_name.empty()); info.dex_file = &dex_file; info.class_def_index = class_def_index; info.dex_method_index = dex_method_index; diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc index 4d1c85a1c2..0e295e2442 100644 --- a/runtime/jit/debugger_interface.cc +++ b/runtime/jit/debugger_interface.cc @@ -42,6 +42,7 @@ extern "C" { JITCodeEntry* prev_; const uint8_t *symfile_addr_; uint64_t symfile_size_; + uint32_t ref_count; // ART internal field. }; struct JITDescriptor { @@ -69,10 +70,11 @@ extern "C" { JITDescriptor __jit_debug_descriptor = { 1, JIT_NOACTION, nullptr, nullptr }; } -static Mutex g_jit_debug_mutex("JIT debug interface lock", kJitDebugInterfaceLock); +Mutex g_jit_debug_mutex("JIT debug interface lock", kJitDebugInterfaceLock); -static JITCodeEntry* CreateJITCodeEntryInternal(std::vector<uint8_t> symfile) - REQUIRES(g_jit_debug_mutex) { +static size_t g_jit_debug_mem_usage = 0; + +JITCodeEntry* CreateJITCodeEntry(const std::vector<uint8_t>& symfile) { DCHECK_NE(symfile.size(), 0u); // Make a copy of the buffer. We want to shrink it anyway. @@ -85,20 +87,20 @@ static JITCodeEntry* CreateJITCodeEntryInternal(std::vector<uint8_t> symfile) entry->symfile_addr_ = symfile_copy; entry->symfile_size_ = symfile.size(); entry->prev_ = nullptr; - + entry->ref_count = 0; entry->next_ = __jit_debug_descriptor.first_entry_; if (entry->next_ != nullptr) { entry->next_->prev_ = entry; } + g_jit_debug_mem_usage += sizeof(JITCodeEntry) + entry->symfile_size_; __jit_debug_descriptor.first_entry_ = entry; __jit_debug_descriptor.relevant_entry_ = entry; - __jit_debug_descriptor.action_flag_ = JIT_REGISTER_FN; (*__jit_debug_register_code_ptr)(); return entry; } -static void DeleteJITCodeEntryInternal(JITCodeEntry* entry) REQUIRES(g_jit_debug_mutex) { +void DeleteJITCodeEntry(JITCodeEntry* entry) { if (entry->prev_ != nullptr) { entry->prev_->next_ = entry->next_; } else { @@ -109,6 +111,7 @@ static void DeleteJITCodeEntryInternal(JITCodeEntry* entry) REQUIRES(g_jit_debug entry->next_->prev_ = entry->prev_; } + g_jit_debug_mem_usage -= sizeof(JITCodeEntry) + entry->symfile_size_; __jit_debug_descriptor.relevant_entry_ = entry; __jit_debug_descriptor.action_flag_ = JIT_UNREGISTER_FN; (*__jit_debug_register_code_ptr)(); @@ -116,41 +119,33 @@ static void DeleteJITCodeEntryInternal(JITCodeEntry* entry) REQUIRES(g_jit_debug delete entry; } -JITCodeEntry* CreateJITCodeEntry(std::vector<uint8_t> symfile) { - Thread* self = Thread::Current(); - MutexLock mu(self, g_jit_debug_mutex); - return CreateJITCodeEntryInternal(std::move(symfile)); +// Mapping from code address to entry. Used to manage life-time of the entries. +static std::unordered_map<uintptr_t, JITCodeEntry*> g_jit_code_entries + GUARDED_BY(g_jit_debug_mutex); + +void IncrementJITCodeEntryRefcount(JITCodeEntry* entry, uintptr_t code_address) { + DCHECK(entry != nullptr); + DCHECK_EQ(g_jit_code_entries.count(code_address), 0u); + entry->ref_count++; + g_jit_code_entries.emplace(code_address, entry); } -void DeleteJITCodeEntry(JITCodeEntry* entry) { - Thread* self = Thread::Current(); - MutexLock mu(self, g_jit_debug_mutex); - DeleteJITCodeEntryInternal(entry); +void DecrementJITCodeEntryRefcount(JITCodeEntry* entry, uintptr_t code_address) { + DCHECK(entry != nullptr); + DCHECK(g_jit_code_entries[code_address] == entry); + if (--entry->ref_count == 0) { + DeleteJITCodeEntry(entry); + } + g_jit_code_entries.erase(code_address); } -// Mapping from address to entry. It takes ownership of the entries -// so that the user of the JIT interface does not have to store them. -static std::unordered_map<uintptr_t, JITCodeEntry*> g_jit_code_entries; - -void CreateJITCodeEntryForAddress(uintptr_t address, std::vector<uint8_t> symfile) { - Thread* self = Thread::Current(); - MutexLock mu(self, g_jit_debug_mutex); - DCHECK_NE(address, 0u); - DCHECK(g_jit_code_entries.find(address) == g_jit_code_entries.end()); - JITCodeEntry* entry = CreateJITCodeEntryInternal(std::move(symfile)); - g_jit_code_entries.emplace(address, entry); +JITCodeEntry* GetJITCodeEntry(uintptr_t code_address) { + auto it = g_jit_code_entries.find(code_address); + return it == g_jit_code_entries.end() ? nullptr : it->second; } -bool DeleteJITCodeEntryForAddress(uintptr_t address) { - Thread* self = Thread::Current(); - MutexLock mu(self, g_jit_debug_mutex); - const auto it = g_jit_code_entries.find(address); - if (it == g_jit_code_entries.end()) { - return false; - } - DeleteJITCodeEntryInternal(it->second); - g_jit_code_entries.erase(it); - return true; +size_t GetJITCodeEntryMemUsage() { + return g_jit_debug_mem_usage + g_jit_code_entries.size() * 2 * sizeof(void*); } } // namespace art diff --git a/runtime/jit/debugger_interface.h b/runtime/jit/debugger_interface.h index d9bf331aab..9aec988f67 100644 --- a/runtime/jit/debugger_interface.h +++ b/runtime/jit/debugger_interface.h @@ -21,28 +21,45 @@ #include <memory> #include <vector> +#include "base/array_ref.h" +#include "base/mutex.h" + namespace art { extern "C" { struct JITCodeEntry; } +extern Mutex g_jit_debug_mutex; + // Notify native debugger about new JITed code by passing in-memory ELF. // It takes ownership of the in-memory ELF file. -JITCodeEntry* CreateJITCodeEntry(std::vector<uint8_t> symfile); +JITCodeEntry* CreateJITCodeEntry(const std::vector<uint8_t>& symfile) + REQUIRES(g_jit_debug_mutex); // Notify native debugger that JITed code has been removed. // It also releases the associated in-memory ELF file. -void DeleteJITCodeEntry(JITCodeEntry* entry); +void DeleteJITCodeEntry(JITCodeEntry* entry) + REQUIRES(g_jit_debug_mutex); -// Notify native debugger about new JITed code by passing in-memory ELF. -// The address is used only to uniquely identify the entry. -// It takes ownership of the in-memory ELF file. -void CreateJITCodeEntryForAddress(uintptr_t address, std::vector<uint8_t> symfile); +// Helper method to track life-time of JITCodeEntry. +// It registers given code address as being described by the given entry. +void IncrementJITCodeEntryRefcount(JITCodeEntry* entry, uintptr_t code_address) + REQUIRES(g_jit_debug_mutex); -// Notify native debugger that JITed code has been removed. -// Returns false if entry for the given address was not found. -bool DeleteJITCodeEntryForAddress(uintptr_t address); +// Helper method to track life-time of JITCodeEntry. +// It de-registers given code address as being described by the given entry. +void DecrementJITCodeEntryRefcount(JITCodeEntry* entry, uintptr_t code_address) + REQUIRES(g_jit_debug_mutex); + +// Find the registered JITCodeEntry for given code address. +// There can be only one entry per address at any given time. +JITCodeEntry* GetJITCodeEntry(uintptr_t code_address) + REQUIRES(g_jit_debug_mutex); + +// Returns approximate memory used by all JITCodeEntries. +size_t GetJITCodeEntryMemUsage() + REQUIRES(g_jit_debug_mutex); } // namespace art diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index 659c55a289..e41667a5bf 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -549,7 +549,11 @@ void JitCodeCache::FreeCode(const void* code_ptr) { uintptr_t allocation = FromCodeToAllocation(code_ptr); // Notify native debugger that we are about to remove the code. // It does nothing if we are not using native debugger. - DeleteJITCodeEntryForAddress(reinterpret_cast<uintptr_t>(code_ptr)); + MutexLock mu(Thread::Current(), g_jit_debug_mutex); + JITCodeEntry* entry = GetJITCodeEntry(reinterpret_cast<uintptr_t>(code_ptr)); + if (entry != nullptr) { + DecrementJITCodeEntryRefcount(entry, reinterpret_cast<uintptr_t>(code_ptr)); + } if (OatQuickMethodHeader::FromCodePointer(code_ptr)->IsOptimized()) { FreeData(GetRootTable(code_ptr)); } // else this is a JNI stub without any data. |