diff options
| -rw-r--r-- | compiler/jit/jit_compiler.cc | 4 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 5 | ||||
| -rw-r--r-- | runtime/Android.bp | 5 | ||||
| -rw-r--r-- | runtime/base/mutex.cc | 8 | ||||
| -rw-r--r-- | runtime/base/mutex.h | 2 | ||||
| -rw-r--r-- | runtime/class_linker.cc | 3 | ||||
| -rw-r--r-- | runtime/elf_file_impl.h | 4 | ||||
| -rw-r--r-- | runtime/jit/debugger_interface.cc | 278 | ||||
| -rw-r--r-- | runtime/jit/debugger_interface.h | 41 | ||||
| -rw-r--r-- | runtime/jit/jit_code_cache.cc | 7 | ||||
| -rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 3 |
11 files changed, 191 insertions, 169 deletions
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc index 17b94d3bdf..ac5c6fb01f 100644 --- a/compiler/jit/jit_compiler.cc +++ b/compiler/jit/jit_compiler.cc @@ -77,7 +77,9 @@ extern "C" void jit_types_loaded(void* handle, mirror::Class** types, size_t cou std::vector<uint8_t> elf_file = debug::WriteDebugElfFileForClasses( kRuntimeISA, jit_compiler->GetCompilerDriver()->GetInstructionSetFeatures(), types_array); MutexLock mu(Thread::Current(), *Locks::native_debug_interface_lock_); - CreateJITCodeEntry(std::move(elf_file)); + // We never free debug info for types, so we don't need to provide a handle + // (which would have been otherwise used as identifier to remove it later). + AddNativeDebugInfoForJit(nullptr /* handle */, elf_file); } } diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index b3f23a0dcd..e42dfc10ba 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -1411,13 +1411,12 @@ void OptimizingCompiler::GenerateJitDebugInfo(ArtMethod* method, debug::MethodDe mini_debug_info, ArrayRef<const debug::MethodDebugInfo>(&info, 1)); MutexLock mu(Thread::Current(), *Locks::native_debug_interface_lock_); - JITCodeEntry* entry = CreateJITCodeEntry(elf_file); - IncrementJITCodeEntryRefcount(entry, info.code_address); + AddNativeDebugInfoForJit(reinterpret_cast<const void*>(info.code_address), elf_file); VLOG(jit) << "JIT mini-debug-info added for " << ArtMethod::PrettyMethod(method) << " size=" << PrettySize(elf_file.size()) - << " total_size=" << PrettySize(GetJITCodeEntryMemUsage()); + << " total_size=" << PrettySize(GetJitNativeDebugInfoMemUsage()); } } // namespace art diff --git a/runtime/Android.bp b/runtime/Android.bp index 27025d1969..46e0ee405e 100644 --- a/runtime/Android.bp +++ b/runtime/Android.bp @@ -18,7 +18,10 @@ // we use gold as the linker (arm, x86, x86_64). The symbol is used by the debuggers to detect when // new jit code is generated. We don't want it to be called when a different function with the same // (empty) body is called. -JIT_DEBUG_REGISTER_CODE_LDFLAGS = ["-Wl,--keep-unique,__jit_debug_register_code"] +JIT_DEBUG_REGISTER_CODE_LDFLAGS = [ + "-Wl,--keep-unique,__jit_debug_register_code", + "-Wl,--keep-unique,__dex_debug_register_code" +] cc_defaults { name: "libart_defaults", diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc index a4c32dd814..8a24daacb3 100644 --- a/runtime/base/mutex.cc +++ b/runtime/base/mutex.cc @@ -1218,6 +1218,10 @@ void Locks::Init() { DCHECK(jni_function_table_lock_ == nullptr); jni_function_table_lock_ = new Mutex("JNI function table lock", current_lock_level); + UPDATE_CURRENT_LOCK_LEVEL(kNativeDebugInterfaceLock); + DCHECK(native_debug_interface_lock_ == nullptr); + native_debug_interface_lock_ = new Mutex("Native debug interface lock", current_lock_level); + UPDATE_CURRENT_LOCK_LEVEL(kAbortLock); DCHECK(abort_lock_ == nullptr); abort_lock_ = new Mutex("abort lock", current_lock_level, true); @@ -1230,10 +1234,6 @@ void Locks::Init() { DCHECK(unexpected_signal_lock_ == nullptr); unexpected_signal_lock_ = new Mutex("unexpected signal lock", current_lock_level, true); - UPDATE_CURRENT_LOCK_LEVEL(kNativeDebugInterfaceLock); - DCHECK(native_debug_interface_lock_ == nullptr); - native_debug_interface_lock_ = new Mutex("Native debug interface lock", current_lock_level); - UPDATE_CURRENT_LOCK_LEVEL(kLoggingLock); DCHECK(logging_lock_ == nullptr); logging_lock_ = new Mutex("logging lock", current_lock_level, true); diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h index bf27b7f17c..4f7001a101 100644 --- a/runtime/base/mutex.h +++ b/runtime/base/mutex.h @@ -58,11 +58,11 @@ class Thread; // [1] http://www.drdobbs.com/parallel/use-lock-hierarchies-to-avoid-deadlock/204801163 enum LockLevel { kLoggingLock = 0, - kNativeDebugInterfaceLock, kSwapMutexesLock, kUnexpectedSignalLock, kThreadSuspendCountLock, kAbortLock, + kNativeDebugInterfaceLock, kSignalHandlingLock, kJdwpAdbStateLock, kJdwpSocketLock, diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index ad2e7a77dd..856e538ad6 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3434,7 +3434,8 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, data.weak_root = dex_cache_jweak; data.dex_file = dex_cache->GetDexFile(); data.class_table = ClassTableForClassLoader(class_loader); - RegisterDexFileForNative(self, data.dex_file->Begin()); + AddNativeDebugInfoForDex(self, ArrayRef<const uint8_t>(data.dex_file->Begin(), + data.dex_file->Size())); DCHECK(data.class_table != nullptr); // Make sure to hold the dex cache live in the class table. This case happens for the boot class // path dex caches without an image. diff --git a/runtime/elf_file_impl.h b/runtime/elf_file_impl.h index 04c224387b..3143df537f 100644 --- a/runtime/elf_file_impl.h +++ b/runtime/elf_file_impl.h @@ -28,10 +28,6 @@ namespace art { -extern "C" { - struct JITCodeEntry; -} - template <typename ElfTypes> class ElfFileImpl { public: diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc index d60f70a54f..505e626f67 100644 --- a/runtime/jit/debugger_interface.cc +++ b/runtime/jit/debugger_interface.cc @@ -18,18 +18,35 @@ #include <android-base/logging.h> +#include "base/array_ref.h" #include "base/mutex.h" +#include "base/time_utils.h" #include "thread-current-inl.h" #include "thread.h" #include <unordered_map> -namespace art { +// +// Debug interface for native tools (gdb, lldb, libunwind, simpleperf). +// +// See http://sourceware.org/gdb/onlinedocs/gdb/Declarations.html +// +// There are two ways for native tools to access the debug data safely: +// +// 1) Synchronously, by setting a breakpoint in the __*_debug_register_code +// method, which is called after every modification of the linked list. +// GDB does this, but it is complex to set up and it stops the process. +// +// 2) Asynchronously, by monitoring the action_counter_, which is incremented +// on every modification of the linked list and kept at -1 during updates. +// Therefore, if the tool process reads the counter both before and after +// iterating over the linked list, and the counters match and are not -1, +// the tool process can be sure the list was not modified during the read. +// Obviously, it can also cache the data and use the counter to determine +// if the cache is up to date, or to intelligently update it if needed. +// -// ------------------------------------------------------------------- -// Binary GDB JIT Interface as described in -// http://sourceware.org/gdb/onlinedocs/gdb/Declarations.html -// ------------------------------------------------------------------- +namespace art { extern "C" { typedef enum { JIT_NOACTION = 0, @@ -40,168 +57,193 @@ extern "C" { struct JITCodeEntry { JITCodeEntry* next_; JITCodeEntry* prev_; - const uint8_t *symfile_addr_; - uint64_t symfile_size_; - uint32_t ref_count; // ART internal field. + const uint8_t* symfile_addr_; + uint64_t symfile_size_; // Beware of the offset (12 on x86; but 16 on ARM32). + + // Android-specific fields: + uint64_t register_timestamp_; // CLOCK_MONOTONIC time of entry registration. }; struct JITDescriptor { - uint32_t version_; - uint32_t action_flag_; - JITCodeEntry* relevant_entry_; - JITCodeEntry* first_entry_; + uint32_t version_ = 1; // NB: GDB supports only version 1. + uint32_t action_flag_ = JIT_NOACTION; // One of the JITAction enum values. + JITCodeEntry* relevant_entry_ = nullptr; // The entry affected by the action. + JITCodeEntry* first_entry_ = nullptr; // Head of link list of all entries. + + // Android-specific fields: + uint8_t magic_[8] = {'A', 'n', 'd', 'r', 'o', 'i', 'd', '1'}; + uint32_t flags_ = 0; // Reserved for future use. Must be 0. + uint32_t sizeof_descriptor = sizeof(JITDescriptor); + uint32_t sizeof_entry = sizeof(JITCodeEntry); + std::atomic_int32_t action_counter_; // Number of actions, or -1 if locked. + // It can overflow from INT32_MAX to 0. + uint64_t action_timestamp_ = 1; // CLOCK_MONOTONIC time of last action. }; - // GDB will place breakpoint into this function. - // To prevent GCC from inlining or removing it we place noinline attribute - // and inline assembler statement inside. - void __attribute__((noinline)) __jit_debug_register_code(); + // Check that std::atomic_int32_t has the same layout as int32_t. + static_assert(alignof(std::atomic_int32_t) == alignof(int32_t), "Weird alignment"); + static_assert(sizeof(std::atomic_int32_t) == sizeof(int32_t), "Weird size"); + + // GDB may set breakpoint here. We must ensure it is not removed or deduplicated. void __attribute__((noinline)) __jit_debug_register_code() { __asm__(""); } - // Call __jit_debug_register_code indirectly via global variable. - // This gives the debugger an easy way to inject custom code to handle the events. + // Alternatively, native tools may overwrite this field to execute custom handler. void (*__jit_debug_register_code_ptr)() = __jit_debug_register_code; - // GDB will inspect contents of this descriptor. - // Static initialization is necessary to prevent GDB from seeing - // uninitialized descriptor. - JITDescriptor __jit_debug_descriptor = { 1, JIT_NOACTION, nullptr, nullptr }; - - // Incremented whenever __jit_debug_descriptor is modified. - uint32_t __jit_debug_descriptor_timestamp = 0; - - struct DEXFileEntry { - DEXFileEntry* next_; - DEXFileEntry* prev_; - const void* dexfile_; - }; - - DEXFileEntry* __art_debug_dexfiles = nullptr; - - // Incremented whenever __art_debug_dexfiles is modified. - uint32_t __art_debug_dexfiles_timestamp = 0; -} + // The root data structure describing of all JITed methods. + JITDescriptor __jit_debug_descriptor {}; -static size_t g_jit_debug_mem_usage - GUARDED_BY(Locks::native_debug_interface_lock_) = 0; - -static std::unordered_map<const void*, DEXFileEntry*> g_dexfile_entries - GUARDED_BY(Locks::native_debug_interface_lock_); - -void RegisterDexFileForNative(Thread* current_thread, const void* dexfile_header) { - MutexLock mu(current_thread, *Locks::native_debug_interface_lock_); - if (g_dexfile_entries.count(dexfile_header) == 0) { - DEXFileEntry* entry = new DEXFileEntry(); - CHECK(entry != nullptr); - entry->dexfile_ = dexfile_header; - entry->prev_ = nullptr; - entry->next_ = __art_debug_dexfiles; - if (entry->next_ != nullptr) { - entry->next_->prev_ = entry; - } - __art_debug_dexfiles = entry; - __art_debug_dexfiles_timestamp++; - g_dexfile_entries.emplace(dexfile_header, entry); + // The following globals mirror the ones above, but are used to register dex files. + void __attribute__((noinline)) __dex_debug_register_code() { + __asm__(""); } + void (*__dex_debug_register_code_ptr)() = __dex_debug_register_code; + JITDescriptor __dex_debug_descriptor {}; } -void DeregisterDexFileForNative(Thread* current_thread, const void* dexfile_header) { - MutexLock mu(current_thread, *Locks::native_debug_interface_lock_); - auto it = g_dexfile_entries.find(dexfile_header); - // We register dex files in the class linker and free them in DexFile_closeDexFile, - // but might be cases where we load the dex file without using it in the class linker. - if (it != g_dexfile_entries.end()) { - DEXFileEntry* entry = it->second; - if (entry->prev_ != nullptr) { - entry->prev_->next_ = entry->next_; - } else { - __art_debug_dexfiles = entry->next_; - } - if (entry->next_ != nullptr) { - entry->next_->prev_ = entry->prev_; - } - __art_debug_dexfiles_timestamp++; - delete entry; - g_dexfile_entries.erase(it); - } +// Mark the descriptor as "locked", so native tools know the data is unstable. +// Returns the old value of the counter. +static int32_t LockActionCounter(JITDescriptor& descriptor) { + return descriptor.action_counter_.exchange(-1); } -JITCodeEntry* CreateJITCodeEntry(const std::vector<uint8_t>& symfile) { - DCHECK_NE(symfile.size(), 0u); +// Mark the descriptor as "unlocked", so native tools know the data is safe to read. +// It will also increment the value so that the tools know the data has changed. +static void UnlockActionCounter(JITDescriptor& descriptor, int32_t old_value) { + int32_t new_value = (old_value + 1) & 0x7FFFFFFF; // Handle overflow to avoid -1. + descriptor.action_counter_.store(new_value); +} - // Make a copy of the buffer. We want to shrink it anyway. - uint8_t* symfile_copy = new uint8_t[symfile.size()]; - CHECK(symfile_copy != nullptr); - memcpy(symfile_copy, symfile.data(), symfile.size()); +static JITCodeEntry* CreateJITCodeEntryInternal( + JITDescriptor& descriptor, + void (*register_code_ptr)(), + const ArrayRef<const uint8_t>& symfile) + REQUIRES(Locks::native_debug_interface_lock_) { + int32_t old_action_counter = LockActionCounter(descriptor); JITCodeEntry* entry = new JITCodeEntry; CHECK(entry != nullptr); - entry->symfile_addr_ = symfile_copy; + entry->symfile_addr_ = symfile.data(); entry->symfile_size_ = symfile.size(); entry->prev_ = nullptr; - entry->ref_count = 0; - entry->next_ = __jit_debug_descriptor.first_entry_; + entry->next_ = descriptor.first_entry_; + entry->register_timestamp_ = NanoTime(); 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_descriptor_timestamp++; - (*__jit_debug_register_code_ptr)(); + descriptor.first_entry_ = entry; + descriptor.relevant_entry_ = entry; + descriptor.action_flag_ = JIT_REGISTER_FN; + descriptor.action_timestamp_ = entry->register_timestamp_; + UnlockActionCounter(descriptor, old_action_counter); + + (*register_code_ptr)(); return entry; } -void DeleteJITCodeEntry(JITCodeEntry* entry) { +static void DeleteJITCodeEntryInternal( + JITDescriptor& descriptor, + void (*register_code_ptr)(), + JITCodeEntry* entry) + REQUIRES(Locks::native_debug_interface_lock_) { + CHECK(entry != nullptr); + int32_t old_action_counter = LockActionCounter(descriptor); + if (entry->prev_ != nullptr) { entry->prev_->next_ = entry->next_; } else { - __jit_debug_descriptor.first_entry_ = entry->next_; + descriptor.first_entry_ = entry->next_; } - if (entry->next_ != nullptr) { 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_descriptor_timestamp++; - (*__jit_debug_register_code_ptr)(); - delete[] entry->symfile_addr_; + descriptor.relevant_entry_ = entry; + descriptor.action_flag_ = JIT_UNREGISTER_FN; + descriptor.action_timestamp_ = NanoTime(); + UnlockActionCounter(descriptor, old_action_counter); + + (*register_code_ptr)(); delete entry; } -// 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 +static std::unordered_map<const void*, JITCodeEntry*> __dex_debug_entries GUARDED_BY(Locks::native_debug_interface_lock_); -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 AddNativeDebugInfoForDex(Thread* current_thread, ArrayRef<const uint8_t> dexfile) { + MutexLock mu(current_thread, *Locks::native_debug_interface_lock_); + DCHECK(dexfile.data() != nullptr); + // This is just defensive check. The class linker should not register the dex file twice. + if (__dex_debug_entries.count(dexfile.data()) == 0) { + JITCodeEntry* entry = CreateJITCodeEntryInternal(__dex_debug_descriptor, + __dex_debug_register_code_ptr, + dexfile); + __dex_debug_entries.emplace(dexfile.data(), 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); +void RemoveNativeDebugInfoForDex(Thread* current_thread, ArrayRef<const uint8_t> dexfile) { + MutexLock mu(current_thread, *Locks::native_debug_interface_lock_); + auto it = __dex_debug_entries.find(dexfile.data()); + // We register dex files in the class linker and free them in DexFile_closeDexFile, but + // there might be cases where we load the dex file without using it in the class linker. + if (it != __dex_debug_entries.end()) { + DeleteJITCodeEntryInternal(__dex_debug_descriptor, + __dex_debug_register_code_ptr, + it->second); + __dex_debug_entries.erase(it); } - g_jit_code_entries.erase(code_address); } -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; +static size_t __jit_debug_mem_usage + GUARDED_BY(Locks::native_debug_interface_lock_) = 0; + +// Mapping from handle to entry. Used to manage life-time of the entries. +static std::unordered_map<const void*, JITCodeEntry*> __jit_debug_entries + GUARDED_BY(Locks::native_debug_interface_lock_); + +void AddNativeDebugInfoForJit(const void* handle, const std::vector<uint8_t>& symfile) { + DCHECK_NE(symfile.size(), 0u); + + // Make a copy of the buffer to shrink it and to pass ownership to JITCodeEntry. + uint8_t* copy = new uint8_t[symfile.size()]; + CHECK(copy != nullptr); + memcpy(copy, symfile.data(), symfile.size()); + + JITCodeEntry* entry = CreateJITCodeEntryInternal( + __jit_debug_descriptor, + __jit_debug_register_code_ptr, + ArrayRef<const uint8_t>(copy, symfile.size())); + __jit_debug_mem_usage += sizeof(JITCodeEntry) + entry->symfile_size_; + + // We don't provide handle for type debug info, which means we cannot free it later. + // (this only happens when --generate-debug-info flag is enabled for the purpose + // of being debugged with gdb; it does not happen for debuggable apps by default). + bool ok = handle == nullptr || __jit_debug_entries.emplace(handle, entry).second; + DCHECK(ok) << "Native debug entry already exists for " << std::hex << handle; +} + +void RemoveNativeDebugInfoForJit(const void* handle) { + auto it = __jit_debug_entries.find(handle); + // We generate JIT native debug info only if the right runtime flags are enabled, + // but we try to remove it unconditionally whenever code is freed from JIT cache. + if (it != __jit_debug_entries.end()) { + JITCodeEntry* entry = it->second; + const uint8_t* symfile_addr = entry->symfile_addr_; + uint64_t symfile_size = entry->symfile_size_; + DeleteJITCodeEntryInternal(__jit_debug_descriptor, + __jit_debug_register_code_ptr, + entry); + __jit_debug_entries.erase(it); + __jit_debug_mem_usage -= sizeof(JITCodeEntry) + symfile_size; + delete[] symfile_addr; + } } -size_t GetJITCodeEntryMemUsage() { - return g_jit_debug_mem_usage + g_jit_code_entries.size() * 2 * sizeof(void*); +size_t GetJitNativeDebugInfoMemUsage() { + return __jit_debug_mem_usage + __jit_debug_entries.size() * 2 * sizeof(void*); } } // namespace art diff --git a/runtime/jit/debugger_interface.h b/runtime/jit/debugger_interface.h index 8c4bb3fdf4..3d25910f26 100644 --- a/runtime/jit/debugger_interface.h +++ b/runtime/jit/debugger_interface.h @@ -26,45 +26,26 @@ namespace art { -extern "C" { - struct JITCodeEntry; -} - // Notify native tools (e.g. libunwind) that DEX file has been opened. -// The pointer needs to point the start of the dex data (not the DexFile* object). -void RegisterDexFileForNative(Thread* current_thread, const void* dexfile_header); +// It takes the lock itself. The parameter must point to dex data (not the DexFile* object). +void AddNativeDebugInfoForDex(Thread* current_thread, ArrayRef<const uint8_t> dexfile); // Notify native tools (e.g. libunwind) that DEX file has been closed. -// The pointer needs to point the start of the dex data (not the DexFile* object). -void DeregisterDexFileForNative(Thread* current_thread, const void* dexfile_header); - -// Notify native debugger about new JITed code by passing in-memory ELF. -// It takes ownership of the in-memory ELF file. -JITCodeEntry* CreateJITCodeEntry(const std::vector<uint8_t>& symfile) - REQUIRES(Locks::native_debug_interface_lock_); - -// Notify native debugger that JITed code has been removed. -// It also releases the associated in-memory ELF file. -void DeleteJITCodeEntry(JITCodeEntry* entry) - REQUIRES(Locks::native_debug_interface_lock_); - -// 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(Locks::native_debug_interface_lock_); +// It takes the lock itself. The parameter must point to dex data (not the DexFile* object). +void RemoveNativeDebugInfoForDex(Thread* current_thread, ArrayRef<const uint8_t> dexfile); -// 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) +// Notify native tools about new JITed code by passing in-memory ELF. +// The handle is the object that is being described (needed to be able to remove the entry). +// The method will make copy of the passed ELF file (to shrink it to the minimum size). +void AddNativeDebugInfoForJit(const void* handle, const std::vector<uint8_t>& symfile) REQUIRES(Locks::native_debug_interface_lock_); -// 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) +// Notify native debugger that JITed code has been removed and free the debug info. +void RemoveNativeDebugInfoForJit(const void* handle) REQUIRES(Locks::native_debug_interface_lock_); // Returns approximate memory used by all JITCodeEntries. -size_t GetJITCodeEntryMemUsage() +size_t GetJitNativeDebugInfoMemUsage() REQUIRES(Locks::native_debug_interface_lock_); } // namespace art diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc index c8c13cb20f..68a3647974 100644 --- a/runtime/jit/jit_code_cache.cc +++ b/runtime/jit/jit_code_cache.cc @@ -550,10 +550,7 @@ void JitCodeCache::FreeCode(const void* code_ptr) { // Notify native debugger that we are about to remove the code. // It does nothing if we are not using native debugger. MutexLock mu(Thread::Current(), *Locks::native_debug_interface_lock_); - JITCodeEntry* entry = GetJITCodeEntry(reinterpret_cast<uintptr_t>(code_ptr)); - if (entry != nullptr) { - DecrementJITCodeEntryRefcount(entry, reinterpret_cast<uintptr_t>(code_ptr)); - } + RemoveNativeDebugInfoForJit(code_ptr); if (OatQuickMethodHeader::FromCodePointer(code_ptr)->IsOptimized()) { FreeData(GetRootTable(code_ptr)); } // else this is a JNI stub without any data. @@ -1828,7 +1825,7 @@ void JitCodeCache::Dump(std::ostream& os) { MutexLock mu2(Thread::Current(), *Locks::native_debug_interface_lock_); os << "Current JIT code cache size: " << PrettySize(used_memory_for_code_) << "\n" << "Current JIT data cache size: " << PrettySize(used_memory_for_data_) << "\n" - << "Current JIT mini-debug-info size: " << PrettySize(GetJITCodeEntryMemUsage()) << "\n" + << "Current JIT mini-debug-info size: " << PrettySize(GetJitNativeDebugInfoMemUsage()) << "\n" << "Current JIT capacity: " << PrettySize(current_capacity_) << "\n" << "Current number of JIT JNI stub entries: " << jni_stubs_map_.size() << "\n" << "Current number of JIT code cache entries: " << method_code_map_.size() << "\n" diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index dd7b34ae21..5d18b6e757 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -333,7 +333,8 @@ static jboolean DexFile_closeDexFile(JNIEnv* env, jclass, jobject cookie) { int32_t i = kDexFileIndexStart; // Oat file is at index 0. for (const DexFile* dex_file : dex_files) { if (dex_file != nullptr) { - DeregisterDexFileForNative(soa.Self(), dex_file->Begin()); + RemoveNativeDebugInfoForDex(soa.Self(), ArrayRef<const uint8_t>(dex_file->Begin(), + dex_file->Size())); // Only delete the dex file if the dex cache is not found to prevent runtime crashes if there // are calls to DexFile.close while the ART DexFile is still in use. if (!class_linker->IsDexFileRegistered(soa.Self(), *dex_file)) { |