diff options
Diffstat (limited to 'runtime/jit/debugger_interface.cc')
-rw-r--r-- | runtime/jit/debugger_interface.cc | 61 |
1 files changed, 52 insertions, 9 deletions
diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc index cecf533a7d..0efa4d2cdd 100644 --- a/runtime/jit/debugger_interface.cc +++ b/runtime/jit/debugger_interface.cc @@ -101,7 +101,14 @@ static Mutex g_dex_debug_lock("DEX native debug entries", kNativeDebugInterfaceL // Some writes are synchronized so libunwindstack can read the memory safely from another process. constexpr std::memory_order kNonRacingRelaxed = std::memory_order_relaxed; +// Size of JIT code range covered by each packed JITCodeEntry. +constexpr uint32_t kJitRepackGroupSize = 64 * KB; + +// Automatically call the repack method every 'n' new entries. +constexpr uint32_t kJitRepackFrequency = 64; + // Public binary interface between ART and native tools (gdb, libunwind, etc). +// The fields below need to be exported and have special names as per the gdb api. extern "C" { enum JITAction { JIT_NOACTION = 0, @@ -191,6 +198,18 @@ extern "C" { JITDescriptor __dex_debug_descriptor GUARDED_BY(g_dex_debug_lock) {}; } +// The fields below are internal, but we keep them here anyway for consistency. +// Their state is related to the static state above and it must be kept in sync. + +// Used only in debug builds to check that we are not adding duplicate entries. +static std::unordered_set<const void*> g_dcheck_all_jit_functions GUARDED_BY(g_jit_debug_lock); + +// Methods that have been marked for deletion on the next repack pass. +static std::vector<const void*> g_removed_jit_functions GUARDED_BY(g_jit_debug_lock); + +// Number of small (single symbol) ELF files. Used to trigger repacking. +static uint32_t g_jit_num_unpacked_entries = 0; + struct DexNativeInfo { static constexpr bool kCopySymfileData = false; // Just reference DEX files. static JITDescriptor& Descriptor() { return __dex_debug_descriptor; } @@ -459,13 +478,6 @@ void NativeDebugInfoPostFork() { descriptor.free_entries_ = nullptr; // Don't reuse zygote's entries. } -// Size of JIT code range covered by each packed JITCodeEntry. -static constexpr uint32_t kJitRepackGroupSize = 64 * KB; - -// Automatically call the repack method every 'n' new entries. -static constexpr uint32_t kJitRepackFrequency = 64; -static uint32_t g_jit_num_unpacked_entries = 0; - // Split the JIT code cache into groups of fixed size and create single JITCodeEntry for each group. // The start address of method's code determines which group it belongs to. The end is irrelevant. // New mini debug infos will be merged if possible, and entries for GCed functions will be removed. @@ -549,11 +561,23 @@ static void RepackEntries(bool compress_entries, ArrayRef<const void*> removed) g_jit_num_unpacked_entries = 0; } +void RepackNativeDebugInfoForJitLocked() REQUIRES(g_jit_debug_lock); + void AddNativeDebugInfoForJit(const void* code_ptr, const std::vector<uint8_t>& symfile, bool allow_packing) { MutexLock mu(Thread::Current(), g_jit_debug_lock); DCHECK_NE(symfile.size(), 0u); + if (kIsDebugBuild && code_ptr != nullptr) { + DCHECK(g_dcheck_all_jit_functions.insert(code_ptr).second) << code_ptr << " already added"; + } + + // Remove all methods which have been marked for removal. The JIT GC should + // force repack, so this should happen only rarely for various corner cases. + // Must be done before addition in case the added code_ptr is in the removed set. + if (!g_removed_jit_functions.empty()) { + RepackNativeDebugInfoForJitLocked(); + } CreateJITCodeEntryInternal<JitNativeInfo>(ArrayRef<const uint8_t>(symfile), /*addr=*/ code_ptr, @@ -575,9 +599,20 @@ void AddNativeDebugInfoForJit(const void* code_ptr, } } -void RemoveNativeDebugInfoForJit(ArrayRef<const void*> removed) { +void RemoveNativeDebugInfoForJit(const void* code_ptr) { MutexLock mu(Thread::Current(), g_jit_debug_lock); - RepackEntries(/*compress_entries=*/ true, removed); + g_dcheck_all_jit_functions.erase(code_ptr); + + // Method removal is very expensive since we need to decompress and read ELF files. + // Collet methods to be removed and do the removal in bulk later. + g_removed_jit_functions.push_back(code_ptr); +} + +void RepackNativeDebugInfoForJitLocked() { + // Remove entries which are inside packed and compressed ELF files. + std::vector<const void*>& removed = g_removed_jit_functions; + std::sort(removed.begin(), removed.end()); + RepackEntries(/*compress_entries=*/ true, ArrayRef<const void*>(removed)); // Remove entries which are not allowed to be packed (containing single method each). for (const JITCodeEntry* it = __jit_debug_descriptor.head_; it != nullptr;) { @@ -587,6 +622,14 @@ void RemoveNativeDebugInfoForJit(ArrayRef<const void*> removed) { } it = next; } + + removed.clear(); + removed.shrink_to_fit(); +} + +void RepackNativeDebugInfoForJit() { + MutexLock mu(Thread::Current(), g_jit_debug_lock); + RepackNativeDebugInfoForJitLocked(); } size_t GetJitMiniDebugInfoMemUsage() { |