Templatize `ClassLinker::LinkMethodsHelper`.

Make the pointer size a template parameter to let the C++
compiler better optimize the method linking. Use constant
expressions for `ArtMethod` size and alignment.

Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 181943478
Change-Id: Iebfdbac60c33b5194e86be2e73cb8ea5331b2947
diff --git a/runtime/art_method.h b/runtime/art_method.h
index b501484..3c0492e 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -669,13 +669,13 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Size of an instance of this native class.
-  static size_t Size(PointerSize pointer_size) {
+  static constexpr size_t Size(PointerSize pointer_size) {
     return PtrSizedFieldsOffset(pointer_size) +
         (sizeof(PtrSizedFields) / sizeof(void*)) * static_cast<size_t>(pointer_size);
   }
 
   // Alignment of an instance of this native class.
-  static size_t Alignment(PointerSize pointer_size) {
+  static constexpr size_t Alignment(PointerSize pointer_size) {
     // The ArtMethod alignment is the same as image pointer size. This differs from
     // alignof(ArtMethod) if cross-compiling with pointer_size != sizeof(void*).
     return static_cast<size_t>(pointer_size);
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 82b1cc2..96164f7 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -7174,6 +7174,7 @@
   }
 }
 
+template <PointerSize kPointerSize>
 class ClassLinker::LinkMethodsHelper {
  public:
   LinkMethodsHelper(ClassLinker* class_linker,
@@ -7182,8 +7183,6 @@
                     Runtime* runtime)
       : class_linker_(class_linker),
         klass_(klass),
-        method_alignment_(ArtMethod::Alignment(class_linker->GetImagePointerSize())),
-        method_size_(ArtMethod::Size(class_linker->GetImagePointerSize())),
         self_(self),
         stack_(runtime->GetLinearAlloc()->GetArenaPool()),
         allocator_(&stack_),
@@ -7218,6 +7217,9 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
  private:
+  bool LinkJavaLangObjectVirtualMethods(Thread* self, Handle<mirror::Class> klass)
+      REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
+
   ArtMethod* FindOrCreateImplementationMethod(
       ArtMethod* interface_method,
       MethodNameAndSignatureComparator& interface_name_comparator,
@@ -7247,7 +7249,6 @@
 
   void CheckNoStaleMethodsInDexCache() REQUIRES_SHARED(Locks::mutator_lock_) {
     if (kIsDebugBuild) {
-      PointerSize pointer_size = class_linker_->GetImagePointerSize();
       // Check that there are no stale methods are in the dex cache array.
       ObjPtr<mirror::DexCache> dex_cache = klass_->GetDexCache();
       auto* resolved_methods = dex_cache->GetResolvedMethods();
@@ -7258,11 +7259,11 @@
         CHECK(move_table_.find(m) == move_table_.end() ||
               // The original versions of copied methods will still be present so allow those too.
               // Note that if the first check passes this might fail to GetDeclaringClass().
-              std::find_if(m->GetDeclaringClass()->GetMethods(pointer_size).begin(),
-                           m->GetDeclaringClass()->GetMethods(pointer_size).end(),
+              std::find_if(m->GetDeclaringClass()->GetMethods(kPointerSize).begin(),
+                           m->GetDeclaringClass()->GetMethods(kPointerSize).end(),
                            [m] (ArtMethod& meth) {
                              return &meth == m;
-                           }) != m->GetDeclaringClass()->GetMethods(pointer_size).end())
+                           }) != m->GetDeclaringClass()->GetMethods(kPointerSize).end())
             << "Obsolete method " << m->PrettyMethod() << " is in dex cache!";
       }
     }
@@ -7281,8 +7282,8 @@
                                         gc::kGcCauseClassLinker,
                                         gc::kCollectorTypeClassLinker);
         const size_t old_size = LengthPrefixedArray<ArtMethod>::ComputeSize(old_methods->size(),
-                                                                            method_size_,
-                                                                            method_alignment_);
+                                                                            kMethodSize,
+                                                                            kMethodAlignment);
         memset(old_methods, 0xFEu, old_size);
       }
     }
@@ -7312,10 +7313,11 @@
                        << overriding_default_conflict_methods_.size();
   }
 
+  static constexpr size_t kMethodAlignment = ArtMethod::Alignment(kPointerSize);
+  static constexpr size_t kMethodSize = ArtMethod::Size(kPointerSize);
+
   ClassLinker* class_linker_;
   Handle<mirror::Class> klass_;
-  size_t method_alignment_;
-  size_t method_size_;
   Thread* const self_;
 
   // These are allocated on the heap to begin, we then transfer to linear alloc when we re-create
@@ -7353,7 +7355,8 @@
   ScopedArenaUnorderedMap<ArtMethod*, ArtMethod*> move_table_;
 };
 
-ArtMethod* ClassLinker::LinkMethodsHelper::FindOrCreateImplementationMethod(
+template <PointerSize kPointerSize>
+ArtMethod* ClassLinker::LinkMethodsHelper<kPointerSize>::FindOrCreateImplementationMethod(
     ArtMethod* interface_method,
     MethodNameAndSignatureComparator& interface_name_comparator,
     ArtMethod* vtable_impl) {
@@ -7382,7 +7385,7 @@
           // Note that we do this even if we are an interface since we need to create this and
           // cannot reuse another classes.
           // Create a new conflict method for this to use.
-          default_conflict_method = reinterpret_cast<ArtMethod*>(allocator_.Alloc(method_size_));
+          default_conflict_method = reinterpret_cast<ArtMethod*>(allocator_.Alloc(kMethodSize));
           new(default_conflict_method) ArtMethod(interface_method,
                                                  class_linker_->GetImagePointerSize());
           if (vtable_impl == nullptr) {
@@ -7445,7 +7448,8 @@
   return current_method;
 }
 
-ArtMethod* ClassLinker::LinkMethodsHelper::GetOrCreateMirandaMethod(
+template <PointerSize kPointerSize>
+ArtMethod* ClassLinker::LinkMethodsHelper<kPointerSize>::GetOrCreateMirandaMethod(
     ArtMethod* interface_method,
     MethodNameAndSignatureComparator& interface_name_comparator) {
   // Find out if there is already a miranda method we can use.
@@ -7453,7 +7457,7 @@
                                                        miranda_methods_);
   if (miranda_method == nullptr) {
     DCHECK(interface_method->IsAbstract()) << interface_method->PrettyMethod();
-    miranda_method = reinterpret_cast<ArtMethod*>(allocator_.Alloc(method_size_));
+    miranda_method = reinterpret_cast<ArtMethod*>(allocator_.Alloc(kMethodSize));
     CHECK(miranda_method != nullptr);
     // Point the interface table at a phantom slot.
     new(miranda_method) ArtMethod(interface_method, class_linker_->GetImagePointerSize());
@@ -7462,7 +7466,8 @@
   return miranda_method;
 }
 
-void ClassLinker::LinkMethodsHelper::ReallocMethods() {
+template <PointerSize kPointerSize>
+void ClassLinker::LinkMethodsHelper<kPointerSize>::ReallocMethods() {
   LogNewVirtuals();
 
   const size_t old_method_count = klass_->NumMethods();
@@ -7478,37 +7483,36 @@
   //
   // TODO We should maybe move some of this into mirror::Class or at least into another method.
   const size_t old_size = LengthPrefixedArray<ArtMethod>::ComputeSize(old_method_count,
-                                                                      method_size_,
-                                                                      method_alignment_);
+                                                                      kMethodSize,
+                                                                      kMethodAlignment);
   const size_t new_size = LengthPrefixedArray<ArtMethod>::ComputeSize(new_method_count,
-                                                                      method_size_,
-                                                                      method_alignment_);
+                                                                      kMethodSize,
+                                                                      kMethodAlignment);
   const size_t old_methods_ptr_size = (old_methods != nullptr) ? old_size : 0;
   auto* methods = reinterpret_cast<LengthPrefixedArray<ArtMethod>*>(
       class_linker_->GetAllocatorForClassLoader(klass_->GetClassLoader())->Realloc(
           self_, old_methods, old_methods_ptr_size, new_size));
   CHECK(methods != nullptr);  // Native allocation failure aborts.
 
-  PointerSize pointer_size = class_linker_->GetImagePointerSize();
   if (methods != old_methods) {
     // Maps from heap allocated miranda method to linear alloc miranda method.
-    StrideIterator<ArtMethod> out = methods->begin(method_size_, method_alignment_);
+    StrideIterator<ArtMethod> out = methods->begin(kMethodSize, kMethodAlignment);
     // Copy over the old methods.
-    for (auto& m : klass_->GetMethods(pointer_size)) {
+    for (auto& m : klass_->GetMethods(kPointerSize)) {
       move_table_.emplace(&m, &*out);
       // The CopyFrom is only necessary to not miss read barriers since Realloc won't do read
       // barriers when it copies.
-      out->CopyFrom(&m, pointer_size);
+      out->CopyFrom(&m, kPointerSize);
       ++out;
     }
   }
-  StrideIterator<ArtMethod> out(methods->begin(method_size_, method_alignment_) + old_method_count);
+  StrideIterator<ArtMethod> out(methods->begin(kMethodSize, kMethodAlignment) + old_method_count);
   // Copy over miranda methods before copying vtable since CopyOf may cause thread suspension and
   // we want the roots of the miranda methods to get visited.
   for (size_t i = 0; i < miranda_methods_.size(); ++i) {
     ArtMethod* mir_method = miranda_methods_[i];
     ArtMethod& new_method = *out;
-    new_method.CopyFrom(mir_method, pointer_size);
+    new_method.CopyFrom(mir_method, kPointerSize);
     uint32_t access_flags = new_method.GetAccessFlags();
     DCHECK_EQ(access_flags & kAccIntrinsic, 0u) << "Miranda method should not be an intrinsic!";
     DCHECK_EQ(access_flags & kAccDefault, 0u) << "Miranda method should not be a default method!";
@@ -7533,7 +7537,7 @@
     for (size_t i = 0; i < methods_vec->size(); ++i) {
       ArtMethod* def_method = (*methods_vec)[i];
       ArtMethod& new_method = *out;
-      new_method.CopyFrom(def_method, pointer_size);
+      new_method.CopyFrom(def_method, kPointerSize);
       // Clear the kAccSkipAccessChecks flag if it is present. Since this class hasn't been
       // verified yet it shouldn't have methods that are skipping access checks.
       // TODO This is rather arbitrary. We should maybe support classes where only some of its
@@ -7556,7 +7560,7 @@
     for (size_t i = 0; i < methods_vec->size(); ++i) {
       ArtMethod* conf_method = (*methods_vec)[i];
       ArtMethod& new_method = *out;
-      new_method.CopyFrom(conf_method, pointer_size);
+      new_method.CopyFrom(conf_method, kPointerSize);
       // This is a type of default method (there are default method impls, just a conflict) so
       // mark this as a default. We use the `kAccAbstract` flag to distinguish it from invokable
       // copied default method without using a separate access flag but the default conflicting
@@ -7589,7 +7593,8 @@
   class_linker_->UpdateClassMethods(klass_.Get(), methods);
 }
 
-ObjPtr<mirror::PointerArray> ClassLinker::LinkMethodsHelper::UpdateVtable(
+template <PointerSize kPointerSize>
+ObjPtr<mirror::PointerArray> ClassLinker::LinkMethodsHelper<kPointerSize>::UpdateVtable(
     Handle<mirror::PointerArray> old_vtable) {
   // Update the vtable to the new method structures. We can skip this for interfaces since they
   // do not have vtables.
@@ -7607,7 +7612,6 @@
   }
 
   size_t vtable_pos = old_vtable_count;
-  PointerSize pointer_size = class_linker_->GetImagePointerSize();
   // Update all the newly copied method's indexes so they denote their placement in the vtable.
   for (const ScopedArenaVector<ArtMethod*>& methods_vec : {default_methods_,
                                                            default_conflict_methods_,
@@ -7618,7 +7622,7 @@
       // fields are references into the dex file the method was defined in. Since the ArtMethod
       // does not store that information it uses declaring_class_->dex_cache_.
       new_vtable_method->SetMethodIndex(0xFFFF & vtable_pos);
-      vtable->SetElementPtrSize(vtable_pos, new_vtable_method, pointer_size);
+      vtable->SetElementPtrSize(vtable_pos, new_vtable_method, kPointerSize);
       ++vtable_pos;
     }
   }
@@ -7627,14 +7631,14 @@
   // Update old vtable methods. We use the `default_translations_` map to figure out what each
   // vtable entry should be updated to, if they need to be at all.
   for (size_t i = 0; i < old_vtable_count; ++i) {
-    ArtMethod* translated_method = vtable->GetElementPtrSize<ArtMethod*>(i, pointer_size);
+    ArtMethod* translated_method = vtable->GetElementPtrSize<ArtMethod*>(i, kPointerSize);
     // Try and find what we need to change this method to.
     auto translation_it = default_translations_.find(i);
     if (translation_it != default_translations_.end()) {
       if (translation_it->second.IsInConflict()) {
         // Find which conflict method we are to use for this method.
         MethodNameAndSignatureComparator old_method_comparator(
-            translated_method->GetInterfaceMethodIfProxy(pointer_size));
+            translated_method->GetInterfaceMethodIfProxy(kPointerSize));
         // We only need to look through overriding_default_conflict_methods since this is an
         // overridden method we are fixing up here.
         ArtMethod* new_conflict_method = FindSameNameAndSignature(
@@ -7644,7 +7648,7 @@
       } else if (translation_it->second.IsAbstract()) {
         // Find which miranda method we are to use for this method.
         MethodNameAndSignatureComparator old_method_comparator(
-            translated_method->GetInterfaceMethodIfProxy(pointer_size));
+            translated_method->GetInterfaceMethodIfProxy(kPointerSize));
         ArtMethod* miranda_method = FindSameNameAndSignature(old_method_comparator,
                                                              miranda_methods_);
         DCHECK(miranda_method != nullptr);
@@ -7667,40 +7671,41 @@
       if (translated_method->GetMethodIndexDuringLinking() != i) {
         if (kIsDebugBuild) {
           auto* methods = klass_->GetMethodsPtr();
-          CHECK_LE(reinterpret_cast<uintptr_t>(&*methods->begin(method_size_, method_alignment_)),
+          CHECK_LE(reinterpret_cast<uintptr_t>(&*methods->begin(kMethodSize, kMethodAlignment)),
                    reinterpret_cast<uintptr_t>(translated_method));
           CHECK_LT(reinterpret_cast<uintptr_t>(translated_method),
-                   reinterpret_cast<uintptr_t>(&*methods->end(method_size_, method_alignment_)));
+                   reinterpret_cast<uintptr_t>(&*methods->end(kMethodSize, kMethodAlignment)));
         }
         translated_method->SetMethodIndex(0xFFFF & i);
       }
-      vtable->SetElementPtrSize(i, translated_method, pointer_size);
+      vtable->SetElementPtrSize(i, translated_method, kPointerSize);
     }
   }
   klass_->SetVTable(vtable);
   return vtable;
 }
 
-void ClassLinker::LinkMethodsHelper::UpdateIfTable(Handle<mirror::IfTable> iftable) {
-  PointerSize pointer_size = class_linker_->GetImagePointerSize();
+template <PointerSize kPointerSize>
+void ClassLinker::LinkMethodsHelper<kPointerSize>::UpdateIfTable(Handle<mirror::IfTable> iftable) {
   const size_t ifcount = klass_->GetIfTableCount();
   // Go fix up all the stale iftable pointers.
   for (size_t i = 0; i < ifcount; ++i) {
     for (size_t j = 0, count = iftable->GetMethodArrayCount(i); j < count; ++j) {
       ObjPtr<mirror::PointerArray> method_array = iftable->GetMethodArray(i);
-      ArtMethod* m = method_array->GetElementPtrSize<ArtMethod*>(j, pointer_size);
+      ArtMethod* m = method_array->GetElementPtrSize<ArtMethod*>(j, kPointerSize);
       DCHECK(m != nullptr) << klass_->PrettyClass();
       auto it = move_table_.find(m);
       if (it != move_table_.end()) {
         auto* new_m = it->second;
         DCHECK(new_m != nullptr) << klass_->PrettyClass();
-        method_array->SetElementPtrSize(j, new_m, pointer_size);
+        method_array->SetElementPtrSize(j, new_m, kPointerSize);
       }
     }
   }
 }
 
-void ClassLinker::LinkMethodsHelper::UpdateIMT(ArtMethod** out_imt) {
+template <PointerSize kPointerSize>
+void ClassLinker::LinkMethodsHelper<kPointerSize>::UpdateIMT(ArtMethod** out_imt) {
   // Fix up IMT next.
   for (size_t i = 0; i < ImTable::kSize; ++i) {
     auto it = move_table_.find(out_imt[i]);
@@ -7710,10 +7715,11 @@
   }
 }
 
-bool ClassLinker::LinkMethodsHelper::LinkVirtualMethods(
+template <PointerSize kPointerSize>
+FLATTEN
+bool ClassLinker::LinkMethodsHelper<kPointerSize>::LinkVirtualMethods(
     Thread* self,
     Handle<mirror::Class> klass) {
-  const PointerSize image_pointer_size = class_linker_->GetImagePointerSize();
   const size_t num_virtual_methods = klass->NumVirtualMethods();
   if (klass->IsInterface()) {
     // No vtable.
@@ -7724,7 +7730,7 @@
     bool has_defaults = false;
     // Assign each method an IMT index and set the default flag.
     for (size_t i = 0; i < num_virtual_methods; ++i) {
-      ArtMethod* m = klass->GetVirtualMethodDuringLinking(i, image_pointer_size);
+      ArtMethod* m = klass->GetVirtualMethodDuringLinking(i, kPointerSize);
       m->SetMethodIndex(i);
       if (!m->IsAbstract()) {
         // If the dex file does not support default methods, throw ClassFormatError.
@@ -7751,7 +7757,7 @@
       klass->SetHasDefaultMethods();
     }
     return true;
-  } else if (klass->HasSuperClass()) {
+  } else if (LIKELY(klass->HasSuperClass())) {
     const size_t super_vtable_length = klass->GetSuperClass()->GetVTableLength();
     const size_t max_count = num_virtual_methods + super_vtable_length;
     StackHandleScope<3> hs(self);
@@ -7765,7 +7771,7 @@
       }
       for (size_t i = 0; i < super_vtable_length; i++) {
         vtable->SetElementPtrSize(
-            i, super_class->GetEmbeddedVTableEntry(i, image_pointer_size), image_pointer_size);
+            i, super_class->GetEmbeddedVTableEntry(i, kPointerSize), kPointerSize);
       }
       // We might need to change vtable if we have new virtual methods or new interfaces (since that
       // might give us new default methods). If no new interfaces then we can skip the rest since
@@ -7815,18 +7821,18 @@
       hash_heap_storage.reset(new uint32_t[hash_table_size]);
       hash_table_ptr = hash_heap_storage.get();
     }
-    LinkVirtualHashTable hash_table(klass, hash_table_size, hash_table_ptr, image_pointer_size);
+    LinkVirtualHashTable hash_table(klass, hash_table_size, hash_table_ptr, kPointerSize);
     // Add virtual methods to the hash table.
     for (size_t i = 0; i < num_virtual_methods; ++i) {
       DCHECK(klass->GetVirtualMethodDuringLinking(
-          i, image_pointer_size)->GetDeclaringClass() != nullptr);
+          i, kPointerSize)->GetDeclaringClass() != nullptr);
       hash_table.Add(i);
     }
     // Loop through each super vtable method and see if they are overridden by a method we added to
     // the hash table.
     for (size_t j = 0; j < super_vtable_length; ++j) {
       // Search the hash table to see if we are overridden by any method.
-      ArtMethod* super_method = vtable->GetElementPtrSize<ArtMethod*>(j, image_pointer_size);
+      ArtMethod* super_method = vtable->GetElementPtrSize<ArtMethod*>(j, kPointerSize);
       if (!klass->CanAccessMember(super_method->GetDeclaringClass(),
                                   super_method->GetAccessFlags())) {
         // Continue on to the next method since this one is package private
@@ -7835,7 +7841,7 @@
         continue;
       }
       MethodNameAndSignatureComparator super_method_name_comparator(
-          super_method->GetInterfaceMethodIfProxy(image_pointer_size));
+          super_method->GetInterfaceMethodIfProxy(kPointerSize));
       // We remove the method so that subsequent lookups will be faster by making the hash-map
       // smaller as we go on.
       uint32_t hash = (j < mirror::Object::kVTableLength)
@@ -7843,15 +7849,14 @@
           : ComputeModifiedUtf8Hash(super_method_name_comparator.GetNameView());
       uint32_t hash_index = hash_table.FindAndRemove(&super_method_name_comparator, hash);
       if (hash_index != hash_table.GetNotFoundIndex()) {
-        ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(
-            hash_index, image_pointer_size);
+        ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(hash_index, kPointerSize);
         if (super_method->IsFinal()) {
           ThrowLinkageError(klass.Get(), "Method %s overrides final method in class %s",
                             virtual_method->PrettyMethod().c_str(),
                             super_method->GetDeclaringClassDescriptor());
           return false;
         }
-        vtable->SetElementPtrSize(j, virtual_method, image_pointer_size);
+        vtable->SetElementPtrSize(j, virtual_method, kPointerSize);
         virtual_method->SetMethodIndex(j);
       } else if (super_method->IsOverridableByDefaultMethod()) {
         // We didn't directly override this method but we might through default methods...
@@ -7909,13 +7914,13 @@
     size_t actual_count = super_vtable_length;
     // Add the non-overridden methods at the end.
     for (size_t i = 0; i < num_virtual_methods; ++i) {
-      ArtMethod* local_method = klass->GetVirtualMethodDuringLinking(i, image_pointer_size);
+      ArtMethod* local_method = klass->GetVirtualMethodDuringLinking(i, kPointerSize);
       size_t method_idx = local_method->GetMethodIndexDuringLinking();
       if (method_idx < super_vtable_length &&
-          local_method == vtable->GetElementPtrSize<ArtMethod*>(method_idx, image_pointer_size)) {
+          local_method == vtable->GetElementPtrSize<ArtMethod*>(method_idx, kPointerSize)) {
         continue;
       }
-      vtable->SetElementPtrSize(actual_count, local_method, image_pointer_size);
+      vtable->SetElementPtrSize(actual_count, local_method, kPointerSize);
       local_method->SetMethodIndex(actual_count);
       ++actual_count;
     }
@@ -7935,40 +7940,46 @@
     }
     klass->SetVTable(vtable.Get());
   } else {
-    CHECK_EQ(klass.Get(), GetClassRoot<mirror::Object>(class_linker_));
-    if (!IsUint<16>(num_virtual_methods)) {
-      ThrowClassFormatError(klass.Get(), "Too many methods: %d",
-                            static_cast<int>(num_virtual_methods));
-      return false;
-    }
-    ObjPtr<mirror::PointerArray> vtable =
-        class_linker_->AllocPointerArray(self, num_virtual_methods);
-    if (UNLIKELY(vtable == nullptr)) {
-      self->AssertPendingOOMException();
-      return false;
-    }
-    for (size_t i = 0; i < num_virtual_methods; ++i) {
-      ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(i, image_pointer_size);
-      vtable->SetElementPtrSize(i, virtual_method, image_pointer_size);
-      virtual_method->SetMethodIndex(i & 0xFFFF);
-    }
-    klass->SetVTable(vtable);
-    InitializeObjectVirtualMethodHashes(
-        klass.Get(),
-        image_pointer_size,
-        ArrayRef<uint32_t>(class_linker_->object_virtual_method_hashes_));
+    return LinkJavaLangObjectVirtualMethods(self, klass);
   }
   return true;
 }
 
+template <PointerSize kPointerSize>
+bool ClassLinker::LinkMethodsHelper<kPointerSize>::LinkJavaLangObjectVirtualMethods(
+    Thread* self,
+    Handle<mirror::Class> klass) {
+  DCHECK_EQ(klass.Get(), GetClassRoot<mirror::Object>(class_linker_));
+  DCHECK_EQ(klass->NumVirtualMethods(), mirror::Object::kVTableLength);
+  static_assert(IsUint<16>(mirror::Object::kVTableLength));
+  ObjPtr<mirror::PointerArray> vtable =
+      class_linker_->AllocPointerArray(self, mirror::Object::kVTableLength);
+  if (UNLIKELY(vtable == nullptr)) {
+    self->AssertPendingOOMException();
+    return false;
+  }
+  for (size_t i = 0; i < mirror::Object::kVTableLength; ++i) {
+    ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(i, kPointerSize);
+    vtable->SetElementPtrSize(i, virtual_method, kPointerSize);
+    virtual_method->SetMethodIndex(i);
+  }
+  klass->SetVTable(vtable);
+  InitializeObjectVirtualMethodHashes(
+      klass.Get(),
+      kPointerSize,
+      ArrayRef<uint32_t>(class_linker_->object_virtual_method_hashes_));
+  return true;
+}
+
 // TODO This method needs to be split up into several smaller methods.
-bool ClassLinker::LinkMethodsHelper::LinkInterfaceMethods(
+template <PointerSize kPointerSize>
+FLATTEN
+bool ClassLinker::LinkMethodsHelper<kPointerSize>::LinkInterfaceMethods(
     Thread* self,
     Handle<mirror::Class> klass,
     Runtime* runtime,
     bool* out_new_conflict,
     ArtMethod** out_imt) {
-  const PointerSize image_pointer_size = class_linker_->GetImagePointerSize();
   StackHandleScope<3> hs(self);
 
   const bool is_interface = klass->IsInterface();
@@ -8035,7 +8046,7 @@
         // If we are overwriting a super class interface, try to only virtual methods instead of the
         // whole vtable.
         using_virtuals = true;
-        input_virtual_methods = klass->GetDeclaredVirtualMethodsSlice(image_pointer_size);
+        input_virtual_methods = klass->GetDeclaredVirtualMethodsSlice(kPointerSize);
         input_array_length = input_virtual_methods.size();
       } else {
         // For a new interface, however, we need the whole vtable in case a new
@@ -8048,9 +8059,9 @@
 
       // For each method in interface
       for (size_t j = 0; j < num_methods; ++j) {
-        auto* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j, image_pointer_size);
+        auto* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j, kPointerSize);
         MethodNameAndSignatureComparator interface_name_comparator(
-            interface_method->GetInterfaceMethodIfProxy(image_pointer_size));
+            interface_method->GetInterfaceMethodIfProxy(kPointerSize));
         uint32_t imt_index = interface_method->GetImtIndex();
         ArtMethod** imt_ptr = &out_imt[imt_index];
         // For each method listed in the interface's method list, find the
@@ -8068,9 +8079,9 @@
         for (int32_t k = input_array_length - 1; k >= 0; --k) {
           ArtMethod* vtable_method = using_virtuals ?
               &input_virtual_methods[k] :
-              input_vtable_array->GetElementPtrSize<ArtMethod*>(k, image_pointer_size);
+              input_vtable_array->GetElementPtrSize<ArtMethod*>(k, kPointerSize);
           ArtMethod* vtable_method_for_name_comparison =
-              vtable_method->GetInterfaceMethodIfProxy(image_pointer_size);
+              vtable_method->GetInterfaceMethodIfProxy(kPointerSize);
           DCHECK(!vtable_method->IsStatic()) << vtable_method->PrettyMethod();
           if (interface_name_comparator.HasSameNameAndSignature(
               vtable_method_for_name_comparison)) {
@@ -8094,7 +8105,7 @@
             } else {
               found_impl = true;
               if (LIKELY(fill_tables)) {
-                method_array->SetElementPtrSize(j, vtable_method, image_pointer_size);
+                method_array->SetElementPtrSize(j, vtable_method, kPointerSize);
                 // Place method in imt if entry is empty, place conflict otherwise.
                 class_linker_->SetIMTRef(unimplemented_method,
                                          imt_conflict_method,
@@ -8125,7 +8136,7 @@
           // TODO This is rather dirty but it is faster than searching through the entire vtable
           //      every time.
           ArtMethod* supers_method =
-              method_array->GetElementPtrSize<ArtMethod*>(j, image_pointer_size);
+              method_array->GetElementPtrSize<ArtMethod*>(j, kPointerSize);
           DCHECK(supers_method != nullptr);
           DCHECK(interface_name_comparator.HasSameNameAndSignature(supers_method));
           if (LIKELY(!supers_method->IsOverridableByDefaultMethod())) {
@@ -8161,7 +8172,7 @@
 
           if (current_method != nullptr) {
             // We found a default method implementation. Record it in the iftable and IMT.
-            method_array->SetElementPtrSize(j, current_method, image_pointer_size);
+            method_array->SetElementPtrSize(j, current_method, kPointerSize);
             class_linker_->SetIMTRef(unimplemented_method,
                                      imt_conflict_method,
                                      current_method,
@@ -8198,7 +8209,7 @@
     self->EndAssertNoThreadSuspension(old_cause);
   }
   if (kIsDebugBuild && !is_interface) {
-    CheckVTable(self, klass, image_pointer_size);
+    CheckVTable(self, klass, kPointerSize);
   }
   return true;
 }
@@ -8217,9 +8228,17 @@
   }
   // Link virtual methods then interface methods.
   Runtime* const runtime = Runtime::Current();
-  LinkMethodsHelper helper(this, klass, self, runtime);
-  return helper.LinkVirtualMethods(self, klass) &&
-         helper.LinkInterfaceMethods(self, klass, runtime, out_new_conflict, out_imt);
+  if (LIKELY(GetImagePointerSize() == kRuntimePointerSize)) {
+    LinkMethodsHelper<kRuntimePointerSize> helper(this, klass, self, runtime);
+    return helper.LinkVirtualMethods(self, klass) &&
+           helper.LinkInterfaceMethods(self, klass, runtime, out_new_conflict, out_imt);
+  } else {
+    constexpr PointerSize kOtherPointerSize =
+        (kRuntimePointerSize == PointerSize::k64) ? PointerSize::k32 : PointerSize::k64;
+    LinkMethodsHelper<kOtherPointerSize> helper(this, klass, self, runtime);
+    return helper.LinkVirtualMethods(self, klass) &&
+           helper.LinkInterfaceMethods(self, klass, runtime, out_new_conflict, out_imt);
+  }
 }
 
 class ClassLinker::LinkFieldsHelper {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index c40cea3..b0c02e5 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -863,6 +863,7 @@
 
  private:
   class LinkFieldsHelper;
+  template <PointerSize kPointerSize>
   class LinkMethodsHelper;
   class MethodTranslation;
   class VisiblyInitializedCallback;