diff options
Diffstat (limited to 'runtime/class_linker.cc')
| -rw-r--r-- | runtime/class_linker.cc | 520 | 
1 files changed, 321 insertions, 199 deletions
| diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 0c3549a0bd..0878667872 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1104,6 +1104,19 @@ void ClassLinker::RunRootClinits(Thread* self) {    }  } +ALWAYS_INLINE +static uint32_t ComputeMethodHash(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { +  DCHECK(!method->IsRuntimeMethod()); +  DCHECK(!method->IsProxyMethod()); +  DCHECK(!method->IsObsolete()); +  // Do not use `ArtMethod::GetNameView()` to avoid unnecessary runtime/proxy/obsolete method +  // checks. It is safe to avoid the read barrier here, see `ArtMethod::GetDexFile()`. +  const DexFile& dex_file = method->GetDeclaringClass<kWithoutReadBarrier>()->GetDexFile(); +  const dex::MethodId& method_id = dex_file.GetMethodId(method->GetDexMethodIndex()); +  std::string_view name = dex_file.GetMethodNameView(method_id); +  return ComputeModifiedUtf8Hash(name); +} +  static void InitializeObjectVirtualMethodHashes(ObjPtr<mirror::Class> java_lang_Object,                                                  PointerSize pointer_size,                                                  /*out*/ ArrayRef<uint32_t> virtual_method_hashes) @@ -1111,8 +1124,7 @@ static void InitializeObjectVirtualMethodHashes(ObjPtr<mirror::Class> java_lang_    ArraySlice<ArtMethod> virtual_methods = java_lang_Object->GetVirtualMethods(pointer_size);    DCHECK_EQ(virtual_method_hashes.size(), virtual_methods.size());    for (size_t i = 0; i != virtual_method_hashes.size(); ++i) { -    std::string_view name = virtual_methods[i].GetNameView(); -    virtual_method_hashes[i] = ComputeModifiedUtf8Hash(name); +    virtual_method_hashes[i] = ComputeMethodHash(&virtual_methods[i]);    }  } @@ -6169,79 +6181,6 @@ class MethodNameAndSignatureComparator final : public ValueObject {    std::string_view name_view_;  }; -class LinkVirtualHashTable { - public: -  LinkVirtualHashTable(Handle<mirror::Class> klass, -                       size_t hash_size, -                       uint32_t* hash_table, -                       PointerSize image_pointer_size) -     : klass_(klass), -       hash_size_(hash_size), -       hash_table_(hash_table), -       image_pointer_size_(image_pointer_size) { -    std::fill(hash_table_, hash_table_ + hash_size_, invalid_index_); -  } - -  void Add(uint32_t virtual_method_index) REQUIRES_SHARED(Locks::mutator_lock_) { -    ArtMethod* local_method = klass_->GetVirtualMethodDuringLinking( -        virtual_method_index, image_pointer_size_); -    std::string_view name_view = -        local_method->GetInterfaceMethodIfProxy(image_pointer_size_)->GetNameView(); -    uint32_t hash = ComputeModifiedUtf8Hash(name_view); -    uint32_t index = hash % hash_size_; -    // Linear probe until we have an empty slot. -    while (hash_table_[index] != invalid_index_) { -      if (++index == hash_size_) { -        index = 0; -      } -    } -    hash_table_[index] = virtual_method_index; -  } - -  uint32_t FindAndRemove(MethodNameAndSignatureComparator* comparator, uint32_t hash) -      REQUIRES_SHARED(Locks::mutator_lock_) { -    DCHECK_EQ(hash, ComputeModifiedUtf8Hash(comparator->GetNameView())); -    size_t index = hash % hash_size_; -    while (true) { -      const uint32_t value = hash_table_[index]; -      // Since linear probe makes continuous blocks, hitting an invalid index means we are done -      // the block and can safely assume not found. -      if (value == invalid_index_) { -        break; -      } -      if (value != removed_index_) {  // This signifies not already overriden. -        ArtMethod* virtual_method = -            klass_->GetVirtualMethodDuringLinking(value, image_pointer_size_); -        if (comparator->HasSameNameAndSignature( -            virtual_method->GetInterfaceMethodIfProxy(image_pointer_size_))) { -          hash_table_[index] = removed_index_; -          return value; -        } -      } -      if (++index == hash_size_) { -        index = 0; -      } -    } -    return GetNotFoundIndex(); -  } - -  static uint32_t GetNotFoundIndex() { -    return invalid_index_; -  } - - private: -  static const uint32_t invalid_index_; -  static const uint32_t removed_index_; - -  Handle<mirror::Class> klass_; -  const size_t hash_size_; -  uint32_t* const hash_table_; -  const PointerSize image_pointer_size_; -}; - -const uint32_t LinkVirtualHashTable::invalid_index_ = std::numeric_limits<uint32_t>::max(); -const uint32_t LinkVirtualHashTable::removed_index_ = std::numeric_limits<uint32_t>::max() - 1; -  // Determine if the given iface has any subinterface in the given list that declares the method  // specified by 'target'.  // @@ -7216,6 +7155,14 @@ class ClassLinker::LinkMethodsHelper {        REQUIRES_SHARED(Locks::mutator_lock_);   private: +  // Assign vtable indexes to declared virtual methods for a non-interface class other +  // than `java.lang.Object`. Returns the number of vtable entries on success, 0 on failure. +  template <bool kEmbeddedSuperVTable> +  size_t AssignVtableIndexes(ObjPtr<mirror::Class> klass, +                             ObjPtr<mirror::Class> super_class, +                             size_t num_virtual_methods) +      REQUIRES_SHARED(Locks::mutator_lock_); +    bool LinkJavaLangObjectVirtualMethods(Thread* self, Handle<mirror::Class> klass)        REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; @@ -7312,6 +7259,123 @@ class ClassLinker::LinkMethodsHelper {                         << overriding_default_conflict_methods_.size();    } +  class MethodIndexEmptyFn { +   public: +    void MakeEmpty(uint32_t& item) const { +      item = dex::kDexNoIndex; +    } +    bool IsEmpty(const uint32_t& item) const { +      return item == dex::kDexNoIndex; +    } +  }; + +  class VTableAccessorEmbedded { +   public: +    explicit VTableAccessorEmbedded(ObjPtr<mirror::Class> klass) +        REQUIRES_SHARED(Locks::mutator_lock_) +        : klass_(klass) { +      DCHECK(klass->ShouldHaveEmbeddedVTable()); +    } + +    size_t GetVTableLength() const REQUIRES_SHARED(Locks::mutator_lock_) { +      return dchecked_integral_cast<size_t>(klass_->GetEmbeddedVTableLength()); +    } + +    ArtMethod* GetVTableEntry(uint32_t index) const REQUIRES_SHARED(Locks::mutator_lock_) { +      DCHECK_LT(index, GetVTableLength()); +      return klass_->GetEmbeddedVTableEntry(index, kPointerSize); +    } + +   private: +    ObjPtr<mirror::Class> klass_; +  }; + +  class VTableAccessorNotEmbedded { +   public: +    explicit VTableAccessorNotEmbedded(ObjPtr<mirror::Class> klass) +        REQUIRES_SHARED(Locks::mutator_lock_) +        : vtable_(klass->GetVTable()) { +      DCHECK(!klass->ShouldHaveEmbeddedVTable()); +      DCHECK(vtable_ != nullptr); +    } + +    size_t GetVTableLength() const REQUIRES_SHARED(Locks::mutator_lock_) { +      return dchecked_integral_cast<size_t>(vtable_->GetLength()); +    } + +    ArtMethod* GetVTableEntry(uint32_t index) const REQUIRES_SHARED(Locks::mutator_lock_) { +      DCHECK_LT(index, GetVTableLength()); +      return vtable_->GetElementPtrSize<ArtMethod*, kPointerSize>(index); +    } + +   private: +    ObjPtr<mirror::PointerArray> vtable_; +  }; + +  template <bool kEmbedded> +  using VTableAccessor = +      std::conditional_t<kEmbedded, VTableAccessorEmbedded, VTableAccessorNotEmbedded>; + +  template <bool kEmbedded> +  class VTableSignatureHash { +   public: +    explicit VTableSignatureHash(VTableAccessor<kEmbedded> accessor) +        REQUIRES_SHARED(Locks::mutator_lock_) +        : accessor_(accessor) {} + +    // NO_THREAD_SAFETY_ANALYSIS: This is called from unannotated `HashSet<>` functions. +    size_t operator()(ArtMethod* method) const NO_THREAD_SAFETY_ANALYSIS { +      return ComputeMethodHash(method); +    } + +    // NO_THREAD_SAFETY_ANALYSIS: This is called from unannotated `HashSet<>` functions. +    size_t operator()(uint32_t index) const NO_THREAD_SAFETY_ANALYSIS { +      return ComputeMethodHash(accessor_.GetVTableEntry(index)); +    } + +   private: +    VTableAccessor<kEmbedded> accessor_; +  }; + +  template <bool kEmbedded> +  class VTableSignatureEqual { +   public: +    explicit VTableSignatureEqual(VTableAccessor<kEmbedded> accessor) +        REQUIRES_SHARED(Locks::mutator_lock_) +        : accessor_(accessor) {} + +    // NO_THREAD_SAFETY_ANALYSIS: This is called from unannotated `HashSet<>` functions. +    bool operator()(uint32_t lhs_index, ArtMethod* rhs) const NO_THREAD_SAFETY_ANALYSIS { +      ArtMethod* lhs = accessor_.GetVTableEntry(lhs_index); +      const DexFile* lhs_dex_file = lhs->GetDexFile(); +      const DexFile* rhs_dex_file = rhs->GetDexFile(); +      const dex::MethodId& lhs_mid = lhs_dex_file->GetMethodId(lhs->GetDexMethodIndex()); +      const dex::MethodId& rhs_mid = rhs_dex_file->GetMethodId(rhs->GetDexMethodIndex()); +      if (lhs_dex_file == rhs_dex_file) { +        return lhs_mid.name_idx_ == rhs_mid.name_idx_ && +               lhs_mid.proto_idx_ == rhs_mid.proto_idx_; +      } else { +        return +            lhs_dex_file->GetMethodNameView(lhs_mid) == rhs_dex_file->GetMethodNameView(rhs_mid) && +            lhs_dex_file->GetMethodSignature(lhs_mid) == rhs_dex_file->GetMethodSignature(rhs_mid); +      } +    } + +    // NO_THREAD_SAFETY_ANALYSIS: This is called from unannotated `HashSet<>` functions. +    bool operator()(uint32_t lhs_index, uint32_t rhs_index) const NO_THREAD_SAFETY_ANALYSIS { +      return (*this)(lhs_index, accessor_.GetVTableEntry(rhs_index)); +    } + +   private: +    VTableAccessor<kEmbedded> accessor_; +  }; + +  template <bool kEmbedded> +  using VTableSignatureSet = ScopedArenaHashSet<uint32_t, +                                                MethodIndexEmptyFn, +                                                VTableSignatureHash<kEmbedded>, +                                                VTableSignatureEqual<kEmbedded>>; +    static constexpr size_t kMethodAlignment = ArtMethod::Alignment(kPointerSize);    static constexpr size_t kMethodSize = ArtMethod::Size(kPointerSize); @@ -7630,7 +7694,7 @@ ObjPtr<mirror::PointerArray> ClassLinker::LinkMethodsHelper<kPointerSize>::Updat    // 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, kPointerSize); +    ArtMethod* translated_method = vtable->GetElementPtrSize<ArtMethod*, kPointerSize>(i);      // Try and find what we need to change this method to.      auto translation_it = default_translations_.find(i);      if (translation_it != default_translations_.end()) { @@ -7691,7 +7755,7 @@ void ClassLinker::LinkMethodsHelper<kPointerSize>::UpdateIfTable(Handle<mirror::    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, kPointerSize); +      ArtMethod* m = method_array->GetElementPtrSize<ArtMethod*, kPointerSize>(j);        DCHECK(m != nullptr) << klass_->PrettyClass();        auto it = move_table_.find(m);        if (it != move_table_.end()) { @@ -7715,6 +7779,126 @@ void ClassLinker::LinkMethodsHelper<kPointerSize>::UpdateIMT(ArtMethod** out_imt  }  template <PointerSize kPointerSize> +template <bool kEmbeddedSuperVTable> +size_t ClassLinker::LinkMethodsHelper<kPointerSize>::AssignVtableIndexes( +    ObjPtr<mirror::Class> klass, ObjPtr<mirror::Class> super_class, size_t num_virtual_methods) { +  DCHECK(!klass->IsInterface()); +  DCHECK(klass->HasSuperClass()); +  DCHECK(klass->GetSuperClass() == super_class); +  DCHECK_EQ(kEmbeddedSuperVTable, super_class->ShouldHaveEmbeddedVTable()); + +  // There should be no thread suspension unless we want to throw an exception. +  std::optional<ScopedAssertNoThreadSuspension> sants(__FUNCTION__); + +  // Prepare a hash table with virtual methods from the superclass. +  // For the unlikely cases that there are multiple methods with the same signature +  // but different vtable indexes, keep an array with indexes of the previous +  // methods with the same signature (walked as singly-linked lists). +  VTableAccessor<kEmbeddedSuperVTable> super_vtable_accessor(super_class); +  const size_t super_vtable_length = super_vtable_accessor.GetVTableLength(); +  static constexpr double kMinLoadFactor = 0.3; +  static constexpr double kMaxLoadFactor = 0.5; +  static constexpr size_t kMaxStackBuferSize = 250; +  const size_t hash_table_size = super_vtable_length * 3; +  uint32_t* hash_table_ptr = (hash_table_size <= kMaxStackBuferSize) +      ? reinterpret_cast<uint32_t*>(alloca(hash_table_size * sizeof(*hash_table_ptr))) +      : allocator_.AllocArray<uint32_t>(hash_table_size); +  VTableSignatureSet<kEmbeddedSuperVTable> super_vtable_signatures( +      kMinLoadFactor, +      kMaxLoadFactor, +      VTableSignatureHash<kEmbeddedSuperVTable>(super_vtable_accessor), +      VTableSignatureEqual<kEmbeddedSuperVTable>(super_vtable_accessor), +      hash_table_ptr, +      hash_table_size, +      allocator_.Adapter()); +  ScopedArenaVector<uint32_t> same_signature_virtual_methods_lists_(allocator_.Adapter()); +  // Insert the first `mirror::Object::kVTableLength` indexes with pre-calculated hashes. +  DCHECK_GE(super_vtable_length, mirror::Object::kVTableLength); +  for (uint32_t i = 0; i != mirror::Object::kVTableLength; ++i) { +    size_t hash = class_linker_->object_virtual_method_hashes_[i]; +    bool inserted = super_vtable_signatures.InsertWithHash(i, hash).second; +    DCHECK(inserted);  // No duplicate signatures in `java.lang.Object`. +  } +  // Insert the remaining indexes, check for duplicate signatures. +  if (super_vtable_length > mirror::Object::kVTableLength) { +    for (size_t i = mirror::Object::kVTableLength; i < super_vtable_length; ++i) { +      // Use `super_vtable_accessor` for getting the method for hash calculation. +      // Letting `HashSet<>::insert()` use the internal accessor copy in the hash +      // function prevents the compiler from optimizing this properly because the +      // compiler cannot prove that the accessor copy is immutable. +      size_t hash = ComputeMethodHash(super_vtable_accessor.GetVTableEntry(i)); +      auto [it, inserted] = super_vtable_signatures.InsertWithHash(i, hash); +      if (UNLIKELY(!inserted)) { +        if (same_signature_virtual_methods_lists_.empty()) { +          same_signature_virtual_methods_lists_.resize(super_vtable_length, dex::kDexNoIndex); +        } +        DCHECK_LT(*it, i); +        same_signature_virtual_methods_lists_[i] = *it; +        *it = i; +      } +    } +  } + +  // For each declared virtual method, look for a superclass virtual method +  // to override and assign a new vtable index if no method was overridden. +  const bool is_proxy_class = klass->IsProxyClass(); +  size_t vtable_length = super_vtable_length; +  for (size_t i = 0; i < num_virtual_methods; ++i) { +    ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(i, kPointerSize); +    ArtMethod* signature_method = UNLIKELY(is_proxy_class) +        ? virtual_method->GetInterfaceMethodForProxyUnchecked(kPointerSize) +        : virtual_method; +    size_t hash = ComputeMethodHash(signature_method); +    auto it = super_vtable_signatures.FindWithHash(signature_method, hash); +    if (it != super_vtable_signatures.end()) { +      size_t super_index = *it; +      DCHECK_LT(super_index, super_vtable_length); +      ArtMethod* super_method = super_vtable_accessor.GetVTableEntry(super_index); +      // Historical note: Before Android 4.1, an inaccessible package-private +      // superclass method would have been incorrectly overridden. +      bool overrides = klass->CanAccessMember(super_method->GetDeclaringClass(), +                                              super_method->GetAccessFlags()); +      if (UNLIKELY(!same_signature_virtual_methods_lists_.empty())) { +        // We override only the first accessible virtual method from superclass. +        // TODO: Override all methods that need to be overridden according to JLS. b/211854716 +        size_t current_index = super_index; +        while (same_signature_virtual_methods_lists_[current_index] != dex::kDexNoIndex) { +          DCHECK_LT(same_signature_virtual_methods_lists_[current_index], current_index); +          current_index = same_signature_virtual_methods_lists_[current_index]; +          ArtMethod* current_method = super_vtable_accessor.GetVTableEntry(current_index); +          if (klass->CanAccessMember(current_method->GetDeclaringClass(), +                                     current_method->GetAccessFlags())) { +            overrides = true; +            super_index = current_index; +            super_method = current_method; +          } +        } +      } +      if (overrides) { +        if (super_method->IsFinal()) { +          sants.reset(); +          ThrowLinkageError(klass, "Method %s overrides final method in class %s", +                            virtual_method->PrettyMethod().c_str(), +                            super_method->GetDeclaringClassDescriptor()); +          return 0u; +        } +        virtual_method->SetMethodIndex(super_index); +        continue; +      } +    } +    // The method does not override any method from superclass, so it needs a new vtable index. +    virtual_method->SetMethodIndex(vtable_length); +    ++vtable_length; +  } +  if (UNLIKELY(!IsUint<16>(vtable_length))) { +    sants.reset(); +    ThrowClassFormatError(klass, "Too many methods defined on class: %zd", vtable_length); +    return 0u; +  } +  return vtable_length; +} + +template <PointerSize kPointerSize>  FLATTEN  bool ClassLinker::LinkMethodsHelper<kPointerSize>::LinkVirtualMethods(      Thread* self, @@ -7758,106 +7942,70 @@ bool ClassLinker::LinkMethodsHelper<kPointerSize>::LinkVirtualMethods(      return true;    } 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);      Handle<mirror::Class> super_class(hs.NewHandle(klass->GetSuperClass())); -    MutableHandle<mirror::PointerArray> vtable; -    if (super_class->ShouldHaveEmbeddedVTable()) { -      vtable = hs.NewHandle(class_linker_->AllocPointerArray(self, max_count)); -      if (UNLIKELY(vtable == nullptr)) { -        self->AssertPendingOOMException(); -        return false; -      } -      for (size_t i = 0; i < super_vtable_length; i++) { -        vtable->SetElementPtrSize( -            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 -      // the class cannot override any of the super-class's methods. This is required for -      // correctness since without it we might not update overridden default method vtable entries -      // correctly. -      if (num_virtual_methods == 0 && super_class->GetIfTableCount() == klass->GetIfTableCount()) { -        klass->SetVTable(vtable.Get()); -        return true; -      } -    } else { -      DCHECK(super_class->IsAbstract() && !super_class->IsArrayClass()); -      Handle<mirror::PointerArray> super_vtable = hs.NewHandle(super_class->GetVTable()); -      CHECK(super_vtable != nullptr) << super_class->PrettyClass(); -      // We might need to change vtable if we have new virtual methods or new interfaces (since that -      // might give us new default methods). See comment above. -      if (num_virtual_methods == 0 && super_class->GetIfTableCount() == klass->GetIfTableCount()) { -        klass->SetVTable(super_vtable.Get()); -        return true; -      } -      vtable = hs.NewHandle(ObjPtr<mirror::PointerArray>::DownCast( -          mirror::Array::CopyOf(super_vtable, self, max_count))); -      if (UNLIKELY(vtable == nullptr)) { -        self->AssertPendingOOMException(); -        return false; + +    // If there are no new virtual methods and no new interfaces, we can simply reuse +    // the vtable from superclass. We may need to make a copy if it's embedded. +    if (num_virtual_methods == 0 && super_class->GetIfTableCount() == klass->GetIfTableCount()) { +      if (super_class->ShouldHaveEmbeddedVTable()) { +        ObjPtr<mirror::PointerArray> vtable = +            class_linker_->AllocPointerArray(self, super_vtable_length); +        if (UNLIKELY(vtable == nullptr)) { +          self->AssertPendingOOMException(); +          return false; +        } +        for (size_t i = 0; i < super_vtable_length; i++) { +          vtable->SetElementPtrSize( +              i, super_class->GetEmbeddedVTableEntry(i, kPointerSize), kPointerSize); +        } +        klass->SetVTable(vtable); +      } else { +        DCHECK(super_class->IsAbstract() && !super_class->IsArrayClass()); +        ObjPtr<mirror::PointerArray> super_vtable = super_class->GetVTable(); +        CHECK(super_vtable != nullptr) << super_class->PrettyClass(); +        klass->SetVTable(super_vtable);        } +      return true;      } -    // How the algorithm works: -    // 1. Populate hash table by adding num_virtual_methods from klass. The values in the hash -    // table are: invalid_index for unused slots, index super_vtable_length + i for a virtual -    // method which has not been matched to a vtable method, and j if the virtual method at the -    // index overrode the super virtual method at index j. -    // 2. Loop through super virtual methods, if they overwrite, update hash table to j -    // (j < super_vtable_length) to avoid redundant checks. (TODO maybe use this info for reducing -    // the need for the initial vtable which we later shrink back down). -    // 3. Add non overridden methods to the end of the vtable. -    static constexpr size_t kMaxStackHash = 250; -    // + 1 so that even if we only have new default methods we will still be able to use this hash -    // table (i.e. it will never have 0 size). -    const size_t hash_table_size = num_virtual_methods * 3 + 1; -    uint32_t* hash_table_ptr; -    std::unique_ptr<uint32_t[]> hash_heap_storage; -    if (hash_table_size <= kMaxStackHash) { -      hash_table_ptr = reinterpret_cast<uint32_t*>( -          alloca(hash_table_size * sizeof(*hash_table_ptr))); -    } else { -      hash_heap_storage.reset(new uint32_t[hash_table_size]); -      hash_table_ptr = hash_heap_storage.get(); + +    size_t final_vtable_size = super_class->ShouldHaveEmbeddedVTable() +        ? AssignVtableIndexes</*kEmbeddedSuperVTable=*/ true>( +              klass.Get(), super_class.Get(), num_virtual_methods) +        : AssignVtableIndexes</*kEmbeddedSuperVTable=*/ false>( +              klass.Get(), super_class.Get(), num_virtual_methods); +    if (final_vtable_size == 0u) { +      self->AssertPendingException(); +      return false;      } -    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, 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, kPointerSize); -      if (!klass->CanAccessMember(super_method->GetDeclaringClass(), -                                  super_method->GetAccessFlags())) { -        // Continue on to the next method since this one is package private -        // and cannot be overridden. Before Android 4.1, the package-private -        // method super_method might have been incorrectly overridden. +    DCHECK(IsUint<16>(final_vtable_size)); + +    // Allocate the new vtable. +    Handle<mirror::PointerArray> vtable = +        hs.NewHandle(class_linker_->AllocPointerArray(self, final_vtable_size)); +    if (UNLIKELY(vtable == nullptr)) { +      self->AssertPendingOOMException(); +      return false; +    } + +    // Store new virtual methods in the new vtable. +    for (ArtMethod& virtual_method : klass->GetVirtualMethodsSliceUnchecked(kPointerSize)) { +      int32_t vtable_index = virtual_method.GetMethodIndexDuringLinking(); +      vtable->SetElementPtrSize(vtable_index, &virtual_method, kPointerSize); +    } + +    // For non-overridden vtable slots, copy a method from `super_class`. +    for (size_t j = 0; j != super_vtable_length; ++j) { +      if (vtable->GetElementPtrSize<ArtMethod*, kPointerSize>(j) != nullptr) { +        // Filled with new virtual method.          continue;        } -      MethodNameAndSignatureComparator super_method_name_comparator( -          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) -          ? class_linker_->object_virtual_method_hashes_[j] -          : 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, 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, kPointerSize); -        virtual_method->SetMethodIndex(j); -      } else if (super_method->IsOverridableByDefaultMethod()) { +      ArtMethod* super_method = super_class->GetVTableEntry(j, kPointerSize); +      vtable->SetElementPtrSize(j, super_method, kPointerSize); +      // TODO: Postpone the search for overiding default methods until `LinkInterfaceMethods()`. +      if (klass->CanAccessMember(super_method->GetDeclaringClass(), +                                 super_method->GetAccessFlags()) && +          super_method->IsOverridableByDefaultMethod()) {          // We didn't directly override this method but we might through default methods...          // Check for default method update.          ArtMethod* default_method = nullptr; @@ -7910,33 +8058,7 @@ bool ClassLinker::LinkMethodsHelper<kPointerSize>::LinkVirtualMethods(          }        }      } -    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, kPointerSize); -      size_t method_idx = local_method->GetMethodIndexDuringLinking(); -      if (method_idx < super_vtable_length && -          local_method == vtable->GetElementPtrSize<ArtMethod*>(method_idx, kPointerSize)) { -        continue; -      } -      vtable->SetElementPtrSize(actual_count, local_method, kPointerSize); -      local_method->SetMethodIndex(actual_count); -      ++actual_count; -    } -    if (!IsUint<16>(actual_count)) { -      ThrowClassFormatError(klass.Get(), "Too many methods defined on class: %zd", actual_count); -      return false; -    } -    // Shrink vtable if possible -    CHECK_LE(actual_count, max_count); -    if (actual_count < max_count) { -      vtable.Assign(ObjPtr<mirror::PointerArray>::DownCast( -          mirror::Array::CopyOf(vtable, self, actual_count))); -      if (UNLIKELY(vtable == nullptr)) { -        self->AssertPendingOOMException(); -        return false; -      } -    } +      klass->SetVTable(vtable.Get());    } else {      return LinkJavaLangObjectVirtualMethods(self, klass); @@ -8076,7 +8198,7 @@ bool ClassLinker::LinkMethodsHelper<kPointerSize>::LinkInterfaceMethods(          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, kPointerSize); +              input_vtable_array->GetElementPtrSize<ArtMethod*, kPointerSize>(k);            ArtMethod* vtable_method_for_name_comparison =                vtable_method->GetInterfaceMethodIfProxy(kPointerSize);            DCHECK(!vtable_method->IsStatic()) << vtable_method->PrettyMethod(); @@ -8133,7 +8255,7 @@ bool ClassLinker::LinkMethodsHelper<kPointerSize>::LinkInterfaceMethods(            // 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, kPointerSize); +              method_array->GetElementPtrSize<ArtMethod*, kPointerSize>(j);            DCHECK(supers_method != nullptr);            DCHECK(interface_name_comparator.HasSameNameAndSignature(supers_method));            if (LIKELY(!supers_method->IsOverridableByDefaultMethod())) { |