Add GcRoot to clean up and enforce read barriers.

Introduce a value-type wrapper around Object* for GC roots so that 1)
we won't have to directly add the read barrier code in many places and
2) we can avoid accidentally bypassing/missing read barriers on GC
roots (the GcRoot interface ensures that the read barrier is executed
on a read).

The jdwp test passed.

Bug: 12687968
Change-Id: Ib167c7c325b3c7e3900133578815f04d219972a1
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index 25eb3a3..cf25810 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_CLASS_LINKER_INL_H_
 
 #include "class_linker.h"
+#include "gc_root-inl.h"
 #include "gc/heap-inl.h"
 #include "mirror/art_field.h"
 #include "mirror/class_loader.h"
@@ -40,8 +41,7 @@
 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 = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
-        &find_array_class_cache_[i]);
+    mirror::Class* array_class = find_array_class_cache_[i].Read();
     if (array_class != nullptr && array_class->GetComponentType() == *element_class) {
       return array_class;
     }
@@ -54,7 +54,7 @@
   mirror::Class* array_class = FindClass(self, descriptor.c_str(), class_loader);
   // Benign races in storing array class and incrementing index.
   size_t victim_index = find_array_class_cache_next_victim_;
-  find_array_class_cache_[victim_index] = array_class;
+  find_array_class_cache_[victim_index] = GcRoot<mirror::Class>(array_class);
   find_array_class_cache_next_victim_ = (victim_index + 1) % kFindArrayCacheSize;
   return array_class;
 }
@@ -204,10 +204,8 @@
 
 inline mirror::Class* ClassLinker::GetClassRoot(ClassRoot class_root)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(class_roots_ != NULL);
-  mirror::ObjectArray<mirror::Class>* class_roots =
-      ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Class>, kWithReadBarrier>(
-          &class_roots_);
+  DCHECK(!class_roots_.IsNull());
+  mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read();
   mirror::Class* klass = class_roots->Get(class_root);
   DCHECK(klass != NULL);
   return klass;
@@ -216,7 +214,7 @@
 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]);
+  return dex_caches_[idx].Read();
 }
 
 }  // namespace art
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5599c21..12b7680 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -34,6 +34,7 @@
 #include "compiler_callbacks.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
+#include "gc_root-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/accounting/heap_bitmap.h"
 #include "gc/heap.h"
@@ -267,9 +268,10 @@
   java_lang_ref_Reference->SetStatus(mirror::Class::kStatusResolved, self);
 
   // Create storage for root classes, save away our work so far (requires descriptors).
-  class_roots_ = mirror::ObjectArray<mirror::Class>::Alloc(self, object_array_class.Get(),
-                                                           kClassRootsMax);
-  CHECK(class_roots_ != NULL);
+  class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class> >(
+      mirror::ObjectArray<mirror::Class>::Alloc(self, object_array_class.Get(),
+                                                kClassRootsMax));
+  CHECK(!class_roots_.IsNull());
   SetClassRoot(kJavaLangClass, java_lang_Class.Get());
   SetClassRoot(kJavaLangObject, java_lang_Object.Get());
   SetClassRoot(kClassArrayClass, class_array_class.Get());
@@ -289,7 +291,7 @@
   SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass(self, Primitive::kPrimVoid));
 
   // Create array interface entries to populate once we can load system classes.
-  array_iftable_ = AllocIfTable(self, 2);
+  array_iftable_ = GcRoot<mirror::IfTable>(AllocIfTable(self, 2));
 
   // Create int array type for AllocDexCache (done in AppendToBootClassPath).
   Handle<mirror::Class> int_array_class(hs.NewHandle(
@@ -428,8 +430,7 @@
   // 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.
   {
-    mirror::IfTable* array_iftable =
-        ReadBarrier::BarrierForRoot<mirror::IfTable, kWithReadBarrier>(&array_iftable_);
+    mirror::IfTable* array_iftable = array_iftable_.Read();
     array_iftable->SetInterface(0, java_lang_Cloneable);
     array_iftable->SetInterface(1, java_io_Serializable);
   }
@@ -559,7 +560,7 @@
     // if possible add new checks there to catch errors early
   }
 
-  CHECK(array_iftable_ != NULL);
+  CHECK(!array_iftable_.IsNull());
 
   // disable the slow paths in FindClass and CreatePrimitiveClass now
   // that Object, Class, and Object[] are setup
@@ -1466,7 +1467,7 @@
   Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
           space->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)->
           AsObjectArray<mirror::Class>()));
-  class_roots_ = class_roots.Get();
+  class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(class_roots.Get());
 
   // Special case of setting up the String class early so that we can test arbitrary objects
   // as being Strings or not
@@ -1506,11 +1507,11 @@
 
   // reinit class_roots_
   mirror::Class::SetClassClass(class_roots->Get(kJavaLangClass));
-  class_roots_ = class_roots.Get();
+  class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(class_roots.Get());
 
   // reinit array_iftable_ from any array class instance, they should be ==
-  array_iftable_ = GetClassRoot(kObjectArrayClass)->GetIfTable();
-  DCHECK(array_iftable_ == GetClassRoot(kBooleanArrayClass)->GetIfTable());
+  array_iftable_ = GcRoot<mirror::IfTable>(GetClassRoot(kObjectArrayClass)->GetIfTable());
+  DCHECK(array_iftable_.Read() == GetClassRoot(kBooleanArrayClass)->GetIfTable());
   // String class root was set above
   mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference));
   mirror::ArtField::SetClass(GetClassRoot(kJavaLangReflectArtField));
@@ -1533,22 +1534,23 @@
 void ClassLinker::VisitClassRoots(RootCallback* callback, void* arg, VisitRootFlags flags) {
   WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   if ((flags & kVisitRootFlagAllRoots) != 0) {
-    for (std::pair<const size_t, mirror::Class*>& it : class_table_) {
-      callback(reinterpret_cast<mirror::Object**>(&it.second), arg, 0, kRootStickyClass);
+    for (std::pair<const size_t, GcRoot<mirror::Class> >& it : class_table_) {
+      it.second.VisitRoot(callback, arg, 0, kRootStickyClass);
     }
   } else if ((flags & kVisitRootFlagNewRoots) != 0) {
     for (auto& pair : new_class_roots_) {
-      mirror::Object* old_ref = pair.second;
-      callback(reinterpret_cast<mirror::Object**>(&pair.second), arg, 0, kRootStickyClass);
-      if (UNLIKELY(pair.second != old_ref)) {
+      mirror::Class* old_ref = pair.second.Read<kWithoutReadBarrier>();
+      pair.second.VisitRoot(callback, arg, 0, kRootStickyClass);
+      mirror::Class* new_ref = pair.second.Read<kWithoutReadBarrier>();
+      if (UNLIKELY(new_ref != old_ref)) {
         // Uh ohes, GC moved a root in the log. Need to search the class_table and update the
         // corresponding object. This is slow, but luckily for us, this may only happen with a
         // concurrent moving GC.
         for (auto it = class_table_.lower_bound(pair.first), end = class_table_.end();
             it != end && it->first == pair.first; ++it) {
           // If the class stored matches the old class, update it to the new value.
-          if (old_ref == it->second) {
-            it->second = pair.second;
+          if (old_ref == it->second.Read<kWithoutReadBarrier>()) {
+            it->second = GcRoot<mirror::Class>(new_ref);
           }
         }
       }
@@ -1570,17 +1572,17 @@
 // reinit references to when reinitializing a ClassLinker from a
 // mapped image.
 void ClassLinker::VisitRoots(RootCallback* callback, void* arg, VisitRootFlags flags) {
-  callback(reinterpret_cast<mirror::Object**>(&class_roots_), arg, 0, kRootVMInternal);
+  class_roots_.VisitRoot(callback, arg, 0, kRootVMInternal);
   Thread* self = Thread::Current();
   {
     ReaderMutexLock mu(self, dex_lock_);
     if ((flags & kVisitRootFlagAllRoots) != 0) {
-      for (mirror::DexCache*& dex_cache : dex_caches_) {
-        callback(reinterpret_cast<mirror::Object**>(&dex_cache), arg, 0, kRootVMInternal);
+      for (GcRoot<mirror::DexCache>& dex_cache : dex_caches_) {
+        dex_cache.VisitRoot(callback, arg, 0, kRootVMInternal);
       }
     } else if ((flags & kVisitRootFlagNewRoots) != 0) {
       for (size_t index : new_dex_cache_roots_) {
-        callback(reinterpret_cast<mirror::Object**>(&dex_caches_[index]), arg, 0, kRootVMInternal);
+        dex_caches_[index].VisitRoot(callback, arg, 0, kRootVMInternal);
       }
     }
     if ((flags & kVisitRootFlagClearRootLog) != 0) {
@@ -1593,12 +1595,11 @@
     }
   }
   VisitClassRoots(callback, arg, flags);
-  callback(reinterpret_cast<mirror::Object**>(&array_iftable_), arg, 0, kRootVMInternal);
-  DCHECK(array_iftable_ != nullptr);
+  array_iftable_.VisitRoot(callback, arg, 0, kRootVMInternal);
+  DCHECK(!array_iftable_.IsNull());
   for (size_t i = 0; i < kFindArrayCacheSize; ++i) {
-    if (find_array_class_cache_[i] != nullptr) {
-      callback(reinterpret_cast<mirror::Object**>(&find_array_class_cache_[i]), arg, 0,
-               kRootVMInternal);
+    if (!find_array_class_cache_[i].IsNull()) {
+      find_array_class_cache_[i].VisitRoot(callback, arg, 0, kRootVMInternal);
     }
   }
 }
@@ -1608,9 +1609,8 @@
     MoveImageClassesToClassTable();
   }
   WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-  for (std::pair<const size_t, mirror::Class*>& it : class_table_) {
-    mirror::Class** root = &it.second;
-    mirror::Class* c = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root);
+  for (std::pair<const size_t, GcRoot<mirror::Class> >& it : class_table_) {
+    mirror::Class* c = it.second.Read();
     if (!visitor(c, arg)) {
       return;
     }
@@ -2536,7 +2536,7 @@
   CHECK(dex_cache.Get() != NULL) << dex_file.GetLocation();
   CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()))
       << dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation();
-  dex_caches_.push_back(dex_cache.Get());
+  dex_caches_.push_back(GcRoot<mirror::DexCache>(dex_cache.Get()));
   dex_cache->SetDexFile(&dex_file);
   if (log_new_dex_caches_roots_) {
     // TODO: This is not safe if we can remove dex caches.
@@ -2753,8 +2753,7 @@
   // Use the single, global copies of "interfaces" and "iftable"
   // (remember not to free them for arrays).
   {
-    mirror::IfTable* array_iftable =
-        ReadBarrier::BarrierForRoot<mirror::IfTable, kWithReadBarrier>(&array_iftable_);
+    mirror::IfTable* array_iftable = array_iftable_.Read();
     CHECK(array_iftable != nullptr);
     new_class->SetIfTable(array_iftable);
   }
@@ -2838,9 +2837,9 @@
     }
   }
   VerifyObject(klass);
-  class_table_.insert(std::make_pair(hash, klass));
+  class_table_.insert(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
   if (log_new_class_table_roots_) {
-    new_class_roots_.push_back(std::make_pair(hash, klass));
+    new_class_roots_.push_back(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
   }
   return NULL;
 }
@@ -2862,8 +2861,7 @@
 
   for (auto it = class_table_.lower_bound(hash), end = class_table_.end(); it != end && it->first == hash;
        ++it) {
-    mirror::Class** root = &it->second;
-    mirror::Class* klass = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root);
+    mirror::Class* klass = it->second.Read();
     if (klass == existing) {
       class_table_.erase(it);
       break;
@@ -2882,9 +2880,9 @@
   }
   VerifyObject(klass);
 
-  class_table_.insert(std::make_pair(hash, klass));
+  class_table_.insert(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
   if (log_new_class_table_roots_) {
-    new_class_roots_.push_back(std::make_pair(hash, klass));
+    new_class_roots_.push_back(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
   }
 
   return existing;
@@ -2896,8 +2894,7 @@
   for (auto it = class_table_.lower_bound(hash), end = class_table_.end();
        it != end && it->first == hash;
        ++it) {
-    mirror::Class** root = &it->second;
-    mirror::Class* klass = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root);
+    mirror::Class* klass = it->second.Read();
     if (klass->GetClassLoader() == class_loader && klass->DescriptorEquals(descriptor)) {
       class_table_.erase(it);
       return true;
@@ -2941,14 +2938,12 @@
                                                        size_t hash) {
   auto end = class_table_.end();
   for (auto it = class_table_.lower_bound(hash); it != end && it->first == hash; ++it) {
-    mirror::Class** root = &it->second;
-    mirror::Class* klass = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root);
+    mirror::Class* klass = it->second.Read();
     if (klass->GetClassLoader() == class_loader && klass->DescriptorEquals(descriptor)) {
       if (kIsDebugBuild) {
         // Check for duplicates in the table.
         for (++it; it != end && it->first == hash; ++it) {
-          mirror::Class** root2 = &it->second;
-          mirror::Class* klass2 = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root2);
+          mirror::Class* klass2 = it->second.Read();
           CHECK(!(klass2->GetClassLoader() == class_loader &&
               klass2->DescriptorEquals(descriptor)))
               << PrettyClass(klass) << " " << klass << " " << klass->GetClassLoader() << " "
@@ -2992,9 +2987,9 @@
           CHECK(existing == klass) << PrettyClassAndClassLoader(existing) << " != "
               << PrettyClassAndClassLoader(klass);
         } else {
-          class_table_.insert(std::make_pair(hash, klass));
+          class_table_.insert(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
           if (log_new_class_table_roots_) {
-            new_class_roots_.push_back(std::make_pair(hash, klass));
+            new_class_roots_.push_back(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
           }
         }
       }
@@ -3040,8 +3035,7 @@
   ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   for (auto it = class_table_.lower_bound(hash), end = class_table_.end();
       it != end && it->first == hash; ++it) {
-    mirror::Class** root = &it->second;
-    mirror::Class* klass = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root);
+    mirror::Class* klass = it->second.Read();
     if (klass->DescriptorEquals(descriptor)) {
       result.push_back(klass);
     }
@@ -5017,9 +5011,8 @@
   std::vector<mirror::Class*> all_classes;
   {
     ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-    for (std::pair<const size_t, mirror::Class*>& it : class_table_) {
-      mirror::Class** root = &it.second;
-      mirror::Class* klass = ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(root);
+    for (std::pair<const size_t, GcRoot<mirror::Class> >& it : class_table_) {
+      mirror::Class* klass = it.second.Read();
       all_classes.push_back(klass);
     }
   }
@@ -5059,9 +5052,7 @@
   DCHECK(klass != NULL);
   DCHECK(klass->GetClassLoader() == NULL);
 
-  mirror::ObjectArray<mirror::Class>* class_roots =
-      ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Class>, kWithReadBarrier>(
-          &class_roots_);
+  mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read();
   DCHECK(class_roots != NULL);
   DCHECK(class_roots->Get(class_root) == NULL);
   class_roots->Set<false>(class_root, klass);
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index b108f61..1bb1635 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -24,11 +24,11 @@
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "dex_file.h"
+#include "gc_root.h"
 #include "gtest/gtest.h"
 #include "jni.h"
 #include "oat_file.h"
 #include "object_callbacks.h"
-#include "read_barrier.h"
 
 namespace art {
 
@@ -245,9 +245,11 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void VisitClassRoots(RootCallback* callback, void* arg, VisitRootFlags flags)
-      LOCKS_EXCLUDED(Locks::classlinker_classes_lock_);
+      LOCKS_EXCLUDED(Locks::classlinker_classes_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void VisitRoots(RootCallback* callback, void* arg, VisitRootFlags flags)
-      LOCKS_EXCLUDED(dex_lock_);
+      LOCKS_EXCLUDED(dex_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::DexCache* FindDexCache(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_)
@@ -378,9 +380,7 @@
   mirror::ArtMethod* AllocArtMethod(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   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_);
+    mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read();
     DCHECK(class_roots != NULL);
     return class_roots;
   }
@@ -609,18 +609,18 @@
 
   mutable ReaderWriterMutex dex_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   std::vector<size_t> new_dex_cache_roots_ GUARDED_BY(dex_lock_);;
-  std::vector<mirror::DexCache*> dex_caches_ GUARDED_BY(dex_lock_);
+  std::vector<GcRoot<mirror::DexCache>> dex_caches_ GUARDED_BY(dex_lock_);
   std::vector<const OatFile*> oat_files_ GUARDED_BY(dex_lock_);
 
 
   // multimap from a string hash code of a class descriptor to
   // mirror::Class* instances. Results should be compared for a matching
   // Class::descriptor_ and Class::class_loader_.
-  typedef std::multimap<size_t, mirror::Class*> Table;
+  typedef std::multimap<size_t, GcRoot<mirror::Class>> Table;
   // This contains strong roots. To enable concurrent root scanning of
   // the class table, be careful to use a read barrier when accessing this.
   Table class_table_ GUARDED_BY(Locks::classlinker_classes_lock_);
-  std::vector<std::pair<size_t, mirror::Class*>> new_class_roots_;
+  std::vector<std::pair<size_t, GcRoot<mirror::Class>>> new_class_roots_;
 
   // Do we need to search dex caches to find image classes?
   bool dex_cache_image_class_lookup_required_;
@@ -694,7 +694,7 @@
     kJavaLangStackTraceElementArrayClass,
     kClassRootsMax,
   };
-  mirror::ObjectArray<mirror::Class>* class_roots_;
+  GcRoot<mirror::ObjectArray<mirror::Class>> class_roots_;
 
   mirror::Class* GetClassRoot(ClassRoot class_root) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -710,12 +710,12 @@
   }
 
   // The interface table used by all arrays.
-  mirror::IfTable* array_iftable_;
+  GcRoot<mirror::IfTable> array_iftable_;
 
   // A cache of the last FindArrayClass results. The cache serves to avoid creating array class
   // descriptors for the sake of performing FindClass.
   static constexpr size_t kFindArrayCacheSize = 16;
-  mirror::Class* find_array_class_cache_[kFindArrayCacheSize];
+  GcRoot<mirror::Class> find_array_class_cache_[kFindArrayCacheSize];
   size_t find_array_class_cache_next_victim_;
 
   bool init_done_;
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index a43a645..8e363c4 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -30,6 +30,7 @@
 #include "class_linker.h"
 #include "compiler_callbacks.h"
 #include "dex_file.h"
+#include "gc_root-inl.h"
 #include "gc/heap.h"
 #include "gtest/gtest.h"
 #include "jni_internal.h"
diff --git a/runtime/gc_root-inl.h b/runtime/gc_root-inl.h
new file mode 100644
index 0000000..482f7bc
--- /dev/null
+++ b/runtime/gc_root-inl.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_GC_ROOT_INL_H_
+#define ART_RUNTIME_GC_ROOT_INL_H_
+
+#include "gc_root.h"
+
+#include "read_barrier-inl.h"
+
+namespace art {
+
+template<class MirrorType>
+template<ReadBarrierOption kReadBarrierOption>
+inline MirrorType* GcRoot<MirrorType>::Read() {
+  return ReadBarrier::BarrierForRoot<MirrorType, kReadBarrierOption>(&root_);
+}
+
+}  // namespace art
+#endif  // ART_RUNTIME_GC_ROOT_INL_H_
diff --git a/runtime/gc_root.h b/runtime/gc_root.h
new file mode 100644
index 0000000..86a8847
--- /dev/null
+++ b/runtime/gc_root.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_GC_ROOT_H_
+#define ART_RUNTIME_GC_ROOT_H_
+
+#include "base/mutex.h"       // For Locks::mutator_lock_.
+#include "object_callbacks.h"
+
+namespace art {
+
+template<class MirrorType>
+class GcRoot {
+ public:
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+  ALWAYS_INLINE MirrorType* Read() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  void VisitRoot(RootCallback* callback, void* arg, uint32_t thread_id, RootType root_type) {
+    callback(reinterpret_cast<mirror::Object**>(&root_), arg, thread_id, root_type);
+  }
+
+  // This is only used by IrtIterator.
+  ALWAYS_INLINE MirrorType** AddressWithoutBarrier() {
+    return &root_;
+  }
+
+  bool IsNull() const {
+    // It's safe to null-check it without a read barrier.
+    return root_ == nullptr;
+  }
+
+  ALWAYS_INLINE explicit GcRoot<MirrorType>() : root_(nullptr) {
+  }
+
+  ALWAYS_INLINE explicit GcRoot<MirrorType>(MirrorType* ref)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : root_(ref) {
+  }
+
+ private:
+  MirrorType* root_;
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_GC_ROOT_H_
diff --git a/runtime/indirect_reference_table-inl.h b/runtime/indirect_reference_table-inl.h
index f561643..c826716 100644
--- a/runtime/indirect_reference_table-inl.h
+++ b/runtime/indirect_reference_table-inl.h
@@ -46,7 +46,7 @@
     AbortIfNoCheckJNI();
     return false;
   }
-  if (UNLIKELY(table_[idx] == nullptr)) {
+  if (UNLIKELY(table_[idx].IsNull())) {
     LOG(ERROR) << "JNI ERROR (app bug): accessed deleted " << kind_ << " " << iref;
     AbortIfNoCheckJNI();
     return false;
@@ -75,11 +75,11 @@
   if (!GetChecked(iref)) {
     return kInvalidIndirectRefObject;
   }
-  mirror::Object** root = &table_[ExtractIndex(iref)];
-  mirror::Object* obj = *root;
+  uint32_t idx = ExtractIndex(iref);
+  mirror::Object* obj = table_[idx].Read<kWithoutReadBarrier>();
   if (LIKELY(obj != kClearedJniWeakGlobal)) {
     // The read barrier or VerifyObject won't handle kClearedJniWeakGlobal.
-    obj = ReadBarrier::BarrierForRoot<mirror::Object, kReadBarrierOption>(root);
+    obj = table_[idx].Read();
     VerifyObject(obj);
   }
   return obj;
diff --git a/runtime/indirect_reference_table.cc b/runtime/indirect_reference_table.cc
index 26ddba2..9b2b82e 100644
--- a/runtime/indirect_reference_table.cc
+++ b/runtime/indirect_reference_table.cc
@@ -76,7 +76,7 @@
   CHECK(table_mem_map_.get() != nullptr) << error_str;
   CHECK_EQ(table_mem_map_->Size(), table_bytes);
 
-  table_ = reinterpret_cast<mirror::Object**>(table_mem_map_->Begin());
+  table_ = reinterpret_cast<GcRoot<mirror::Object>*>(table_mem_map_->Begin());
   CHECK(table_ != nullptr);
   memset(table_, 0xd1, initial_bytes);
 
@@ -132,20 +132,22 @@
   if (numHoles > 0) {
     DCHECK_GT(topIndex, 1U);
     // Find the first hole; likely to be near the end of the list.
-    mirror::Object** pScan = &table_[topIndex - 1];
-    DCHECK(*pScan != NULL);
-    while (*--pScan != NULL) {
+    GcRoot<mirror::Object>* pScan = &table_[topIndex - 1];
+    DCHECK(!pScan->IsNull());
+    --pScan;
+    while (!pScan->IsNull()) {
       DCHECK_GE(pScan, table_ + prevState.parts.topIndex);
+      --pScan;
     }
     UpdateSlotAdd(obj, pScan - table_);
     result = ToIndirectRef(pScan - table_);
-    *pScan = obj;
+    *pScan = GcRoot<mirror::Object>(obj);
     segment_state_.parts.numHoles--;
   } else {
     // Add to the end.
     UpdateSlotAdd(obj, topIndex);
     result = ToIndirectRef(topIndex);
-    table_[topIndex++] = obj;
+    table_[topIndex++] = GcRoot<mirror::Object>(obj);
     segment_state_.parts.topIndex = topIndex;
   }
   if (false) {
@@ -211,15 +213,16 @@
       return false;
     }
 
-    table_[idx] = NULL;
+    table_[idx] = GcRoot<mirror::Object>(nullptr);
     int numHoles = segment_state_.parts.numHoles - prevState.parts.numHoles;
     if (numHoles != 0) {
       while (--topIndex > bottomIndex && numHoles != 0) {
         if (false) {
           LOG(INFO) << "+++ checking for hole at " << topIndex-1
-                    << " (cookie=" << cookie << ") val=" << table_[topIndex - 1];
+                    << " (cookie=" << cookie << ") val="
+                    << table_[topIndex - 1].Read<kWithoutReadBarrier>();
         }
-        if (table_[topIndex-1] != NULL) {
+        if (!table_[topIndex-1].IsNull()) {
           break;
         }
         if (false) {
@@ -239,7 +242,7 @@
     // Not the top-most entry.  This creates a hole.  We NULL out the
     // entry to prevent somebody from deleting it twice and screwing up
     // the hole count.
-    if (table_[idx] == NULL) {
+    if (table_[idx].IsNull()) {
       LOG(INFO) << "--- WEIRD: removing null entry " << idx;
       return false;
     }
@@ -247,7 +250,7 @@
       return false;
     }
 
-    table_[idx] = NULL;
+    table_[idx] = GcRoot<mirror::Object>(nullptr);
     segment_state_.parts.numHoles++;
     if (false) {
       LOG(INFO) << "+++ left hole at " << idx << ", holes=" << segment_state_.parts.numHoles;
@@ -269,17 +272,16 @@
   os << kind_ << " table dump:\n";
   ReferenceTable::Table entries;
   for (size_t i = 0; i < Capacity(); ++i) {
-    mirror::Object** root = &table_[i];
-    mirror::Object* obj = *root;
+    mirror::Object* obj = table_[i].Read<kWithoutReadBarrier>();
     if (UNLIKELY(obj == nullptr)) {
       // Remove NULLs.
     } else if (UNLIKELY(obj == kClearedJniWeakGlobal)) {
       // ReferenceTable::Dump() will handle kClearedJniWeakGlobal
       // while the read barrier won't.
-      entries.push_back(obj);
+      entries.push_back(GcRoot<mirror::Object>(obj));
     } else {
-      obj = ReadBarrier::BarrierForRoot<mirror::Object, kWithReadBarrier>(root);
-      entries.push_back(obj);
+      obj = table_[i].Read();
+      entries.push_back(GcRoot<mirror::Object>(obj));
     }
   }
   ReferenceTable::Dump(os, entries);
diff --git a/runtime/indirect_reference_table.h b/runtime/indirect_reference_table.h
index b3a855d..fb910e2 100644
--- a/runtime/indirect_reference_table.h
+++ b/runtime/indirect_reference_table.h
@@ -24,10 +24,11 @@
 
 #include "base/logging.h"
 #include "base/mutex.h"
+#include "gc_root.h"
 #include "mem_map.h"
 #include "object_callbacks.h"
 #include "offsets.h"
-#include "read_barrier.h"
+#include "read_barrier_option.h"
 
 namespace art {
 namespace mirror {
@@ -204,12 +205,13 @@
 
 class IrtIterator {
  public:
-  explicit IrtIterator(mirror::Object** table, size_t i, size_t capacity)
+  explicit IrtIterator(GcRoot<mirror::Object>* table, size_t i, size_t capacity)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       : table_(table), i_(i), capacity_(capacity) {
     SkipNullsAndTombstones();
   }
 
-  IrtIterator& operator++() {
+  IrtIterator& operator++() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     ++i_;
     SkipNullsAndTombstones();
     return *this;
@@ -217,7 +219,7 @@
 
   mirror::Object** operator*() {
     // This does not have a read barrier as this is used to visit roots.
-    return &table_[i_];
+    return table_[i_].AddressWithoutBarrier();
   }
 
   bool equals(const IrtIterator& rhs) const {
@@ -225,14 +227,16 @@
   }
 
  private:
-  void SkipNullsAndTombstones() {
+  void SkipNullsAndTombstones() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     // We skip NULLs and tombstones. Clients don't want to see implementation details.
-    while (i_ < capacity_ && (table_[i_] == NULL || table_[i_] == kClearedJniWeakGlobal)) {
+    while (i_ < capacity_ &&
+           (table_[i_].IsNull() ||
+            table_[i_].Read<kWithoutReadBarrier>() == kClearedJniWeakGlobal)) {
       ++i_;
     }
   }
 
-  mirror::Object** const table_;
+  GcRoot<mirror::Object>* const table_;
   size_t i_;
   size_t capacity_;
 };
@@ -309,7 +313,8 @@
     return IrtIterator(table_, Capacity(), Capacity());
   }
 
-  void VisitRoots(RootCallback* callback, void* arg, uint32_t tid, RootType root_type);
+  void VisitRoots(RootCallback* callback, void* arg, uint32_t tid, RootType root_type)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   uint32_t GetSegmentState() const {
     return segment_state_.all;
@@ -373,7 +378,7 @@
   std::unique_ptr<MemMap> slot_mem_map_;
   // bottom of the stack. Do not directly access the object references
   // in this as they are roots. Use Get() that has a read barrier.
-  mirror::Object** table_;
+  GcRoot<mirror::Object>* table_;
   /* bit mask, ORed into all irefs */
   IndirectRefKind kind_;
   /* extended debugging info */
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 8e375cf..16be077 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -25,6 +25,7 @@
 #include "debugger.h"
 #include "dex_file-inl.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
+#include "gc_root-inl.h"
 #include "interpreter/interpreter.h"
 #include "mirror/art_method-inl.h"
 #include "mirror/class-inl.h"
@@ -628,7 +629,7 @@
   }
   // Not found. Add it.
   int32_t hash_code = method->IdentityHashCode();
-  deoptimized_methods_.insert(std::make_pair(hash_code, method));
+  deoptimized_methods_.insert(std::make_pair(hash_code, GcRoot<mirror::ArtMethod>(method)));
   return true;
 }
 
@@ -636,8 +637,7 @@
   int32_t hash_code = method->IdentityHashCode();
   auto range = deoptimized_methods_.equal_range(hash_code);
   for (auto it = range.first; it != range.second; ++it) {
-    mirror::ArtMethod** root = &it->second;
-    mirror::ArtMethod* m = ReadBarrier::BarrierForRoot<mirror::ArtMethod>(root);
+    mirror::ArtMethod* m = it->second.Read();
     if (m == method) {
       // Found.
       return true;
@@ -653,16 +653,14 @@
     // Empty.
     return nullptr;
   }
-  mirror::ArtMethod** root = &it->second;
-  return ReadBarrier::BarrierForRoot<mirror::ArtMethod>(root);
+  return it->second.Read();
 }
 
 bool Instrumentation::RemoveDeoptimizedMethod(mirror::ArtMethod* method) {
   int32_t hash_code = method->IdentityHashCode();
   auto range = deoptimized_methods_.equal_range(hash_code);
   for (auto it = range.first; it != range.second; ++it) {
-    mirror::ArtMethod** root = &it->second;
-    mirror::ArtMethod* m = ReadBarrier::BarrierForRoot<mirror::ArtMethod>(root);
+    mirror::ArtMethod* m = it->second.Read();
     if (m == method) {
       // Found. Erase and return.
       deoptimized_methods_.erase(it);
@@ -1024,8 +1022,7 @@
     return;
   }
   for (auto pair : deoptimized_methods_) {
-    mirror::ArtMethod** root = &pair.second;
-    callback(reinterpret_cast<mirror::Object**>(root), arg, 0, kRootVMInternal);
+    pair.second.VisitRoot(callback, arg, 0, kRootVMInternal);
   }
 }
 
diff --git a/runtime/instrumentation.h b/runtime/instrumentation.h
index cabb0e9..66c6b38 100644
--- a/runtime/instrumentation.h
+++ b/runtime/instrumentation.h
@@ -25,6 +25,7 @@
 #include "instruction_set.h"
 #include "base/macros.h"
 #include "base/mutex.h"
+#include "gc_root.h"
 #include "object_callbacks.h"
 
 namespace art {
@@ -440,7 +441,8 @@
   // The set of methods being deoptimized (by the debugger) which must be executed with interpreter
   // only.
   mutable ReaderWriterMutex deoptimized_methods_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
-  std::multimap<int32_t, mirror::ArtMethod*> deoptimized_methods_ GUARDED_BY(deoptimized_methods_lock_);
+  std::multimap<int32_t, GcRoot<mirror::ArtMethod>> deoptimized_methods_
+      GUARDED_BY(deoptimized_methods_lock_);
   bool deoptimization_enabled_;
 
   // Current interpreter handler table. This is updated each time the thread state flags are
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 1430500..aadd85a 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -58,27 +58,27 @@
   MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
   if ((flags & kVisitRootFlagAllRoots) != 0) {
     for (auto& strong_intern : strong_interns_) {
-      callback(reinterpret_cast<mirror::Object**>(&strong_intern.second), arg, 0,
-               kRootInternedString);
-      DCHECK(strong_intern.second != nullptr);
+      strong_intern.second.VisitRoot(callback, arg, 0, kRootInternedString);
+      DCHECK(!strong_intern.second.IsNull());
     }
   } else if ((flags & kVisitRootFlagNewRoots) != 0) {
     for (auto& pair : new_strong_intern_roots_) {
-       mirror::String* old_ref = pair.second;
-       callback(reinterpret_cast<mirror::Object**>(&pair.second), arg, 0, kRootInternedString);
-       if (UNLIKELY(pair.second != old_ref)) {
-         // Uh ohes, GC moved a root in the log. Need to search the strong interns and update the
-         // corresponding object. This is slow, but luckily for us, this may only happen with a
-         // concurrent moving GC.
-         for (auto it = strong_interns_.lower_bound(pair.first), end = strong_interns_.end();
+      mirror::String* old_ref = pair.second.Read<kWithoutReadBarrier>();
+      pair.second.VisitRoot(callback, arg, 0, kRootInternedString);
+      mirror::String* new_ref = pair.second.Read<kWithoutReadBarrier>();
+      if (UNLIKELY(new_ref != old_ref)) {
+        // Uh ohes, GC moved a root in the log. Need to search the strong interns and update the
+        // corresponding object. This is slow, but luckily for us, this may only happen with a
+        // concurrent moving GC.
+        for (auto it = strong_interns_.lower_bound(pair.first), end = strong_interns_.end();
              it != end && it->first == pair.first; ++it) {
-           // If the class stored matches the old class, update it to the new value.
-           if (old_ref == it->second) {
-             it->second = pair.second;
-           }
-         }
-       }
-     }
+          // If the class stored matches the old class, update it to the new value.
+          if (old_ref == it->second.Read<kWithoutReadBarrier>()) {
+            it->second = GcRoot<mirror::String>(new_ref);
+          }
+        }
+      }
+    }
   }
 
   if ((flags & kVisitRootFlagClearRootLog) != 0) {
@@ -105,9 +105,7 @@
   Locks::intern_table_lock_->AssertHeld(Thread::Current());
   for (auto it = table->lower_bound(hash_code), end = table->end();
        it != end && it->first == hash_code; ++it) {
-    mirror::String* existing_string;
-    mirror::String** root = &it->second;
-    existing_string = ReadBarrier::BarrierForRoot<mirror::String, kWithReadBarrier>(root);
+    mirror::String* existing_string = it->second.Read();
     if (existing_string->Equals(s)) {
       return existing_string;
     }
@@ -121,9 +119,9 @@
     runtime->RecordStrongStringInsertion(s, hash_code);
   }
   if (log_new_roots_) {
-    new_strong_intern_roots_.push_back(std::make_pair(hash_code, s));
+    new_strong_intern_roots_.push_back(std::make_pair(hash_code, GcRoot<mirror::String>(s)));
   }
-  strong_interns_.insert(std::make_pair(hash_code, s));
+  strong_interns_.insert(std::make_pair(hash_code, GcRoot<mirror::String>(s)));
   return s;
 }
 
@@ -132,7 +130,7 @@
   if (runtime->IsActiveTransaction()) {
     runtime->RecordWeakStringInsertion(s, hash_code);
   }
-  weak_interns_.insert(std::make_pair(hash_code, s));
+  weak_interns_.insert(std::make_pair(hash_code, GcRoot<mirror::String>(s)));
   return s;
 }
 
@@ -151,9 +149,7 @@
 void InternTable::Remove(Table* table, mirror::String* s, int32_t hash_code) {
   for (auto it = table->lower_bound(hash_code), end = table->end();
        it != end && it->first == hash_code; ++it) {
-    mirror::String* existing_string;
-    mirror::String** root = &it->second;
-    existing_string = ReadBarrier::BarrierForRoot<mirror::String, kWithReadBarrier>(root);
+    mirror::String* existing_string = it->second.Read();
     if (existing_string == s) {
       table->erase(it);
       return;
@@ -308,13 +304,13 @@
   MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
   for (auto it = weak_interns_.begin(), end = weak_interns_.end(); it != end;) {
     // This does not need a read barrier because this is called by GC.
-    mirror::Object* object = it->second;
+    mirror::Object* object = it->second.Read<kWithoutReadBarrier>();
     mirror::Object* new_object = callback(object, arg);
     if (new_object == nullptr) {
       // TODO: use it = weak_interns_.erase(it) when we get a c++11 stl.
       weak_interns_.erase(it++);
     } else {
-      it->second = down_cast<mirror::String*>(new_object);
+      it->second = GcRoot<mirror::String>(down_cast<mirror::String*>(new_object));
       ++it;
     }
   }
diff --git a/runtime/intern_table.h b/runtime/intern_table.h
index 6dc7f7b..435cc43 100644
--- a/runtime/intern_table.h
+++ b/runtime/intern_table.h
@@ -20,6 +20,7 @@
 #include <map>
 
 #include "base/mutex.h"
+#include "gc_root.h"
 #include "object_callbacks.h"
 
 namespace art {
@@ -59,7 +60,8 @@
   // Interns a potentially new string in the 'weak' table. (See above.)
   mirror::String* InternWeak(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void SweepInternTableWeaks(IsMarkedCallback* callback, void* arg);
+  void SweepInternTableWeaks(IsMarkedCallback* callback, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool ContainsWeak(mirror::String* s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -67,7 +69,8 @@
   size_t StrongSize() const;
   size_t WeakSize() const;
 
-  void VisitRoots(RootCallback* callback, void* arg, VisitRootFlags flags);
+  void VisitRoots(RootCallback* callback, void* arg, VisitRootFlags flags)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void DumpForSigQuit(std::ostream& os) const;
 
@@ -75,7 +78,7 @@
   void AllowNewInterns() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
-  typedef std::multimap<int32_t, mirror::String*> Table;
+  typedef std::multimap<int32_t, GcRoot<mirror::String>> Table;
 
   mirror::String* Insert(mirror::String* s, bool is_strong)
       LOCKS_EXCLUDED(Locks::intern_table_lock_)
@@ -122,7 +125,7 @@
   // directly access the strings in it. Use functions that contain
   // read barriers.
   Table strong_interns_ GUARDED_BY(Locks::intern_table_lock_);
-  std::vector<std::pair<int32_t, mirror::String*>> new_strong_intern_roots_
+  std::vector<std::pair<int32_t, GcRoot<mirror::String>>> new_strong_intern_roots_
       GUARDED_BY(Locks::intern_table_lock_);
   // Since this contains (weak) roots, they need a read barrier. Do
   // not directly access the strings in it. Use functions that contain
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 64cca3d..d5b90f2 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -29,6 +29,7 @@
 #include "base/stl_util.h"
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
+#include "gc_root.h"
 #include "gc/accounting/card_table-inl.h"
 #include "indirect_reference_table-inl.h"
 #include "interpreter/interpreter.h"
@@ -364,7 +365,7 @@
       : path_(path),
         handle_(handle),
         needs_native_bridge_(false),
-        class_loader_(class_loader),
+        class_loader_(GcRoot<mirror::Object>(class_loader)),
         jni_on_load_lock_("JNI_OnLoad lock"),
         jni_on_load_cond_("JNI_OnLoad condition variable", jni_on_load_lock_),
         jni_on_load_thread_id_(Thread::Current()->GetThreadId()),
@@ -372,8 +373,7 @@
   }
 
   mirror::Object* GetClassLoader() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    mirror::Object** root = &class_loader_;
-    return ReadBarrier::BarrierForRoot<mirror::Object, kWithReadBarrier>(root);
+    return class_loader_.Read();
   }
 
   std::string GetPath() {
@@ -449,8 +449,8 @@
   }
 
   void VisitRoots(RootCallback* visitor, void* arg) {
-    if (class_loader_ != nullptr) {
-      visitor(&class_loader_, arg, 0, kRootVMInternal);
+    if (!class_loader_.IsNull()) {
+      class_loader_.VisitRoot(visitor, arg, 0, kRootVMInternal);
     }
   }
 
@@ -471,7 +471,7 @@
   bool needs_native_bridge_;
 
   // The ClassLoader this library is associated with.
-  mirror::Object* class_loader_;
+  GcRoot<mirror::Object> class_loader_;
 
   // Guards remaining items.
   Mutex jni_on_load_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
diff --git a/runtime/jni_internal.h b/runtime/jni_internal.h
index abb71b7..ac502e6 100644
--- a/runtime/jni_internal.h
+++ b/runtime/jni_internal.h
@@ -85,7 +85,8 @@
 
   void SetCheckJniEnabled(bool enabled);
 
-  void VisitRoots(RootCallback* callback, void* arg);
+  void VisitRoots(RootCallback* callback, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void DisallowNewWeakGlobals() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   void AllowNewWeakGlobals() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -93,7 +94,8 @@
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void DeleteWeakGlobalRef(Thread* self, jweak obj)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void SweepJniWeakGlobals(IsMarkedCallback* callback, void* arg);
+  void SweepJniWeakGlobals(IsMarkedCallback* callback, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::Object* DecodeWeakGlobal(Thread* self, IndirectRef ref)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index f3c8250..2c0ea36 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -166,8 +166,8 @@
 
 template<class T>
 inline void PrimitiveArray<T>::VisitRoots(RootCallback* callback, void* arg) {
-  if (array_class_ != nullptr) {
-    callback(reinterpret_cast<mirror::Object**>(&array_class_), arg, 0, kRootStickyClass);
+  if (!array_class_.IsNull()) {
+    array_class_.VisitRoot(callback, arg, 0, kRootStickyClass);
   }
 }
 
diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc
index 63f9860..f54af85 100644
--- a/runtime/mirror/array.cc
+++ b/runtime/mirror/array.cc
@@ -124,7 +124,7 @@
   art::ThrowArrayStoreException(object->GetClass(), this->GetClass());
 }
 
-template <typename T> Class* PrimitiveArray<T>::array_class_ = NULL;
+template <typename T> GcRoot<Class> PrimitiveArray<T>::array_class_;
 
 // Explicitly instantiate all the primitive array types.
 template class PrimitiveArray<uint8_t>;   // BooleanArray
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 6588b57..7af88d6 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -17,10 +17,10 @@
 #ifndef ART_RUNTIME_MIRROR_ARRAY_H_
 #define ART_RUNTIME_MIRROR_ARRAY_H_
 
+#include "gc_root.h"
 #include "gc/allocator_type.h"
 #include "object.h"
 #include "object_callbacks.h"
-#include "read_barrier.h"
 
 namespace art {
 
@@ -159,27 +159,26 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static void SetArrayClass(Class* array_class) {
-    CHECK(array_class_ == nullptr);
+    CHECK(array_class_.IsNull());
     CHECK(array_class != nullptr);
-    array_class_ = array_class;
+    array_class_ = GcRoot<Class>(array_class);
   }
 
   static Class* GetArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(array_class_ != nullptr);
-    return ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
-        &array_class_);
+    DCHECK(!array_class_.IsNull());
+    return array_class_.Read();
   }
 
   static void ResetArrayClass() {
-    CHECK(array_class_ != nullptr);
-    array_class_ = nullptr;
+    CHECK(!array_class_.IsNull());
+    array_class_ = GcRoot<Class>(nullptr);
   }
 
   static void VisitRoots(RootCallback* callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
-  static Class* array_class_;
+  static GcRoot<Class> array_class_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(PrimitiveArray);
 };
diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc
index da21dfe..3c7c6ce 100644
--- a/runtime/mirror/art_field.cc
+++ b/runtime/mirror/art_field.cc
@@ -29,7 +29,7 @@
 namespace mirror {
 
 // TODO: Get global references for these
-Class* ArtField::java_lang_reflect_ArtField_ = NULL;
+GcRoot<Class> ArtField::java_lang_reflect_ArtField_;
 
 ArtField* ArtField::FromReflectedField(const ScopedObjectAccessAlreadyRunnable& soa,
                                        jobject jlr_field) {
@@ -40,14 +40,14 @@
 }
 
 void ArtField::SetClass(Class* java_lang_reflect_ArtField) {
-  CHECK(java_lang_reflect_ArtField_ == NULL);
+  CHECK(java_lang_reflect_ArtField_.IsNull());
   CHECK(java_lang_reflect_ArtField != NULL);
-  java_lang_reflect_ArtField_ = java_lang_reflect_ArtField;
+  java_lang_reflect_ArtField_ = GcRoot<Class>(java_lang_reflect_ArtField);
 }
 
 void ArtField::ResetClass() {
-  CHECK(java_lang_reflect_ArtField_ != NULL);
-  java_lang_reflect_ArtField_ = NULL;
+  CHECK(!java_lang_reflect_ArtField_.IsNull());
+  java_lang_reflect_ArtField_ = GcRoot<Class>(nullptr);
 }
 
 void ArtField::SetOffset(MemberOffset num_bytes) {
@@ -64,9 +64,8 @@
 }
 
 void ArtField::VisitRoots(RootCallback* callback, void* arg) {
-  if (java_lang_reflect_ArtField_ != nullptr) {
-    callback(reinterpret_cast<mirror::Object**>(&java_lang_reflect_ArtField_), arg, 0,
-             kRootStickyClass);
+  if (!java_lang_reflect_ArtField_.IsNull()) {
+    java_lang_reflect_ArtField_.VisitRoot(callback, arg, 0, kRootStickyClass);
   }
 }
 
diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h
index 741c6eb..f3dfa15 100644
--- a/runtime/mirror/art_field.h
+++ b/runtime/mirror/art_field.h
@@ -19,11 +19,12 @@
 
 #include <jni.h>
 
+#include "gc_root.h"
 #include "modifiers.h"
 #include "object.h"
 #include "object_callbacks.h"
 #include "primitive.h"
-#include "read_barrier.h"
+#include "read_barrier_option.h"
 
 namespace art {
 
@@ -135,9 +136,8 @@
 
   template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   static Class* GetJavaLangReflectArtField()  SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(java_lang_reflect_ArtField_ != nullptr);
-    return ReadBarrier::BarrierForRoot<mirror::Class, kReadBarrierOption>(
-        &java_lang_reflect_ArtField_);
+    DCHECK(!java_lang_reflect_ArtField_.IsNull());
+    return java_lang_reflect_ArtField_.Read<kReadBarrierOption>();
   }
 
   static void SetClass(Class* java_lang_reflect_ArtField);
@@ -180,7 +180,7 @@
   // Offset of field within an instance or in the Class' static fields
   uint32_t offset_;
 
-  static Class* java_lang_reflect_ArtField_;
+  static GcRoot<Class> java_lang_reflect_ArtField_;
 
   friend struct art::ArtFieldOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(ArtField);
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 01b05a6..73de683 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -41,9 +41,8 @@
 
 template<ReadBarrierOption kReadBarrierOption>
 inline Class* ArtMethod::GetJavaLangReflectArtMethod() {
-  DCHECK(java_lang_reflect_ArtMethod_ != nullptr);
-  return ReadBarrier::BarrierForRoot<mirror::Class, kReadBarrierOption>(
-      &java_lang_reflect_ArtMethod_);
+  DCHECK(!java_lang_reflect_ArtMethod_.IsNull());
+  return java_lang_reflect_ArtMethod_.Read<kReadBarrierOption>();
 }
 
 inline Class* ArtMethod::GetDeclaringClass() {
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 211ba1d..4882728 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -47,7 +47,7 @@
 #endif
 
 // TODO: get global references for these
-Class* ArtMethod::java_lang_reflect_ArtMethod_ = NULL;
+GcRoot<Class> ArtMethod::java_lang_reflect_ArtMethod_;
 
 ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa,
                                           jobject jlr_method) {
@@ -60,9 +60,8 @@
 
 
 void ArtMethod::VisitRoots(RootCallback* callback, void* arg) {
-  if (java_lang_reflect_ArtMethod_ != nullptr) {
-    callback(reinterpret_cast<mirror::Object**>(&java_lang_reflect_ArtMethod_), arg, 0,
-             kRootStickyClass);
+  if (!java_lang_reflect_ArtMethod_.IsNull()) {
+    java_lang_reflect_ArtMethod_.VisitRoot(callback, arg, 0, kRootStickyClass);
   }
 }
 
@@ -80,14 +79,14 @@
 }
 
 void ArtMethod::SetClass(Class* java_lang_reflect_ArtMethod) {
-  CHECK(java_lang_reflect_ArtMethod_ == NULL);
+  CHECK(java_lang_reflect_ArtMethod_.IsNull());
   CHECK(java_lang_reflect_ArtMethod != NULL);
-  java_lang_reflect_ArtMethod_ = java_lang_reflect_ArtMethod;
+  java_lang_reflect_ArtMethod_ = GcRoot<Class>(java_lang_reflect_ArtMethod);
 }
 
 void ArtMethod::ResetClass() {
-  CHECK(java_lang_reflect_ArtMethod_ != NULL);
-  java_lang_reflect_ArtMethod_ = NULL;
+  CHECK(!java_lang_reflect_ArtMethod_.IsNull());
+  java_lang_reflect_ArtMethod_ = GcRoot<Class>(nullptr);
 }
 
 void ArtMethod::SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) {
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index 081bee1..01e6149 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_MIRROR_ART_METHOD_H_
 
 #include "dex_file.h"
+#include "gc_root.h"
 #include "invoke_type.h"
 #include "modifiers.h"
 #include "object.h"
@@ -514,7 +515,7 @@
   // ifTable.
   uint32_t method_index_;
 
-  static Class* java_lang_reflect_ArtMethod_;
+  static GcRoot<Class> java_lang_reflect_ArtMethod_;
 
  private:
   friend struct art::ArtMethodOffsets;  // for verifying offset information
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index a218b1c..f29ba73 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -36,24 +36,24 @@
 namespace art {
 namespace mirror {
 
-Class* Class::java_lang_Class_ = nullptr;
+GcRoot<Class> Class::java_lang_Class_;
 
 void Class::SetClassClass(Class* java_lang_Class) {
-  CHECK(java_lang_Class_ == nullptr)
-      << ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(&java_lang_Class_)
+  CHECK(java_lang_Class_.IsNull())
+      << java_lang_Class_.Read()
       << " " << java_lang_Class;
   CHECK(java_lang_Class != nullptr);
-  java_lang_Class_ = java_lang_Class;
+  java_lang_Class_ = GcRoot<Class>(java_lang_Class);
 }
 
 void Class::ResetClass() {
-  CHECK(java_lang_Class_ != nullptr);
-  java_lang_Class_ = nullptr;
+  CHECK(!java_lang_Class_.IsNull());
+  java_lang_Class_ = GcRoot<Class>(nullptr);
 }
 
 void Class::VisitRoots(RootCallback* callback, void* arg) {
-  if (java_lang_Class_ != nullptr) {
-    callback(reinterpret_cast<mirror::Object**>(&java_lang_Class_), arg, 0, kRootStickyClass);
+  if (!java_lang_Class_.IsNull()) {
+    java_lang_Class_.VisitRoot(callback, arg, 0, kRootStickyClass);
   }
 }
 
@@ -879,8 +879,9 @@
   CopyClassVisitor visitor(self, &h_this, new_length, sizeof(Class));
 
   mirror::Object* new_class =
-      kMovingClasses ? heap->AllocObject<true>(self, java_lang_Class_, new_length, visitor)
-                     : heap->AllocNonMovableObject<true>(self, java_lang_Class_, new_length, visitor);
+      kMovingClasses
+         ? heap->AllocObject<true>(self, java_lang_Class_.Read(), new_length, visitor)
+         : heap->AllocNonMovableObject<true>(self, java_lang_Class_.Read(), new_length, visitor);
   if (UNLIKELY(new_class == nullptr)) {
     CHECK(self->IsExceptionPending());  // Expect an OOME.
     return NULL;
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 0525abf..1e254fa 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_MIRROR_CLASS_H_
 
 #include "dex_file.h"
+#include "gc_root.h"
 #include "gc/allocator_type.h"
 #include "invoke_type.h"
 #include "modifiers.h"
@@ -25,7 +26,7 @@
 #include "object_array.h"
 #include "object_callbacks.h"
 #include "primitive.h"
-#include "read_barrier.h"
+#include "read_barrier_option.h"
 
 /*
  * A magic value for refOffsets. Ignore the bits and walk the super
@@ -936,9 +937,8 @@
   }
 
   static Class* GetJavaLangClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(java_lang_Class_ != NULL);
-    return ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
-        &java_lang_Class_);
+    DCHECK(!java_lang_Class_.IsNull());
+    return java_lang_Class_.Read();
   }
 
   // Can't call this SetClass or else gets called instead of Object::SetClass in places.
@@ -1156,7 +1156,7 @@
   uint32_t fields_[0];
 
   // java.lang.Class
-  static Class* java_lang_Class_;
+  static GcRoot<Class> java_lang_Class_;
 
   friend struct art::ClassOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(Class);
diff --git a/runtime/mirror/reference.cc b/runtime/mirror/reference.cc
index 077cd4b..c36bd98 100644
--- a/runtime/mirror/reference.cc
+++ b/runtime/mirror/reference.cc
@@ -19,23 +19,22 @@
 namespace art {
 namespace mirror {
 
-Class* Reference::java_lang_ref_Reference_ = nullptr;
+GcRoot<Class> Reference::java_lang_ref_Reference_;
 
 void Reference::SetClass(Class* java_lang_ref_Reference) {
-  CHECK(java_lang_ref_Reference_ == nullptr);
+  CHECK(java_lang_ref_Reference_.IsNull());
   CHECK(java_lang_ref_Reference != nullptr);
-  java_lang_ref_Reference_ = java_lang_ref_Reference;
+  java_lang_ref_Reference_ = GcRoot<Class>(java_lang_ref_Reference);
 }
 
 void Reference::ResetClass() {
-  CHECK(java_lang_ref_Reference_ != nullptr);
-  java_lang_ref_Reference_ = nullptr;
+  CHECK(!java_lang_ref_Reference_.IsNull());
+  java_lang_ref_Reference_ = GcRoot<Class>(nullptr);
 }
 
 void Reference::VisitRoots(RootCallback* callback, void* arg) {
-  if (java_lang_ref_Reference_ != nullptr) {
-    callback(reinterpret_cast<mirror::Object**>(&java_lang_ref_Reference_),
-             arg, 0, kRootStickyClass);
+  if (!java_lang_ref_Reference_.IsNull()) {
+    java_lang_ref_Reference_.VisitRoot(callback, arg, 0, kRootStickyClass);
   }
 }
 
diff --git a/runtime/mirror/reference.h b/runtime/mirror/reference.h
index 07d47d3..7345448 100644
--- a/runtime/mirror/reference.h
+++ b/runtime/mirror/reference.h
@@ -18,9 +18,10 @@
 #define ART_RUNTIME_MIRROR_REFERENCE_H_
 
 #include "class.h"
+#include "gc_root.h"
 #include "object.h"
 #include "object_callbacks.h"
-#include "read_barrier.h"
+#include "read_barrier_option.h"
 #include "thread.h"
 
 namespace art {
@@ -94,9 +95,8 @@
 
   template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   static Class* GetJavaLangRefReference() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(java_lang_ref_Reference_ != nullptr);
-    return ReadBarrier::BarrierForRoot<mirror::Class, kReadBarrierOption>(
-        &java_lang_ref_Reference_);
+    DCHECK(!java_lang_ref_Reference_.IsNull());
+    return java_lang_ref_Reference_.Read<kReadBarrierOption>();
   }
   static void SetClass(Class* klass);
   static void ResetClass(void);
@@ -114,7 +114,7 @@
   HeapReference<Reference> queue_next_;  // Note this is Java volatile:
   HeapReference<Object> referent_;  // Note this is Java volatile:
 
-  static Class* java_lang_ref_Reference_;
+  static GcRoot<Class> java_lang_ref_Reference_;
 
   friend struct art::ReferenceOffsets;  // for verifying offset information
   friend class gc::ReferenceProcessor;
diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc
index b1de2b6..1eb20f7 100644
--- a/runtime/mirror/stack_trace_element.cc
+++ b/runtime/mirror/stack_trace_element.cc
@@ -26,17 +26,17 @@
 namespace art {
 namespace mirror {
 
-Class* StackTraceElement::java_lang_StackTraceElement_ = NULL;
+GcRoot<Class> StackTraceElement::java_lang_StackTraceElement_;
 
 void StackTraceElement::SetClass(Class* java_lang_StackTraceElement) {
-  CHECK(java_lang_StackTraceElement_ == NULL);
+  CHECK(java_lang_StackTraceElement_.IsNull());
   CHECK(java_lang_StackTraceElement != NULL);
-  java_lang_StackTraceElement_ = java_lang_StackTraceElement;
+  java_lang_StackTraceElement_ = GcRoot<Class>(java_lang_StackTraceElement);
 }
 
 void StackTraceElement::ResetClass() {
-  CHECK(java_lang_StackTraceElement_ != NULL);
-  java_lang_StackTraceElement_ = NULL;
+  CHECK(!java_lang_StackTraceElement_.IsNull());
+  java_lang_StackTraceElement_ = GcRoot<Class>(nullptr);
 }
 
 StackTraceElement* StackTraceElement::Alloc(Thread* self, Handle<String> declaring_class,
@@ -68,9 +68,8 @@
 }
 
 void StackTraceElement::VisitRoots(RootCallback* callback, void* arg) {
-  if (java_lang_StackTraceElement_ != nullptr) {
-    callback(reinterpret_cast<mirror::Object**>(&java_lang_StackTraceElement_), arg, 0,
-             kRootStickyClass);
+  if (!java_lang_StackTraceElement_.IsNull()) {
+    java_lang_StackTraceElement_.VisitRoot(callback, arg, 0, kRootStickyClass);
   }
 }
 
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index 52b0927..70acd1c 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -17,9 +17,9 @@
 #ifndef ART_RUNTIME_MIRROR_STACK_TRACE_ELEMENT_H_
 #define ART_RUNTIME_MIRROR_STACK_TRACE_ELEMENT_H_
 
+#include "gc_root.h"
 #include "object.h"
 #include "object_callbacks.h"
-#include "read_barrier.h"
 
 namespace art {
 
@@ -57,9 +57,8 @@
   static void VisitRoots(RootCallback* callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static Class* GetStackTraceElement() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(java_lang_StackTraceElement_ != NULL);
-    return ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
-        &java_lang_StackTraceElement_);
+    DCHECK(!java_lang_StackTraceElement_.IsNull());
+    return java_lang_StackTraceElement_.Read();
   }
 
  private:
@@ -74,7 +73,7 @@
             int32_t line_number)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static Class* java_lang_StackTraceElement_;
+  static GcRoot<Class> java_lang_StackTraceElement_;
 
   friend struct art::StackTraceElementOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(StackTraceElement);
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index 5c57dce..e81e431 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -31,7 +31,7 @@
 namespace mirror {
 
 // TODO: get global references for these
-Class* String::java_lang_String_ = NULL;
+GcRoot<Class> String::java_lang_String_;
 
 int32_t String::FastIndexOf(int32_t ch, int32_t start) {
   int32_t count = GetLength();
@@ -52,14 +52,14 @@
 }
 
 void String::SetClass(Class* java_lang_String) {
-  CHECK(java_lang_String_ == NULL);
+  CHECK(java_lang_String_.IsNull());
   CHECK(java_lang_String != NULL);
-  java_lang_String_ = java_lang_String;
+  java_lang_String_ = GcRoot<Class>(java_lang_String);
 }
 
 void String::ResetClass() {
-  CHECK(java_lang_String_ != NULL);
-  java_lang_String_ = NULL;
+  CHECK(!java_lang_String_.IsNull());
+  java_lang_String_ = GcRoot<Class>(nullptr);
 }
 
 int32_t String::GetHashCode() {
@@ -233,8 +233,8 @@
 }
 
 void String::VisitRoots(RootCallback* callback, void* arg) {
-  if (java_lang_String_ != nullptr) {
-    callback(reinterpret_cast<mirror::Object**>(&java_lang_String_), arg, 0, kRootStickyClass);
+  if (!java_lang_String_.IsNull()) {
+    java_lang_String_.VisitRoot(callback, arg, 0, kRootStickyClass);
   }
 }
 
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 46bdd59..66a5dd8 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -19,9 +19,9 @@
 
 #include <gtest/gtest.h>
 
+#include "gc_root.h"
 #include "object.h"
 #include "object_callbacks.h"
-#include "read_barrier.h"
 
 namespace art {
 
@@ -111,9 +111,8 @@
   int32_t CompareTo(String* other) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static Class* GetJavaLangString() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(java_lang_String_ != NULL);
-    return ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
-        &java_lang_String_);
+    DCHECK(!java_lang_String_.IsNull());
+    return java_lang_String_.Read();
   }
 
   static void SetClass(Class* java_lang_String);
@@ -160,7 +159,7 @@
 
   int32_t offset_;
 
-  static Class* java_lang_String_;
+  static GcRoot<Class> java_lang_String_;
 
   friend struct art::StringOffsets;  // for verifying offset information
   FRIEND_TEST(ObjectTest, StringLength);  // for SetOffset and SetCount
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index 1c3f1ed..93ed4d4 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -30,7 +30,7 @@
 namespace art {
 namespace mirror {
 
-Class* Throwable::java_lang_Throwable_ = NULL;
+GcRoot<Class> Throwable::java_lang_Throwable_;
 
 void Throwable::SetDetailMessage(String* new_detail_message) {
   if (Runtime::Current()->IsActiveTransaction()) {
@@ -127,19 +127,19 @@
 }
 
 void Throwable::SetClass(Class* java_lang_Throwable) {
-  CHECK(java_lang_Throwable_ == NULL);
+  CHECK(java_lang_Throwable_.IsNull());
   CHECK(java_lang_Throwable != NULL);
-  java_lang_Throwable_ = java_lang_Throwable;
+  java_lang_Throwable_ = GcRoot<Class>(java_lang_Throwable);
 }
 
 void Throwable::ResetClass() {
-  CHECK(java_lang_Throwable_ != NULL);
-  java_lang_Throwable_ = NULL;
+  CHECK(!java_lang_Throwable_.IsNull());
+  java_lang_Throwable_ = GcRoot<Class>(nullptr);
 }
 
 void Throwable::VisitRoots(RootCallback* callback, void* arg) {
-  if (java_lang_Throwable_ != nullptr) {
-    callback(reinterpret_cast<mirror::Object**>(&java_lang_Throwable_), arg, 0, kRootStickyClass);
+  if (!java_lang_Throwable_.IsNull()) {
+    java_lang_Throwable_.VisitRoot(callback, arg, 0, kRootStickyClass);
   }
 }
 
diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h
index cf54ad6..f90812d 100644
--- a/runtime/mirror/throwable.h
+++ b/runtime/mirror/throwable.h
@@ -17,9 +17,9 @@
 #ifndef ART_RUNTIME_MIRROR_THROWABLE_H_
 #define ART_RUNTIME_MIRROR_THROWABLE_H_
 
+#include "gc_root.h"
 #include "object.h"
 #include "object_callbacks.h"
-#include "read_barrier.h"
 #include "string.h"
 
 namespace art {
@@ -47,9 +47,8 @@
   bool IsCheckedException() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static Class* GetJavaLangThrowable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(java_lang_Throwable_ != NULL);
-    return ReadBarrier::BarrierForRoot<mirror::Class, kWithReadBarrier>(
-        &java_lang_Throwable_);
+    DCHECK(!java_lang_Throwable_.IsNull());
+    return java_lang_Throwable_.Read();
   }
 
   static void SetClass(Class* java_lang_Throwable);
@@ -72,7 +71,7 @@
   HeapReference<Object> stack_trace_;
   HeapReference<Object> suppressed_exceptions_;
 
-  static Class* java_lang_Throwable_;
+  static GcRoot<Class> java_lang_Throwable_;
 
   friend struct art::ThrowableOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(Throwable);
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 371a9d9..433c1b2 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -84,7 +84,7 @@
       num_waiters_(0),
       owner_(owner),
       lock_count_(0),
-      obj_(obj),
+      obj_(GcRoot<mirror::Object>(obj)),
       wait_set_(NULL),
       hash_code_(hash_code),
       locking_method_(NULL),
@@ -107,7 +107,7 @@
       num_waiters_(0),
       owner_(owner),
       lock_count_(0),
-      obj_(obj),
+      obj_(GcRoot<mirror::Object>(obj)),
       wait_set_(NULL),
       hash_code_(hash_code),
       locking_method_(NULL),
@@ -225,7 +225,7 @@
 }
 
 void Monitor::SetObject(mirror::Object* object) {
-  obj_ = object;
+  obj_ = GcRoot<mirror::Object>(object);
 }
 
 void Monitor::Lock(Thread* self) {
@@ -636,7 +636,7 @@
     }
     // The monitor is deflated, mark the object as nullptr so that we know to delete it during the
     // next GC.
-    monitor->obj_ = nullptr;
+    monitor->obj_ = GcRoot<mirror::Object>(nullptr);
   }
   return true;
 }
diff --git a/runtime/monitor.h b/runtime/monitor.h
index 0d0ad0b..26d43c9 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -26,8 +26,9 @@
 
 #include "atomic.h"
 #include "base/mutex.h"
+#include "gc_root.h"
 #include "object_callbacks.h"
-#include "read_barrier.h"
+#include "read_barrier_option.h"
 #include "thread_state.h"
 
 namespace art {
@@ -95,7 +96,7 @@
 
   template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   mirror::Object* GetObject() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return ReadBarrier::BarrierForRoot<mirror::Object, kReadBarrierOption>(&obj_);
+    return obj_.Read<kReadBarrierOption>();
   }
 
   void SetObject(mirror::Object* object);
@@ -197,7 +198,7 @@
   // What object are we part of. This is a weak root. Do not access
   // this directly, use GetObject() to read it so it will be guarded
   // by a read barrier.
-  mirror::Object* obj_;
+  GcRoot<mirror::Object> obj_;
 
   // Threads currently waiting on this monitor.
   Thread* wait_set_ GUARDED_BY(monitor_lock_);
diff --git a/runtime/reference_table.cc b/runtime/reference_table.cc
index cd35863..70aba9b 100644
--- a/runtime/reference_table.cc
+++ b/runtime/reference_table.cc
@@ -24,7 +24,6 @@
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/string-inl.h"
-#include "read_barrier.h"
 #include "thread.h"
 #include "utils.h"
 
@@ -46,14 +45,13 @@
     LOG(FATAL) << "ReferenceTable '" << name_ << "' "
                << "overflowed (" << max_size_ << " entries)";
   }
-  entries_.push_back(obj);
+  entries_.push_back(GcRoot<mirror::Object>(obj));
 }
 
 void ReferenceTable::Remove(mirror::Object* obj) {
   // We iterate backwards on the assumption that references are LIFO.
   for (int i = entries_.size() - 1; i >= 0; --i) {
-    mirror::Object* entry =
-        ReadBarrier::BarrierForRoot<mirror::Object, kWithReadBarrier>(&entries_[i]);
+    mirror::Object* entry = entries_[i].Read();
     if (entry == obj) {
       entries_.erase(entries_.begin() + i);
       return;
@@ -71,10 +69,12 @@
 }
 
 struct ObjectComparator {
-  bool operator()(mirror::Object* obj1, mirror::Object* obj2)
+  bool operator()(GcRoot<mirror::Object> root1, GcRoot<mirror::Object> root2)
     // TODO: enable analysis when analysis can work with the STL.
       NO_THREAD_SAFETY_ANALYSIS {
     Locks::mutator_lock_->AssertSharedHeld(Thread::Current());
+    mirror::Object* obj1 = root1.Read<kWithoutReadBarrier>();
+    mirror::Object* obj2 = root2.Read<kWithoutReadBarrier>();
     // Ensure null references and cleared jweaks appear at the end.
     if (obj1 == NULL) {
       return true;
@@ -163,8 +163,7 @@
   }
   os << "  Last " << (count - first) << " entries (of " << count << "):\n";
   for (int idx = count - 1; idx >= first; --idx) {
-    mirror::Object* ref =
-        ReadBarrier::BarrierForRoot<mirror::Object, kWithReadBarrier>(&entries[idx]);
+    mirror::Object* ref = entries[idx].Read();
     if (ref == NULL) {
       continue;
     }
@@ -200,17 +199,17 @@
   // Make a copy of the table and sort it.
   Table sorted_entries;
   for (size_t i = 0; i < entries.size(); ++i) {
-    mirror::Object* entry =
-        ReadBarrier::BarrierForRoot<mirror::Object, kWithReadBarrier>(&entries[i]);
-    sorted_entries.push_back(entry);
+    mirror::Object* entry = entries[i].Read();
+    sorted_entries.push_back(GcRoot<mirror::Object>(entry));
   }
   std::sort(sorted_entries.begin(), sorted_entries.end(), ObjectComparator());
 
   // Remove any uninteresting stuff from the list. The sort moved them all to the end.
-  while (!sorted_entries.empty() && sorted_entries.back() == NULL) {
+  while (!sorted_entries.empty() && sorted_entries.back().IsNull()) {
     sorted_entries.pop_back();
   }
-  while (!sorted_entries.empty() && sorted_entries.back() == kClearedJniWeakGlobal) {
+  while (!sorted_entries.empty() &&
+         sorted_entries.back().Read<kWithoutReadBarrier>() == kClearedJniWeakGlobal) {
     sorted_entries.pop_back();
   }
   if (sorted_entries.empty()) {
@@ -222,8 +221,8 @@
   size_t equiv = 0;
   size_t identical = 0;
   for (size_t idx = 1; idx < count; idx++) {
-    mirror::Object* prev = sorted_entries[idx-1];
-    mirror::Object* current = sorted_entries[idx];
+    mirror::Object* prev = sorted_entries[idx-1].Read<kWithoutReadBarrier>();
+    mirror::Object* current = sorted_entries[idx].Read<kWithoutReadBarrier>();
     size_t element_count = GetElementCount(prev);
     if (current == prev) {
       // Same reference, added more than once.
@@ -238,13 +237,15 @@
     }
   }
   // Handle the last entry.
-  DumpSummaryLine(os, sorted_entries.back(), GetElementCount(sorted_entries.back()), identical, equiv);
+  DumpSummaryLine(os, sorted_entries.back().Read<kWithoutReadBarrier>(),
+                  GetElementCount(sorted_entries.back().Read<kWithoutReadBarrier>()),
+                  identical, equiv);
 }
 
 void ReferenceTable::VisitRoots(RootCallback* visitor, void* arg, uint32_t tid,
                                 RootType root_type) {
-  for (auto& ref : entries_) {
-    visitor(&ref, arg, tid, root_type);
+  for (GcRoot<mirror::Object>& root : entries_) {
+    root.VisitRoot(visitor, arg, tid, root_type);
   }
 }
 
diff --git a/runtime/reference_table.h b/runtime/reference_table.h
index 1cd0999..8765442 100644
--- a/runtime/reference_table.h
+++ b/runtime/reference_table.h
@@ -23,6 +23,7 @@
 #include <vector>
 
 #include "base/mutex.h"
+#include "gc_root.h"
 #include "object_callbacks.h"
 
 namespace art {
@@ -50,7 +51,7 @@
   void VisitRoots(RootCallback* visitor, void* arg, uint32_t tid, RootType root_type);
 
  private:
-  typedef std::vector<mirror::Object*> Table;
+  typedef std::vector<GcRoot<mirror::Object>> Table;
   static void Dump(std::ostream& os, Table& entries)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   friend class IndirectReferenceTable;  // For Dump.
diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h
index f776bcd..ac9026b 100644
--- a/runtime/runtime-inl.h
+++ b/runtime/runtime-inl.h
@@ -41,32 +41,29 @@
 
 inline mirror::ArtMethod* Runtime::GetResolutionMethod() {
   CHECK(HasResolutionMethod());
-  return ReadBarrier::BarrierForRoot<mirror::ArtMethod, kWithReadBarrier>(&resolution_method_);
+  return resolution_method_.Read();
 }
 
 inline mirror::ArtMethod* Runtime::GetImtConflictMethod() {
   CHECK(HasImtConflictMethod());
-  return ReadBarrier::BarrierForRoot<mirror::ArtMethod, kWithReadBarrier>(&imt_conflict_method_);
+  return imt_conflict_method_.Read();
 }
 
 inline mirror::ObjectArray<mirror::ArtMethod>* Runtime::GetDefaultImt()
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   CHECK(HasDefaultImt());
-  return ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::ArtMethod>, kWithReadBarrier>(
-      &default_imt_);
+  return default_imt_.Read();
 }
 
 inline mirror::ArtMethod* Runtime::GetCalleeSaveMethod(CalleeSaveType type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK(HasCalleeSaveMethod(type));
-  return ReadBarrier::BarrierForRoot<mirror::ArtMethod, kWithReadBarrier>(
-      &callee_save_methods_[type]);
+  return callee_save_methods_[type].Read();
 }
 
 inline mirror::ArtMethod* Runtime::GetCalleeSaveMethodUnchecked(CalleeSaveType type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  return ReadBarrier::BarrierForRoot<mirror::ArtMethod, kWithReadBarrier>(
-      &callee_save_methods_[type]);
+  return callee_save_methods_[type].Read();
 }
 
 }  // namespace art
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1cbf841..e34a2d7 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -95,11 +95,7 @@
 Runtime* Runtime::instance_ = NULL;
 
 Runtime::Runtime()
-    : pre_allocated_OutOfMemoryError_(nullptr),
-      resolution_method_(nullptr),
-      imt_conflict_method_(nullptr),
-      default_imt_(nullptr),
-      instruction_set_(kNone),
+    : instruction_set_(kNone),
       compiler_callbacks_(nullptr),
       is_zygote_(false),
       must_relocate_(false),
@@ -147,9 +143,6 @@
       implicit_null_checks_(false),
       implicit_so_checks_(false),
       implicit_suspend_checks_(false) {
-  for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
-    callee_save_methods_[i] = nullptr;
-  }
 }
 
 Runtime::~Runtime() {
@@ -716,7 +709,7 @@
   self->ThrowNewException(ThrowLocation(), "Ljava/lang/OutOfMemoryError;",
                           "OutOfMemoryError thrown while trying to throw OutOfMemoryError; "
                           "no stack available");
-  pre_allocated_OutOfMemoryError_ = self->GetException(NULL);
+  pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>(self->GetException(NULL));
   self->ClearException();
 
   // Look for a native bridge.
@@ -931,8 +924,7 @@
 }
 
 mirror::Throwable* Runtime::GetPreAllocatedOutOfMemoryError() {
-  mirror::Throwable* oome = ReadBarrier::BarrierForRoot<mirror::Throwable, kWithReadBarrier>(
-      &pre_allocated_OutOfMemoryError_);
+  mirror::Throwable* oome = pre_allocated_OutOfMemoryError_.Read();
   if (oome == NULL) {
     LOG(ERROR) << "Failed to return pre-allocated OOME";
   }
@@ -971,23 +963,21 @@
 
 void Runtime::VisitNonThreadRoots(RootCallback* callback, void* arg) {
   java_vm_->VisitRoots(callback, arg);
-  if (pre_allocated_OutOfMemoryError_ != nullptr) {
-    callback(reinterpret_cast<mirror::Object**>(&pre_allocated_OutOfMemoryError_), arg, 0,
-             kRootVMInternal);
-    DCHECK(pre_allocated_OutOfMemoryError_ != nullptr);
+  if (!pre_allocated_OutOfMemoryError_.IsNull()) {
+    pre_allocated_OutOfMemoryError_.VisitRoot(callback, arg, 0, kRootVMInternal);
+    DCHECK(!pre_allocated_OutOfMemoryError_.IsNull());
   }
-  callback(reinterpret_cast<mirror::Object**>(&resolution_method_), arg, 0, kRootVMInternal);
-  DCHECK(resolution_method_ != nullptr);
+  resolution_method_.VisitRoot(callback, arg, 0, kRootVMInternal);
+  DCHECK(!resolution_method_.IsNull());
   if (HasImtConflictMethod()) {
-    callback(reinterpret_cast<mirror::Object**>(&imt_conflict_method_), arg, 0, kRootVMInternal);
+    imt_conflict_method_.VisitRoot(callback, arg, 0, kRootVMInternal);
   }
   if (HasDefaultImt()) {
-    callback(reinterpret_cast<mirror::Object**>(&default_imt_), arg, 0, kRootVMInternal);
+    default_imt_.VisitRoot(callback, arg, 0, kRootVMInternal);
   }
   for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
-    if (callee_save_methods_[i] != nullptr) {
-      callback(reinterpret_cast<mirror::Object**>(&callee_save_methods_[i]), arg, 0,
-               kRootVMInternal);
+    if (!callee_save_methods_[i].IsNull()) {
+      callee_save_methods_[i].VisitRoot(callback, arg, 0, kRootVMInternal);
     }
   }
   {
@@ -1125,7 +1115,7 @@
 
 void Runtime::SetCalleeSaveMethod(mirror::ArtMethod* method, CalleeSaveType type) {
   DCHECK_LT(static_cast<int>(type), static_cast<int>(kLastCalleeSaveType));
-  callee_save_methods_[type] = method;
+  callee_save_methods_[type] = GcRoot<mirror::ArtMethod>(method);
 }
 
 const std::vector<const DexFile*>& Runtime::GetCompileTimeClassPath(jobject class_loader) {
diff --git a/runtime/runtime.h b/runtime/runtime.h
index c8e462e..a85c2e4 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -27,6 +27,7 @@
 #include <vector>
 
 #include "compiler_callbacks.h"
+#include "gc_root.h"
 #include "instrumentation.h"
 #include "instruction_set.h"
 #include "jobject_comparator.h"
@@ -282,11 +283,11 @@
   mirror::ArtMethod* GetResolutionMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool HasResolutionMethod() const {
-    return resolution_method_ != nullptr;
+    return !resolution_method_.IsNull();
   }
 
   void SetResolutionMethod(mirror::ArtMethod* method) {
-    resolution_method_ = method;
+    resolution_method_ = GcRoot<mirror::ArtMethod>(method);
   }
 
   mirror::ArtMethod* CreateResolutionMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -295,11 +296,11 @@
   mirror::ArtMethod* GetImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool HasImtConflictMethod() const {
-    return imt_conflict_method_ != nullptr;
+    return !imt_conflict_method_.IsNull();
   }
 
   void SetImtConflictMethod(mirror::ArtMethod* method) {
-    imt_conflict_method_ = method;
+    imt_conflict_method_ = GcRoot<mirror::ArtMethod>(method);
   }
 
   mirror::ArtMethod* CreateImtConflictMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -309,11 +310,11 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool HasDefaultImt() const {
-    return default_imt_ != nullptr;
+    return !default_imt_.IsNull();
   }
 
   void SetDefaultImt(mirror::ObjectArray<mirror::ArtMethod>* imt) {
-    default_imt_ = imt;
+    default_imt_ = GcRoot<mirror::ObjectArray<mirror::ArtMethod>>(imt);
   }
 
   mirror::ObjectArray<mirror::ArtMethod>* CreateDefaultImt(ClassLinker* cl)
@@ -328,7 +329,7 @@
   };
 
   bool HasCalleeSaveMethod(CalleeSaveType type) const {
-    return callee_save_methods_[type] != NULL;
+    return !callee_save_methods_[type].IsNull();
   }
 
   mirror::ArtMethod* GetCalleeSaveMethod(CalleeSaveType type)
@@ -488,11 +489,11 @@
   static constexpr int kProfileForground = 0;
   static constexpr int kProfileBackgrouud = 1;
 
-  mirror::ArtMethod* callee_save_methods_[kLastCalleeSaveType];
-  mirror::Throwable* pre_allocated_OutOfMemoryError_;
-  mirror::ArtMethod* resolution_method_;
-  mirror::ArtMethod* imt_conflict_method_;
-  mirror::ObjectArray<mirror::ArtMethod>* default_imt_;
+  GcRoot<mirror::ArtMethod> callee_save_methods_[kLastCalleeSaveType];
+  GcRoot<mirror::Throwable> pre_allocated_OutOfMemoryError_;
+  GcRoot<mirror::ArtMethod> resolution_method_;
+  GcRoot<mirror::ArtMethod> imt_conflict_method_;
+  GcRoot<mirror::ObjectArray<mirror::ArtMethod>> default_imt_;
 
   InstructionSet instruction_set_;
   QuickMethodFrameInfo callee_save_method_frame_infos_[kLastCalleeSaveType];
diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h
index d691623..23aca45 100644
--- a/runtime/scoped_thread_state_change.h
+++ b/runtime/scoped_thread_state_change.h
@@ -19,6 +19,7 @@
 
 #include "base/casts.h"
 #include "jni_internal-inl.h"
+#include "read_barrier.h"
 #include "thread-inl.h"
 #include "verify_object.h"