JIT mini-debug-info: Support JIT data dual mapping.
Ensure that we can add/remove mini-debug-info if the JIT data is
read-only and we need to use the other mapping for writes.
Pointers into the read-only memory are marked as "const".
Test: "test.py -b --host --jit" with data dual mapping
Test: device boots with data dual mapping
Bug: 119800099
Change-Id: I9399cffbe5ae13f08f698ab1598c30f13545a767
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index cf7254b..79d1198 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -228,7 +228,7 @@
// Combine several mini-debug-info ELF files into one, while filtering some symbols.
std::vector<uint8_t> PackElfFileForJIT(
- ArrayRef<JITCodeEntry*> jit_entries,
+ ArrayRef<const JITCodeEntry*> jit_entries,
ArrayRef<const void*> removed_symbols,
bool compress,
/*out*/ size_t* num_symbols) {
@@ -260,7 +260,7 @@
using Reader = ElfDebugReader<ElfTypes>;
std::deque<Reader> readers;
- for (JITCodeEntry* it : jit_entries) {
+ for (const JITCodeEntry* it : jit_entries) {
readers.emplace_back(GetJITCodeEntrySymFile(it));
}
diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h
index ed43a0b..1ce3c6f 100644
--- a/compiler/debug/elf_debug_writer.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -57,7 +57,7 @@
const MethodDebugInfo& method_info);
std::vector<uint8_t> PackElfFileForJIT(
- ArrayRef<JITCodeEntry*> jit_entries,
+ ArrayRef<const JITCodeEntry*> jit_entries,
ArrayRef<const void*> removed_symbols,
bool compress,
/*out*/ size_t* num_symbols);
diff --git a/compiler/jit/jit_compiler.cc b/compiler/jit/jit_compiler.cc
index 0bdab0b..9af61e0 100644
--- a/compiler/jit/jit_compiler.cc
+++ b/compiler/jit/jit_compiler.cc
@@ -142,7 +142,7 @@
return GetCompilerOptions().GetGenerateDebugInfo();
}
-std::vector<uint8_t> JitCompiler::PackElfFileForJIT(ArrayRef<JITCodeEntry*> elf_files,
+std::vector<uint8_t> JitCompiler::PackElfFileForJIT(ArrayRef<const JITCodeEntry*> elf_files,
ArrayRef<const void*> removed_symbols,
bool compress,
/*out*/ size_t* num_symbols) {
diff --git a/compiler/jit/jit_compiler.h b/compiler/jit/jit_compiler.h
index c69a376..09de1f8 100644
--- a/compiler/jit/jit_compiler.h
+++ b/compiler/jit/jit_compiler.h
@@ -53,7 +53,7 @@
void TypesLoaded(mirror::Class**, size_t count) REQUIRES_SHARED(Locks::mutator_lock_) override;
- std::vector<uint8_t> PackElfFileForJIT(ArrayRef<JITCodeEntry*> elf_files,
+ std::vector<uint8_t> PackElfFileForJIT(ArrayRef<const JITCodeEntry*> elf_files,
ArrayRef<const void*> removed_symbols,
bool compress,
/*out*/ size_t* num_symbols) override;
diff --git a/runtime/jit/debugger_interface.cc b/runtime/jit/debugger_interface.cc
index a33b6df..fd1d9a6 100644
--- a/runtime/jit/debugger_interface.cc
+++ b/runtime/jit/debugger_interface.cc
@@ -98,8 +98,8 @@
struct JITCodeEntryPublic {
// Atomic to ensure the reader can always iterate over the linked list
// (e.g. the process could crash in the middle of writing this field).
- std::atomic<JITCodeEntry*> next_;
- JITCodeEntry* prev_; // For linked list deletion. Unused in readers.
+ std::atomic<const JITCodeEntry*> next_;
+ const JITCodeEntry* prev_; // For linked list deletion. Unused in readers.
const uint8_t* symfile_addr_; // Address of the in-memory ELF file.
uint64_t symfile_size_; // Beware of the offset (12 on x86; but 16 on ARM32).
@@ -121,10 +121,10 @@
};
struct JITDescriptor {
- 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.
- std::atomic<JITCodeEntry*> head_{nullptr}; // Head of link list of all entries.
+ uint32_t version_ = 1; // NB: GDB supports only version 1.
+ uint32_t action_flag_ = JIT_NOACTION; // One of the JITAction enum values.
+ const JITCodeEntry* relevant_entry_ = nullptr; // The entry affected by the action.
+ std::atomic<const JITCodeEntry*> head_{nullptr}; // Head of link list of all entries.
// Android-specific fields:
uint8_t magic_[8] = {'A', 'n', 'd', 'r', 'o', 'i', 'd', '1'};
@@ -164,18 +164,25 @@
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); }
+ static const void* Alloc(size_t size) { return malloc(size); }
+ static void Free(const void* ptr) { free(const_cast<void*>(ptr)); }
+ template<class T> static T* Writable(const T* v) { return const_cast<T*>(v); }
};
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 const void* Alloc(size_t size) { return Memory()->AllocateData(size); }
+ static void Free(const void* ptr) {
+ Memory()->FreeData(const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(ptr)));
+ }
+ static void Free(void* ptr) = delete;
+ template<class T> static T* Writable(const T* v) {
+ return const_cast<T*>(Memory()->GetWritableDataAddress(v));
+ }
- static jit::JitMemoryRegion* JitMemory() ASSERT_CAPABILITY(Locks::jit_lock_) {
+ static jit::JitMemoryRegion* Memory() ASSERT_CAPABILITY(Locks::jit_lock_) {
Locks::jit_lock_->AssertHeld(Thread::Current());
jit::JitCodeCache* jit_code_cache = Runtime::Current()->GetJitCodeCache();
CHECK(jit_code_cache != nullptr);
@@ -185,7 +192,7 @@
}
};
-ArrayRef<const uint8_t> GetJITCodeEntrySymFile(JITCodeEntry* entry) {
+ArrayRef<const uint8_t> GetJITCodeEntrySymFile(const JITCodeEntry* entry) {
return ArrayRef<const uint8_t>(entry->symfile_addr_, entry->symfile_size_);
}
@@ -206,7 +213,7 @@
}
template<class NativeInfo>
-static JITCodeEntry* CreateJITCodeEntryInternal(
+static const JITCodeEntry* CreateJITCodeEntryInternal(
ArrayRef<const uint8_t> symfile,
const void* addr = nullptr,
bool allow_packing = false,
@@ -214,14 +221,14 @@
JITDescriptor& descriptor = NativeInfo::Descriptor();
// Make a copy of the buffer to shrink it and to pass ownership to JITCodeEntry.
- uint8_t* copy = nullptr;
+ const uint8_t* copy = nullptr;
if (NativeInfo::kCopySymfileData) {
- copy = reinterpret_cast<uint8_t*>(NativeInfo::Alloc(symfile.size()));
+ copy = reinterpret_cast<const 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());
+ memcpy(NativeInfo::Writable(copy), symfile.data(), symfile.size());
symfile = ArrayRef<const uint8_t>(copy, symfile.size());
}
@@ -229,8 +236,8 @@
// granularity system timer. This ensures each entry has unique timestamp.
uint64_t timestamp = std::max(descriptor.action_timestamp_ + 1, NanoTime());
- JITCodeEntry* head = descriptor.head_.load(std::memory_order_relaxed);
- void* memory = NativeInfo::Alloc(sizeof(JITCodeEntry));
+ const JITCodeEntry* head = descriptor.head_.load(std::memory_order_relaxed);
+ const void* memory = NativeInfo::Alloc(sizeof(JITCodeEntry));
if (memory == nullptr) {
LOG(ERROR) << "Failed to allocate memory for native debug info";
if (copy != nullptr) {
@@ -238,20 +245,21 @@
}
return nullptr;
}
- JITCodeEntry* entry = new (memory) JITCodeEntry();
- entry->symfile_addr_ = symfile.data();
- entry->symfile_size_ = symfile.size();
- entry->prev_ = nullptr;
- entry->next_.store(head, std::memory_order_relaxed);
- entry->register_timestamp_ = timestamp;
- entry->addr_ = addr;
- entry->allow_packing_ = allow_packing;
- entry->is_compressed_ = is_compressed;
+ const JITCodeEntry* entry = reinterpret_cast<const JITCodeEntry*>(memory);
+ JITCodeEntry* writable_entry = NativeInfo::Writable(entry);
+ writable_entry->symfile_addr_ = symfile.data();
+ writable_entry->symfile_size_ = symfile.size();
+ writable_entry->prev_ = nullptr;
+ writable_entry->next_.store(head, std::memory_order_relaxed);
+ writable_entry->register_timestamp_ = timestamp;
+ writable_entry->addr_ = addr;
+ writable_entry->allow_packing_ = allow_packing;
+ writable_entry->is_compressed_ = is_compressed;
// We are going to modify the linked list, so take the seqlock.
ActionSeqlock(descriptor);
if (head != nullptr) {
- head->prev_ = entry;
+ NativeInfo::Writable(head)->prev_ = entry;
}
descriptor.head_.store(entry, std::memory_order_relaxed);
descriptor.relevant_entry_ = entry;
@@ -265,7 +273,7 @@
}
template<class NativeInfo>
-static void DeleteJITCodeEntryInternal(JITCodeEntry* entry) {
+static void DeleteJITCodeEntryInternal(const JITCodeEntry* entry) {
CHECK(entry != nullptr);
const uint8_t* symfile = entry->symfile_addr_;
JITDescriptor& descriptor = NativeInfo::Descriptor();
@@ -276,14 +284,14 @@
// We are going to modify the linked list, so take the seqlock.
ActionSeqlock(descriptor);
- JITCodeEntry* next = entry->next_.load(std::memory_order_relaxed);
+ const JITCodeEntry* next = entry->next_.load(std::memory_order_relaxed);
if (entry->prev_ != nullptr) {
- entry->prev_->next_.store(next, std::memory_order_relaxed);
+ NativeInfo::Writable(entry->prev_)->next_.store(next, std::memory_order_relaxed);
} else {
descriptor.head_.store(next, std::memory_order_relaxed);
}
if (next != nullptr) {
- next->prev_ = entry->prev_;
+ NativeInfo::Writable(next)->prev_ = entry->prev_;
}
descriptor.relevant_entry_ = entry;
descriptor.action_flag_ = JIT_UNREGISTER_FN;
@@ -296,11 +304,11 @@
std::atomic_thread_fence(std::memory_order_release);
// Aggressively clear the entry as an extra check of the synchronisation.
- memset(entry, 0, sizeof(*entry));
+ memset(NativeInfo::Writable(entry), 0, sizeof(*entry));
NativeInfo::Free(entry);
if (NativeInfo::kCopySymfileData) {
- NativeInfo::Free(const_cast<uint8_t*>(symfile));
+ NativeInfo::Free(symfile);
}
}
@@ -317,8 +325,8 @@
// 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.
// On the other hand, single dex file might also be used with different class-loaders.
- for (JITCodeEntry* entry = __dex_debug_descriptor.head_; entry != nullptr; ) {
- JITCodeEntry* next = entry->next_; // Save next pointer before we free the memory.
+ for (const JITCodeEntry* entry = __dex_debug_descriptor.head_; entry != nullptr; ) {
+ const JITCodeEntry* next = entry->next_; // Save next pointer before we free the memory.
if (entry->symfile_addr_ == dexfile->Begin()) {
DeleteJITCodeEntryInternal<DexNativeInfo>(entry);
}
@@ -345,9 +353,9 @@
}
// Collect entries that we want to pack.
- std::vector<JITCodeEntry*> entries;
+ std::vector<const JITCodeEntry*> entries;
entries.reserve(2 * kJitRepackFrequency);
- for (JITCodeEntry* it = __jit_debug_descriptor.head_; it != nullptr; it = it->next_) {
+ for (const JITCodeEntry* it = __jit_debug_descriptor.head_; it != nullptr; it = it->next_) {
if (it->allow_packing_) {
if (!compress && it->is_compressed_ && removed.empty()) {
continue; // If we are not compressing, also avoid decompressing.
@@ -355,7 +363,7 @@
entries.push_back(it);
}
}
- auto cmp = [](JITCodeEntry* lhs, JITCodeEntry* rhs) { return lhs->addr_ < rhs->addr_; };
+ auto cmp = [](const JITCodeEntry* l, const JITCodeEntry* r) { return l->addr_ < r->addr_; };
std::sort(entries.begin(), entries.end(), cmp); // Sort by address.
// Process the entries in groups (each spanning memory range of size kJitRepackGroupSize).
@@ -367,7 +375,7 @@
auto begin = group_it;
auto end = std::find_if(begin, entries.end(), [=](auto* e) { return e->addr_ >= group_end; });
CHECK(end > begin);
- ArrayRef<JITCodeEntry*> elfs(&*begin, end - begin);
+ ArrayRef<const JITCodeEntry*> elfs(&*begin, end - begin);
// Find all symbols that have been removed in this memory range.
auto removed_begin = std::lower_bound(removed.begin(), removed.end(), group_ptr);
@@ -441,7 +449,7 @@
RepackEntries(/*compress=*/ true, 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_) {
+ for (const 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<JitNativeInfo>(/*entry=*/ it);
}
@@ -451,7 +459,7 @@
size_t GetJitMiniDebugInfoMemUsage() {
MutexLock mu(Thread::Current(), g_jit_debug_lock);
size_t size = 0;
- for (JITCodeEntry* it = __jit_debug_descriptor.head_; it != nullptr; it = it->next_) {
+ for (const JITCodeEntry* it = __jit_debug_descriptor.head_; it != nullptr; it = it->next_) {
size += sizeof(JITCodeEntry) + it->symfile_size_;
}
return size;
diff --git a/runtime/jit/debugger_interface.h b/runtime/jit/debugger_interface.h
index 55a9137..0bb3236 100644
--- a/runtime/jit/debugger_interface.h
+++ b/runtime/jit/debugger_interface.h
@@ -32,7 +32,7 @@
class Thread;
struct JITCodeEntry;
-ArrayRef<const uint8_t> GetJITCodeEntrySymFile(JITCodeEntry*);
+ArrayRef<const uint8_t> GetJITCodeEntrySymFile(const JITCodeEntry*);
// Notify native tools (e.g. libunwind) that DEX file has been opened.
void AddNativeDebugInfoForDex(Thread* self, const DexFile* dexfile);
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 3a103f5..13a9c7b 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -177,7 +177,7 @@
virtual bool GenerateDebugInfo() = 0;
virtual void ParseCompilerOptions() = 0;
- virtual std::vector<uint8_t> PackElfFileForJIT(ArrayRef<JITCodeEntry*> elf_files,
+ virtual std::vector<uint8_t> PackElfFileForJIT(ArrayRef<const JITCodeEntry*> elf_files,
ArrayRef<const void*> removed_symbols,
bool compress,
/*out*/ size_t* num_symbols) = 0;
diff --git a/runtime/jit/jit_memory_region.h b/runtime/jit/jit_memory_region.h
index a5e3ef3..bc05cb6 100644
--- a/runtime/jit/jit_memory_region.h
+++ b/runtime/jit/jit_memory_region.h
@@ -28,6 +28,8 @@
namespace art {
+struct JitNativeInfo;
+
namespace mirror {
class Object;
}
@@ -277,6 +279,7 @@
friend class ScopedCodeCacheWrite; // For GetUpdatableCodeMapping
friend class TestZygoteMemory;
+ friend struct art::JitNativeInfo; // For GetWritableDataAddress.
};
} // namespace jit