Make entries in dex cache arrays atomic.

They are read / written concurrently, so tell it to the compiler.

Test: m
Change-Id: Iaf3e45100ac57d50a17098d8efacf53597a2882a
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 2e8f6be..c200223 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -398,7 +398,7 @@
     }
     uint32_t size = reinterpret_cast<uint32_t*>(array)[-1];
     for (uint32_t i = 0; i < size; ++i) {
-      PatchGcRoot(&array->GetGcRoot(i));
+      PatchGcRoot(array->GetGcRootAddress(i));
     }
   }
 
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index 3452f17..ddfc6b2 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -118,12 +118,12 @@
 template <typename T>
 inline void GcRootArray<T>::Set(uint32_t index, T* value) {
   GcRoot<T> root(value);
-  entries_[index] = root;
+  entries_[index].store(root, std::memory_order_relaxed);
 }
 
 template <typename T>
 inline T* GcRootArray<T>::Get(uint32_t index) {
-  return entries_[index].Read();
+  return entries_[index].load(std::memory_order_relaxed).Read();
 }
 
 inline uint32_t DexCache::ClassSize(PointerSize pointer_size) {
@@ -214,10 +214,8 @@
   if (UNLIKELY(call_sites == nullptr)) {
     return nullptr;
   }
-  GcRoot<mirror::CallSite>& target = call_sites->GetGcRoot(call_site_idx);
-  Atomic<GcRoot<mirror::CallSite>>& ref =
-      reinterpret_cast<Atomic<GcRoot<mirror::CallSite>>&>(target);
-  return ref.load(std::memory_order_seq_cst).Read();
+  Atomic<GcRoot<mirror::CallSite>>* target = call_sites->GetGcRoot(call_site_idx);
+  return target->load(std::memory_order_seq_cst).Read();
 }
 
 inline ObjPtr<CallSite> DexCache::SetResolvedCallSite(uint32_t call_site_idx,
@@ -231,17 +229,15 @@
   if (UNLIKELY(call_sites == nullptr)) {
     call_sites = AllocateResolvedCallSites();
   }
-  GcRoot<mirror::CallSite>& target = call_sites->GetGcRoot(call_site_idx);
+  Atomic<GcRoot<mirror::CallSite>>* target = call_sites->GetGcRoot(call_site_idx);
 
   // The first assignment for a given call site wins.
-  Atomic<GcRoot<mirror::CallSite>>& ref =
-      reinterpret_cast<Atomic<GcRoot<mirror::CallSite>>&>(target);
-  if (ref.CompareAndSetStrongSequentiallyConsistent(null_call_site, candidate)) {
+  if (target->CompareAndSetStrongSequentiallyConsistent(null_call_site, candidate)) {
     // TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
     WriteBarrier::ForEveryFieldWrite(this);
     return call_site;
   } else {
-    return target.Read();
+    return target->load(std::memory_order_relaxed).Read();
   }
 }
 
@@ -323,26 +319,26 @@
   GcRootArray<mirror::CallSite>* resolved_call_sites = GetResolvedCallSites<kVerifyFlags>();
   size_t num_call_sites = NumResolvedCallSites<kVerifyFlags>();
   for (size_t i = 0; resolved_call_sites != nullptr && i != num_call_sites; ++i) {
-    visitor.VisitRootIfNonNull(resolved_call_sites->GetGcRoot(i).AddressWithoutBarrier());
+    visitor.VisitRootIfNonNull(resolved_call_sites->GetGcRootAddress(i)->AddressWithoutBarrier());
   }
 
   GcRootArray<mirror::Class>* resolved_types = GetResolvedTypesArray<kVerifyFlags>();
   size_t num_resolved_types = NumResolvedTypesArray<kVerifyFlags>();
   for (size_t i = 0; resolved_types != nullptr && i != num_resolved_types; ++i) {
-    visitor.VisitRootIfNonNull(resolved_types->GetGcRoot(i).AddressWithoutBarrier());
+    visitor.VisitRootIfNonNull(resolved_types->GetGcRootAddress(i)->AddressWithoutBarrier());
   }
 
   GcRootArray<mirror::String>* resolved_strings = GetStringsArray<kVerifyFlags>();
   size_t num_resolved_strings = NumStringsArray<kVerifyFlags>();
   for (size_t i = 0; resolved_strings != nullptr && i != num_resolved_strings; ++i) {
-    visitor.VisitRootIfNonNull(resolved_strings->GetGcRoot(i).AddressWithoutBarrier());
+    visitor.VisitRootIfNonNull(resolved_strings->GetGcRootAddress(i)->AddressWithoutBarrier());
   }
 
   GcRootArray<mirror::MethodType>* resolved_method_types =
       GetResolvedMethodTypesArray<kVerifyFlags>();
   size_t num_resolved_method_types = NumResolvedMethodTypesArray<kVerifyFlags>();
   for (size_t i = 0; resolved_method_types != nullptr && i != num_resolved_method_types; ++i) {
-    visitor.VisitRootIfNonNull(resolved_method_types->GetGcRoot(i).AddressWithoutBarrier());
+    visitor.VisitRootIfNonNull(resolved_method_types->GetGcRootAddress(i)->AddressWithoutBarrier());
   }
 }
 
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 856dd1f..099fe00 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -211,14 +211,21 @@
 
   T* Get(uint32_t index) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  GcRoot<T>& GetGcRoot(uint32_t index) REQUIRES_SHARED(Locks::mutator_lock_) {
-    return entries_[index];
+  Atomic<GcRoot<T>>* GetGcRoot(uint32_t index) REQUIRES_SHARED(Locks::mutator_lock_) {
+    return &entries_[index];
+  }
+
+  // Only to be used in locations that don't need the atomic or will later load
+  // and read atomically.
+  GcRoot<T>* GetGcRootAddress(uint32_t index) REQUIRES_SHARED(Locks::mutator_lock_) {
+    static_assert(sizeof(GcRoot<T>) == sizeof(Atomic<GcRoot<T>>));
+    return reinterpret_cast<GcRoot<T>*>(&entries_[index]);
   }
 
   void Set(uint32_t index, T* value) REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
-  GcRoot<T> entries_[0];
+  Atomic<GcRoot<T>> entries_[0];
 };
 
 template <typename T> class NativeArray {
@@ -226,7 +233,7 @@
   NativeArray() {}
 
   T* Get(uint32_t index) {
-    return entries_[index];
+    return entries_[index].load(std::memory_order_relaxed);
   }
 
   T** GetPtrEntryPtrSize(uint32_t index, PointerSize ptr_size) {
@@ -240,11 +247,11 @@
   }
 
   void Set(uint32_t index, T* value) {
-    entries_[index] = value;
+    entries_[index].store(value, std::memory_order_relaxed);
   }
 
  private:
-  T* entries_[0];
+  Atomic<T*> entries_[0];
 };
 
 // C++ mirror of java.lang.DexCache.