ART: Optimize array accesses

Optimize computation of the data offset of arrays by adding
a constant for the array payload field offset, and templatized
versions of the computation. Add a correctness check on runtime
creation.

Templatize CheckVTableHasNoDuplicates.

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

Bug: 123888325
Test: m test-art-host
Change-Id: I8db9df545dc807a307aef8af7dad7a15757670b1
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index d29a6b7..cb1fbfe 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7074,31 +7074,30 @@
 
 // Check to make sure the vtable does not have duplicates. Duplicates could cause problems when a
 // method is overridden in a subclass.
-static void CheckVTableHasNoDuplicates(Thread* self,
-                                       Handle<mirror::Class> klass,
-                                       PointerSize pointer_size)
+template <PointerSize kPointerSize>
+static void CheckVTableHasNoDuplicates(Thread* self, Handle<mirror::Class> klass)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   StackHandleScope<1> hs(self);
   Handle<mirror::PointerArray> vtable(hs.NewHandle(klass->GetVTableDuringLinking()));
   int32_t num_entries = vtable->GetLength();
   for (int32_t i = 0; i < num_entries; i++) {
-    ArtMethod* vtable_entry = vtable->GetElementPtrSize<ArtMethod*>(i, pointer_size);
+    ArtMethod* vtable_entry = vtable->GetElementPtrSize<ArtMethod*, kPointerSize>(i);
     // Don't bother if we cannot 'see' the vtable entry (i.e. it is a package-private member maybe).
     if (!klass->CanAccessMember(vtable_entry->GetDeclaringClass(),
                                 vtable_entry->GetAccessFlags())) {
       continue;
     }
     MethodNameAndSignatureComparator name_comparator(
-        vtable_entry->GetInterfaceMethodIfProxy(pointer_size));
+        vtable_entry->GetInterfaceMethodIfProxy(kPointerSize));
     for (int32_t j = i + 1; j < num_entries; j++) {
-      ArtMethod* other_entry = vtable->GetElementPtrSize<ArtMethod*>(j, pointer_size);
+      ArtMethod* other_entry = vtable->GetElementPtrSize<ArtMethod*, kPointerSize>(j);
       if (!klass->CanAccessMember(other_entry->GetDeclaringClass(),
                                   other_entry->GetAccessFlags())) {
         continue;
       }
       if (vtable_entry == other_entry ||
           name_comparator.HasSameNameAndSignature(
-               other_entry->GetInterfaceMethodIfProxy(pointer_size))) {
+               other_entry->GetInterfaceMethodIfProxy(kPointerSize))) {
         LOG(WARNING) << "vtable entries " << i << " and " << j << " are identical for "
                      << klass->PrettyClass() << " in method " << vtable_entry->PrettyMethod()
                      << " (0x" << std::hex << reinterpret_cast<uintptr_t>(vtable_entry) << ") and "
@@ -7108,6 +7107,19 @@
     }
   }
 }
+static void CheckVTableHasNoDuplicates(Thread* self,
+                                       Handle<mirror::Class> klass,
+                                       PointerSize pointer_size)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  switch (pointer_size) {
+    case PointerSize::k64:
+      CheckVTableHasNoDuplicates<PointerSize::k64>(self, klass);
+      break;
+    case PointerSize::k32:
+      CheckVTableHasNoDuplicates<PointerSize::k32>(self, klass);
+      break;
+  }
+}
 
 static void SanityCheckVTable(Thread* self, Handle<mirror::Class> klass, PointerSize pointer_size)
     REQUIRES_SHARED(Locks::mutator_lock_) {