JIT mini-debug-info: Allocate entries in the JIT data space.
Test: test.py -b --host --jit
Test: device boots
Bug: 119800099
Change-Id: I7efa1e6e6660239cbd6438b829e08dd9cd079343
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index f01554a..0bdab0b 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -123,8 +123,7 @@
return jit_compiler;
}
-void JitCompiler::TypesLoaded(mirror::Class** types, size_t count)
- REQUIRES_SHARED(Locks::mutator_lock_) {
+void JitCompiler::TypesLoaded(mirror::Class** types, size_t count) {
const CompilerOptions& compiler_options = GetCompilerOptions();
if (compiler_options.GetGenerateDebugInfo()) {
InstructionSet isa = compiler_options.GetInstructionSet();
@@ -134,6 +133,7 @@
debug::WriteDebugElfFileForClasses(isa, features, types_array);
// NB: Don't allow packing since it would remove non-backtrace data.
+ MutexLock mu(Thread::Current(), *Locks::jit_lock_);
AddNativeDebugInfoForJit(/*code_ptr=*/ nullptr, elf_file, /*allow_packing=*/ false);
}
}
diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc
index 5d06969..8ef1b55 100644
--- a/compiler/optimizing/optimizing_compiler.cc
+++ b/compiler/optimizing/optimizing_compiler.cc
@@ -1486,6 +1486,7 @@
std::vector<uint8_t> elf = debug::MakeElfFileForJIT(isa, features, mini_debug_info, info);
// NB: Don't allow packing of full info since it would remove non-backtrace data.
+ MutexLock mu(Thread::Current(), *Locks::jit_lock_);
const void* code_ptr = reinterpret_cast<const void*>(info.code_address);
AddNativeDebugInfoForJit(code_ptr, elf, /*allow_packing=*/ mini_debug_info);
}
diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc
index 3fa4c3c..f3fccbb 100644
--- a/runtime/gc/space/dlmalloc_space.cc
+++ b/runtime/gc/space/dlmalloc_space.cc
@@ -384,8 +384,8 @@
::art::gc::space::DlMallocSpace* dlmalloc_space = heap->GetDlMallocSpace();
// Support for multiple DlMalloc provided by a slow path.
if (UNLIKELY(dlmalloc_space == nullptr || dlmalloc_space->GetMspace() != mspace)) {
- if (LIKELY(runtime->GetJit() != nullptr)) {
- jit::JitCodeCache* code_cache = runtime->GetJit()->GetCodeCache();
+ if (LIKELY(runtime->GetJitCodeCache() != nullptr)) {
+ jit::JitCodeCache* code_cache = runtime->GetJitCodeCache();
if (code_cache->OwnsSpace(mspace)) {
return code_cache->MoreCore(mspace, increment);
}
diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc
index 2446a44..a33b6df 100644
--- a/runtime/jit/debugger_interface.cc
+++ b/runtime/jit/debugger_interface.cc
@@ -26,6 +26,8 @@
#include "base/utils.h"
#include "dex/dex_file.h"
#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
+#include "jit/jit_memory_region.h"
#include "runtime.h"
#include "thread-current-inl.h"
#include "thread.h"
@@ -158,6 +160,31 @@
JITDescriptor __dex_debug_descriptor GUARDED_BY(g_dex_debug_lock) {};
}
+struct DexNativeInfo {
+ static constexpr bool kCopySymfileData = false; // Just reference DEX files.
+ static JITDescriptor& Descriptor() { return __dex_debug_descriptor; }
+ static void NotifyNativeDebugger() { __dex_debug_register_code_ptr(); }
+ static void* Alloc(size_t size) { return malloc(size); }
+ static void Free(void* ptr) { free(ptr); }
+};
+
+struct JitNativeInfo {
+ static constexpr bool kCopySymfileData = true; // Copy debug info to JIT memory.
+ static JITDescriptor& Descriptor() { return __jit_debug_descriptor; }
+ static void NotifyNativeDebugger() { __jit_debug_register_code_ptr(); }
+ static void* Alloc(size_t size) { return JitMemory()->AllocateData(size); }
+ static void Free(void* ptr) { JitMemory()->FreeData(reinterpret_cast<uint8_t*>(ptr)); }
+
+ static jit::JitMemoryRegion* JitMemory() ASSERT_CAPABILITY(Locks::jit_lock_) {
+ Locks::jit_lock_->AssertHeld(Thread::Current());
+ jit::JitCodeCache* jit_code_cache = Runtime::Current()->GetJitCodeCache();
+ CHECK(jit_code_cache != nullptr);
+ jit::JitMemoryRegion* memory = jit_code_cache->GetCurrentRegion();
+ CHECK(memory->IsValid());
+ return memory;
+ }
+};
+
ArrayRef<const uint8_t> GetJITCodeEntrySymFile(JITCodeEntry* entry) {
return ArrayRef<const uint8_t>(entry->symfile_addr_, entry->symfile_size_);
}
@@ -178,18 +205,22 @@
descriptor.action_seqlock_.fetch_add(1, std::memory_order_relaxed);
}
+template<class NativeInfo>
static JITCodeEntry* CreateJITCodeEntryInternal(
- JITDescriptor& descriptor,
- void (*register_code_ptr)(),
ArrayRef<const uint8_t> symfile,
- bool copy_symfile,
const void* addr = nullptr,
bool allow_packing = false,
bool is_compressed = false) {
+ JITDescriptor& descriptor = NativeInfo::Descriptor();
+
// Make a copy of the buffer to shrink it and to pass ownership to JITCodeEntry.
- if (copy_symfile) {
- uint8_t* copy = new uint8_t[symfile.size()];
- CHECK(copy != nullptr);
+ uint8_t* copy = nullptr;
+ if (NativeInfo::kCopySymfileData) {
+ copy = reinterpret_cast<uint8_t*>(NativeInfo::Alloc(symfile.size()));
+ if (copy == nullptr) {
+ LOG(ERROR) << "Failed to allocate memory for native debug info";
+ return nullptr;
+ }
memcpy(copy, symfile.data(), symfile.size());
symfile = ArrayRef<const uint8_t>(copy, symfile.size());
}
@@ -199,8 +230,15 @@
uint64_t timestamp = std::max(descriptor.action_timestamp_ + 1, NanoTime());
JITCodeEntry* head = descriptor.head_.load(std::memory_order_relaxed);
- JITCodeEntry* entry = new JITCodeEntry();
- CHECK(entry != nullptr);
+ void* memory = NativeInfo::Alloc(sizeof(JITCodeEntry));
+ if (memory == nullptr) {
+ LOG(ERROR) << "Failed to allocate memory for native debug info";
+ if (copy != nullptr) {
+ NativeInfo::Free(copy);
+ }
+ return nullptr;
+ }
+ JITCodeEntry* entry = new (memory) JITCodeEntry();
entry->symfile_addr_ = symfile.data();
entry->symfile_size_ = symfile.size();
entry->prev_ = nullptr;
@@ -221,17 +259,16 @@
descriptor.action_timestamp_ = timestamp;
ActionSequnlock(descriptor);
- (*register_code_ptr)();
+ NativeInfo::NotifyNativeDebugger();
+
return entry;
}
-static void DeleteJITCodeEntryInternal(
- JITDescriptor& descriptor,
- void (*register_code_ptr)(),
- JITCodeEntry* entry,
- bool free_symfile) {
+template<class NativeInfo>
+static void DeleteJITCodeEntryInternal(JITCodeEntry* entry) {
CHECK(entry != nullptr);
const uint8_t* symfile = entry->symfile_addr_;
+ JITDescriptor& descriptor = NativeInfo::Descriptor();
// Ensure the timestamp is monotonically increasing even in presence of low
// granularity system timer. This ensures each entry has unique timestamp.
@@ -253,7 +290,7 @@
descriptor.action_timestamp_ = timestamp;
ActionSequnlock(descriptor);
- (*register_code_ptr)();
+ NativeInfo::NotifyNativeDebugger();
// Ensure that clear below can not be reordered above the unlock above.
std::atomic_thread_fence(std::memory_order_release);
@@ -261,9 +298,9 @@
// Aggressively clear the entry as an extra check of the synchronisation.
memset(entry, 0, sizeof(*entry));
- delete entry;
- if (free_symfile) {
- delete[] symfile;
+ NativeInfo::Free(entry);
+ if (NativeInfo::kCopySymfileData) {
+ NativeInfo::Free(const_cast<uint8_t*>(symfile));
}
}
@@ -271,10 +308,7 @@
MutexLock mu(self, g_dex_debug_lock);
DCHECK(dexfile != nullptr);
const ArrayRef<const uint8_t> symfile(dexfile->Begin(), dexfile->Size());
- CreateJITCodeEntryInternal(__dex_debug_descriptor,
- __dex_debug_register_code_ptr,
- symfile,
- /*copy_symfile=*/ false);
+ CreateJITCodeEntryInternal<DexNativeInfo>(symfile);
}
void RemoveNativeDebugInfoForDex(Thread* self, const DexFile* dexfile) {
@@ -286,10 +320,7 @@
for (JITCodeEntry* entry = __dex_debug_descriptor.head_; entry != nullptr; ) {
JITCodeEntry* next = entry->next_; // Save next pointer before we free the memory.
if (entry->symfile_addr_ == dexfile->Begin()) {
- DeleteJITCodeEntryInternal(__dex_debug_descriptor,
- __dex_debug_register_code_ptr,
- entry,
- /*free_symfile=*/ false);
+ DeleteJITCodeEntryInternal<DexNativeInfo>(entry);
}
entry = next;
}
@@ -365,19 +396,12 @@
<< " size=" << packed.size() << (compress ? "(lzma)" : "");
// Replace the old entries with the new one (with their lifetime temporally overlapping).
- CreateJITCodeEntryInternal(
- __jit_debug_descriptor,
- __jit_debug_register_code_ptr,
- ArrayRef<const uint8_t>(packed),
- /*copy_symfile=*/ true,
- /*addr_=*/ group_ptr,
- /*allow_packing_=*/ true,
- /*is_compressed_=*/ compress);
+ CreateJITCodeEntryInternal<JitNativeInfo>(ArrayRef<const uint8_t>(packed),
+ /*addr_=*/ group_ptr,
+ /*allow_packing_=*/ true,
+ /*is_compressed_=*/ compress);
for (auto it : elfs) {
- DeleteJITCodeEntryInternal(__jit_debug_descriptor,
- __jit_debug_register_code_ptr,
- /*entry=*/ it,
- /*free_symfile=*/ true);
+ DeleteJITCodeEntryInternal<JitNativeInfo>(/*entry=*/ it);
}
group_it = end; // Go to next group.
}
@@ -390,14 +414,14 @@
MutexLock mu(Thread::Current(), g_jit_debug_lock);
DCHECK_NE(symfile.size(), 0u);
- CreateJITCodeEntryInternal(
- __jit_debug_descriptor,
- __jit_debug_register_code_ptr,
- ArrayRef<const uint8_t>(symfile),
- /*copy_symfile=*/ true,
- /*addr=*/ code_ptr,
- /*allow_packing=*/ allow_packing,
- /*is_compressed=*/ false);
+ if (Runtime::Current()->IsZygote()) {
+ return; // TODO: Implement memory sharing with the zygote process.
+ }
+
+ CreateJITCodeEntryInternal<JitNativeInfo>(ArrayRef<const uint8_t>(symfile),
+ /*addr=*/ code_ptr,
+ /*allow_packing=*/ allow_packing,
+ /*is_compressed=*/ false);
VLOG(jit)
<< "JIT mini-debug-info added"
@@ -419,10 +443,7 @@
// Remove entries which are not allowed to be packed (containing single method each).
for (JITCodeEntry* it = __jit_debug_descriptor.head_; it != nullptr; it = it->next_) {
if (!it->allow_packing_ && std::binary_search(removed.begin(), removed.end(), it->addr_)) {
- DeleteJITCodeEntryInternal(__jit_debug_descriptor,
- __jit_debug_register_code_ptr,
- /*entry=*/ it,
- /*free_symfile=*/ true);
+ DeleteJITCodeEntryInternal<JitNativeInfo>(/*entry=*/ it);
}
}
}
diff --git a/runtime/jit/debugger_interface.h b/runtime/jit/debugger_interface.h
index be5e5ac..55a9137 100644
--- a/runtime/jit/debugger_interface.h
+++ b/runtime/jit/debugger_interface.h
@@ -46,10 +46,12 @@
// (however, this drops all ELF sections other than symbols names and unwinding info).
void AddNativeDebugInfoForJit(const void* code_ptr,
const std::vector<uint8_t>& symfile,
- bool allow_packing);
+ bool allow_packing)
+ REQUIRES_SHARED(Locks::jit_lock_); // Might need JIT code cache to allocate memory.
// Notify native tools (e.g. libunwind) that JIT code has been garbage collected.
-void RemoveNativeDebugInfoForJit(ArrayRef<const void*> removed_code_ptrs);
+void RemoveNativeDebugInfoForJit(ArrayRef<const void*> removed_code_ptrs)
+ REQUIRES_SHARED(Locks::jit_lock_); // Might need JIT code cache to allocate memory.
// Returns approximate memory used by debug info for JIT code.
size_t GetJitMiniDebugInfoMemUsage();
diff --git a/runtime/runtime.h b/runtime/runtime.h
index ea516cd..6735216 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -484,6 +484,10 @@
return jit_.get();
}
+ jit::JitCodeCache* GetJitCodeCache() const {
+ return jit_code_cache_.get();
+ }
+
// Returns true if JIT compilations are enabled. GetJit() will be not null in this case.
bool UseJitCompilation() const;