ART: Ensure dex caches keep classloader live
Live dex caches must keep their associated classloader live. Otherwise
the classloader may get unloaded, attempting to free DexFiles which
cannot be unregistered.
Test: art/test/testrunner/testrunner.py -b --host
Test: m test-art-host-gtest
Change-Id: I0eed5b3b46ed681c739d6923a57d0878afbba1a7
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 73b8166..3919204 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -4025,6 +4025,8 @@
// Make sure to hold the dex cache live in the class table. This case happens for the boot class
// path dex caches without an image.
data.class_table->InsertStrongRoot(dex_cache);
+ // Make sure that the dex cache holds the classloader live.
+ dex_cache->SetClassLoader(class_loader);
if (class_loader != nullptr) {
// Since we added a strong root to the class table, do the write barrier as required for
// remembered sets and generational GCs.
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 1e501a7..931f6df 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -672,6 +672,7 @@
struct DexCacheOffsets : public CheckOffsets<mirror::DexCache> {
DexCacheOffsets() : CheckOffsets<mirror::DexCache>(false, "Ljava/lang/DexCache;") {
+ addOffset(OFFSETOF_MEMBER(mirror::DexCache, class_loader_), "classLoader");
addOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_file_), "dexFile");
addOffset(OFFSETOF_MEMBER(mirror::DexCache, location_), "location");
addOffset(OFFSETOF_MEMBER(mirror::DexCache, num_preresolved_strings_), "numPreResolvedStrings");
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index 0c49b90..eab26d8 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -279,6 +279,10 @@
SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location);
}
+void DexCache::SetClassLoader(ObjPtr<ClassLoader> class_loader) {
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, class_loader_), class_loader);
+}
+
#if !defined(__aarch64__) && !defined(__x86_64__)
static pthread_mutex_t dex_cache_slow_atomic_mutex = PTHREAD_MUTEX_INITIALIZER;
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 9dc029b..6067c76 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -44,6 +44,7 @@
class CallSite;
class Class;
+class ClassLoader;
class MethodType;
class String;
@@ -479,6 +480,8 @@
void VisitReflectiveTargets(ReflectiveValueVisitor* visitor) REQUIRES(Locks::mutator_lock_);
+ void SetClassLoader(ObjPtr<ClassLoader> class_loader) REQUIRES_SHARED(Locks::mutator_lock_);
+
private:
void Init(const DexFile* dex_file,
ObjPtr<String> location,
@@ -559,10 +562,8 @@
static void AtomicStoreRelease16B(std::atomic<ConversionPair64>* target, ConversionPair64 value);
#endif
+ HeapReference<ClassLoader> class_loader_;
HeapReference<String> location_;
- // Number of elements in the preresolved_strings_ array. Note that this appears here because of
- // our packing logic for 32 bit fields.
- uint32_t num_preresolved_strings_;
uint64_t dex_file_; // const DexFile*
uint64_t preresolved_strings_; // GcRoot<mirror::String*> array with num_preresolved_strings
@@ -578,6 +579,7 @@
uint64_t strings_; // std::atomic<StringDexCachePair>*, array with num_strings_
// elements.
+ uint32_t num_preresolved_strings_; // Number of elements in the preresolved_strings_ array.
uint32_t num_resolved_call_sites_; // Number of elements in the call_sites_ array.
uint32_t num_resolved_fields_; // Number of elements in the resolved_fields_ array.
uint32_t num_resolved_method_types_; // Number of elements in the resolved_method_types_ array.