summaryrefslogtreecommitdiff
path: root/runtime/jit/debugger_interface.cc
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/jit/debugger_interface.cc')
-rw-r--r--runtime/jit/debugger_interface.cc61
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() {