Initialize array classes in pre-fence visitor.

Rewrite array class initialization to make it easier to
reason about memory visibility. Initialize all members in
the pre-fence visitor for the normal use case. Refactor
initialization of core array classes without boot image to
avoid special-casing in ClassLinker::CreateArrayClass().

Note that the Class::object_size_alloc_fast_path_ field
of primitive classes (instances of which cannot be
allocated) will be kept at numeric_limits<uint32_t>::max().
The boot image before and after is otherwise identical.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: aosp_taimen-userdebug boots.
Test: run-gtests.sh
Test: testrunner.py --target --optimizing
Change-Id: I570e3af011c8d3383ce46c81eb6f2fa60c5a4b0f
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 2bbcbb7..b0d2da6 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -559,27 +559,27 @@
   DCHECK_EQ(GetArrayIfTable(), object_array_class->GetIfTable());
 
   // Setup the primitive type classes.
-  SetClassRoot(ClassRoot::kPrimitiveBoolean, CreatePrimitiveClass(self, Primitive::kPrimBoolean));
-  SetClassRoot(ClassRoot::kPrimitiveByte, CreatePrimitiveClass(self, Primitive::kPrimByte));
-  SetClassRoot(ClassRoot::kPrimitiveChar, CreatePrimitiveClass(self, Primitive::kPrimChar));
-  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));
+  CreatePrimitiveClass(self, Primitive::kPrimBoolean, ClassRoot::kPrimitiveBoolean);
+  CreatePrimitiveClass(self, Primitive::kPrimByte, ClassRoot::kPrimitiveByte);
+  CreatePrimitiveClass(self, Primitive::kPrimChar, ClassRoot::kPrimitiveChar);
+  CreatePrimitiveClass(self, Primitive::kPrimShort, ClassRoot::kPrimitiveShort);
+  CreatePrimitiveClass(self, Primitive::kPrimInt, ClassRoot::kPrimitiveInt);
+  CreatePrimitiveClass(self, Primitive::kPrimLong, ClassRoot::kPrimitiveLong);
+  CreatePrimitiveClass(self, Primitive::kPrimFloat, ClassRoot::kPrimitiveFloat);
+  CreatePrimitiveClass(self, Primitive::kPrimDouble, ClassRoot::kPrimitiveDouble);
+  CreatePrimitiveClass(self, Primitive::kPrimVoid, ClassRoot::kPrimitiveVoid);
 
-  // Create int array type for native pointer arrays (for example vtables) on 32-bit archs.
-  Handle<mirror::Class> int_array_class(hs.NewHandle(
-      AllocPrimitiveArrayClass(self, java_lang_Class.Get())));
-  int_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveInt, this));
-  SetClassRoot(ClassRoot::kIntArrayClass, int_array_class.Get());
-
-  // Create long array type for native pointer arrays (for example vtables) on 64-bit archs.
-  Handle<mirror::Class> long_array_class(hs.NewHandle(
-      AllocPrimitiveArrayClass(self, java_lang_Class.Get())));
-  long_array_class->SetComponentType(GetClassRoot(ClassRoot::kPrimitiveLong, this));
-  SetClassRoot(ClassRoot::kLongArrayClass, long_array_class.Get());
+  // Allocate the primitive array classes. We need only the native pointer
+  // array at this point (int[] or long[], depending on architecture) but
+  // we shall perform the same setup steps for all primitive array classes.
+  AllocPrimitiveArrayClass(self, ClassRoot::kPrimitiveBoolean, ClassRoot::kBooleanArrayClass);
+  AllocPrimitiveArrayClass(self, ClassRoot::kPrimitiveByte, ClassRoot::kByteArrayClass);
+  AllocPrimitiveArrayClass(self, ClassRoot::kPrimitiveChar, ClassRoot::kCharArrayClass);
+  AllocPrimitiveArrayClass(self, ClassRoot::kPrimitiveShort, ClassRoot::kShortArrayClass);
+  AllocPrimitiveArrayClass(self, ClassRoot::kPrimitiveInt, ClassRoot::kIntArrayClass);
+  AllocPrimitiveArrayClass(self, ClassRoot::kPrimitiveLong, ClassRoot::kLongArrayClass);
+  AllocPrimitiveArrayClass(self, ClassRoot::kPrimitiveFloat, ClassRoot::kFloatArrayClass);
+  AllocPrimitiveArrayClass(self, ClassRoot::kPrimitiveDouble, ClassRoot::kDoubleArrayClass);
 
   // now that these are registered, we can use AllocClass() and AllocObjectArray
 
@@ -652,37 +652,23 @@
   CheckSystemClass(self, dalvik_system_ClassExt, "Ldalvik/system/ClassExt;");
   CHECK_EQ(dalvik_system_ClassExt->GetObjectSize(), mirror::ClassExt::InstanceSize());
 
-  // Setup the primitive array type classes - can't be done until Object has a vtable.
-  AllocAndSetPrimitiveArrayClassRoot(self,
-                                     java_lang_Class.Get(),
-                                     ClassRoot::kBooleanArrayClass,
-                                     ClassRoot::kPrimitiveBoolean,
-                                     "[Z");
-
-  AllocAndSetPrimitiveArrayClassRoot(
-      self, java_lang_Class.Get(), ClassRoot::kByteArrayClass, ClassRoot::kPrimitiveByte, "[B");
-
-  AllocAndSetPrimitiveArrayClassRoot(
-      self, java_lang_Class.Get(), ClassRoot::kCharArrayClass, ClassRoot::kPrimitiveChar, "[C");
-
-  AllocAndSetPrimitiveArrayClassRoot(
-      self, java_lang_Class.Get(), ClassRoot::kShortArrayClass, ClassRoot::kPrimitiveShort, "[S");
-
-  CheckSystemClass(self, int_array_class, "[I");
-  CheckSystemClass(self, long_array_class, "[J");
-
-  AllocAndSetPrimitiveArrayClassRoot(
-      self, java_lang_Class.Get(), ClassRoot::kFloatArrayClass, ClassRoot::kPrimitiveFloat, "[F");
-
-  AllocAndSetPrimitiveArrayClassRoot(
-      self, java_lang_Class.Get(), ClassRoot::kDoubleArrayClass, ClassRoot::kPrimitiveDouble, "[D");
-
   // Run Class through FindSystemClass. This initializes the dex_cache_ fields and register it
   // in class_table_.
   CheckSystemClass(self, java_lang_Class, "Ljava/lang/Class;");
 
-  CheckSystemClass(self, class_array_class, "[Ljava/lang/Class;");
-  CheckSystemClass(self, object_array_class, "[Ljava/lang/Object;");
+  // Setup core array classes, i.e. Object[], String[] and Class[] and primitive
+  // arrays - can't be done until Object has a vtable and component classes are loaded.
+  FinishCoreArrayClassSetup(ClassRoot::kObjectArrayClass);
+  FinishCoreArrayClassSetup(ClassRoot::kClassArrayClass);
+  FinishCoreArrayClassSetup(ClassRoot::kJavaLangStringArrayClass);
+  FinishCoreArrayClassSetup(ClassRoot::kBooleanArrayClass);
+  FinishCoreArrayClassSetup(ClassRoot::kByteArrayClass);
+  FinishCoreArrayClassSetup(ClassRoot::kCharArrayClass);
+  FinishCoreArrayClassSetup(ClassRoot::kShortArrayClass);
+  FinishCoreArrayClassSetup(ClassRoot::kIntArrayClass);
+  FinishCoreArrayClassSetup(ClassRoot::kLongArrayClass);
+  FinishCoreArrayClassSetup(ClassRoot::kFloatArrayClass);
+  FinishCoreArrayClassSetup(ClassRoot::kDoubleArrayClass);
 
   // Setup the single, global copy of "iftable".
   auto java_lang_Cloneable = hs.NewHandle(FindSystemClass(self, "Ljava/lang/Cloneable;"));
@@ -2567,16 +2553,16 @@
   return dex_cache;
 }
 
-template <bool kMovable>
+template <bool kMovable, typename PreFenceVisitor>
 ObjPtr<mirror::Class> ClassLinker::AllocClass(Thread* self,
                                               ObjPtr<mirror::Class> java_lang_Class,
-                                              uint32_t class_size) {
+                                              uint32_t class_size,
+                                              const PreFenceVisitor& pre_fence_visitor) {
   DCHECK_GE(class_size, sizeof(mirror::Class));
   gc::Heap* heap = Runtime::Current()->GetHeap();
-  mirror::Class::InitializeClassVisitor visitor(class_size);
   ObjPtr<mirror::Object> k = (kMovingClasses && kMovable) ?
-      heap->AllocObject(self, java_lang_Class, class_size, visitor) :
-      heap->AllocNonMovableObject(self, java_lang_Class, class_size, visitor);
+      heap->AllocObject(self, java_lang_Class, class_size, pre_fence_visitor) :
+      heap->AllocNonMovableObject(self, java_lang_Class, class_size, pre_fence_visitor);
   if (UNLIKELY(k == nullptr)) {
     self->AssertPendingOOMException();
     return nullptr;
@@ -2584,20 +2570,96 @@
   return k->AsClass();
 }
 
+template <bool kMovable>
+ObjPtr<mirror::Class> ClassLinker::AllocClass(Thread* self,
+                                              ObjPtr<mirror::Class> java_lang_Class,
+                                              uint32_t class_size) {
+  mirror::Class::InitializeClassVisitor visitor(class_size);
+  return AllocClass<kMovable>(self, java_lang_Class, class_size, visitor);
+}
+
 ObjPtr<mirror::Class> ClassLinker::AllocClass(Thread* self, uint32_t class_size) {
   return AllocClass(self, GetClassRoot<mirror::Class>(this), class_size);
 }
 
-ObjPtr<mirror::Class> ClassLinker::AllocPrimitiveArrayClass(Thread* self,
-                                                            ObjPtr<mirror::Class> java_lang_Class) {
+void ClassLinker::AllocPrimitiveArrayClass(Thread* self,
+                                           ClassRoot primitive_root,
+                                           ClassRoot array_root) {
   // We make this class non-movable for the unlikely case where it were to be
   // moved by a sticky-bit (minor) collection when using the Generational
   // Concurrent Copying (CC) collector, potentially creating a stale reference
   // in the `klass_` field of one of its instances allocated in the Large-Object
   // Space (LOS) -- see the comment about the dirty card scanning logic in
   // art::gc::collector::ConcurrentCopying::MarkingPhase.
-  return AllocClass</* kMovable= */ false>(
-      self, java_lang_Class, mirror::Array::ClassSize(image_pointer_size_));
+  ObjPtr<mirror::Class> array_class = AllocClass</* kMovable= */ false>(
+      self, GetClassRoot<mirror::Class>(this), mirror::Array::ClassSize(image_pointer_size_));
+  ObjPtr<mirror::Class> component_type = GetClassRoot(primitive_root, this);
+  DCHECK(component_type->IsPrimitive());
+  array_class->SetComponentType(component_type);
+  SetClassRoot(array_root, array_class);
+}
+
+void ClassLinker::FinishArrayClassSetup(ObjPtr<mirror::Class> array_class) {
+  ObjPtr<mirror::Class> java_lang_Object = GetClassRoot<mirror::Object>(this);
+  array_class->SetSuperClass(java_lang_Object);
+  array_class->SetVTable(java_lang_Object->GetVTable());
+  array_class->SetPrimitiveType(Primitive::kPrimNot);
+  ObjPtr<mirror::Class> component_type = array_class->GetComponentType();
+  array_class->SetClassFlags(component_type->IsPrimitive()
+                                 ? mirror::kClassFlagNoReferenceFields
+                                 : mirror::kClassFlagObjectArray);
+  array_class->SetClassLoader(component_type->GetClassLoader());
+  array_class->SetStatusForPrimitiveOrArray(ClassStatus::kLoaded);
+  array_class->PopulateEmbeddedVTable(image_pointer_size_);
+  ImTable* object_imt = java_lang_Object->GetImt(image_pointer_size_);
+  array_class->SetImt(object_imt, image_pointer_size_);
+  // Skip EnsureSkipAccessChecksMethods(). We can skip the verified status,
+  // the kAccVerificationAttempted flag is added below, and there are no
+  // methods that need the kAccSkipAccessChecks flag.
+  DCHECK_EQ(array_class->NumMethods(), 0u);
+
+  // don't need to set new_class->SetObjectSize(..)
+  // because Object::SizeOf delegates to Array::SizeOf
+
+  // All arrays have java/lang/Cloneable and java/io/Serializable as
+  // interfaces.  We need to set that up here, so that stuff like
+  // "instanceof" works right.
+
+  // Use the single, global copies of "interfaces" and "iftable"
+  // (remember not to free them for arrays).
+  {
+    ObjPtr<mirror::IfTable> array_iftable = GetArrayIfTable();
+    CHECK(array_iftable != nullptr);
+    array_class->SetIfTable(array_iftable);
+  }
+
+  // Inherit access flags from the component type.
+  int access_flags = component_type->GetAccessFlags();
+  // Lose any implementation detail flags; in particular, arrays aren't finalizable.
+  access_flags &= kAccJavaFlagsMask;
+  // Arrays can't be used as a superclass or interface, so we want to add "abstract final"
+  // and remove "interface".
+  access_flags |= kAccAbstract | kAccFinal;
+  access_flags &= ~kAccInterface;
+  // Arrays are access-checks-clean and preverified.
+  access_flags |= kAccVerificationAttempted;
+
+  array_class->SetAccessFlags(access_flags);
+
+  array_class->SetStatusForPrimitiveOrArray(ClassStatus::kInitialized);
+}
+
+void ClassLinker::FinishCoreArrayClassSetup(ClassRoot array_root) {
+  // Do not hold lock on the array class object, the initialization of
+  // core array classes is done while the process is still single threaded.
+  ObjPtr<mirror::Class> array_class = GetClassRoot(array_root, this);
+  FinishArrayClassSetup(array_class);
+
+  std::string temp;
+  const char* descriptor = array_class->GetDescriptor(&temp);
+  size_t hash = ComputeModifiedUtf8Hash(descriptor);
+  ObjPtr<mirror::Class> existing = InsertClass(descriptor, array_class, hash);
+  CHECK(existing == nullptr);
 }
 
 ObjPtr<mirror::ObjectArray<mirror::StackTraceElement>> ClassLinker::AllocStackTraceElementArray(
@@ -4081,28 +4143,29 @@
   return DexCacheData();
 }
 
-ObjPtr<mirror::Class> ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) {
+void ClassLinker::CreatePrimitiveClass(Thread* self,
+                                       Primitive::Type type,
+                                       ClassRoot primitive_root) {
   ObjPtr<mirror::Class> primitive_class =
       AllocClass(self, mirror::Class::PrimitiveClassSize(image_pointer_size_));
-  if (UNLIKELY(primitive_class == nullptr)) {
-    self->AssertPendingOOMException();
-    return nullptr;
-  }
-  // Must hold lock on object when initializing.
-  StackHandleScope<1> hs(self);
-  Handle<mirror::Class> h_class(hs.NewHandle(primitive_class));
-  ObjectLock<mirror::Class> lock(self, h_class);
-  h_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
-  h_class->SetPrimitiveType(type);
-  h_class->SetIfTable(GetClassRoot<mirror::Object>(this)->GetIfTable());
-  EnsureSkipAccessChecksMethods</* kNeedsVerified= */ true>(h_class, image_pointer_size_);
-  mirror::Class::SetStatus(h_class, ClassStatus::kInitialized, self);
+  CHECK(primitive_class != nullptr) << "OOM for primitive class " << type;
+  // Do not hold lock on the primitive class object, the initialization of
+  // primitive classes is done while the process is still single threaded.
+  primitive_class->SetAccessFlags(
+      kAccPublic | kAccFinal | kAccAbstract | kAccVerificationAttempted);
+  primitive_class->SetPrimitiveType(type);
+  primitive_class->SetIfTable(GetClassRoot<mirror::Object>(this)->GetIfTable());
+  // Skip EnsureSkipAccessChecksMethods(). We can skip the verified status,
+  // the kAccVerificationAttempted flag was added above, and there are no
+  // methods that need the kAccSkipAccessChecks flag.
+  DCHECK_EQ(primitive_class->NumMethods(), 0u);
+  primitive_class->SetStatusForPrimitiveOrArray(ClassStatus::kInitialized);
   const char* descriptor = Primitive::Descriptor(type);
   ObjPtr<mirror::Class> existing = InsertClass(descriptor,
-                                               h_class.Get(),
+                                               primitive_class,
                                                ComputeModifiedUtf8Hash(descriptor));
   CHECK(existing == nullptr) << "InitPrimitiveClass(" << type << ") failed";
-  return h_class.Get();
+  SetClassRoot(primitive_root, primitive_class);
 }
 
 inline ObjPtr<mirror::IfTable> ClassLinker::GetArrayIfTable() {
@@ -4183,6 +4246,14 @@
       return new_class;
     }
   }
+  // Core array classes, i.e. Object[], Class[], String[] and primitive
+  // arrays, have special initialization and they should be found above.
+  DCHECK(!component_type->IsObjectClass() ||
+         // Guard from false positives for errors before setting superclass.
+         component_type->IsErroneousUnresolved());
+  DCHECK(!component_type->IsStringClass());
+  DCHECK(!component_type->IsClassClass());
+  DCHECK(!component_type->IsPrimitive());
 
   // Fill out the fields in the Class.
   //
@@ -4192,92 +4263,26 @@
   //
   // Array classes are simple enough that we don't need to do a full
   // link step.
-  auto new_class = hs.NewHandle<mirror::Class>(nullptr);
-  if (UNLIKELY(!init_done_)) {
-    // Classes that were hand created, ie not by FindSystemClass
-    if (strcmp(descriptor, "[Ljava/lang/Class;") == 0) {
-      new_class.Assign(GetClassRoot<mirror::ObjectArray<mirror::Class>>(this));
-    } else if (strcmp(descriptor, "[Ljava/lang/Object;") == 0) {
-      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, "[Z") == 0) {
-      new_class.Assign(GetClassRoot<mirror::BooleanArray>(this));
-    } else if (strcmp(descriptor, "[B") == 0) {
-      new_class.Assign(GetClassRoot<mirror::ByteArray>(this));
-    } else if (strcmp(descriptor, "[C") == 0) {
-      new_class.Assign(GetClassRoot<mirror::CharArray>(this));
-    } else if (strcmp(descriptor, "[S") == 0) {
-      new_class.Assign(GetClassRoot<mirror::ShortArray>(this));
-    } else if (strcmp(descriptor, "[I") == 0) {
-      new_class.Assign(GetClassRoot<mirror::IntArray>(this));
-    } else if (strcmp(descriptor, "[J") == 0) {
-      new_class.Assign(GetClassRoot<mirror::LongArray>(this));
-    } else if (strcmp(descriptor, "[F") == 0) {
-      new_class.Assign(GetClassRoot<mirror::FloatArray>(this));
-    } else if (strcmp(descriptor, "[D") == 0) {
-      new_class.Assign(GetClassRoot<mirror::DoubleArray>(this));
-    }
-  }
+  size_t array_class_size = mirror::Array::ClassSize(image_pointer_size_);
+  auto visitor = [this, array_class_size, component_type](ObjPtr<mirror::Object> obj,
+                                                          size_t usable_size)
+      REQUIRES_SHARED(Locks::mutator_lock_) {
+    mirror::Class::InitializeClassVisitor init_class(array_class_size);
+    init_class(obj, usable_size);
+    ObjPtr<mirror::Class> klass = ObjPtr<mirror::Class>::DownCast(obj);
+    klass->SetComponentType(component_type.Get());
+    // Do not hold lock for initialization, the fence issued after the visitor
+    // returns ensures memory visibility together with the implicit consume
+    // semantics (for all supported architectures) for any thread that loads
+    // the array class reference from any memory locations afterwards.
+    FinishArrayClassSetup(klass);
+  };
+  auto new_class = hs.NewHandle<mirror::Class>(
+      AllocClass(self, GetClassRoot<mirror::Class>(this), array_class_size, visitor));
   if (new_class == nullptr) {
-    new_class.Assign(AllocClass(self, mirror::Array::ClassSize(image_pointer_size_)));
-    if (new_class == nullptr) {
-      self->AssertPendingOOMException();
-      return nullptr;
-    }
-    new_class->SetComponentType(component_type.Get());
+    self->AssertPendingOOMException();
+    return nullptr;
   }
-  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<mirror::Object>(this);
-  new_class->SetSuperClass(java_lang_Object);
-  new_class->SetVTable(java_lang_Object->GetVTable());
-  new_class->SetPrimitiveType(Primitive::kPrimNot);
-  new_class->SetClassLoader(component_type->GetClassLoader());
-  if (component_type->IsPrimitive()) {
-    new_class->SetClassFlags(mirror::kClassFlagNoReferenceFields);
-  } else {
-    new_class->SetClassFlags(mirror::kClassFlagObjectArray);
-  }
-  mirror::Class::SetStatus(new_class, ClassStatus::kLoaded, self);
-  new_class->PopulateEmbeddedVTable(image_pointer_size_);
-  ImTable* object_imt = java_lang_Object->GetImt(image_pointer_size_);
-  new_class->SetImt(object_imt, image_pointer_size_);
-  EnsureSkipAccessChecksMethods</* kNeedsVerified= */ true>(new_class, image_pointer_size_);
-  mirror::Class::SetStatus(new_class, ClassStatus::kInitialized, self);
-  // don't need to set new_class->SetObjectSize(..)
-  // because Object::SizeOf delegates to Array::SizeOf
-
-  // All arrays have java/lang/Cloneable and java/io/Serializable as
-  // interfaces.  We need to set that up here, so that stuff like
-  // "instanceof" works right.
-  //
-  // Note: The GC could run during the call to FindSystemClass,
-  // so we need to make sure the class object is GC-valid while we're in
-  // there.  Do this by clearing the interface list so the GC will just
-  // think that the entries are null.
-
-
-  // Use the single, global copies of "interfaces" and "iftable"
-  // (remember not to free them for arrays).
-  {
-    ObjPtr<mirror::IfTable> array_iftable = GetArrayIfTable();
-    CHECK(array_iftable != nullptr);
-    new_class->SetIfTable(array_iftable);
-  }
-
-  // Inherit access flags from the component type.
-  int access_flags = new_class->GetComponentType()->GetAccessFlags();
-  // Lose any implementation detail flags; in particular, arrays aren't finalizable.
-  access_flags &= kAccJavaFlagsMask;
-  // Arrays can't be used as a superclass or interface, so we want to add "abstract final"
-  // and remove "interface".
-  access_flags |= kAccAbstract | kAccFinal;
-  access_flags &= ~kAccInterface;
-  // Arrays are access-checks-clean and preverified.
-  access_flags |= kAccVerificationAttempted;
-
-  new_class->SetAccessFlags(access_flags);
 
   ObjPtr<mirror::Class> existing = InsertClass(descriptor, new_class.Get(), hash);
   if (existing == nullptr) {
@@ -9398,19 +9403,6 @@
   class_roots->Set<false>(index, klass);
 }
 
-void ClassLinker::AllocAndSetPrimitiveArrayClassRoot(Thread* self,
-                                                     ObjPtr<mirror::Class> java_lang_Class,
-                                                     ClassRoot primitive_array_class_root,
-                                                     ClassRoot primitive_class_root,
-                                                     const char* descriptor) {
-  StackHandleScope<1> hs(self);
-  Handle<mirror::Class> primitive_array_class(hs.NewHandle(
-      AllocPrimitiveArrayClass(self, java_lang_Class)));
-  primitive_array_class->SetComponentType(GetClassRoot(primitive_class_root, this));
-  SetClassRoot(primitive_array_class_root, primitive_array_class.Get());
-  CheckSystemClass(self, primitive_array_class, descriptor);
-}
-
 ObjPtr<mirror::ClassLoader> ClassLinker::CreateWellKnownClassLoader(
     Thread* self,
     const std::vector<const DexFile*>& dex_files,