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.