ART: Add unchecked conversions of arrays

Add array conversion functions that do not check the type,
and use them in an unchecked version for PointerArray.

Decreases dex2oatd preopting of a big app from 151s to 150s.

Bug: 123888325
Test: m test-art-host
Change-Id: Id58c65ac603a20c2cfb9e3289af4f3bc323554b6
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index cb1fbfe..ef0d72f 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7090,7 +7090,9 @@
     MethodNameAndSignatureComparator name_comparator(
         vtable_entry->GetInterfaceMethodIfProxy(kPointerSize));
     for (int32_t j = i + 1; j < num_entries; j++) {
-      ArtMethod* other_entry = vtable->GetElementPtrSize<ArtMethod*, kPointerSize>(j);
+      // Can use Unchecked here as the outer loop already ensured that the arrays are correct
+      // wrt/ kPointerSize.
+      ArtMethod* other_entry = vtable->GetElementPtrSizeUnchecked<ArtMethod*, kPointerSize>(j);
       if (!klass->CanAccessMember(other_entry->GetDeclaringClass(),
                                   other_entry->GetAccessFlags())) {
         continue;
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index 40507e7..c4a892b 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -233,6 +233,15 @@
   }
   return (T)static_cast<uintptr_t>(AsIntArray<kVerifyFlags>()->GetWithoutChecks(idx));
 }
+template<typename T, PointerSize kPointerSize, VerifyObjectFlags kVerifyFlags>
+inline T PointerArray::GetElementPtrSizeUnchecked(uint32_t idx) {
+  // C style casts here since we sometimes have T be a pointer, or sometimes an integer
+  // (for stack traces).
+  if (kPointerSize == PointerSize::k64) {
+    return (T)static_cast<uintptr_t>(AsLongArrayUnchecked<kVerifyFlags>()->GetWithoutChecks(idx));
+  }
+  return (T)static_cast<uintptr_t>(AsIntArrayUnchecked<kVerifyFlags>()->GetWithoutChecks(idx));
+}
 template<typename T, VerifyObjectFlags kVerifyFlags>
 inline T PointerArray::GetElementPtrSize(uint32_t idx, PointerSize ptr_size) {
   // C style casts here since we sometimes have T be a pointer, or sometimes an integer
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index ce64272..2e894d5 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -224,6 +224,12 @@
   template<typename T, PointerSize kPtrSize, VerifyObjectFlags kVerifyFlags = kVerifyNone>
   T GetElementPtrSize(uint32_t idx)
       REQUIRES_SHARED(Locks::mutator_lock_);
+  // Same as GetElementPtrSize, but uses unchecked version of array conversion. It is thus not
+  // checked whether kPtrSize matches the underlying array. Only use after at least one invocation
+  // of GetElementPtrSize!
+  template<typename T, PointerSize kPtrSize, VerifyObjectFlags kVerifyFlags = kVerifyNone>
+  T GetElementPtrSizeUnchecked(uint32_t idx)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kVerifyNone>
   void** ElementAddress(size_t index, PointerSize ptr_size) REQUIRES_SHARED(Locks::mutator_lock_) {
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index 2c2ad9b..005e272 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -253,9 +253,13 @@
 }
 
 template<VerifyObjectFlags kVerifyFlags>
+inline IntArray* Object::AsIntArrayUnchecked() {
+  return down_cast<IntArray*>(this);
+}
+template<VerifyObjectFlags kVerifyFlags>
 inline IntArray* Object::AsIntArray() {
   DCHECK((IsIntArray<kVerifyFlags>()));
-  return down_cast<IntArray*>(this);
+  return AsIntArrayUnchecked<kVerifyFlags>();
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -264,9 +268,13 @@
 }
 
 template<VerifyObjectFlags kVerifyFlags>
+inline LongArray* Object::AsLongArrayUnchecked() {
+  return down_cast<LongArray*>(this);
+}
+template<VerifyObjectFlags kVerifyFlags>
 inline LongArray* Object::AsLongArray() {
   DCHECK((IsLongArray<kVerifyFlags>()));
-  return down_cast<LongArray*>(this);
+  return AsLongArrayUnchecked<kVerifyFlags>();
 }
 
 template<VerifyObjectFlags kVerifyFlags>
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index ba222f6..ca8867d8 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -223,11 +223,15 @@
   bool IsIntArray() REQUIRES_SHARED(Locks::mutator_lock_);
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   IntArray* AsIntArray() REQUIRES_SHARED(Locks::mutator_lock_);
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  IntArray* AsIntArrayUnchecked() REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsLongArray() REQUIRES_SHARED(Locks::mutator_lock_);
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   LongArray* AsLongArray() REQUIRES_SHARED(Locks::mutator_lock_);
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  LongArray* AsLongArrayUnchecked() REQUIRES_SHARED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsFloatArray() REQUIRES_SHARED(Locks::mutator_lock_);