Remove CHA dependencies for class unloading when JIT is disabled

When a linear alloc is unloaded, remove the corresponding CHA
dependencies to prevent any dangling pointers to ArtMethods.

Bug: 63905544
Bug: 63467744
Test: test-art-host

(cherry-picked from commit cf79cf51feeea395a965c8dc452f86be60c00aab)

Change-Id: I2a9bd434bfa89aa01ebb603cb2ae31afcb002f58
diff --git a/runtime/cha.cc b/runtime/cha.cc
index e6bdb84..31ae9e4 100644
--- a/runtime/cha.cc
+++ b/runtime/cha.cc
@@ -19,6 +19,7 @@
 #include "art_method-inl.h"
 #include "jit/jit.h"
 #include "jit/jit_code_cache.h"
+#include "linear_alloc.h"
 #include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
 #include "stack.h"
@@ -568,4 +569,17 @@
   }
 }
 
+void ClassHierarchyAnalysis::RemoveDependenciesForLinearAlloc(const LinearAlloc* linear_alloc) {
+  MutexLock mu(Thread::Current(), *Locks::cha_lock_);
+  for (auto it = cha_dependency_map_.begin(); it != cha_dependency_map_.end(); ) {
+    // Use unsafe to avoid locking since the allocator is going to be deleted.
+    if (linear_alloc->ContainsUnsafe(it->first)) {
+      // About to delete the ArtMethod, erase the entry from the map.
+      it = cha_dependency_map_.erase(it);
+    } else {
+      ++it;
+    }
+  }
+}
+
 }  // namespace art
diff --git a/runtime/cha.h b/runtime/cha.h
index 81458db..a1ac8b7 100644
--- a/runtime/cha.h
+++ b/runtime/cha.h
@@ -28,6 +28,7 @@
 namespace art {
 
 class ArtMethod;
+class LinearAlloc;
 
 /**
  * Class Hierarchy Analysis (CHA) tries to devirtualize virtual calls into
@@ -111,6 +112,11 @@
   // Update CHA info for methods that `klass` overrides, after loading `klass`.
   void UpdateAfterLoadingOf(Handle<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Remove all of the dependencies for a linear allocator. This is called when dex cache unloading
+  // occurs.
+  void RemoveDependenciesForLinearAlloc(const LinearAlloc* linear_alloc)
+      REQUIRES(!Locks::cha_lock_);
+
  private:
   void InitSingleImplementationFlag(Handle<mirror::Class> klass,
                                     ArtMethod* method,
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5b9cd3a..d1c2d69 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2309,11 +2309,16 @@
   JavaVMExt* const vm = runtime->GetJavaVM();
   vm->DeleteWeakGlobalRef(self, data.weak_root);
   // Notify the JIT that we need to remove the methods and/or profiling info.
+  ClassHierarchyAnalysis* const cha = runtime->GetClassHierarchyAnalysis();
   if (runtime->GetJit() != nullptr) {
     jit::JitCodeCache* code_cache = runtime->GetJit()->GetCodeCache();
     if (code_cache != nullptr) {
+      // For the JIT case, RemoveMethodsIn removes the CHA dependencies.
       code_cache->RemoveMethodsIn(self, *data.allocator);
     }
+  } else {
+    // If we don't have a JIT, we need to manually remove the CHA dependencies manually.
+    cha->RemoveDependenciesForLinearAlloc(data.allocator);
   }
   delete data.allocator;
   delete data.class_table;