Store zygote compiled code in a shared map.

- Store flags in the ArtMethod to know that it is compiled by the zygote
- Query the map when entering a zygote compiled method from the
interpreter.

Bug: 119800099
Test: boots
Change-Id: Ib1a38266573e28d371034d02d6bb83f9b8b2e317
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index 88b440b..20b74d6 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -25,6 +25,7 @@
 #include <vector>
 
 #include "base/arena_containers.h"
+#include "base/array_ref.h"
 #include "base/atomic.h"
 #include "base/histogram.h"
 #include "base/macros.h"
@@ -78,6 +79,51 @@
 // of garbage collecting code.
 using CodeCacheBitmap = gc::accounting::MemoryRangeBitmap<kJitCodeAccountingBytes>;
 
+// Class abstraction over a map of ArtMethod -> compiled code, where the
+// ArtMethod are compiled by the zygote, and the map acts as a communication
+// channel between the zygote and the other processes.
+// For the zygote process, this map is the only map it is placing the compiled
+// code. JitCodeCache.method_code_map_ is empty.
+//
+// This map is writable only by the zygote, and readable by all children.
+class ZygoteMap {
+ public:
+  explicit ZygoteMap(JitMemoryRegion* region) : map_(), region_(region) {}
+
+  // Initialize the data structure so it can hold `number_of_methods` mappings.
+  // Note that the map is fixed size and never grows.
+  void Initialize(uint32_t number_of_methods) REQUIRES(!Locks::jit_lock_);
+
+  // Add the mapping method -> code.
+  void Put(const void* code, ArtMethod* method) REQUIRES(Locks::jit_lock_);
+
+  // Return the code pointer for the given method. If pc is not zero, check that
+  // the pc falls into that code range. Return null otherwise.
+  const void* GetCodeFor(ArtMethod* method, uintptr_t pc = 0) const;
+
+  // Return whether the map has associated code for the given method.
+  bool ContainsMethod(ArtMethod* method) const {
+    return GetCodeFor(method) != nullptr;
+  }
+
+ private:
+  struct Entry {
+    ArtMethod* method;
+    // Note we currently only allocate code in the low 4g, so we could just reserve 4 bytes
+    // for the code pointer. For simplicity and in the case we move to 64bit
+    // addresses for code, just keep it void* for now.
+    const void* code_ptr;
+  };
+
+  // The map allocated with `region_`.
+  ArrayRef<Entry> map_;
+
+  // The region in which the map is allocated.
+  JitMemoryRegion* const region_;
+
+  DISALLOW_COPY_AND_ASSIGN(ZygoteMap);
+};
+
 class JitCodeCache {
  public:
   static constexpr size_t kMaxCapacity = 64 * MB;
@@ -260,6 +306,9 @@
   bool GetGarbageCollectCodeUnsafe() const NO_THREAD_SAFETY_ANALYSIS {
     return garbage_collect_code_;
   }
+  ZygoteMap* GetZygoteMap() {
+    return &zygote_map_;
+  }
 
   // If Jit-gc has been disabled (and instrumentation has been enabled) this will return the
   // jit-compiled entrypoint for this method.  Otherwise it will return null.
@@ -423,6 +472,10 @@
   // ProfilingInfo objects we have allocated.
   std::vector<ProfilingInfo*> profiling_infos_ GUARDED_BY(Locks::jit_lock_);
 
+  // Methods that the zygote has compiled and can be shared across processes
+  // forked from the zygote.
+  ZygoteMap zygote_map_;
+
   // -------------- JIT GC related data structures ----------------------- //
 
   // Condition to wait on during collection.