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/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));
 }