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