Refactor ClassRoot/GetClassRoot().

Move it outside the ClassLinker, into its own header file,
and add retrieval based on a mirror class template argument.
Keep the SetClassRoot() as a private member of ClassLinker.

Make the new GetClassRoot()s return ObjPtr<>.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 31113334
Change-Id: Icbc6b62b41f6ffd65b437297a21eadbb0454e2b7
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 92607f5..9043866 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -40,6 +40,7 @@
         "check_jni.cc",
         "class_linker.cc",
         "class_loader_context.cc",
+        "class_root.cc",
         "class_table.cc",
         "common_throws.cc",
         "compiler_filter.cc",
diff --git a/runtime/class_linker-inl.h b/runtime/class_linker-inl.h
index ae06f8f..7a99d3d 100644
--- a/runtime/class_linker-inl.h
+++ b/runtime/class_linker-inl.h
@@ -365,14 +365,6 @@
   return resolved_field;
 }
 
-inline mirror::Class* ClassLinker::GetClassRoot(ClassRoot class_root) {
-  DCHECK(!class_roots_.IsNull());
-  mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read();
-  ObjPtr<mirror::Class> klass = class_roots->Get(class_root);
-  DCHECK(klass != nullptr);
-  return klass.Ptr();
-}
-
 template <class Visitor>
 inline void ClassLinker::VisitClassTables(const Visitor& visitor) {
   Thread* const self = Thread::Current();
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index b88aa5e..e2449f9 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -51,6 +51,7 @@
 #include "cha.h"
 #include "class_linker-inl.h"
 #include "class_loader_utils.h"
+#include "class_root.h"
 #include "class_table-inl.h"
 #include "compiler_callbacks.h"
 #include "debug_print.h"
@@ -516,29 +517,30 @@
 
   // Create storage for root classes, save away our work so far (requires descriptors).
   class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(
-      mirror::ObjectArray<mirror::Class>::Alloc(self, object_array_class.Get(),
-                                                kClassRootsMax));
+      mirror::ObjectArray<mirror::Class>::Alloc(self,
+                                                object_array_class.Get(),
+                                                static_cast<int32_t>(ClassRoot::kMax)));
   CHECK(!class_roots_.IsNull());
-  SetClassRoot(kJavaLangClass, java_lang_Class.Get());
-  SetClassRoot(kJavaLangObject, java_lang_Object.Get());
-  SetClassRoot(kClassArrayClass, class_array_class.Get());
-  SetClassRoot(kObjectArrayClass, object_array_class.Get());
-  SetClassRoot(kCharArrayClass, char_array_class.Get());
-  SetClassRoot(kJavaLangString, java_lang_String.Get());
-  SetClassRoot(kJavaLangRefReference, java_lang_ref_Reference.Get());
+  SetClassRoot(ClassRoot::kJavaLangClass, java_lang_Class.Get());
+  SetClassRoot(ClassRoot::kJavaLangObject, java_lang_Object.Get());
+  SetClassRoot(ClassRoot::kClassArrayClass, class_array_class.Get());
+  SetClassRoot(ClassRoot::kObjectArrayClass, object_array_class.Get());
+  SetClassRoot(ClassRoot::kCharArrayClass, char_array_class.Get());
+  SetClassRoot(ClassRoot::kJavaLangString, java_lang_String.Get());
+  SetClassRoot(ClassRoot::kJavaLangRefReference, java_lang_ref_Reference.Get());
 
   // Fill in the empty iftable. Needs to be done after the kObjectArrayClass root is set.
   java_lang_Object->SetIfTable(AllocIfTable(self, 0));
 
   // Setup the primitive type classes.
-  SetClassRoot(kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean));
-  SetClassRoot(kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte));
-  SetClassRoot(kPrimitiveShort, CreatePrimitiveClass(self, Primitive::kPrimShort));
-  SetClassRoot(kPrimitiveInt, CreatePrimitiveClass(self, Primitive::kPrimInt));
-  SetClassRoot(kPrimitiveLong, CreatePrimitiveClass(self, Primitive::kPrimLong));
-  SetClassRoot(kPrimitiveFloat, CreatePrimitiveClass(self, Primitive::kPrimFloat));
-  SetClassRoot(kPrimitiveDouble, CreatePrimitiveClass(self, Primitive::kPrimDouble));
-  SetClassRoot(kPrimitiveVoid, CreatePrimitiveClass(self, Primitive::kPrimVoid));
+  SetClassRoot(ClassRoot::kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean));
+  SetClassRoot(ClassRoot::kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte));
+  SetClassRoot(ClassRoot::kPrimitiveShort, CreatePrimitiveClass(self, Primitive::kPrimShort));
+  SetClassRoot(ClassRoot::kPrimitiveInt, CreatePrimitiveClass(self, Primitive::kPrimInt));
+  SetClassRoot(ClassRoot::kPrimitiveLong, CreatePrimitiveClass(self, Primitive::kPrimLong));
+  SetClassRoot(ClassRoot::kPrimitiveFloat, CreatePrimitiveClass(self, Primitive::kPrimFloat));
+  SetClassRoot(ClassRoot::kPrimitiveDouble, CreatePrimitiveClass(self, Primitive::kPrimDouble));
+  SetClassRoot(ClassRoot::kPrimitiveVoid, CreatePrimitiveClass(self, Primitive::kPrimVoid));
 
   // Create array interface entries to populate once we can load system classes.
   array_iftable_ = GcRoot<mirror::IfTable>(AllocIfTable(self, 2));
@@ -546,23 +548,23 @@
   // Create int array type for AllocDexCache (done in AppendToBootClassPath).
   Handle<mirror::Class> int_array_class(hs.NewHandle(
       AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_))));
-  int_array_class->SetComponentType(GetClassRoot(kPrimitiveInt));
+  int_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveInt, this));
   mirror::IntArray::SetArrayClass(int_array_class.Get());
-  SetClassRoot(kIntArrayClass, int_array_class.Get());
+  SetClassRoot(ClassRoot::kIntArrayClass, int_array_class.Get());
 
   // Create long array type for AllocDexCache (done in AppendToBootClassPath).
   Handle<mirror::Class> long_array_class(hs.NewHandle(
       AllocClass(self, java_lang_Class.Get(), mirror::Array::ClassSize(image_pointer_size_))));
-  long_array_class->SetComponentType(GetClassRoot(kPrimitiveLong));
+  long_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveLong, this));
   mirror::LongArray::SetArrayClass(long_array_class.Get());
-  SetClassRoot(kLongArrayClass, long_array_class.Get());
+  SetClassRoot(ClassRoot::kLongArrayClass, long_array_class.Get());
 
   // now that these are registered, we can use AllocClass() and AllocObjectArray
 
   // Set up DexCache. This cannot be done later since AppendToBootClassPath calls AllocDexCache.
   Handle<mirror::Class> java_lang_DexCache(hs.NewHandle(
       AllocClass(self, java_lang_Class.Get(), mirror::DexCache::ClassSize(image_pointer_size_))));
-  SetClassRoot(kJavaLangDexCache, java_lang_DexCache.Get());
+  SetClassRoot(ClassRoot::kJavaLangDexCache, java_lang_DexCache.Get());
   java_lang_DexCache->SetDexCacheClass();
   java_lang_DexCache->SetObjectSize(mirror::DexCache::InstanceSize());
   mirror::Class::SetStatus(java_lang_DexCache, ClassStatus::kResolved, self);
@@ -571,7 +573,7 @@
   // Setup dalvik.system.ClassExt
   Handle<mirror::Class> dalvik_system_ClassExt(hs.NewHandle(
       AllocClass(self, java_lang_Class.Get(), mirror::ClassExt::ClassSize(image_pointer_size_))));
-  SetClassRoot(kDalvikSystemClassExt, dalvik_system_ClassExt.Get());
+  SetClassRoot(ClassRoot::kDalvikSystemClassExt, dalvik_system_ClassExt.Get());
   mirror::ClassExt::SetClass(dalvik_system_ClassExt.Get());
   mirror::Class::SetStatus(dalvik_system_ClassExt, ClassStatus::kResolved, self);
 
@@ -580,7 +582,7 @@
       AllocClass(self, java_lang_Class.Get(),
                  mirror::ObjectArray<mirror::String>::ClassSize(image_pointer_size_))));
   object_array_string->SetComponentType(java_lang_String.Get());
-  SetClassRoot(kJavaLangStringArrayClass, object_array_string.Get());
+  SetClassRoot(ClassRoot::kJavaLangStringArrayClass, object_array_string.Get());
 
   LinearAlloc* linear_alloc = runtime->GetLinearAlloc();
   // Create runtime resolution and imt conflict methods.
@@ -608,7 +610,7 @@
 
   // run char class through InitializePrimitiveClass to finish init
   InitializePrimitiveClass(char_class.Get(), Primitive::kPrimChar);
-  SetClassRoot(kPrimitiveChar, char_class.Get());  // needs descriptor
+  SetClassRoot(ClassRoot::kPrimitiveChar, char_class.Get());  // needs descriptor
 
   // Set up GenericJNI entrypoint. That is mainly a hack for common_compiler_test.h so that
   // we do not need friend classes or a publicly exposed setter.
@@ -634,25 +636,25 @@
   CHECK_EQ(dalvik_system_ClassExt->GetObjectSize(), mirror::ClassExt::InstanceSize());
 
   // Setup the primitive array type classes - can't be done until Object has a vtable.
-  SetClassRoot(kBooleanArrayClass, FindSystemClass(self, "[Z"));
-  mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
+  SetClassRoot(ClassRoot::kBooleanArrayClass, FindSystemClass(self, "[Z"));
+  mirror::BooleanArray::SetArrayClass(GetClassRoot(ClassRoot::kBooleanArrayClass, this));
 
-  SetClassRoot(kByteArrayClass, FindSystemClass(self, "[B"));
-  mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
+  SetClassRoot(ClassRoot::kByteArrayClass, FindSystemClass(self, "[B"));
+  mirror::ByteArray::SetArrayClass(GetClassRoot(ClassRoot::kByteArrayClass, this));
 
   CheckSystemClass(self, char_array_class, "[C");
 
-  SetClassRoot(kShortArrayClass, FindSystemClass(self, "[S"));
-  mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
+  SetClassRoot(ClassRoot::kShortArrayClass, FindSystemClass(self, "[S"));
+  mirror::ShortArray::SetArrayClass(GetClassRoot(ClassRoot::kShortArrayClass, this));
 
   CheckSystemClass(self, int_array_class, "[I");
   CheckSystemClass(self, long_array_class, "[J");
 
-  SetClassRoot(kFloatArrayClass, FindSystemClass(self, "[F"));
-  mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
+  SetClassRoot(ClassRoot::kFloatArrayClass, FindSystemClass(self, "[F"));
+  mirror::FloatArray::SetArrayClass(GetClassRoot(ClassRoot::kFloatArrayClass, this));
 
-  SetClassRoot(kDoubleArrayClass, FindSystemClass(self, "[D"));
-  mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
+  SetClassRoot(ClassRoot::kDoubleArrayClass, FindSystemClass(self, "[D"));
+  mirror::DoubleArray::SetArrayClass(GetClassRoot(ClassRoot::kDoubleArrayClass, this));
 
   // Run Class through FindSystemClass. This initializes the dex_cache_ fields and register it
   // in class_table_.
@@ -683,102 +685,103 @@
            mirror::Class::GetDirectInterface(self, object_array_class.Get(), 1));
 
   CHECK_EQ(object_array_string.Get(),
-           FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass)));
+           FindSystemClass(self, GetClassRootDescriptor(ClassRoot::kJavaLangStringArrayClass)));
 
   // End of special init trickery, all subsequent classes may be loaded via FindSystemClass.
 
   // Create java.lang.reflect.Proxy root.
-  SetClassRoot(kJavaLangReflectProxy, FindSystemClass(self, "Ljava/lang/reflect/Proxy;"));
+  SetClassRoot(ClassRoot::kJavaLangReflectProxy,
+               FindSystemClass(self, "Ljava/lang/reflect/Proxy;"));
 
   // Create java.lang.reflect.Field.class root.
   auto* class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangReflectField, class_root);
+  SetClassRoot(ClassRoot::kJavaLangReflectField, class_root);
   mirror::Field::SetClass(class_root);
 
   // Create java.lang.reflect.Field array root.
   class_root = FindSystemClass(self, "[Ljava/lang/reflect/Field;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangReflectFieldArrayClass, class_root);
+  SetClassRoot(ClassRoot::kJavaLangReflectFieldArrayClass, class_root);
   mirror::Field::SetArrayClass(class_root);
 
   // Create java.lang.reflect.Constructor.class root and array root.
   class_root = FindSystemClass(self, "Ljava/lang/reflect/Constructor;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangReflectConstructor, class_root);
+  SetClassRoot(ClassRoot::kJavaLangReflectConstructor, class_root);
   mirror::Constructor::SetClass(class_root);
   class_root = FindSystemClass(self, "[Ljava/lang/reflect/Constructor;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangReflectConstructorArrayClass, class_root);
+  SetClassRoot(ClassRoot::kJavaLangReflectConstructorArrayClass, class_root);
   mirror::Constructor::SetArrayClass(class_root);
 
   // Create java.lang.reflect.Method.class root and array root.
   class_root = FindSystemClass(self, "Ljava/lang/reflect/Method;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangReflectMethod, class_root);
+  SetClassRoot(ClassRoot::kJavaLangReflectMethod, class_root);
   mirror::Method::SetClass(class_root);
   class_root = FindSystemClass(self, "[Ljava/lang/reflect/Method;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangReflectMethodArrayClass, class_root);
+  SetClassRoot(ClassRoot::kJavaLangReflectMethodArrayClass, class_root);
   mirror::Method::SetArrayClass(class_root);
 
   // Create java.lang.invoke.CallSite.class root
   class_root = FindSystemClass(self, "Ljava/lang/invoke/CallSite;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangInvokeCallSite, class_root);
+  SetClassRoot(ClassRoot::kJavaLangInvokeCallSite, class_root);
   mirror::CallSite::SetClass(class_root);
 
   // Create java.lang.invoke.MethodType.class root
   class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodType;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangInvokeMethodType, class_root);
+  SetClassRoot(ClassRoot::kJavaLangInvokeMethodType, class_root);
   mirror::MethodType::SetClass(class_root);
 
   // Create java.lang.invoke.MethodHandleImpl.class root
   class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandleImpl;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangInvokeMethodHandleImpl, class_root);
+  SetClassRoot(ClassRoot::kJavaLangInvokeMethodHandleImpl, class_root);
   mirror::MethodHandleImpl::SetClass(class_root);
 
   // Create java.lang.invoke.MethodHandles.Lookup.class root
   class_root = FindSystemClass(self, "Ljava/lang/invoke/MethodHandles$Lookup;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangInvokeMethodHandlesLookup, class_root);
+  SetClassRoot(ClassRoot::kJavaLangInvokeMethodHandlesLookup, class_root);
   mirror::MethodHandlesLookup::SetClass(class_root);
 
   // Create java.lang.invoke.VarHandle.class root
   class_root = FindSystemClass(self, "Ljava/lang/invoke/VarHandle;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangInvokeVarHandle, class_root);
+  SetClassRoot(ClassRoot::kJavaLangInvokeVarHandle, class_root);
   mirror::VarHandle::SetClass(class_root);
 
   // Create java.lang.invoke.FieldVarHandle.class root
   class_root = FindSystemClass(self, "Ljava/lang/invoke/FieldVarHandle;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangInvokeFieldVarHandle, class_root);
+  SetClassRoot(ClassRoot::kJavaLangInvokeFieldVarHandle, class_root);
   mirror::FieldVarHandle::SetClass(class_root);
 
   // Create java.lang.invoke.ArrayElementVarHandle.class root
   class_root = FindSystemClass(self, "Ljava/lang/invoke/ArrayElementVarHandle;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangInvokeArrayElementVarHandle, class_root);
+  SetClassRoot(ClassRoot::kJavaLangInvokeArrayElementVarHandle, class_root);
   mirror::ArrayElementVarHandle::SetClass(class_root);
 
   // Create java.lang.invoke.ByteArrayViewVarHandle.class root
   class_root = FindSystemClass(self, "Ljava/lang/invoke/ByteArrayViewVarHandle;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangInvokeByteArrayViewVarHandle, class_root);
+  SetClassRoot(ClassRoot::kJavaLangInvokeByteArrayViewVarHandle, class_root);
   mirror::ByteArrayViewVarHandle::SetClass(class_root);
 
   // Create java.lang.invoke.ByteBufferViewVarHandle.class root
   class_root = FindSystemClass(self, "Ljava/lang/invoke/ByteBufferViewVarHandle;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kJavaLangInvokeByteBufferViewVarHandle, class_root);
+  SetClassRoot(ClassRoot::kJavaLangInvokeByteBufferViewVarHandle, class_root);
   mirror::ByteBufferViewVarHandle::SetClass(class_root);
 
   class_root = FindSystemClass(self, "Ldalvik/system/EmulatedStackFrame;");
   CHECK(class_root != nullptr);
-  SetClassRoot(kDalvikSystemEmulatedStackFrame, class_root);
+  SetClassRoot(ClassRoot::kDalvikSystemEmulatedStackFrame, class_root);
   mirror::EmulatedStackFrame::SetClass(class_root);
 
   // java.lang.ref classes need to be specially flagged, but otherwise are normal classes
@@ -805,18 +808,19 @@
   class_root = FindSystemClass(self, "Ljava/lang/ClassLoader;");
   class_root->SetClassLoaderClass();
   CHECK_EQ(class_root->GetObjectSize(), mirror::ClassLoader::InstanceSize());
-  SetClassRoot(kJavaLangClassLoader, class_root);
+  SetClassRoot(ClassRoot::kJavaLangClassLoader, class_root);
 
   // Set up java.lang.Throwable, java.lang.ClassNotFoundException, and
   // java.lang.StackTraceElement as a convenience.
-  SetClassRoot(kJavaLangThrowable, FindSystemClass(self, "Ljava/lang/Throwable;"));
-  mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
-  SetClassRoot(kJavaLangClassNotFoundException,
+  SetClassRoot(ClassRoot::kJavaLangThrowable, FindSystemClass(self, "Ljava/lang/Throwable;"));
+  mirror::Throwable::SetClass(GetClassRoot(ClassRoot::kJavaLangThrowable, this));
+  SetClassRoot(ClassRoot::kJavaLangClassNotFoundException,
                FindSystemClass(self, "Ljava/lang/ClassNotFoundException;"));
-  SetClassRoot(kJavaLangStackTraceElement, FindSystemClass(self, "Ljava/lang/StackTraceElement;"));
-  SetClassRoot(kJavaLangStackTraceElementArrayClass,
+  SetClassRoot(ClassRoot::kJavaLangStackTraceElement,
+               FindSystemClass(self, "Ljava/lang/StackTraceElement;"));
+  SetClassRoot(ClassRoot::kJavaLangStackTraceElementArrayClass,
                FindSystemClass(self, "[Ljava/lang/StackTraceElement;"));
-  mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
+  mirror::StackTraceElement::SetClass(GetClassRoot(ClassRoot::kJavaLangStackTraceElement, this));
 
   // Create conflict tables that depend on the class linker.
   runtime->FixupConflictTables();
@@ -834,8 +838,7 @@
   ObjPtr<mirror::Class> string_factory_class =
       class_linker->FindSystemClass(self, "Ljava/lang/StringFactory;");
   CHECK(string_factory_class != nullptr);
-  ObjPtr<mirror::Class> string_class =
-      class_linker->GetClassRoot(ClassLinker::ClassRoot::kJavaLangString);
+  ObjPtr<mirror::Class> string_class = GetClassRoot<mirror::String>(class_linker);
   WellKnownClasses::InitStringInit(string_class, string_factory_class);
   // Update the primordial thread.
   self->InitStringEntryPoints();
@@ -851,7 +854,8 @@
   // as the types of the field can't be resolved prior to the runtime being
   // fully initialized
   StackHandleScope<2> hs(self);
-  Handle<mirror::Class> java_lang_ref_Reference = hs.NewHandle(GetClassRoot(kJavaLangRefReference));
+  Handle<mirror::Class> java_lang_ref_Reference =
+      hs.NewHandle(GetClassRoot<mirror::Reference>(this));
   Handle<mirror::Class> java_lang_ref_FinalizerReference =
       hs.NewHandle(FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;"));
 
@@ -876,7 +880,7 @@
   CHECK_STREQ(zombie->GetTypeDescriptor(), "Ljava/lang/Object;");
 
   // ensure all class_roots_ are initialized
-  for (size_t i = 0; i < kClassRootsMax; i++) {
+  for (size_t i = 0; i < static_cast<size_t>(ClassRoot::kMax); i++) {
     ClassRoot class_root = static_cast<ClassRoot>(i);
     ObjPtr<mirror::Class> klass = GetClassRoot(class_root);
     CHECK(klass != nullptr);
@@ -896,11 +900,11 @@
 
 void ClassLinker::RunRootClinits() {
   Thread* self = Thread::Current();
-  for (size_t i = 0; i < ClassLinker::kClassRootsMax; ++i) {
-    ObjPtr<mirror::Class> c = GetClassRoot(ClassRoot(i));
+  for (size_t i = 0; i < static_cast<size_t>(ClassRoot::kMax); ++i) {
+    ObjPtr<mirror::Class> c = GetClassRoot(ClassRoot(i), this);
     if (!c->IsArrayClass() && !c->IsPrimitive()) {
       StackHandleScope<1> hs(self);
-      Handle<mirror::Class> h_class(hs.NewHandle(GetClassRoot(ClassRoot(i))));
+      Handle<mirror::Class> h_class(hs.NewHandle(c));
       EnsureInitialized(self, h_class, true, true);
       self->AssertNoPendingException();
     }
@@ -1034,13 +1038,13 @@
   class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>(
       down_cast<mirror::ObjectArray<mirror::Class>*>(
           spaces[0]->GetImageHeader().GetImageRoot(ImageHeader::kClassRoots)));
-  mirror::Class::SetClassClass(class_roots_.Read()->Get(kJavaLangClass));
+  mirror::Class::SetClassClass(GetClassRoot(ClassRoot::kJavaLangClass, this));
 
   // Special case of setting up the String class early so that we can test arbitrary objects
   // as being Strings or not
-  mirror::String::SetClass(GetClassRoot(kJavaLangString));
+  mirror::String::SetClass(GetClassRoot<mirror::String>(this));
 
-  ObjPtr<mirror::Class> java_lang_Object = GetClassRoot(kJavaLangObject);
+  ObjPtr<mirror::Class> java_lang_Object = GetClassRoot<mirror::Object>(this);
   java_lang_Object->SetObjectSize(sizeof(mirror::Object));
   // Allocate in non-movable so that it's possible to check if a JNI weak global ref has been
   // cleared without triggering the read barrier and unintentionally mark the sentinel alive.
@@ -1048,37 +1052,48 @@
       self, java_lang_Object, java_lang_Object->GetObjectSize(), VoidFunctor()));
 
   // reinit array_iftable_ from any array class instance, they should be ==
-  array_iftable_ = GcRoot<mirror::IfTable>(GetClassRoot(kObjectArrayClass)->GetIfTable());
-  DCHECK_EQ(array_iftable_.Read(), GetClassRoot(kBooleanArrayClass)->GetIfTable());
+  array_iftable_ =
+      GcRoot<mirror::IfTable>(GetClassRoot(ClassRoot::kObjectArrayClass, this)->GetIfTable());
+  DCHECK_EQ(array_iftable_.Read(), GetClassRoot(ClassRoot::kBooleanArrayClass, this)->GetIfTable());
   // String class root was set above
-  mirror::Field::SetClass(GetClassRoot(kJavaLangReflectField));
-  mirror::Field::SetArrayClass(GetClassRoot(kJavaLangReflectFieldArrayClass));
-  mirror::Constructor::SetClass(GetClassRoot(kJavaLangReflectConstructor));
-  mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass));
-  mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod));
-  mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass));
-  mirror::CallSite::SetClass(GetClassRoot(kJavaLangInvokeCallSite));
-  mirror::MethodHandleImpl::SetClass(GetClassRoot(kJavaLangInvokeMethodHandleImpl));
-  mirror::MethodHandlesLookup::SetClass(GetClassRoot(kJavaLangInvokeMethodHandlesLookup));
-  mirror::MethodType::SetClass(GetClassRoot(kJavaLangInvokeMethodType));
-  mirror::VarHandle::SetClass(GetClassRoot(kJavaLangInvokeVarHandle));
-  mirror::FieldVarHandle::SetClass(GetClassRoot(kJavaLangInvokeFieldVarHandle));
-  mirror::ArrayElementVarHandle::SetClass(GetClassRoot(kJavaLangInvokeArrayElementVarHandle));
-  mirror::ByteArrayViewVarHandle::SetClass(GetClassRoot(kJavaLangInvokeByteArrayViewVarHandle));
-  mirror::ByteBufferViewVarHandle::SetClass(GetClassRoot(kJavaLangInvokeByteBufferViewVarHandle));
-  mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference));
-  mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
-  mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
-  mirror::CharArray::SetArrayClass(GetClassRoot(kCharArrayClass));
-  mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
-  mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
-  mirror::IntArray::SetArrayClass(GetClassRoot(kIntArrayClass));
-  mirror::LongArray::SetArrayClass(GetClassRoot(kLongArrayClass));
-  mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
-  mirror::Throwable::SetClass(GetClassRoot(kJavaLangThrowable));
-  mirror::StackTraceElement::SetClass(GetClassRoot(kJavaLangStackTraceElement));
-  mirror::EmulatedStackFrame::SetClass(GetClassRoot(kDalvikSystemEmulatedStackFrame));
-  mirror::ClassExt::SetClass(GetClassRoot(kDalvikSystemClassExt));
+  mirror::Field::SetClass(GetClassRoot(ClassRoot::kJavaLangReflectField, this));
+  mirror::Field::SetArrayClass(GetClassRoot(ClassRoot::kJavaLangReflectFieldArrayClass, this));
+  mirror::Constructor::SetClass(GetClassRoot(ClassRoot::kJavaLangReflectConstructor, this).Ptr());
+  mirror::Constructor::SetArrayClass(
+      GetClassRoot(ClassRoot::kJavaLangReflectConstructorArrayClass, this).Ptr());
+  mirror::Method::SetClass(GetClassRoot(ClassRoot::kJavaLangReflectMethod, this).Ptr());
+  mirror::Method::SetArrayClass(
+      GetClassRoot(ClassRoot::kJavaLangReflectMethodArrayClass, this).Ptr());
+  mirror::CallSite::SetClass(GetClassRoot(ClassRoot::kJavaLangInvokeCallSite, this).Ptr());
+  mirror::MethodHandleImpl::SetClass(
+      GetClassRoot(ClassRoot::kJavaLangInvokeMethodHandleImpl, this).Ptr());
+  mirror::MethodHandlesLookup::SetClass(
+      GetClassRoot(ClassRoot::kJavaLangInvokeMethodHandlesLookup, this).Ptr());
+  mirror::MethodType::SetClass(
+      GetClassRoot(ClassRoot::kJavaLangInvokeMethodType, this).Ptr());
+  mirror::VarHandle::SetClass(GetClassRoot(ClassRoot::kJavaLangInvokeVarHandle, this).Ptr());
+  mirror::FieldVarHandle::SetClass(
+      GetClassRoot(ClassRoot::kJavaLangInvokeFieldVarHandle, this).Ptr());
+  mirror::ArrayElementVarHandle::SetClass(
+      GetClassRoot(ClassRoot::kJavaLangInvokeArrayElementVarHandle, this).Ptr());
+  mirror::ByteArrayViewVarHandle::SetClass(
+      GetClassRoot(ClassRoot::kJavaLangInvokeByteArrayViewVarHandle, this).Ptr());
+  mirror::ByteBufferViewVarHandle::SetClass(
+      GetClassRoot(ClassRoot::kJavaLangInvokeByteBufferViewVarHandle, this).Ptr());
+  mirror::Reference::SetClass(GetClassRoot(ClassRoot::kJavaLangRefReference, this));
+  mirror::BooleanArray::SetArrayClass(GetClassRoot(ClassRoot::kBooleanArrayClass, this));
+  mirror::ByteArray::SetArrayClass(GetClassRoot(ClassRoot::kByteArrayClass, this));
+  mirror::CharArray::SetArrayClass(GetClassRoot(ClassRoot::kCharArrayClass, this));
+  mirror::DoubleArray::SetArrayClass(GetClassRoot(ClassRoot::kDoubleArrayClass, this));
+  mirror::FloatArray::SetArrayClass(GetClassRoot(ClassRoot::kFloatArrayClass, this));
+  mirror::IntArray::SetArrayClass(GetClassRoot(ClassRoot::kIntArrayClass, this));
+  mirror::LongArray::SetArrayClass(GetClassRoot(ClassRoot::kLongArrayClass, this));
+  mirror::ShortArray::SetArrayClass(GetClassRoot(ClassRoot::kShortArrayClass, this));
+  mirror::Throwable::SetClass(GetClassRoot(ClassRoot::kJavaLangThrowable, this));
+  mirror::StackTraceElement::SetClass(GetClassRoot(ClassRoot::kJavaLangStackTraceElement, this));
+  mirror::EmulatedStackFrame::SetClass(
+      GetClassRoot(ClassRoot::kDalvikSystemEmulatedStackFrame, this).Ptr());
+  mirror::ClassExt::SetClass(GetClassRoot(ClassRoot::kDalvikSystemClassExt, this));
 
   for (gc::space::ImageSpace* image_space : spaces) {
     // Boot class loader, use a null handle.
@@ -1695,15 +1710,16 @@
   MutableHandle<mirror::ClassLoader> image_class_loader(hs.NewHandle(
       app_image ? header.GetImageRoot(ImageHeader::kClassLoader)->AsClassLoader() : nullptr));
   DCHECK(class_roots != nullptr);
-  if (class_roots->GetLength() != static_cast<int32_t>(kClassRootsMax)) {
+  if (class_roots->GetLength() != static_cast<int32_t>(ClassRoot::kMax)) {
     *error_msg = StringPrintf("Expected %d class roots but got %d",
                               class_roots->GetLength(),
-                              static_cast<int32_t>(kClassRootsMax));
+                              static_cast<int32_t>(ClassRoot::kMax));
     return false;
   }
   // Check against existing class roots to make sure they match the ones in the boot image.
-  for (size_t i = 0; i < kClassRootsMax; i++) {
-    if (class_roots->Get(i) != GetClassRoot(static_cast<ClassRoot>(i))) {
+  ObjPtr<mirror::ObjectArray<mirror::Class>> existing_class_roots = GetClassRoots();
+  for (size_t i = 0; i < static_cast<size_t>(ClassRoot::kMax); i++) {
+    if (class_roots->Get(i) != GetClassRoot(static_cast<ClassRoot>(i), existing_class_roots)) {
       *error_msg = "App image class roots must have pointer equality with runtime ones.";
       return false;
     }
@@ -2231,7 +2247,7 @@
   StackHandleScope<1> hs(self);
   DCHECK(out_location != nullptr);
   auto dex_cache(hs.NewHandle(ObjPtr<mirror::DexCache>::DownCast(
-      GetClassRoot(kJavaLangDexCache)->AllocObject(self))));
+      GetClassRoot<mirror::DexCache>(this)->AllocObject(self))));
   if (dex_cache == nullptr) {
     self->AssertPendingOOMException();
     return nullptr;
@@ -2280,14 +2296,14 @@
 }
 
 mirror::Class* ClassLinker::AllocClass(Thread* self, uint32_t class_size) {
-  return AllocClass(self, GetClassRoot(kJavaLangClass), class_size);
+  return AllocClass(self, GetClassRoot<mirror::Class>(this), class_size);
 }
 
 mirror::ObjectArray<mirror::StackTraceElement>* ClassLinker::AllocStackTraceElementArray(
     Thread* self,
     size_t length) {
   return mirror::ObjectArray<mirror::StackTraceElement>::Alloc(
-      self, GetClassRoot(kJavaLangStackTraceElementArrayClass), length);
+      self, GetClassRoot<mirror::ObjectArray<mirror::StackTraceElement>>(this), length);
 }
 
 mirror::Class* ClassLinker::EnsureResolved(Thread* self,
@@ -2684,17 +2700,17 @@
   if (UNLIKELY(!init_done_)) {
     // finish up init of hand crafted class_roots_
     if (strcmp(descriptor, "Ljava/lang/Object;") == 0) {
-      klass.Assign(GetClassRoot(kJavaLangObject));
+      klass.Assign(GetClassRoot<mirror::Object>(this));
     } else if (strcmp(descriptor, "Ljava/lang/Class;") == 0) {
-      klass.Assign(GetClassRoot(kJavaLangClass));
+      klass.Assign(GetClassRoot<mirror::Class>(this));
     } else if (strcmp(descriptor, "Ljava/lang/String;") == 0) {
-      klass.Assign(GetClassRoot(kJavaLangString));
+      klass.Assign(GetClassRoot<mirror::String>(this));
     } else if (strcmp(descriptor, "Ljava/lang/ref/Reference;") == 0) {
-      klass.Assign(GetClassRoot(kJavaLangRefReference));
+      klass.Assign(GetClassRoot<mirror::Reference>(this));
     } else if (strcmp(descriptor, "Ljava/lang/DexCache;") == 0) {
-      klass.Assign(GetClassRoot(kJavaLangDexCache));
+      klass.Assign(GetClassRoot<mirror::DexCache>(this));
     } else if (strcmp(descriptor, "Ldalvik/system/ClassExt;") == 0) {
-      klass.Assign(GetClassRoot(kDalvikSystemClassExt));
+      klass.Assign(GetClassRoot<mirror::ClassExt>(this));
     }
   }
 
@@ -2744,7 +2760,7 @@
   ObjectLock<mirror::Class> lock(self, klass);
   klass->SetClinitThreadId(self->GetTid());
   // Make sure we have a valid empty iftable even if there are errors.
-  klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
+  klass->SetIfTable(GetClassRoot<mirror::Object>(this)->GetIfTable());
 
   // Add the newly loaded class to the loaded classes table.
   ObjPtr<mirror::Class> existing = InsertClass(descriptor, klass.Get(), hash);
@@ -3084,7 +3100,7 @@
   const char* descriptor = dex_file.GetClassDescriptor(dex_class_def);
   CHECK(descriptor != nullptr);
 
-  klass->SetClass(GetClassRoot(kJavaLangClass));
+  klass->SetClass(GetClassRoot<mirror::Class>(this));
   uint32_t access_flags = dex_class_def.GetJavaAccessFlags();
   CHECK_EQ(access_flags & ~kAccJavaFlagsMask, 0U);
   klass->SetAccessFlags(access_flags);
@@ -3654,7 +3670,7 @@
   ObjectLock<mirror::Class> lock(self, h_class);
   h_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
   h_class->SetPrimitiveType(type);
-  h_class->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
+  h_class->SetIfTable(GetClassRoot<mirror::Object>(this)->GetIfTable());
   mirror::Class::SetStatus(h_class, ClassStatus::kInitialized, self);
   const char* descriptor = Primitive::Descriptor(type);
   ObjPtr<mirror::Class> existing = InsertClass(descriptor,
@@ -3737,17 +3753,17 @@
   if (UNLIKELY(!init_done_)) {
     // Classes that were hand created, ie not by FindSystemClass
     if (strcmp(descriptor, "[Ljava/lang/Class;") == 0) {
-      new_class.Assign(GetClassRoot(kClassArrayClass));
+      new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::Class>>(this));
     } else if (strcmp(descriptor, "[Ljava/lang/Object;") == 0) {
-      new_class.Assign(GetClassRoot(kObjectArrayClass));
-    } else if (strcmp(descriptor, GetClassRootDescriptor(kJavaLangStringArrayClass)) == 0) {
-      new_class.Assign(GetClassRoot(kJavaLangStringArrayClass));
+      new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::Object>>(this));
+    } else if (strcmp(descriptor, "[Ljava/lang/String;") == 0) {
+      new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::String>>(this));
     } else if (strcmp(descriptor, "[C") == 0) {
-      new_class.Assign(GetClassRoot(kCharArrayClass));
+      new_class.Assign(GetClassRoot<mirror::CharArray>(this));
     } else if (strcmp(descriptor, "[I") == 0) {
-      new_class.Assign(GetClassRoot(kIntArrayClass));
+      new_class.Assign(GetClassRoot<mirror::IntArray>(this));
     } else if (strcmp(descriptor, "[J") == 0) {
-      new_class.Assign(GetClassRoot(kLongArrayClass));
+      new_class.Assign(GetClassRoot<mirror::LongArray>(this));
     }
   }
   if (new_class == nullptr) {
@@ -3760,7 +3776,7 @@
   }
   ObjectLock<mirror::Class> lock(self, new_class);  // Must hold lock on object when initializing.
   DCHECK(new_class->GetComponentType() != nullptr);
-  ObjPtr<mirror::Class> java_lang_Object = GetClassRoot(kJavaLangObject);
+  ObjPtr<mirror::Class> java_lang_Object = GetClassRoot<mirror::Object>(this);
   new_class->SetSuperClass(java_lang_Object);
   new_class->SetVTable(java_lang_Object->GetVTable());
   new_class->SetPrimitiveType(Primitive::kPrimNot);
@@ -3828,25 +3844,26 @@
 }
 
 mirror::Class* ClassLinker::FindPrimitiveClass(char type) {
+  ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots = GetClassRoots();
   switch (type) {
     case 'B':
-      return GetClassRoot(kPrimitiveByte);
+      return GetClassRoot(ClassRoot::kPrimitiveByte, class_roots).Ptr();
     case 'C':
-      return GetClassRoot(kPrimitiveChar);
+      return GetClassRoot(ClassRoot::kPrimitiveChar, class_roots).Ptr();
     case 'D':
-      return GetClassRoot(kPrimitiveDouble);
+      return GetClassRoot(ClassRoot::kPrimitiveDouble, class_roots).Ptr();
     case 'F':
-      return GetClassRoot(kPrimitiveFloat);
+      return GetClassRoot(ClassRoot::kPrimitiveFloat, class_roots).Ptr();
     case 'I':
-      return GetClassRoot(kPrimitiveInt);
+      return GetClassRoot(ClassRoot::kPrimitiveInt, class_roots).Ptr();
     case 'J':
-      return GetClassRoot(kPrimitiveLong);
+      return GetClassRoot(ClassRoot::kPrimitiveLong, class_roots).Ptr();
     case 'S':
-      return GetClassRoot(kPrimitiveShort);
+      return GetClassRoot(ClassRoot::kPrimitiveShort, class_roots).Ptr();
     case 'Z':
-      return GetClassRoot(kPrimitiveBoolean);
+      return GetClassRoot(ClassRoot::kPrimitiveBoolean, class_roots).Ptr();
     case 'V':
-      return GetClassRoot(kPrimitiveVoid);
+      return GetClassRoot(ClassRoot::kPrimitiveVoid, class_roots).Ptr();
     default:
       break;
   }
@@ -4381,7 +4398,7 @@
   Thread* self = soa.Self();
   StackHandleScope<10> hs(self);
   MutableHandle<mirror::Class> temp_klass(hs.NewHandle(
-      AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::Class))));
+      AllocClass(self, GetClassRoot<mirror::Class>(this), sizeof(mirror::Class))));
   if (temp_klass == nullptr) {
     CHECK(self->IsExceptionPending());  // OOME.
     return nullptr;
@@ -4394,9 +4411,9 @@
   temp_klass->SetClassLoader(soa.Decode<mirror::ClassLoader>(loader));
   DCHECK_EQ(temp_klass->GetPrimitiveType(), Primitive::kPrimNot);
   temp_klass->SetName(soa.Decode<mirror::String>(name));
-  temp_klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache());
+  temp_klass->SetDexCache(GetClassRoot<mirror::Proxy>(this)->GetDexCache());
   // Object has an empty iftable, copy it for that reason.
-  temp_klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
+  temp_klass->SetIfTable(GetClassRoot<mirror::Object>(this)->GetIfTable());
   mirror::Class::SetStatus(temp_klass, ClassStatus::kIdx, self);
   std::string descriptor(GetDescriptorForProxy(temp_klass.Get()));
   const size_t hash = ComputeModifiedUtf8Hash(descriptor.c_str());
@@ -4463,7 +4480,7 @@
   }
 
   // The super class is java.lang.reflect.Proxy
-  temp_klass->SetSuperClass(GetClassRoot(kJavaLangReflectProxy));
+  temp_klass->SetSuperClass(GetClassRoot<mirror::Proxy>(this));
   // Now effectively in the loaded state.
   mirror::Class::SetStatus(temp_klass, ClassStatus::kLoaded, self);
   self->AssertNoPendingException();
@@ -4551,11 +4568,12 @@
 
 void ClassLinker::CreateProxyConstructor(Handle<mirror::Class> klass, ArtMethod* out) {
   // Create constructor for Proxy that must initialize the method.
-  CHECK_EQ(GetClassRoot(kJavaLangReflectProxy)->NumDirectMethods(), 21u);
+  ObjPtr<mirror::Class> proxy_class = GetClassRoot<mirror::Proxy>(this);
+  CHECK_EQ(proxy_class->NumDirectMethods(), 21u);
 
   // Find the <init>(InvocationHandler)V method. The exact method offset varies depending
   // on which front-end compiler was used to build the libcore DEX files.
-  ArtMethod* proxy_constructor = GetClassRoot(kJavaLangReflectProxy)->FindConstructor(
+  ArtMethod* proxy_constructor = proxy_class->FindConstructor(
       "(Ljava/lang/reflect/InvocationHandler;)V", image_pointer_size_);
   DCHECK(proxy_constructor != nullptr)
       << "Could not find <init> method in java.lang.reflect.Proxy";
@@ -5553,7 +5571,8 @@
 bool ClassLinker::LinkSuperClass(Handle<mirror::Class> klass) {
   CHECK(!klass->IsPrimitive());
   ObjPtr<mirror::Class> super = klass->GetSuperClass();
-  if (klass.Get() == GetClassRoot(kJavaLangObject)) {
+  ObjPtr<mirror::Class> object_class = GetClassRoot<mirror::Object>(this);
+  if (klass.Get() == object_class) {
     if (super != nullptr) {
       ThrowClassFormatError(klass.Get(), "java.lang.Object must not have a superclass");
       return false;
@@ -5566,7 +5585,7 @@
     return false;
   }
   // Verify
-  if (klass->IsInterface() && super != GetClassRoot(kJavaLangObject)) {
+  if (klass->IsInterface() && super != object_class) {
     ThrowClassFormatError(klass.Get(), "Interfaces must have java.lang.Object as superclass");
     return false;
   }
@@ -5609,7 +5628,7 @@
     klass->SetClassFlags(klass->GetClassFlags() | reference_flags);
   }
   // Disallow custom direct subclasses of java.lang.ref.Reference.
-  if (init_done_ && super == GetClassRoot(kJavaLangRefReference)) {
+  if (init_done_ && super == GetClassRoot<mirror::Reference>(this)) {
     ThrowLinkageError(klass.Get(),
                       "Class %s attempts to subclass java.lang.ref.Reference, which is not allowed",
                       klass->PrettyDescriptor().c_str());
@@ -5974,7 +5993,7 @@
     }
     klass->SetVTable(vtable.Get());
   } else {
-    CHECK_EQ(klass.Get(), GetClassRoot(kJavaLangObject));
+    CHECK_EQ(klass.Get(), GetClassRoot<mirror::Object>(this));
     if (!IsUint<16>(num_virtual_methods)) {
       ThrowClassFormatError(klass.Get(), "Too many methods: %d",
                             static_cast<int>(num_virtual_methods));
@@ -7851,7 +7870,7 @@
     // Convert a ClassNotFoundException to a NoClassDefFoundError.
     StackHandleScope<1> hs(self);
     Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException()));
-    if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
+    if (cause->InstanceOf(GetClassRoot(ClassRoot::kJavaLangClassNotFoundException, this))) {
       DCHECK(resolved == nullptr);  // No Handle needed to preserve resolved.
       self->ClearException();
       ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
@@ -8678,67 +8697,10 @@
 
   mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read();
   DCHECK(class_roots != nullptr);
-  DCHECK(class_roots->Get(class_root) == nullptr);
-  class_roots->Set<false>(class_root, klass);
-}
-
-const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) {
-  static const char* class_roots_descriptors[] = {
-    "Ljava/lang/Class;",
-    "Ljava/lang/Object;",
-    "[Ljava/lang/Class;",
-    "[Ljava/lang/Object;",
-    "Ljava/lang/String;",
-    "Ljava/lang/DexCache;",
-    "Ljava/lang/ref/Reference;",
-    "Ljava/lang/reflect/Constructor;",
-    "Ljava/lang/reflect/Field;",
-    "Ljava/lang/reflect/Method;",
-    "Ljava/lang/reflect/Proxy;",
-    "[Ljava/lang/String;",
-    "[Ljava/lang/reflect/Constructor;",
-    "[Ljava/lang/reflect/Field;",
-    "[Ljava/lang/reflect/Method;",
-    "Ljava/lang/invoke/CallSite;",
-    "Ljava/lang/invoke/MethodHandleImpl;",
-    "Ljava/lang/invoke/MethodHandles$Lookup;",
-    "Ljava/lang/invoke/MethodType;",
-    "Ljava/lang/invoke/VarHandle;",
-    "Ljava/lang/invoke/FieldVarHandle;",
-    "Ljava/lang/invoke/ArrayElementVarHandle;",
-    "Ljava/lang/invoke/ByteArrayViewVarHandle;",
-    "Ljava/lang/invoke/ByteBufferViewVarHandle;",
-    "Ljava/lang/ClassLoader;",
-    "Ljava/lang/Throwable;",
-    "Ljava/lang/ClassNotFoundException;",
-    "Ljava/lang/StackTraceElement;",
-    "Ldalvik/system/EmulatedStackFrame;",
-    "Z",
-    "B",
-    "C",
-    "D",
-    "F",
-    "I",
-    "J",
-    "S",
-    "V",
-    "[Z",
-    "[B",
-    "[C",
-    "[D",
-    "[F",
-    "[I",
-    "[J",
-    "[S",
-    "[Ljava/lang/StackTraceElement;",
-    "Ldalvik/system/ClassExt;",
-  };
-  static_assert(arraysize(class_roots_descriptors) == size_t(kClassRootsMax),
-                "Mismatch between class descriptors and class-root enum");
-
-  const char* descriptor = class_roots_descriptors[class_root];
-  CHECK(descriptor != nullptr);
-  return descriptor;
+  DCHECK_LT(static_cast<uint32_t>(class_root), static_cast<uint32_t>(ClassRoot::kMax));
+  int32_t index = static_cast<int32_t>(class_root);
+  DCHECK(class_roots->Get(index) == nullptr);
+  class_roots->Set<false>(index, klass);
 }
 
 jobject ClassLinker::CreateWellKnownClassLoader(Thread* self,
@@ -9071,7 +9033,7 @@
 mirror::IfTable* ClassLinker::AllocIfTable(Thread* self, size_t ifcount) {
   return down_cast<mirror::IfTable*>(
       mirror::IfTable::Alloc(self,
-                             GetClassRoot(kObjectArrayClass),
+                             GetClassRoot<mirror::ObjectArray<mirror::Object>>(this),
                              ifcount * mirror::IfTable::kMax));
 }
 
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 52ecf82..afe5c99 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -68,6 +68,7 @@
 }  // namespace mirror
 
 class ClassHierarchyAnalysis;
+enum class ClassRoot : uint32_t;
 class ClassTable;
 template<class T> class Handle;
 class ImtConflictTable;
@@ -107,59 +108,6 @@
 
 class ClassLinker {
  public:
-  // Well known mirror::Class roots accessed via GetClassRoot.
-  enum ClassRoot {
-    kJavaLangClass,
-    kJavaLangObject,
-    kClassArrayClass,
-    kObjectArrayClass,
-    kJavaLangString,
-    kJavaLangDexCache,
-    kJavaLangRefReference,
-    kJavaLangReflectConstructor,
-    kJavaLangReflectField,
-    kJavaLangReflectMethod,
-    kJavaLangReflectProxy,
-    kJavaLangStringArrayClass,
-    kJavaLangReflectConstructorArrayClass,
-    kJavaLangReflectFieldArrayClass,
-    kJavaLangReflectMethodArrayClass,
-    kJavaLangInvokeCallSite,
-    kJavaLangInvokeMethodHandleImpl,
-    kJavaLangInvokeMethodHandlesLookup,
-    kJavaLangInvokeMethodType,
-    kJavaLangInvokeVarHandle,
-    kJavaLangInvokeFieldVarHandle,
-    kJavaLangInvokeArrayElementVarHandle,
-    kJavaLangInvokeByteArrayViewVarHandle,
-    kJavaLangInvokeByteBufferViewVarHandle,
-    kJavaLangClassLoader,
-    kJavaLangThrowable,
-    kJavaLangClassNotFoundException,
-    kJavaLangStackTraceElement,
-    kDalvikSystemEmulatedStackFrame,
-    kPrimitiveBoolean,
-    kPrimitiveByte,
-    kPrimitiveChar,
-    kPrimitiveDouble,
-    kPrimitiveFloat,
-    kPrimitiveInt,
-    kPrimitiveLong,
-    kPrimitiveShort,
-    kPrimitiveVoid,
-    kBooleanArrayClass,
-    kByteArrayClass,
-    kCharArrayClass,
-    kDoubleArrayClass,
-    kFloatArrayClass,
-    kIntArrayClass,
-    kLongArrayClass,
-    kShortArrayClass,
-    kJavaLangStackTraceElementArrayClass,
-    kDalvikSystemClassExt,
-    kClassRootsMax,
-  };
-
   static constexpr bool kAppImageMayContainStrings = false;
 
   explicit ClassLinker(InternTable* intern_table);
@@ -552,10 +500,6 @@
   pid_t GetClassesLockOwner();  // For SignalCatcher.
   pid_t GetDexLockOwner();  // For SignalCatcher.
 
-  mirror::Class* GetClassRoot(ClassRoot class_root) REQUIRES_SHARED(Locks::mutator_lock_);
-
-  static const char* GetClassRootDescriptor(ClassRoot class_root);
-
   // Is the given entry point quick code to run the resolution stub?
   bool IsQuickResolutionStub(const void* entry_point) const;
 
@@ -597,8 +541,9 @@
       REQUIRES(!Locks::classlinker_classes_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
   mirror::ObjectArray<mirror::Class>* GetClassRoots() REQUIRES_SHARED(Locks::mutator_lock_) {
-    mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read();
+    mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read<kReadBarrierOption>();
     DCHECK(class_roots != nullptr);
     return class_roots;
   }
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 6ed029c..48ec6b6 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -25,6 +25,7 @@
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "class_linker-inl.h"
+#include "class_root.h"
 #include "common_runtime_test.h"
 #include "dex/dex_file_types.h"
 #include "dex/standard_dex_file.h"
@@ -1387,11 +1388,10 @@
 TEST_F(ClassLinkerTest, ClassRootDescriptors) {
   ScopedObjectAccess soa(Thread::Current());
   std::string temp;
-  for (int i = 0; i < ClassLinker::kClassRootsMax; i++) {
-    ObjPtr<mirror::Class> klass = class_linker_->GetClassRoot(ClassLinker::ClassRoot(i));
+  for (size_t i = 0; i < static_cast<size_t>(ClassRoot::kMax); i++) {
+    ObjPtr<mirror::Class> klass = GetClassRoot(ClassRoot(i), class_linker_);
     EXPECT_GT(strlen(klass->GetDescriptor(&temp)), 0U);
-    EXPECT_STREQ(klass->GetDescriptor(&temp),
-                 class_linker_->GetClassRootDescriptor(ClassLinker::ClassRoot(i))) << " i = " << i;
+    EXPECT_STREQ(klass->GetDescriptor(&temp), GetClassRootDescriptor(ClassRoot(i))) << " i = " << i;
   }
 }
 
diff --git a/runtime/class_root.cc b/runtime/class_root.cc
new file mode 100644
index 0000000..08820b0
--- /dev/null
+++ b/runtime/class_root.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include "class_root.h"
+
+namespace art {
+
+const char* GetClassRootDescriptor(ClassRoot class_root) {
+  static const char* class_roots_descriptors[] = {
+#define CLASS_ROOT_DESCRIPTOR(name, descriptor, mirror_type) descriptor,
+      CLASS_ROOT_LIST(CLASS_ROOT_DESCRIPTOR)
+#undef CLASS_ROOT_DESCRIPTOR
+  };
+  static_assert(arraysize(class_roots_descriptors) == static_cast<size_t>(ClassRoot::kMax),
+                "Mismatch between class descriptors and class-root enum");
+
+  DCHECK_LT(static_cast<uint32_t>(class_root), static_cast<uint32_t>(ClassRoot::kMax));
+  const char* descriptor = class_roots_descriptors[static_cast<size_t>(class_root)];
+  CHECK(descriptor != nullptr);
+  return descriptor;
+}
+
+}  // namespace art
diff --git a/runtime/class_root.h b/runtime/class_root.h
new file mode 100644
index 0000000..f43e2c6
--- /dev/null
+++ b/runtime/class_root.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2018 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_CLASS_ROOT_H_
+#define ART_RUNTIME_CLASS_ROOT_H_
+
+#include "class_linker.h"
+#include "mirror/class.h"
+#include "mirror/object_array-inl.h"
+#include "obj_ptr-inl.h"
+#include "runtime.h"
+
+namespace art {
+
+namespace mirror {
+class ArrayElementVarHandle;
+class ByteArrayViewVarHandle;
+class ByteBufferViewVarHandle;
+class CallSite;
+class ClassExt;
+class ClassLoader;
+class Constructor;
+class DexCache;
+class EmulatedStackFrame;
+class Field;
+class FieldVarHandle;
+class Method;
+class MethodHandleImpl;
+class MethodHandlesLookup;
+class MethodType;
+class Object;
+class Proxy;
+template<typename T> class PrimitiveArray;
+class Reference;
+class StackTraceElement;
+class String;
+class Throwable;
+class VarHandle;
+}  // namespace mirror
+
+#define CLASS_ROOT_LIST(M)                                                                                                                          \
+  M(kJavaLangClass,                         "Ljava/lang/Class;",                          mirror::Class)                                            \
+  M(kJavaLangObject,                        "Ljava/lang/Object;",                         mirror::Object)                                           \
+  M(kClassArrayClass,                       "[Ljava/lang/Class;",                         mirror::ObjectArray<mirror::Class>)                       \
+  M(kObjectArrayClass,                      "[Ljava/lang/Object;",                        mirror::ObjectArray<mirror::Object>)                      \
+  M(kJavaLangString,                        "Ljava/lang/String;",                         mirror::String)                                           \
+  M(kJavaLangDexCache,                      "Ljava/lang/DexCache;",                       mirror::DexCache)                                         \
+  M(kJavaLangRefReference,                  "Ljava/lang/ref/Reference;",                  mirror::Reference)                                        \
+  M(kJavaLangReflectConstructor,            "Ljava/lang/reflect/Constructor;",            mirror::Constructor)                                      \
+  M(kJavaLangReflectField,                  "Ljava/lang/reflect/Field;",                  mirror::Field)                                            \
+  M(kJavaLangReflectMethod,                 "Ljava/lang/reflect/Method;",                 mirror::Method)                                           \
+  M(kJavaLangReflectProxy,                  "Ljava/lang/reflect/Proxy;",                  mirror::Proxy)                                            \
+  M(kJavaLangStringArrayClass,              "[Ljava/lang/String;",                        mirror::ObjectArray<mirror::String>)                      \
+  M(kJavaLangReflectConstructorArrayClass,  "[Ljava/lang/reflect/Constructor;",           mirror::ObjectArray<mirror::Constructor>)                 \
+  M(kJavaLangReflectFieldArrayClass,        "[Ljava/lang/reflect/Field;",                 mirror::ObjectArray<mirror::Field>)                       \
+  M(kJavaLangReflectMethodArrayClass,       "[Ljava/lang/reflect/Method;",                mirror::ObjectArray<mirror::Method>)                      \
+  M(kJavaLangInvokeCallSite,                "Ljava/lang/invoke/CallSite;",                mirror::CallSite)                                         \
+  M(kJavaLangInvokeMethodHandleImpl,        "Ljava/lang/invoke/MethodHandleImpl;",        mirror::MethodHandleImpl)                                 \
+  M(kJavaLangInvokeMethodHandlesLookup,     "Ljava/lang/invoke/MethodHandles$Lookup;",    mirror::MethodHandlesLookup)                              \
+  M(kJavaLangInvokeMethodType,              "Ljava/lang/invoke/MethodType;",              mirror::MethodType)                                       \
+  M(kJavaLangInvokeVarHandle,               "Ljava/lang/invoke/VarHandle;",               mirror::VarHandle)                                        \
+  M(kJavaLangInvokeFieldVarHandle,          "Ljava/lang/invoke/FieldVarHandle;",          mirror::FieldVarHandle)                                   \
+  M(kJavaLangInvokeArrayElementVarHandle,   "Ljava/lang/invoke/ArrayElementVarHandle;",   mirror::ArrayElementVarHandle)                            \
+  M(kJavaLangInvokeByteArrayViewVarHandle,  "Ljava/lang/invoke/ByteArrayViewVarHandle;",  mirror::ByteArrayViewVarHandle)                           \
+  M(kJavaLangInvokeByteBufferViewVarHandle, "Ljava/lang/invoke/ByteBufferViewVarHandle;", mirror::ByteBufferViewVarHandle)                          \
+  M(kJavaLangClassLoader,                   "Ljava/lang/ClassLoader;",                    mirror::ClassLoader)                                      \
+  M(kJavaLangThrowable,                     "Ljava/lang/Throwable;",                      mirror::Throwable)                                        \
+  M(kJavaLangClassNotFoundException,        "Ljava/lang/ClassNotFoundException;",         detail::NoMirrorType<detail::ClassNotFoundExceptionTag>)  \
+  M(kJavaLangStackTraceElement,             "Ljava/lang/StackTraceElement;",              mirror::StackTraceElement)                                \
+  M(kDalvikSystemEmulatedStackFrame,        "Ldalvik/system/EmulatedStackFrame;",         mirror::EmulatedStackFrame)                               \
+  M(kPrimitiveBoolean,                      "Z",                                          detail::NoMirrorType<uint8_t>)                            \
+  M(kPrimitiveByte,                         "B",                                          detail::NoMirrorType<int8_t>)                             \
+  M(kPrimitiveChar,                         "C",                                          detail::NoMirrorType<uint16_t>)                           \
+  M(kPrimitiveDouble,                       "D",                                          detail::NoMirrorType<double>)                             \
+  M(kPrimitiveFloat,                        "F",                                          detail::NoMirrorType<float>)                              \
+  M(kPrimitiveInt,                          "I",                                          detail::NoMirrorType<int32_t>)                            \
+  M(kPrimitiveLong,                         "J",                                          detail::NoMirrorType<int64_t>)                            \
+  M(kPrimitiveShort,                        "S",                                          detail::NoMirrorType<int16_t>)                            \
+  M(kPrimitiveVoid,                         "V",                                          detail::NoMirrorType<void>)                               \
+  M(kBooleanArrayClass,                     "[Z",                                         mirror::PrimitiveArray<uint8_t>)                          \
+  M(kByteArrayClass,                        "[B",                                         mirror::PrimitiveArray<int8_t>)                           \
+  M(kCharArrayClass,                        "[C",                                         mirror::PrimitiveArray<uint16_t>)                         \
+  M(kDoubleArrayClass,                      "[D",                                         mirror::PrimitiveArray<double>)                           \
+  M(kFloatArrayClass,                       "[F",                                         mirror::PrimitiveArray<float>)                            \
+  M(kIntArrayClass,                         "[I",                                         mirror::PrimitiveArray<int32_t>)                          \
+  M(kLongArrayClass,                        "[J",                                         mirror::PrimitiveArray<int64_t>)                          \
+  M(kShortArrayClass,                       "[S",                                         mirror::PrimitiveArray<int16_t>)                          \
+  M(kJavaLangStackTraceElementArrayClass,   "[Ljava/lang/StackTraceElement;",             mirror::ObjectArray<mirror::StackTraceElement>)           \
+  M(kDalvikSystemClassExt,                  "Ldalvik/system/ClassExt;",                   mirror::ClassExt)
+
+// Well known mirror::Class roots accessed via ClassLinker::GetClassRoots().
+enum class ClassRoot : uint32_t {
+#define CLASS_ROOT_ENUMERATOR(name, descriptor, mirror_type) name,
+  CLASS_ROOT_LIST(CLASS_ROOT_ENUMERATOR)
+#undef CLASS_ROOT_ENUMERATOR
+  kMax,
+};
+
+const char* GetClassRootDescriptor(ClassRoot class_root);
+
+template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+inline ObjPtr<mirror::Class> GetClassRoot(
+    ClassRoot class_root,
+    ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots) REQUIRES_SHARED(Locks::mutator_lock_) {
+  DCHECK(class_roots != nullptr);
+  if (kReadBarrierOption == kWithReadBarrier) {
+    // With read barrier all references must point to the to-space.
+    // Without read barrier, this check could fail.
+    DCHECK_EQ(class_roots, Runtime::Current()->GetClassLinker()->GetClassRoots());
+  }
+  DCHECK_LT(static_cast<uint32_t>(class_root), static_cast<uint32_t>(ClassRoot::kMax));
+  int32_t index = static_cast<int32_t>(class_root);
+  ObjPtr<mirror::Class> klass =
+      class_roots->GetWithoutChecks<kDefaultVerifyFlags, kReadBarrierOption>(index);
+  DCHECK(klass != nullptr);
+  return klass.Ptr();
+}
+
+template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+inline ObjPtr<mirror::Class> GetClassRoot(ClassRoot class_root, ClassLinker* linker)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  return GetClassRoot<kReadBarrierOption>(class_root, linker->GetClassRoots<kReadBarrierOption>());
+}
+
+template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+inline ObjPtr<mirror::Class> GetClassRoot(ClassRoot class_root)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  return GetClassRoot<kReadBarrierOption>(class_root, Runtime::Current()->GetClassLinker());
+}
+
+namespace detail {
+
+class ClassNotFoundExceptionTag;
+template <class Tag> struct NoMirrorType;
+
+template <class MirrorType>
+struct ClassRootSelector;  // No definition for unspecialized ClassRoot selector.
+
+#define SPECIALIZE_CLASS_ROOT_SELECTOR(name, descriptor, mirror_type) \
+  template <>                                                         \
+  struct ClassRootSelector<mirror_type> {                             \
+    static constexpr ClassRoot value = ClassRoot::name;               \
+  };
+
+CLASS_ROOT_LIST(SPECIALIZE_CLASS_ROOT_SELECTOR)
+
+#undef SPECIALIZE_CLASS_ROOT_SELECTOR
+
+}  // namespace detail
+
+template <class MirrorType, ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+inline ObjPtr<mirror::Class> GetClassRoot(ObjPtr<mirror::ObjectArray<mirror::Class>> class_roots)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  return GetClassRoot<kWithReadBarrier>(detail::ClassRootSelector<MirrorType>::value, class_roots);
+}
+
+template <class MirrorType, ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+inline ObjPtr<mirror::Class> GetClassRoot(ClassLinker* linker)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  return GetClassRoot<kWithReadBarrier>(detail::ClassRootSelector<MirrorType>::value, linker);
+}
+
+template <class MirrorType, ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+inline ObjPtr<mirror::Class> GetClassRoot() REQUIRES_SHARED(Locks::mutator_lock_) {
+  return GetClassRoot<kWithReadBarrier>(detail::ClassRootSelector<MirrorType>::value);
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_CLASS_ROOT_H_
diff --git a/runtime/entrypoints/quick/callee_save_frame.h b/runtime/entrypoints/quick/callee_save_frame.h
index 6f1bbaa..1e30907 100644
--- a/runtime/entrypoints/quick/callee_save_frame.h
+++ b/runtime/entrypoints/quick/callee_save_frame.h
@@ -68,7 +68,7 @@
   bool exit_check_;
 };
 
-namespace detail_ {
+namespace detail {
 
 template <InstructionSet>
 struct CSFSelector;  // No definition for unspecialized callee save frame selector.
@@ -87,9 +87,9 @@
 template <>
 struct CSFSelector<InstructionSet::kX86_64> { using type = x86_64::X86_64CalleeSaveFrame; };
 
-}  // namespace detail_
+}  // namespace detail
 
-using RuntimeCalleeSaveFrame = detail_::CSFSelector<kRuntimeISA>::type;
+using RuntimeCalleeSaveFrame = detail::CSFSelector<kRuntimeISA>::type;
 
 }  // namespace art
 
diff --git a/runtime/gc/accounting/mod_union_table_test.cc b/runtime/gc/accounting/mod_union_table_test.cc
index e5b8ea5..d59ff71 100644
--- a/runtime/gc/accounting/mod_union_table_test.cc
+++ b/runtime/gc/accounting/mod_union_table_test.cc
@@ -17,6 +17,7 @@
 #include "mod_union_table-inl.h"
 
 #include "class_linker-inl.h"
+#include "class_root.h"
 #include "common_runtime_test.h"
 #include "gc/space/space-inl.h"
 #include "mirror/array-inl.h"
@@ -70,8 +71,7 @@
   mirror::Class* GetObjectArrayClass(Thread* self, space::ContinuousMemMapAllocSpace* space)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     if (java_lang_object_array_ == nullptr) {
-      java_lang_object_array_ =
-          Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kObjectArrayClass);
+      java_lang_object_array_ = GetClassRoot<mirror::ObjectArray<mirror::Object>>().Ptr();
       // Since the test doesn't have an image, the class of the object array keeps cards live
       // inside the card cache mod-union table and causes the check
       // ASSERT_FALSE(table->ContainsCardFor(reinterpret_cast<uintptr_t>(obj3)));
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 0747c3c..2c2c437 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -23,6 +23,7 @@
 #include "base/quasi_atomic.h"
 #include "base/stl_util.h"
 #include "base/systrace.h"
+#include "class_root.h"
 #include "debugger.h"
 #include "gc/accounting/atomic_stack.h"
 #include "gc/accounting/heap_bitmap-inl.h"
@@ -2244,7 +2245,7 @@
   // Avoid going through read barrier for since kDisallowReadBarrierDuringScan may be enabled.
   // Explicitly mark to make sure to get an object in the to-space.
   mirror::Class* int_array_class = down_cast<mirror::Class*>(
-      Mark(mirror::IntArray::GetArrayClass<kWithoutReadBarrier>()));
+      Mark(GetClassRoot<mirror::IntArray, kWithoutReadBarrier>().Ptr()));
   CHECK(int_array_class != nullptr);
   if (ReadBarrier::kEnableToSpaceInvariantChecks) {
     AssertToSpaceInvariant(nullptr, MemberOffset(0), int_array_class);
@@ -2324,7 +2325,7 @@
     CHECK_GE(byte_size - alloc_size, min_object_size);
     // FillWithDummyObject may mark an object, avoid holding skipped_blocks_lock_ to prevent lock
     // violation and possible deadlock. The deadlock case is a recursive case:
-    // FillWithDummyObject -> IntArray::GetArrayClass -> Mark -> Copy -> AllocateInSkippedBlock.
+    // FillWithDummyObject -> Mark(IntArray.class) -> Copy -> AllocateInSkippedBlock.
     FillWithDummyObject(reinterpret_cast<mirror::Object*>(addr + alloc_size),
                         byte_size - alloc_size);
     CHECK(region_space_->IsInToSpace(reinterpret_cast<mirror::Object*>(addr + alloc_size)));
diff --git a/runtime/gc/heap_verification_test.cc b/runtime/gc/heap_verification_test.cc
index 40ee86c..4f06ee6 100644
--- a/runtime/gc/heap_verification_test.cc
+++ b/runtime/gc/heap_verification_test.cc
@@ -18,6 +18,7 @@
 
 #include "base/memory_tool.h"
 #include "class_linker-inl.h"
+#include "class_root.h"
 #include "handle_scope-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object_array-inl.h"
@@ -36,10 +37,9 @@
   template <class T>
   mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
     return mirror::ObjectArray<T>::Alloc(
         self,
-        class_linker->GetClassRoot(ClassLinker::ClassRoot::kObjectArrayClass),
+        GetClassRoot<mirror::ObjectArray<mirror::Object>>(),
         length);
   }
 };
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index 3b64874..7bd5a6a 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -50,6 +50,7 @@
 #include "base/time_utils.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker.h"
+#include "class_root.h"
 #include "common_throws.h"
 #include "debugger.h"
 #include "dex/dex_file-inl.h"
@@ -1418,8 +1419,7 @@
   __ AddObjectId(obj);
   __ AddStackTraceSerialNumber(LookupStackTraceSerialNumber(obj));
   __ AddU4(elements.size());
-  __ AddClassId(LookupClassId(
-      Runtime::Current()->GetClassLinker()->GetClassRoot(ClassLinker::kObjectArrayClass)));
+  __ AddClassId(LookupClassId(GetClassRoot<mirror::ObjectArray<mirror::Object>>().Ptr()));
   for (mirror::Object* e : elements) {
     __ AddObjectId(e);
   }
diff --git a/runtime/interpreter/unstarted_runtime_test.cc b/runtime/interpreter/unstarted_runtime_test.cc
index 860de2c..98fe8b2 100644
--- a/runtime/interpreter/unstarted_runtime_test.cc
+++ b/runtime/interpreter/unstarted_runtime_test.cc
@@ -23,6 +23,7 @@
 #include "base/enums.h"
 #include "base/memory_tool.h"
 #include "class_linker.h"
+#include "class_root.h"
 #include "common_runtime_test.h"
 #include "dex/descriptors_names.h"
 #include "dex/dex_instruction.h"
@@ -1370,7 +1371,7 @@
 
   Handle<mirror::ObjectArray<mirror::Object>> args = hs.NewHandle(
       mirror::ObjectArray<mirror::Object>::Alloc(
-          self, class_linker_->GetClassRoot(ClassLinker::ClassRoot::kObjectArrayClass), 1));
+          self, GetClassRoot<mirror::ObjectArray<mirror::Object>>(class_linker_), 1));
   ASSERT_TRUE(args != nullptr);
   args->Set(0, input.Get());
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 3f4e841..ad6b37b 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -26,6 +26,7 @@
 #include "class_ext.h"
 #include "class_linker-inl.h"
 #include "class_loader.h"
+#include "class_root.h"
 #include "dex/descriptors_names.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_annotations.h"
@@ -75,26 +76,26 @@
 
 ObjPtr<mirror::Class> Class::GetPrimitiveClass(ObjPtr<mirror::String> name) {
   const char* expected_name = nullptr;
-  ClassLinker::ClassRoot class_root = ClassLinker::kJavaLangObject;  // Invalid.
+  ClassRoot class_root = ClassRoot::kJavaLangObject;  // Invalid.
   if (name != nullptr && name->GetLength() >= 2) {
     // Perfect hash for the expected values: from the second letters of the primitive types,
     // only 'y' has the bit 0x10 set, so use it to change 'b' to 'B'.
     char hash = name->CharAt(0) ^ ((name->CharAt(1) & 0x10) << 1);
     switch (hash) {
-      case 'b': expected_name = "boolean"; class_root = ClassLinker::kPrimitiveBoolean; break;
-      case 'B': expected_name = "byte";    class_root = ClassLinker::kPrimitiveByte;    break;
-      case 'c': expected_name = "char";    class_root = ClassLinker::kPrimitiveChar;    break;
-      case 'd': expected_name = "double";  class_root = ClassLinker::kPrimitiveDouble;  break;
-      case 'f': expected_name = "float";   class_root = ClassLinker::kPrimitiveFloat;   break;
-      case 'i': expected_name = "int";     class_root = ClassLinker::kPrimitiveInt;     break;
-      case 'l': expected_name = "long";    class_root = ClassLinker::kPrimitiveLong;    break;
-      case 's': expected_name = "short";   class_root = ClassLinker::kPrimitiveShort;   break;
-      case 'v': expected_name = "void";    class_root = ClassLinker::kPrimitiveVoid;    break;
+      case 'b': expected_name = "boolean"; class_root = ClassRoot::kPrimitiveBoolean; break;
+      case 'B': expected_name = "byte";    class_root = ClassRoot::kPrimitiveByte;    break;
+      case 'c': expected_name = "char";    class_root = ClassRoot::kPrimitiveChar;    break;
+      case 'd': expected_name = "double";  class_root = ClassRoot::kPrimitiveDouble;  break;
+      case 'f': expected_name = "float";   class_root = ClassRoot::kPrimitiveFloat;   break;
+      case 'i': expected_name = "int";     class_root = ClassRoot::kPrimitiveInt;     break;
+      case 'l': expected_name = "long";    class_root = ClassRoot::kPrimitiveLong;    break;
+      case 's': expected_name = "short";   class_root = ClassRoot::kPrimitiveShort;   break;
+      case 'v': expected_name = "void";    class_root = ClassRoot::kPrimitiveVoid;    break;
       default: break;
     }
   }
   if (expected_name != nullptr && name->Equals(expected_name)) {
-    ObjPtr<mirror::Class> klass = Runtime::Current()->GetClassLinker()->GetClassRoot(class_root);
+    ObjPtr<mirror::Class> klass = GetClassRoot(class_root);
     DCHECK(klass != nullptr);
     return klass;
   } else {
diff --git a/runtime/mirror/emulated_stack_frame.cc b/runtime/mirror/emulated_stack_frame.cc
index 5f00c6e..527408b 100644
--- a/runtime/mirror/emulated_stack_frame.cc
+++ b/runtime/mirror/emulated_stack_frame.cc
@@ -17,6 +17,7 @@
 #include "emulated_stack_frame.h"
 
 #include "class-inl.h"
+#include "class_root.h"
 #include "gc_root-inl.h"
 #include "jvalue-inl.h"
 #include "method_handles-inl.h"
@@ -166,8 +167,7 @@
   CalculateFrameAndReferencesSize(to_types.Get(), r_type.Get(), &frame_size, &refs_size);
 
   // Step 3 : Allocate the arrays.
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  ObjPtr<mirror::Class> array_class(class_linker->GetClassRoot(ClassLinker::kObjectArrayClass));
+  ObjPtr<mirror::Class> array_class(GetClassRoot<mirror::ObjectArray<mirror::Object>>());
 
   Handle<mirror::ObjectArray<mirror::Object>> references(hs.NewHandle(
       mirror::ObjectArray<mirror::Object>::Alloc(self, array_class, refs_size)));
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 69ba4b9..8b7a1b6 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -28,6 +28,7 @@
 #include "class-inl.h"
 #include "class_linker-inl.h"
 #include "class_linker.h"
+#include "class_root.h"
 #include "common_runtime_test.h"
 #include "dex/dex_file.h"
 #include "entrypoints/entrypoint_utils-inl.h"
@@ -78,7 +79,7 @@
   mirror::ObjectArray<T>* AllocObjectArray(Thread* self, size_t length)
       REQUIRES_SHARED(Locks::mutator_lock_) {
     return mirror::ObjectArray<T>::Alloc(
-        self, class_linker_->GetClassRoot(ClassLinker::ClassRoot::kObjectArrayClass), length);
+        self, GetClassRoot(ClassRoot::kObjectArrayClass, class_linker_), length);
   }
 };
 
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 5a80929..129bae6 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -47,6 +47,7 @@
 #include "base/to_str.h"
 #include "base/utils.h"
 #include "class_linker-inl.h"
+#include "class_root.h"
 #include "debugger.h"
 #include "dex/descriptors_names.h"
 #include "dex/dex_file-inl.h"
@@ -2510,7 +2511,8 @@
     // class of the ArtMethod pointers.
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
     StackHandleScope<1> hs(self_);
-    ObjPtr<mirror::Class> array_class = class_linker->GetClassRoot(ClassLinker::kObjectArrayClass);
+    ObjPtr<mirror::Class> array_class =
+        GetClassRoot<mirror::ObjectArray<mirror::Object>>(class_linker);
     // The first element is the methods and dex pc array, the other elements are declaring classes
     // for the methods to ensure classes in the stack trace don't get unloaded.
     Handle<mirror::ObjectArray<mirror::Object>> trace(