Add more read barriers to the class linker.

This change makes it possible to concurrently scan the remaining roots
in the class linker (the non-class-table roots that are visited by
ClassLinker::VisitRoots()) by adding read barriers.

Bug: 12687968
Change-Id: I66fecf7a303eee7537429e018f38da8270b18c67
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index ca1239f..6e5f19a 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -263,7 +263,11 @@
   }
   mirror::String* string = obj->AsString();
   const uint16_t* utf16_string = string->GetCharArray()->GetData() + string->GetOffset();
-  for (DexCache* dex_cache : Runtime::Current()->GetClassLinker()->GetDexCaches()) {
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+  size_t dex_cache_count = class_linker->GetDexCacheCount();
+  for (size_t i = 0; i < dex_cache_count; ++i) {
+    DexCache* dex_cache = class_linker->GetDexCache(i);
     const DexFile& dex_file = *dex_cache->GetDexFile();
     const DexFile::StringId* string_id;
     if (UNLIKELY(string->GetLength() == 0)) {
@@ -316,7 +320,10 @@
 
   // Clear references to removed classes from the DexCaches.
   ArtMethod* resolution_method = runtime->GetResolutionMethod();
-  for (DexCache* dex_cache : class_linker->GetDexCaches()) {
+  ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+  size_t dex_cache_count = class_linker->GetDexCacheCount();
+  for (size_t idx = 0; idx < dex_cache_count; ++idx) {
+    DexCache* dex_cache = class_linker->GetDexCache(idx);
     for (size_t i = 0; i < dex_cache->NumResolvedTypes(); i++) {
       Class* klass = dex_cache->GetResolvedType(i);
       if (klass != NULL && !IsImageClass(klass)) {
@@ -408,13 +415,27 @@
   Handle<Class> object_array_class(hs.NewHandle(
       class_linker->FindSystemClass(self, "[Ljava/lang/Object;")));
 
-  // build an Object[] of all the DexCaches used in the source_space_
+  // build an Object[] of all the DexCaches used in the source_space_.
+  // Since we can't hold the dex lock when allocating the dex_caches
+  // ObjectArray, we lock the dex lock twice, first to get the number
+  // of dex caches first and then lock it again to copy the dex
+  // caches. We check that the number of dex caches does not change.
+  size_t dex_cache_count;
+  {
+    ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+    dex_cache_count = class_linker->GetDexCacheCount();
+  }
   Handle<ObjectArray<Object>> dex_caches(
       hs.NewHandle(ObjectArray<Object>::Alloc(self, object_array_class.Get(),
-                                              class_linker->GetDexCaches().size())));
-  int i = 0;
-  for (DexCache* dex_cache : class_linker->GetDexCaches()) {
-    dex_caches->Set<false>(i++, dex_cache);
+                                              dex_cache_count)));
+  CHECK(dex_caches.Get() != nullptr) << "Failed to allocate a dex cache array.";
+  {
+    ReaderMutexLock mu(Thread::Current(), *class_linker->DexLock());
+    CHECK_EQ(dex_cache_count, class_linker->GetDexCacheCount())
+        << "The number of dex caches changed.";
+    for (size_t i = 0; i < dex_cache_count; ++i) {
+      dex_caches->Set<false>(i, class_linker->GetDexCache(i));
+    }
   }
 
   // build an Object[] of the roots needed to restore the runtime
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 16e0ec3..a40a2e4 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -41,7 +41,8 @@
 inline mirror::Class* ClassLinker::FindArrayClass(Thread* self, mirror::Class** element_class) {
   for (size_t i = 0; i < kFindArrayCacheSize; ++i) {
     // Read the cached array class once to avoid races with other threads setting it.
-    mirror::Class* array_class = find_array_class_cache_[i];
+    mirror::Class* array_class = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
+        &find_array_class_cache_[i]);
     if (array_class != nullptr && array_class->GetComponentType() == *element_class) {
       return array_class;
     }
@@ -205,11 +206,20 @@
 inline mirror::Class* ClassLinker::GetClassRoot(ClassRoot class_root)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK(class_roots_ != NULL);
-  mirror::Class* klass = class_roots_->Get(class_root);
+  mirror::ObjectArray<mirror::Class>* class_roots =
+      ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Class>, kWithReadBarrier>(
+          &class_roots_);
+  mirror::Class* klass = class_roots->Get(class_root);
   DCHECK(klass != NULL);
   return klass;
 }
 
+inline mirror::DexCache* ClassLinker::GetDexCache(size_t idx) {
+  dex_lock_.AssertSharedHeld(Thread::Current());
+  DCHECK(idx < dex_caches_.size());
+  return ReadBarrier::BarrierForRoot<mirror::DexCache, kWithReadBarrier>(&dex_caches_[idx]);
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_CLASS_LINKER_INL_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d68aca9..61f94d4 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -408,8 +408,12 @@
   CHECK(java_io_Serializable != NULL);
   // We assume that Cloneable/Serializable don't have superinterfaces -- normally we'd have to
   // crawl up and explicitly list all of the supers as well.
-  array_iftable_->SetInterface(0, java_lang_Cloneable);
-  array_iftable_->SetInterface(1, java_io_Serializable);
+  {
+    mirror::IfTable* array_iftable =
+        ReadBarrier::BarrierForRoot<mirror::IfTable, kWithReadBarrier>(&array_iftable_);
+    array_iftable->SetInterface(0, java_lang_Cloneable);
+    array_iftable->SetInterface(1, java_io_Serializable);
+  }
 
   // Sanity check Class[] and Object[]'s interfaces.
   CHECK_EQ(java_lang_Cloneable, mirror::Class::GetDirectInterface(self, class_array_class, 0));
@@ -2036,17 +2040,18 @@
   RegisterDexFile(dex_file, dex_cache);
 }
 
-bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) const {
+bool ClassLinker::IsDexFileRegisteredLocked(const DexFile& dex_file) {
   dex_lock_.AssertSharedHeld(Thread::Current());
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
-    if (dex_caches_[i]->GetDexFile() == &dex_file) {
+    mirror::DexCache* dex_cache = GetDexCache(i);
+    if (dex_cache->GetDexFile() == &dex_file) {
       return true;
     }
   }
   return false;
 }
 
-bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) const {
+bool ClassLinker::IsDexFileRegistered(const DexFile& dex_file) {
   ReaderMutexLock mu(Thread::Current(), dex_lock_);
   return IsDexFileRegisteredLocked(dex_file);
 }
@@ -2094,11 +2099,11 @@
   RegisterDexFileLocked(dex_file, dex_cache);
 }
 
-mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) const {
+mirror::DexCache* ClassLinker::FindDexCache(const DexFile& dex_file) {
   ReaderMutexLock mu(Thread::Current(), dex_lock_);
   // Search assuming unique-ness of dex file.
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
-    mirror::DexCache* dex_cache = dex_caches_[i];
+    mirror::DexCache* dex_cache = GetDexCache(i);
     if (dex_cache->GetDexFile() == &dex_file) {
       return dex_cache;
     }
@@ -2106,24 +2111,25 @@
   // Search matching by location name.
   std::string location(dex_file.GetLocation());
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
-    mirror::DexCache* dex_cache = dex_caches_[i];
+    mirror::DexCache* dex_cache = GetDexCache(i);
     if (dex_cache->GetDexFile()->GetLocation() == location) {
       return dex_cache;
     }
   }
   // Failure, dump diagnostic and abort.
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
-    mirror::DexCache* dex_cache = dex_caches_[i];
+    mirror::DexCache* dex_cache = GetDexCache(i);
     LOG(ERROR) << "Registered dex file " << i << " = " << dex_cache->GetDexFile()->GetLocation();
   }
   LOG(FATAL) << "Failed to find DexCache for DexFile " << location;
   return NULL;
 }
 
-void ClassLinker::FixupDexCaches(mirror::ArtMethod* resolution_method) const {
+void ClassLinker::FixupDexCaches(mirror::ArtMethod* resolution_method) {
   ReaderMutexLock mu(Thread::Current(), dex_lock_);
   for (size_t i = 0; i != dex_caches_.size(); ++i) {
-    dex_caches_[i]->Fixup(resolution_method);
+    mirror::DexCache* dex_cache = GetDexCache(i);
+    dex_cache->Fixup(resolution_method);
   }
 }
 
@@ -2263,8 +2269,12 @@
 
   // Use the single, global copies of "interfaces" and "iftable"
   // (remember not to free them for arrays).
-  CHECK(array_iftable_ != nullptr);
-  new_class->SetIfTable(array_iftable_);
+  {
+    mirror::IfTable* array_iftable =
+        ReadBarrier::BarrierForRoot<mirror::IfTable, kWithReadBarrier>(&array_iftable_);
+    CHECK(array_iftable != nullptr);
+    new_class->SetIfTable(array_iftable);
+  }
 
   // Inherit access flags from the component type.
   int access_flags = new_class->GetComponentType()->GetAccessFlags();
@@ -2931,8 +2941,9 @@
     mirror::ObjectArray<mirror::Class>* resolved_types = proxy_method->GetDexCacheResolvedTypes();
     ReaderMutexLock mu(Thread::Current(), dex_lock_);
     for (size_t i = 0; i != dex_caches_.size(); ++i) {
-      if (dex_caches_[i]->GetResolvedTypes() == resolved_types) {
-        dex_cache = dex_caches_[i];
+      mirror::DexCache* a_dex_cache = GetDexCache(i);
+      if (a_dex_cache->GetResolvedTypes() == resolved_types) {
+        dex_cache = a_dex_cache;
         break;
       }
     }
@@ -4412,9 +4423,12 @@
   DCHECK(klass != NULL);
   DCHECK(klass->GetClassLoader() == NULL);
 
-  DCHECK(class_roots_ != NULL);
-  DCHECK(class_roots_->Get(class_root) == NULL);
-  class_roots_->Set<false>(class_root, klass);
+  mirror::ObjectArray<mirror::Class>* class_roots =
+      ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Class>, kWithReadBarrier>(
+          &class_roots_);
+  DCHECK(class_roots != NULL);
+  DCHECK(class_roots->Get(class_root) == NULL);
+  class_roots->Set<false>(class_root, klass);
 }
 
 }  // namespace art
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 62b5ea8..7d7bf15 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -28,6 +28,7 @@
 #include "jni.h"
 #include "oat_file.h"
 #include "object_callbacks.h"
+#include "read_barrier.h"
 
 namespace art {
 namespace gc {
@@ -252,12 +253,12 @@
   void VisitRoots(RootCallback* callback, void* arg, VisitRootFlags flags)
       LOCKS_EXCLUDED(dex_lock_);
 
-  mirror::DexCache* FindDexCache(const DexFile& dex_file) const
+  mirror::DexCache* FindDexCache(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool IsDexFileRegistered(const DexFile& dex_file) const
+  bool IsDexFileRegistered(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void FixupDexCaches(mirror::ArtMethod* resolution_method) const
+  void FixupDexCaches(mirror::ArtMethod* resolution_method)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -470,7 +471,7 @@
   void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
       EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool IsDexFileRegisteredLocked(const DexFile& dex_file) const
+  bool IsDexFileRegisteredLocked(const DexFile& dex_file)
       SHARED_LOCKS_REQUIRED(dex_lock_, Locks::mutator_lock_);
 
   bool InitializeClass(Handle<mirror::Class> klass, bool can_run_clinit,
@@ -532,9 +533,14 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // For use by ImageWriter to find DexCaches for its roots
-  const std::vector<mirror::DexCache*>& GetDexCaches() {
-    return dex_caches_;
+  ReaderWriterMutex* DexLock()
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCK_RETURNED(dex_lock_) {
+    return &dex_lock_;
   }
+  size_t GetDexCacheCount() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, dex_lock_) {
+    return dex_caches_.size();
+  }
+  mirror::DexCache* GetDexCache(size_t idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, dex_lock_);
 
   const OatFile* FindOpenedOatFileForDexFile(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_)
@@ -643,9 +649,12 @@
   void SetClassRoot(ClassRoot class_root, mirror::Class* klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  mirror::ObjectArray<mirror::Class>* GetClassRoots() {
-    DCHECK(class_roots_ != NULL);
-    return class_roots_;
+  mirror::ObjectArray<mirror::Class>* GetClassRoots() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::ObjectArray<mirror::Class>* class_roots =
+        ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Class>, kWithReadBarrier>(
+            &class_roots_);
+    DCHECK(class_roots != NULL);
+    return class_roots;
   }
 
   static const char* class_roots_descriptors_[];