Skip to content

Commit

Permalink
JIT mini-debug-info: Allocate entries in the JIT data space.
Browse files Browse the repository at this point in the history
Test: test.py -b --host --jit
Test: device boots
Bug: 119800099
Change-Id: I7efa1e6e6660239cbd6438b829e08dd9cd079343
  • Loading branch information
dsrbecky committed Aug 22, 2019
1 parent 29e740f commit 9ac8e43
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 56 deletions.
4 changes: 2 additions & 2 deletions compiler/jit/jit_compiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,7 @@ extern "C" JitCompilerInterface* jit_load() {
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();
Expand All @@ -134,6 +133,7 @@ void JitCompiler::TypesLoaded(mirror::Class** types, size_t count)
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);
}
}
Expand Down
1 change: 1 addition & 0 deletions compiler/optimizing/optimizing_compiler.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1486,6 +1486,7 @@ void OptimizingCompiler::GenerateJitDebugInfo(ArtMethod* method ATTRIBUTE_UNUSED
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);
}
Expand Down
4 changes: 2 additions & 2 deletions runtime/gc/space/dlmalloc_space.cc
Original file line number Diff line number Diff line change
Expand Up @@ -384,8 +384,8 @@ void* ArtDlMallocMoreCore(void* mspace, intptr_t increment) REQUIRES_SHARED(Lock
::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);
}
Expand Down
121 changes: 71 additions & 50 deletions runtime/jit/debugger_interface.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -158,6 +160,31 @@ extern "C" {
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_);
}
Expand All @@ -178,18 +205,22 @@ static void ActionSequnlock(JITDescriptor& descriptor) {
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());
}
Expand All @@ -199,8 +230,15 @@ static JITCodeEntry* CreateJITCodeEntryInternal(
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;
Expand All @@ -221,17 +259,16 @@ static JITCodeEntry* CreateJITCodeEntryInternal(
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.
Expand All @@ -253,28 +290,25 @@ static void DeleteJITCodeEntryInternal(
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);

// 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));
}
}

void AddNativeDebugInfoForDex(Thread* self, const DexFile* dexfile) {
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) {
Expand All @@ -286,10 +320,7 @@ void RemoveNativeDebugInfoForDex(Thread* self, const DexFile* dexfile) {
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;
}
Expand Down Expand Up @@ -365,19 +396,12 @@ static void RepackEntries(bool compress, ArrayRef<const void*> removed)
<< " 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.
}
Expand All @@ -390,14 +414,14 @@ void AddNativeDebugInfoForJit(const void* code_ptr,
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"
Expand All @@ -419,10 +443,7 @@ void RemoveNativeDebugInfoForJit(ArrayRef<const void*> removed) {
// 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);
}
}
}
Expand Down
6 changes: 4 additions & 2 deletions runtime/jit/debugger_interface.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,12 @@ void RemoveNativeDebugInfoForDex(Thread* self, const DexFile* dexfile);
// (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();
Expand Down
4 changes: 4 additions & 0 deletions runtime/runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,10 @@ class Runtime {
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;

Expand Down

0 comments on commit 9ac8e43

Please sign in to comment.