Reland "Adjust how we assign vtable indexes during class loading."

This reverts commit 07c2fec6b025d5cc104ab4f210c3941528f56fd6.

Bug: 211854716
Bug: 233545487
Bug: 181943478

Reason for revert: addressed comments

Change-Id: Id45c8e826b81f00190920a2b3270937614700f5f
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c2ce3e2..fd721cd 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -37,6 +37,7 @@
 #include "art_method-inl.h"
 #include "barrier.h"
 #include "base/arena_allocator.h"
+#include "base/arena_bit_vector.h"
 #include "base/casts.h"
 #include "base/file_utils.h"
 #include "base/hash_map.h"
@@ -7945,55 +7946,17 @@
   static constexpr double kMinLoadFactor = 0.3;
   static constexpr double kMaxLoadFactor = 0.5;
   static constexpr size_t kMaxStackBuferSize = 256;
-  const size_t super_vtable_buffer_size = super_vtable_length * 3;
   const size_t declared_virtuals_buffer_size = num_virtual_methods * 3;
-  const size_t total_buffer_size = super_vtable_buffer_size + declared_virtuals_buffer_size;
-  uint32_t* super_vtable_buffer_ptr = (total_buffer_size <= kMaxStackBuferSize)
-      ? reinterpret_cast<uint32_t*>(alloca(total_buffer_size * sizeof(uint32_t)))
-      : allocator_.AllocArray<uint32_t>(total_buffer_size);
-  uint32_t* declared_virtuals_buffer_ptr = super_vtable_buffer_ptr + super_vtable_buffer_size;
-  VTableSignatureSet super_vtable_signatures(
-      kMinLoadFactor,
-      kMaxLoadFactor,
-      VTableSignatureHash(super_vtable_accessor),
-      VTableSignatureEqual(super_vtable_accessor),
-      super_vtable_buffer_ptr,
-      super_vtable_buffer_size,
-      allocator_.Adapter());
-  ArrayRef<uint32_t> same_signature_vtable_lists;
-  // 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];
-    // There are no duplicate signatures in `java.lang.Object`, so use `HashSet<>::PutWithHash()`.
-    // This avoids equality comparison for the three `java.lang.Object.wait()` overloads.
-    super_vtable_signatures.PutWithHash(i, hash);
-  }
-  // 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_vtable_lists.empty()) {
-          same_signature_vtable_lists = ArrayRef<uint32_t>(
-              allocator_.AllocArray<uint32_t>(super_vtable_length), super_vtable_length);
-          std::fill_n(same_signature_vtable_lists.data(), super_vtable_length, dex::kDexNoIndex);
-          same_signature_vtable_lists_ = same_signature_vtable_lists;
-        }
-        DCHECK_LT(*it, i);
-        same_signature_vtable_lists[i] = *it;
-        *it = i;
-      }
-    }
-  }
+  const size_t super_vtable_buffer_size = super_vtable_length * 3;
+  const size_t bit_vector_size = BitVector::BitsToWords(num_virtual_methods);
+  const size_t total_size =
+      declared_virtuals_buffer_size + super_vtable_buffer_size + bit_vector_size;
 
-  // For each declared virtual method, look for a superclass virtual method
-  // to override and assign a new vtable index if no method was overridden.
+  uint32_t* declared_virtuals_buffer_ptr = (total_size <= kMaxStackBuferSize)
+      ? reinterpret_cast<uint32_t*>(alloca(total_size * sizeof(uint32_t)))
+      : allocator_.AllocArray<uint32_t>(total_size);
+  uint32_t* bit_vector_buffer_ptr = declared_virtuals_buffer_ptr + declared_virtuals_buffer_size;
+
   DeclaredVirtualSignatureSet declared_virtual_signatures(
       kMinLoadFactor,
       kMaxLoadFactor,
@@ -8002,8 +7965,24 @@
       declared_virtuals_buffer_ptr,
       declared_virtuals_buffer_size,
       allocator_.Adapter());
+
+  ArrayRef<uint32_t> same_signature_vtable_lists;
   const bool is_proxy_class = klass->IsProxyClass();
   size_t vtable_length = super_vtable_length;
+
+  // Record which declared methods are overriding a super method.
+  BitVector initialized_methods(/* expandable= */ false,
+                                Allocator::GetNoopAllocator(),
+                                bit_vector_size,
+                                bit_vector_buffer_ptr);
+
+  // Note: our sets hash on the method name, and therefore we pay a high
+  // performance price when a class has many overloads.
+  //
+  // We populate a set of declared signatures instead of signatures from the
+  // super vtable (which is only lazy populated in case of interface overriding,
+  // see below). This makes sure that we pay the performance price only on that
+  // class, and not on its subclasses (except in the case of interface overriding, see below).
   for (size_t i = 0; i != num_virtual_methods; ++i) {
     ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(i, kPointerSize);
     DCHECK(!virtual_method->IsStatic()) << virtual_method->PrettyMethod();
@@ -8012,59 +7991,79 @@
         : virtual_method;
     size_t hash = ComputeMethodHash(signature_method);
     declared_virtual_signatures.PutWithHash(i, hash);
-    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 (overrides && 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;
-      }
-      if (UNLIKELY(!same_signature_vtable_lists.empty())) {
-        // We may override more than one method according to JLS, see b/211854716 .
-        // We record the highest overridden vtable index here so that we can walk
-        // the list to find other overridden methods when constructing the vtable.
-        // However, we walk all the methods to check for final method overriding.
-        size_t current_index = super_index;
-        while (same_signature_vtable_lists[current_index] != dex::kDexNoIndex) {
-          DCHECK_LT(same_signature_vtable_lists[current_index], current_index);
-          current_index = same_signature_vtable_lists[current_index];
-          ArtMethod* current_method = super_vtable_accessor.GetVTableEntry(current_index);
-          if (klass->CanAccessMember(current_method->GetDeclaringClass(),
-                                     current_method->GetAccessFlags())) {
-            if (current_method->IsFinal()) {
-              sants.reset();
-              ThrowLinkageError(klass, "Method %s overrides final method in class %s",
-                                virtual_method->PrettyMethod().c_str(),
-                                current_method->GetDeclaringClassDescriptor());
-              return 0u;
-            }
-            if (!overrides) {
-              overrides = true;
-              super_index = current_index;
-              super_method = current_method;
-            }
-          }
-        }
-      }
-      if (overrides) {
-        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;
   }
 
+  // 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 = super_vtable_accessor.GetVTableEntry(j);
+    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.
+      continue;
+    }
+    size_t hash = (j < mirror::Object::kVTableLength)
+        ? class_linker_->object_virtual_method_hashes_[j]
+        : ComputeMethodHash(super_method);
+    auto it = declared_virtual_signatures.FindWithHash(super_method, hash);
+    if (it == declared_virtual_signatures.end()) {
+      continue;
+    }
+    ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(*it, kPointerSize);
+    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;
+    }
+    if (initialized_methods.IsBitSet(*it)) {
+      // The method is overriding more than one method.
+      // We record that information in a linked list to later set the method in the vtable
+      // locations that are not the method index.
+      if (same_signature_vtable_lists.empty()) {
+        same_signature_vtable_lists = ArrayRef<uint32_t>(
+            allocator_.AllocArray<uint32_t>(super_vtable_length), super_vtable_length);
+        std::fill_n(same_signature_vtable_lists.data(), super_vtable_length, dex::kDexNoIndex);
+        same_signature_vtable_lists_ = same_signature_vtable_lists;
+      }
+      same_signature_vtable_lists[j] = virtual_method->GetMethodIndexDuringLinking();
+    } else {
+      initialized_methods.SetBit(*it);
+    }
+
+    // We arbitrarily set to the largest index. This is also expected when
+    // iterating over the `same_signature_vtable_lists_`.
+    virtual_method->SetMethodIndex(j);
+  }
+
+  // Add the non-overridden methods at the end.
+  for (size_t i = 0; i < num_virtual_methods; ++i) {
+    if (!initialized_methods.IsBitSet(i)) {
+      ArtMethod* local_method = klass->GetVirtualMethodDuringLinking(i, kPointerSize);
+      local_method->SetMethodIndex(vtable_length);
+      vtable_length++;
+    }
+  }
+
+  // A lazily constructed super vtable set, which we only populate in the less
+  // common sittuation of a superclass implementing a method declared in an
+  // interface this class inherits.
+  // We still try to allocate the set on the stack as using the arena will have
+  // a larger cost.
+  uint32_t* super_vtable_buffer_ptr = bit_vector_buffer_ptr + bit_vector_size;
+  VTableSignatureSet super_vtable_signatures(
+      kMinLoadFactor,
+      kMaxLoadFactor,
+      VTableSignatureHash(super_vtable_accessor),
+      VTableSignatureEqual(super_vtable_accessor),
+      super_vtable_buffer_ptr,
+      super_vtable_buffer_size,
+      allocator_.Adapter());
+
   // Assign vtable indexes for interface methods in new interfaces and store them
   // in implementation method arrays. These shall be replaced by actual method
   // pointers later. We do not need to do this for superclass interfaces as we can
@@ -8083,38 +8082,39 @@
       ArtMethod* interface_method = iface->GetVirtualMethod(j, kPointerSize);
       size_t hash = ComputeMethodHash(interface_method);
       ArtMethod* vtable_method = nullptr;
-      bool found = false;
       auto it1 = declared_virtual_signatures.FindWithHash(interface_method, hash);
       if (it1 != declared_virtual_signatures.end()) {
-        vtable_method = klass->GetVirtualMethodDuringLinking(*it1, kPointerSize);
-        found = true;
+        ArtMethod* found_method = klass->GetVirtualMethodDuringLinking(*it1, kPointerSize);
+        // For interface overriding, we only look at public methods.
+        if (found_method->IsPublic()) {
+          vtable_method = found_method;
+        }
       } else {
+        // This situation should be rare (a superclass implements a method
+        // declared in an interface this class is inheriting). Only in this case
+        // do we lazily populate the super_vtable_signatures.
+        if (super_vtable_signatures.empty()) {
+          for (size_t k = 0; k < super_vtable_length; ++k) {
+            ArtMethod* super_method = super_vtable_accessor.GetVTableEntry(k);
+            if (!super_method->IsPublic()) {
+              // For interface overriding, we only look at public methods.
+              continue;
+            }
+            size_t super_hash = (k < mirror::Object::kVTableLength)
+                ? class_linker_->object_virtual_method_hashes_[k]
+                : ComputeMethodHash(super_method);
+            auto [it, inserted] = super_vtable_signatures.InsertWithHash(k, super_hash);
+            DCHECK(inserted || super_vtable_accessor.GetVTableEntry(*it) == super_method);
+          }
+        }
         auto it2 = super_vtable_signatures.FindWithHash(interface_method, hash);
         if (it2 != super_vtable_signatures.end()) {
-          // If there are multiple vtable methods with the same signature, the one with
-          // the highest vtable index is not nessarily the one in most-derived class.
-          // Find the most-derived method. See b/211854716 .
           vtable_method = super_vtable_accessor.GetVTableEntry(*it2);
-          if (UNLIKELY(!same_signature_vtable_lists.empty())) {
-            size_t current_index = *it2;
-            while (same_signature_vtable_lists[current_index] != dex::kDexNoIndex) {
-              DCHECK_LT(same_signature_vtable_lists[current_index], current_index);
-              current_index = same_signature_vtable_lists[current_index];
-              ArtMethod* current_method = super_vtable_accessor.GetVTableEntry(current_index);
-              ObjPtr<mirror::Class> current_class = current_method->GetDeclaringClass();
-              if (current_class->IsSubClass(vtable_method->GetDeclaringClass())) {
-                vtable_method = current_method;
-              }
-            }
-          }
-          found = true;
         }
       }
-      found = found && vtable_method->IsPublic();
 
       uint32_t vtable_index = vtable_length;
-      if (found) {
-        DCHECK(vtable_method != nullptr);
+      if (vtable_method != nullptr) {
         vtable_index = vtable_method->GetMethodIndexDuringLinking();
         if (!vtable_method->IsOverridableByDefaultMethod()) {
           method_array->SetElementPtrSize(j, vtable_index, kPointerSize);
@@ -8124,7 +8124,7 @@
 
       auto [it, inserted] = copied_method_records_.InsertWithHash(
           CopiedMethodRecord(interface_method, vtable_index), hash);
-      if (found) {
+      if (vtable_method != nullptr) {
         DCHECK_EQ(vtable_index, it->GetMethodIndex());
       } else if (inserted) {
         DCHECK_EQ(vtable_index, it->GetMethodIndex());
@@ -8464,17 +8464,16 @@
       uint32_t vtable_index = virtual_method.GetMethodIndexDuringLinking();
       vtable->SetElementPtrSize(vtable_index, &virtual_method, kPointerSize);
       if (UNLIKELY(vtable_index < same_signature_vtable_lists.size())) {
-        // We may override more than one method according to JLS, see b/211854716 .
-        // If we do, arbitrarily update the method index to the lowest overridden vtable index.
+        // We may override more than one method according to JLS, see b/211854716.
         while (same_signature_vtable_lists[vtable_index] != dex::kDexNoIndex) {
           DCHECK_LT(same_signature_vtable_lists[vtable_index], vtable_index);
           vtable_index = same_signature_vtable_lists[vtable_index];
-          ArtMethod* current_method = super_class->GetVTableEntry(vtable_index, kPointerSize);
-          if (klass->CanAccessMember(current_method->GetDeclaringClass(),
-                                     current_method->GetAccessFlags())) {
+          vtable->SetElementPtrSize(vtable_index, &virtual_method, kPointerSize);
+          if (kIsDebugBuild) {
+            ArtMethod* current_method = super_class->GetVTableEntry(vtable_index, kPointerSize);
+            DCHECK(klass->CanAccessMember(current_method->GetDeclaringClass(),
+                                          current_method->GetAccessFlags()));
             DCHECK(!current_method->IsFinal());
-            vtable->SetElementPtrSize(vtable_index, &virtual_method, kPointerSize);
-            virtual_method.SetMethodIndex(vtable_index);
           }
         }
       }
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index b0e77b4..b7a8a8c 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -98,7 +98,7 @@
   if (kTransactionActive) {
     Runtime::Current()->RecordWriteArray(this, i, GetWithoutChecks(i));
   }
-  DCHECK(CheckIsValidIndex<kVerifyFlags>(i));
+  DCHECK(CheckIsValidIndex<kVerifyFlags>(i)) << i << " " << GetLength<kVerifyFlags>();
   GetData()[i] = value;
 }
 // Backward copy where elements are of aligned appropriately for T. Count is in T sized units.
diff --git a/test/838-override/expected-stderr.txt b/test/838-override/expected-stderr.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/838-override/expected-stderr.txt
diff --git a/test/838-override/expected-stdout.txt b/test/838-override/expected-stdout.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/838-override/expected-stdout.txt
diff --git a/test/838-override/info.txt b/test/838-override/info.txt
new file mode 100644
index 0000000..a33ddb2
--- /dev/null
+++ b/test/838-override/info.txt
@@ -0,0 +1 @@
+Tests for method overriding in the presence of package private methods.
diff --git a/test/838-override/src/Main.java b/test/838-override/src/Main.java
new file mode 100644
index 0000000..1e6aa49
--- /dev/null
+++ b/test/838-override/src/Main.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+
+  public static void assertEquals(Object expected, Object actual) {
+    if (expected != actual) {
+      throw new Error("Expected " + expected + ", got " + actual);
+    }
+  }
+
+  public static void main(String[] args) {
+    // Tescase 1: a class with:
+    // - a package-private pkg1 'foo'
+    // - a public pkg2 'foo'.
+    {
+      pkg2.PublicFoo obj = new pkg2.PublicFoo();
+      assertEquals(pkg1.Pkg1Foo.class, pkg1.Pkg1Foo.callFoo(obj));
+      assertEquals(pkg2.PublicFoo.class, pkg2.Pkg2Foo.callFoo(obj));
+      assertEquals(pkg2.PublicFoo.class, pkg3.Pkg3Foo.callFoo(obj));
+      assertEquals(pkg2.PublicFoo.class, obj.foo());
+    }
+    // Tescase 2: a class with:
+    // - a package-private pkg1 'foo'
+    // - a public pkg2 'foo'
+    // - a public pkg1 'foo.
+    {
+      pkg1.PublicFoo obj = new pkg1.PublicFoo();
+      assertEquals(pkg1.PublicFoo.class, pkg1.Pkg1Foo.callFoo(obj));
+      assertEquals(pkg1.PublicFoo.class, pkg2.Pkg2Foo.callFoo(obj));
+      assertEquals(pkg1.PublicFoo.class, pkg3.Pkg3Foo.callFoo(obj));
+      assertEquals(pkg1.PublicFoo.class, obj.foo());
+    }
+
+    // Tescase 3: a class with:
+    // - a package-private pkg1 'foo'
+    // - a package-private pkg2 'foo'
+    // - a public pkg3 'foo.
+    {
+      pkg3.PublicFoo obj = new pkg3.PublicFoo();
+      assertEquals(pkg1.Pkg1Foo.class, pkg1.Pkg1Foo.callFoo(obj));
+      assertEquals(pkg2.Pkg2Foo.class, pkg2.Pkg2Foo.callFoo(obj));
+      assertEquals(pkg3.PublicFoo.class, pkg3.Pkg3Foo.callFoo(obj));
+      assertEquals(pkg3.PublicFoo.class, obj.foo());
+    }
+
+    // Tescase 4: a class with:
+    // - a package-private pkg1 'foo'
+    // - a package-private pkg2 'foo'
+    // - a public pkg3 'foo.
+    // - a public pkg2 'foo'
+    {
+      pkg2.PublicFooInheritsPkg3 obj = new pkg2.PublicFooInheritsPkg3();
+      assertEquals(pkg1.Pkg1Foo.class, pkg1.Pkg1Foo.callFoo(obj));
+      assertEquals(pkg2.PublicFooInheritsPkg3.class, pkg2.Pkg2Foo.callFoo(obj));
+      assertEquals(pkg2.PublicFooInheritsPkg3.class, pkg3.Pkg3Foo.callFoo(obj));
+      assertEquals(pkg2.PublicFooInheritsPkg3.class, obj.foo());
+    }
+
+    // Tescase 5: a class with:
+    // - a package-private pkg1 'foo'
+    // - a package-private pkg2 'foo'
+    // - a public pkg3 'foo.
+    // - a public pkg2 'foo'
+    // - a public pkg1 'foo'
+    {
+      pkg1.PublicFooInheritsPkg2 obj = new pkg1.PublicFooInheritsPkg2();
+      assertEquals(pkg1.PublicFooInheritsPkg2.class, pkg1.Pkg1Foo.callFoo(obj));
+      assertEquals(pkg1.PublicFooInheritsPkg2.class, pkg2.Pkg2Foo.callFoo(obj));
+      assertEquals(pkg1.PublicFooInheritsPkg2.class, pkg3.Pkg3Foo.callFoo(obj));
+      assertEquals(pkg1.PublicFooInheritsPkg2.class, obj.foo());
+    }
+
+    // Tescase 6: a class with:
+    // - a package-private pkg1 'foo'
+    // - a package-private pkg2 'foo'
+    // - a public pkg1 'foo.
+    {
+      pkg1.LowerIndexImplementsFoo obj = new pkg1.LowerIndexImplementsFoo();
+      assertEquals(pkg1.LowerIndexPublicFoo.class, pkg1.Pkg1Foo.callFoo(obj));
+      assertEquals(pkg2.Pkg2Foo.class, pkg2.Pkg2Foo.callFoo(obj));
+      assertEquals(pkg2.Pkg2Foo.class, pkg3.Pkg3Foo.callFoo(obj));
+      assertEquals(pkg1.LowerIndexPublicFoo.class, obj.foo());
+    }
+  }
+}
diff --git a/test/838-override/src/pkg1/InterfaceFoo.java b/test/838-override/src/pkg1/InterfaceFoo.java
new file mode 100644
index 0000000..cd9e44b
--- /dev/null
+++ b/test/838-override/src/pkg1/InterfaceFoo.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg1;
+
+public interface InterfaceFoo {
+  public Class<?> foo();
+}
diff --git a/test/838-override/src/pkg1/LowerIndexImplementsFoo.java b/test/838-override/src/pkg1/LowerIndexImplementsFoo.java
new file mode 100644
index 0000000..290f07b
--- /dev/null
+++ b/test/838-override/src/pkg1/LowerIndexImplementsFoo.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg1;
+
+public class LowerIndexImplementsFoo extends LowerIndexPublicFoo implements InterfaceFoo {
+}
diff --git a/test/838-override/src/pkg1/LowerIndexPublicFoo.java b/test/838-override/src/pkg1/LowerIndexPublicFoo.java
new file mode 100644
index 0000000..87c0c72
--- /dev/null
+++ b/test/838-override/src/pkg1/LowerIndexPublicFoo.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg1;
+
+public class LowerIndexPublicFoo extends pkg2.Pkg2Foo {
+  public Class<?> foo() {
+    return LowerIndexPublicFoo.class;
+  }
+}
diff --git a/test/838-override/src/pkg1/Pkg1Foo.java b/test/838-override/src/pkg1/Pkg1Foo.java
new file mode 100644
index 0000000..0ffbc27
--- /dev/null
+++ b/test/838-override/src/pkg1/Pkg1Foo.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg1;
+
+public class Pkg1Foo {
+
+  Class<?> foo() {
+    return Pkg1Foo.class;
+  }
+
+  public static Class<?> callFoo(Pkg1Foo obj) {
+    return obj.foo();
+  }
+}
diff --git a/test/838-override/src/pkg1/PublicFoo.java b/test/838-override/src/pkg1/PublicFoo.java
new file mode 100644
index 0000000..c43b282
--- /dev/null
+++ b/test/838-override/src/pkg1/PublicFoo.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg1;
+
+public class PublicFoo extends pkg2.PublicFoo {
+  public Class<?> foo() {
+    return PublicFoo.class;
+  }
+}
diff --git a/test/838-override/src/pkg1/PublicFooInheritsPkg2.java b/test/838-override/src/pkg1/PublicFooInheritsPkg2.java
new file mode 100644
index 0000000..a255f36
--- /dev/null
+++ b/test/838-override/src/pkg1/PublicFooInheritsPkg2.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg1;
+
+public class PublicFooInheritsPkg2 extends pkg2.PublicFooInheritsPkg3 {
+  public Class<?> foo() {
+    return PublicFooInheritsPkg2.class;
+  }
+}
diff --git a/test/838-override/src/pkg2/Pkg2Foo.java b/test/838-override/src/pkg2/Pkg2Foo.java
new file mode 100644
index 0000000..c521914
--- /dev/null
+++ b/test/838-override/src/pkg2/Pkg2Foo.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg2;
+
+public class Pkg2Foo extends pkg1.Pkg1Foo{
+  Class<?> foo() {
+    return Pkg2Foo.class;
+  }
+
+  public static Class<?> callFoo(Pkg2Foo obj) {
+    return obj.foo();
+  }
+}
diff --git a/test/838-override/src/pkg2/PublicFoo.java b/test/838-override/src/pkg2/PublicFoo.java
new file mode 100644
index 0000000..5434234
--- /dev/null
+++ b/test/838-override/src/pkg2/PublicFoo.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg2;
+
+public class PublicFoo extends Pkg2Foo {
+  public Class<?> foo() {
+    return PublicFoo.class;
+  }
+}
diff --git a/test/838-override/src/pkg2/PublicFooInheritsPkg3.java b/test/838-override/src/pkg2/PublicFooInheritsPkg3.java
new file mode 100644
index 0000000..1a983a1
--- /dev/null
+++ b/test/838-override/src/pkg2/PublicFooInheritsPkg3.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg2;
+
+public class PublicFooInheritsPkg3 extends pkg3.PublicFoo {
+  public Class<?> foo() {
+    return PublicFooInheritsPkg3.class;
+  }
+}
diff --git a/test/838-override/src/pkg3/Pkg3Foo.java b/test/838-override/src/pkg3/Pkg3Foo.java
new file mode 100644
index 0000000..72a16aa
--- /dev/null
+++ b/test/838-override/src/pkg3/Pkg3Foo.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg3;
+
+public class Pkg3Foo extends pkg2.Pkg2Foo {
+  Class<?> foo() {
+    return Pkg3Foo.class;
+  }
+
+  public static Class<?> callFoo(Pkg3Foo obj) {
+    return obj.foo();
+  }
+}
diff --git a/test/838-override/src/pkg3/PublicFoo.java b/test/838-override/src/pkg3/PublicFoo.java
new file mode 100644
index 0000000..9d37137
--- /dev/null
+++ b/test/838-override/src/pkg3/PublicFoo.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package pkg3;
+
+public class PublicFoo extends Pkg3Foo {
+  public Class<?> foo() {
+    return PublicFoo.class;
+  }
+}