Revert "Revert "Revert "CHA for interface method."""

Breaks libcore tests.

This reverts commit 8f301e26943c53485abc2da5ff1907f7c2e0ff0c.

Change-Id: Iea46176118be9e05aceb06f2d290961bb1f38265
(cherry picked from commit 43e99be9db10111a2d6e094882cd06c248c69e11)
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 68ebbe7..664b95a 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1023,17 +1023,6 @@
       // 1) In the best case, the interface call has one more indirection (to fetch the IMT).
       // 2) We will not go to the conflict trampoline with an invoke-virtual.
       // TODO: Consider sharpening once it is not dependent on the compiler driver.
-
-      if (method->IsDefault() && !method->IsCopied()) {
-        // Changing to invoke-virtual cannot be done on an original default method
-        // since it's not in any vtable. Devirtualization by exact type/inline-cache
-        // always uses a method in the iftable which is never an original default
-        // method.
-        // On the other hand, inlining an original default method by CHA is fine.
-        DCHECK(cha_devirtualize);
-        return false;
-      }
-
       const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile();
       uint32_t dex_method_index = FindMethodIndexIn(
           method, caller_dex_file, invoke_instruction->GetDexMethodIndex());
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 8f09cc6..2248c3b 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -691,7 +691,7 @@
 
     // Pointer to JNI function registered to this method, or a function to resolve the JNI function,
     // or the profiling data for non-native methods, or an ImtConflictTable, or the
-    // single-implementation of an abstract/interface method.
+    // single-implementation of an abstract method.
     void* data_;
 
     // Method dispatch from quick compiled code invokes this pointer which may cause bridging into
diff --git a/runtime/cha.cc b/runtime/cha.cc
index 7948c29..eaba01b 100644
--- a/runtime/cha.cc
+++ b/runtime/cha.cc
@@ -210,7 +210,7 @@
   }
 }
 
-void ClassHierarchyAnalysis::CheckVirtualMethodSingleImplementationInfo(
+void ClassHierarchyAnalysis::CheckSingleImplementationInfo(
     Handle<mirror::Class> klass,
     ArtMethod* virtual_method,
     ArtMethod* method_in_super,
@@ -290,9 +290,8 @@
       // A non-abstract method overrides an abstract method.
       if (method_in_super->GetSingleImplementation(pointer_size) == nullptr) {
         // Abstract method_in_super has no implementation yet.
-        // We need to grab cha_lock_ since there may be multiple class linking
-        // going on that can check/modify the single-implementation flag/method
-        // of method_in_super.
+        // We need to grab cha_lock_ for further checking/updating due to possible
+        // races.
         MutexLock cha_mu(Thread::Current(), *Locks::cha_lock_);
         if (!method_in_super->HasSingleImplementation()) {
           return;
@@ -363,55 +362,6 @@
   }
 }
 
-void ClassHierarchyAnalysis::CheckInterfaceMethodSingleImplementationInfo(
-    Handle<mirror::Class> klass,
-    ArtMethod* interface_method,
-    ArtMethod* implementation_method,
-    std::unordered_set<ArtMethod*>& invalidated_single_impl_methods,
-    PointerSize pointer_size) {
-  DCHECK(klass->IsInstantiable());
-  DCHECK(interface_method->IsAbstract() || interface_method->IsDefault());
-
-  if (!interface_method->HasSingleImplementation()) {
-    return;
-  }
-
-  if (implementation_method->IsAbstract()) {
-    // An instantiable class doesn't supply an implementation for
-    // interface_method. Invoking the interface method on the class will throw
-    // AbstractMethodError. This is an uncommon case, so we simply treat
-    // interface_method as not having single-implementation.
-    invalidated_single_impl_methods.insert(interface_method);
-    return;
-  }
-
-  // We need to grab cha_lock_ since there may be multiple class linking going
-  // on that can check/modify the single-implementation flag/method of
-  // interface_method.
-  MutexLock cha_mu(Thread::Current(), *Locks::cha_lock_);
-  // Do this check again after we grab cha_lock_.
-  if (!interface_method->HasSingleImplementation()) {
-    return;
-  }
-
-  ArtMethod* single_impl = interface_method->GetSingleImplementation(pointer_size);
-  if (single_impl == nullptr) {
-    // implementation_method becomes the first implementation for
-    // interface_method.
-    interface_method->SetSingleImplementation(implementation_method, pointer_size);
-    // Keep interface_method's single-implementation status.
-    return;
-  }
-  DCHECK(!single_impl->IsAbstract());
-  if (single_impl->GetDeclaringClass() == implementation_method->GetDeclaringClass()) {
-    // Same implementation. Since implementation_method may be a copy of a default
-    // method, we need to check the declaring class for equality.
-    return;
-  }
-  // Another implementation for interface_method.
-  invalidated_single_impl_methods.insert(interface_method);
-}
-
 void ClassHierarchyAnalysis::InitSingleImplementationFlag(Handle<mirror::Class> klass,
                                                           ArtMethod* method,
                                                           PointerSize pointer_size) {
@@ -432,7 +382,6 @@
       // Rare case, but we do accept it (such as 800-smali/smali/b_26143249.smali).
       // Do not attempt to devirtualize it.
       method->SetHasSingleImplementation(false);
-      DCHECK(method->GetSingleImplementation(pointer_size) == nullptr);
     } else {
       // Abstract method starts with single-implementation flag set and null
       // implementation method.
@@ -447,15 +396,9 @@
 }
 
 void ClassHierarchyAnalysis::UpdateAfterLoadingOf(Handle<mirror::Class> klass) {
-  PointerSize image_pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
   if (klass->IsInterface()) {
-    for (ArtMethod& method : klass->GetDeclaredVirtualMethods(image_pointer_size)) {
-      DCHECK(method.IsAbstract() || method.IsDefault());
-      InitSingleImplementationFlag(klass, &method, image_pointer_size);
-    }
     return;
   }
-
   mirror::Class* super_class = klass->GetSuperClass();
   if (super_class == nullptr) {
     return;
@@ -465,6 +408,7 @@
   // is invalidated by linking `klass`.
   std::unordered_set<ArtMethod*> invalidated_single_impl_methods;
 
+  PointerSize image_pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
   // Do an entry-by-entry comparison of vtable contents with super's vtable.
   for (int32_t i = 0; i < super_class->GetVTableLength(); ++i) {
     ArtMethod* method = klass->GetVTableEntry(i, image_pointer_size);
@@ -474,59 +418,33 @@
       if (method->IsAbstract() && klass->IsInstantiable()) {
         // An instantiable class that inherits an abstract method is treated as
         // supplying an implementation that throws AbstractMethodError.
-        CheckVirtualMethodSingleImplementationInfo(klass,
-                                                   method,
-                                                   method_in_super,
-                                                   invalidated_single_impl_methods,
-                                                   image_pointer_size);
+        CheckSingleImplementationInfo(klass,
+                                      method,
+                                      method_in_super,
+                                      invalidated_single_impl_methods,
+                                      image_pointer_size);
       }
       continue;
     }
     InitSingleImplementationFlag(klass, method, image_pointer_size);
-    CheckVirtualMethodSingleImplementationInfo(klass,
-                                               method,
-                                               method_in_super,
-                                               invalidated_single_impl_methods,
-                                               image_pointer_size);
+    CheckSingleImplementationInfo(klass,
+                                  method,
+                                  method_in_super,
+                                  invalidated_single_impl_methods,
+                                  image_pointer_size);
   }
+
   // For new virtual methods that don't override.
   for (int32_t i = super_class->GetVTableLength(); i < klass->GetVTableLength(); ++i) {
     ArtMethod* method = klass->GetVTableEntry(i, image_pointer_size);
     InitSingleImplementationFlag(klass, method, image_pointer_size);
   }
 
-  if (klass->IsInstantiable()) {
-    auto* iftable = klass->GetIfTable();
-    const size_t ifcount = klass->GetIfTableCount();
-    for (size_t i = 0; i < ifcount; ++i) {
-      mirror::Class* interface = iftable->GetInterface(i);
-      for (size_t j = 0, count = iftable->GetMethodArrayCount(i); j < count; ++j) {
-        ArtMethod* interface_method = interface->GetVirtualMethod(j, image_pointer_size);
-        mirror::PointerArray* method_array = iftable->GetMethodArray(i);
-        ArtMethod* implementation_method =
-            method_array->GetElementPtrSize<ArtMethod*>(j, image_pointer_size);
-        DCHECK(implementation_method != nullptr) << klass->PrettyClass();
-        CheckInterfaceMethodSingleImplementationInfo(klass,
-                                                     interface_method,
-                                                     implementation_method,
-                                                     invalidated_single_impl_methods,
-                                                     image_pointer_size);
-      }
-    }
-  }
-
-  InvalidateSingleImplementationMethods(invalidated_single_impl_methods);
-}
-
-void ClassHierarchyAnalysis::InvalidateSingleImplementationMethods(
-    std::unordered_set<ArtMethod*>& invalidated_single_impl_methods) {
+  Runtime* const runtime = Runtime::Current();
   if (!invalidated_single_impl_methods.empty()) {
-    Runtime* const runtime = Runtime::Current();
     Thread *self = Thread::Current();
     // Method headers for compiled code to be invalidated.
     std::unordered_set<OatQuickMethodHeader*> dependent_method_headers;
-    PointerSize image_pointer_size =
-        Runtime::Current()->GetClassLinker()->GetImagePointerSize();
 
     {
       // We do this under cha_lock_. Committing code also grabs this lock to
diff --git a/runtime/cha.h b/runtime/cha.h
index 99c49d2..a56a752 100644
--- a/runtime/cha.h
+++ b/runtime/cha.h
@@ -117,13 +117,11 @@
                                     PointerSize pointer_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  // Check/update single-implementation info when one virtual method
-  // overrides another.
   // `virtual_method` in `klass` overrides `method_in_super`.
-  // This may invalidate some assumptions on single-implementation.
+  // This will invalidate some assumptions on single-implementation.
   // Append methods that should have their single-implementation flag invalidated
   // to `invalidated_single_impl_methods`.
-  void CheckVirtualMethodSingleImplementationInfo(
+  void CheckSingleImplementationInfo(
       Handle<mirror::Class> klass,
       ArtMethod* virtual_method,
       ArtMethod* method_in_super,
@@ -131,23 +129,6 @@
       PointerSize pointer_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  // Check/update single-implementation info when one method
-  // implements an interface method.
-  // `implementation_method` in `klass` implements `interface_method`.
-  // Append `interface_method` to `invalidated_single_impl_methods`
-  // if `interface_method` gets a new implementation.
-  void CheckInterfaceMethodSingleImplementationInfo(
-      Handle<mirror::Class> klass,
-      ArtMethod* interface_method,
-      ArtMethod* implementation_method,
-      std::unordered_set<ArtMethod*>& invalidated_single_impl_methods,
-      PointerSize pointer_size)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  void InvalidateSingleImplementationMethods(
-      std::unordered_set<ArtMethod*>& invalidated_single_impl_methods)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   // For all methods in vtable slot at `verify_index` of `verify_class` and its
   // superclasses, single-implementation status should be false, except if the
   // method is `excluded_method`.
diff --git a/test/616-cha-abstract/src/Main.java b/test/616-cha-abstract/src/Main.java
index b33f575..e1d7db1 100644
--- a/test/616-cha-abstract/src/Main.java
+++ b/test/616-cha-abstract/src/Main.java
@@ -39,8 +39,8 @@
 }
 
 public class Main {
-  static Base sMain1;
-  static Base sMain2;
+  static Main1 sMain1;
+  static Main1 sMain2;
 
   static boolean sIsOptimizing = true;
   static boolean sHasJIT = true;
diff --git a/test/616-cha-interface-default/expected.txt b/test/616-cha-interface-default/expected.txt
deleted file mode 100644
index 6a5618e..0000000
--- a/test/616-cha-interface-default/expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-JNI_OnLoad called
diff --git a/test/616-cha-interface-default/info.txt b/test/616-cha-interface-default/info.txt
deleted file mode 100644
index 11baa1f..0000000
--- a/test/616-cha-interface-default/info.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Test for Class Hierarchy Analysis (CHA) on interface method.
-Test it under multidex configuration to check cross-dex inlining.
diff --git a/test/616-cha-interface-default/multidex.jpp b/test/616-cha-interface-default/multidex.jpp
deleted file mode 100644
index b0d200e..0000000
--- a/test/616-cha-interface-default/multidex.jpp
+++ /dev/null
@@ -1,3 +0,0 @@
-Main:
-  @@com.android.jack.annotations.ForceInMainDex
-  class Main
diff --git a/test/616-cha-interface-default/run b/test/616-cha-interface-default/run
deleted file mode 100644
index d8b4f0d..0000000
--- a/test/616-cha-interface-default/run
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2017 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.
-
-# Run without an app image to prevent the classes to be loaded at startup.
-exec ${RUN} "${@}" --no-app-image
diff --git a/test/616-cha-interface-default/src-multidex/Base.java b/test/616-cha-interface-default/src-multidex/Base.java
deleted file mode 100644
index 2cbcb50..0000000
--- a/test/616-cha-interface-default/src-multidex/Base.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-interface Base {
-  default public int foo(int i) {
-    if (i != 1) {
-      return -2;
-    }
-    return i + 10;
-  }
-
-  // Test default method that's not inlined.
-  default public int $noinline$bar() {
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    return -1;
-  }
-
-  default void printError(String msg) {
-    System.out.println(msg);
-  }
-}
diff --git a/test/616-cha-interface-default/src/Main.java b/test/616-cha-interface-default/src/Main.java
deleted file mode 100644
index 951607d..0000000
--- a/test/616-cha-interface-default/src/Main.java
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-class Main1 implements Base {
-}
-
-class Main2 extends Main1 {
-  public void foobar() {}
-}
-
-class Main3 implements Base {
-  public int foo(int i) {
-    if (i != 3) {
-      printError("error3");
-    }
-    return -(i + 10);
-  }
-}
-
-public class Main {
-  static Base sMain1;
-  static Base sMain2;
-  static Base sMain3;
-
-  static boolean sIsOptimizing = true;
-  static boolean sHasJIT = true;
-  static volatile boolean sOtherThreadStarted;
-
-  private static void assertSingleImplementation(Class<?> clazz, String method_name, boolean b) {
-    if (hasSingleImplementation(clazz, method_name) != b) {
-      System.out.println(clazz + "." + method_name +
-          " doesn't have single implementation value of " + b);
-    }
-  }
-
-  static int getValue(Class<?> cls) {
-    if (cls == Main1.class || cls == Main2.class) {
-      return 1;
-    }
-    return 3;
-  }
-
-  // sMain1.foo()/sMain2.foo() will be always be Base.foo() before Main3 is loaded/linked.
-  // So sMain1.foo() can be devirtualized to Base.foo() and be inlined.
-  // After Dummy.createMain3() which links in Main3, live testImplement() on stack
-  // should be deoptimized.
-  static void testImplement(boolean createMain3, boolean wait, boolean setHasJIT) {
-    if (setHasJIT) {
-      if (isInterpreted()) {
-        sHasJIT = false;
-      }
-      return;
-    }
-
-    if (createMain3 && (sIsOptimizing || sHasJIT)) {
-      assertIsManaged();
-    }
-
-    if (sMain1.foo(getValue(sMain1.getClass())) != 11) {
-      System.out.println("11 expected.");
-    }
-    if (sMain1.$noinline$bar() != -1) {
-      System.out.println("-1 expected.");
-    }
-    if (sMain2.foo(getValue(sMain2.getClass())) != 11) {
-      System.out.println("11 expected.");
-    }
-
-    if (createMain3) {
-      // Wait for the other thread to start.
-      while (!sOtherThreadStarted);
-      // Create an Main2 instance and assign it to sMain2.
-      // sMain1 is kept the same.
-      sMain3 = Dummy.createMain3();
-      // Wake up the other thread.
-      synchronized(Main.class) {
-        Main.class.notify();
-      }
-    } else if (wait) {
-      // This is the other thread.
-      synchronized(Main.class) {
-        sOtherThreadStarted = true;
-        // Wait for Main2 to be linked and deoptimization is triggered.
-        try {
-          Main.class.wait();
-        } catch (Exception e) {
-        }
-      }
-    }
-
-    // There should be a deoptimization here right after Main3 is linked by
-    // calling Dummy.createMain3(), even though sMain1 didn't change.
-    // The behavior here would be different if inline-cache is used, which
-    // doesn't deoptimize since sMain1 still hits the type cache.
-    if (sMain1.foo(getValue(sMain1.getClass())) != 11) {
-      System.out.println("11 expected.");
-    }
-    if ((createMain3 || wait) && sHasJIT && !sIsOptimizing) {
-      // This method should be deoptimized right after Main3 is created.
-      assertIsInterpreted();
-    }
-
-    if (sMain3 != null) {
-      if (sMain3.foo(getValue(sMain3.getClass())) != -13) {
-        System.out.println("-13 expected.");
-      }
-    }
-  }
-
-  // Test scenarios under which CHA-based devirtualization happens,
-  // and class loading that implements a method can invalidate compiled code.
-  public static void main(String[] args) {
-    System.loadLibrary(args[0]);
-
-    if (isInterpreted()) {
-      sIsOptimizing = false;
-    }
-
-    // sMain1 is an instance of Main1.
-    // sMain2 is an instance of Main2.
-    // Neither Main1 nor Main2 override default method Base.foo().
-    // Main3 hasn't bee loaded yet.
-    sMain1 = new Main1();
-    sMain2 = new Main2();
-
-    ensureJitCompiled(Main.class, "testImplement");
-    testImplement(false, false, true);
-
-    if (sHasJIT && !sIsOptimizing) {
-      assertSingleImplementation(Base.class, "foo", true);
-      assertSingleImplementation(Main1.class, "foo", true);
-    } else {
-      // Main3 is verified ahead-of-time so it's linked in already.
-    }
-
-    // Create another thread that also calls sMain1.foo().
-    // Try to test suspend and deopt another thread.
-    new Thread() {
-      public void run() {
-        testImplement(false, true, false);
-      }
-    }.start();
-
-    // This will create Main3 instance in the middle of testImplement().
-    testImplement(true, false, false);
-    assertSingleImplementation(Base.class, "foo", false);
-    assertSingleImplementation(Main1.class, "foo", true);
-    assertSingleImplementation(sMain3.getClass(), "foo", true);
-  }
-
-  private static native void ensureJitCompiled(Class<?> itf, String method_name);
-  private static native void assertIsInterpreted();
-  private static native void assertIsManaged();
-  private static native boolean isInterpreted();
-  private static native boolean hasSingleImplementation(Class<?> clazz, String method_name);
-}
-
-// Put createMain3() in another class to avoid class loading due to verifier.
-class Dummy {
-  static Base createMain3() {
-    return new Main3();
-  }
-}
diff --git a/test/616-cha-interface/expected.txt b/test/616-cha-interface/expected.txt
deleted file mode 100644
index 6a5618e..0000000
--- a/test/616-cha-interface/expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-JNI_OnLoad called
diff --git a/test/616-cha-interface/info.txt b/test/616-cha-interface/info.txt
deleted file mode 100644
index 1fd330a..0000000
--- a/test/616-cha-interface/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test for Class Hierarchy Analysis (CHA) on interface method.
diff --git a/test/616-cha-interface/run b/test/616-cha-interface/run
deleted file mode 100644
index d8b4f0d..0000000
--- a/test/616-cha-interface/run
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2017 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.
-
-# Run without an app image to prevent the classes to be loaded at startup.
-exec ${RUN} "${@}" --no-app-image
diff --git a/test/616-cha-interface/src/Main.java b/test/616-cha-interface/src/Main.java
deleted file mode 100644
index 3c93496..0000000
--- a/test/616-cha-interface/src/Main.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-interface Base {
-  void foo(int i);
-  void $noinline$bar();
-}
-
-class Main1 implements Base {
-  public void foo(int i) {
-    if (i != 1) {
-      printError("error1");
-    }
-  }
-
-  // Test rewriting invoke-interface into invoke-virtual when inlining fails.
-  public void $noinline$bar() {
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-    System.out.print("");
-  }
-
-  void printError(String msg) {
-    System.out.println(msg);
-  }
-}
-
-class Main2 extends Main1 {
-  public void foo(int i) {
-    if (i != 2) {
-      printError("error2");
-    }
-  }
-}
-
-public class Main {
-  static Base sMain1;
-  static Base sMain2;
-
-  static boolean sIsOptimizing = true;
-  static boolean sHasJIT = true;
-  static volatile boolean sOtherThreadStarted;
-
-  private static void assertSingleImplementation(Class<?> clazz, String method_name, boolean b) {
-    if (hasSingleImplementation(clazz, method_name) != b) {
-      System.out.println(clazz + "." + method_name +
-          " doesn't have single implementation value of " + b);
-    }
-  }
-
-  // sMain1.foo() will be always be Main1.foo() before Main2 is loaded/linked.
-  // So sMain1.foo() can be devirtualized to Main1.foo() and be inlined.
-  // After Dummy.createMain2() which links in Main2, live testImplement() on stack
-  // should be deoptimized.
-  static void testImplement(boolean createMain2, boolean wait, boolean setHasJIT) {
-    if (setHasJIT) {
-      if (isInterpreted()) {
-        sHasJIT = false;
-      }
-      return;
-    }
-
-    if (createMain2 && (sIsOptimizing || sHasJIT)) {
-      assertIsManaged();
-    }
-
-    sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2);
-    sMain1.$noinline$bar();
-
-    if (createMain2) {
-      // Wait for the other thread to start.
-      while (!sOtherThreadStarted);
-      // Create an Main2 instance and assign it to sMain2.
-      // sMain1 is kept the same.
-      sMain2 = Dummy.createMain2();
-      // Wake up the other thread.
-      synchronized(Main.class) {
-        Main.class.notify();
-      }
-    } else if (wait) {
-      // This is the other thread.
-      synchronized(Main.class) {
-        sOtherThreadStarted = true;
-        // Wait for Main2 to be linked and deoptimization is triggered.
-        try {
-          Main.class.wait();
-        } catch (Exception e) {
-        }
-      }
-    }
-
-    // There should be a deoptimization here right after Main2 is linked by
-    // calling Dummy.createMain2(), even though sMain1 didn't change.
-    // The behavior here would be different if inline-cache is used, which
-    // doesn't deoptimize since sMain1 still hits the type cache.
-    sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2);
-    if ((createMain2 || wait) && sHasJIT && !sIsOptimizing) {
-      // This method should be deoptimized right after Main2 is created.
-      assertIsInterpreted();
-    }
-
-    if (sMain2 != null) {
-      sMain2.foo(sMain2.getClass() == Main1.class ? 1 : 2);
-    }
-  }
-
-  // Test scenarios under which CHA-based devirtualization happens,
-  // and class loading that overrides a method can invalidate compiled code.
-  public static void main(String[] args) {
-    System.loadLibrary(args[0]);
-
-    if (isInterpreted()) {
-      sIsOptimizing = false;
-    }
-
-    // sMain1 is an instance of Main1. Main2 hasn't bee loaded yet.
-    sMain1 = new Main1();
-
-    ensureJitCompiled(Main.class, "testImplement");
-    testImplement(false, false, true);
-
-    if (sHasJIT && !sIsOptimizing) {
-      assertSingleImplementation(Base.class, "foo", true);
-      assertSingleImplementation(Main1.class, "foo", true);
-    } else {
-      // Main2 is verified ahead-of-time so it's linked in already.
-    }
-
-    // Create another thread that also calls sMain1.foo().
-    // Try to test suspend and deopt another thread.
-    new Thread() {
-      public void run() {
-        testImplement(false, true, false);
-      }
-    }.start();
-
-    // This will create Main2 instance in the middle of testImplement().
-    testImplement(true, false, false);
-    assertSingleImplementation(Base.class, "foo", false);
-    assertSingleImplementation(Main1.class, "foo", false);
-  }
-
-  private static native void ensureJitCompiled(Class<?> itf, String method_name);
-  private static native void assertIsInterpreted();
-  private static native void assertIsManaged();
-  private static native boolean isInterpreted();
-  private static native boolean hasSingleImplementation(Class<?> clazz, String method_name);
-}
-
-// Put createMain2() in another class to avoid class loading due to verifier.
-class Dummy {
-  static Main1 createMain2() {
-    return new Main2();
-  }
-}
diff --git a/test/616-cha-miranda/expected.txt b/test/616-cha-miranda/expected.txt
deleted file mode 100644
index 6a5618e..0000000
--- a/test/616-cha-miranda/expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-JNI_OnLoad called
diff --git a/test/616-cha-miranda/info.txt b/test/616-cha-miranda/info.txt
deleted file mode 100644
index c46f33f..0000000
--- a/test/616-cha-miranda/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test for Class Hierarchy Analysis (CHA) on miranda method.
diff --git a/test/616-cha-miranda/run b/test/616-cha-miranda/run
deleted file mode 100644
index d8b4f0d..0000000
--- a/test/616-cha-miranda/run
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2017 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.
-
-# Run without an app image to prevent the classes to be loaded at startup.
-exec ${RUN} "${@}" --no-app-image
diff --git a/test/616-cha-miranda/src/Main.java b/test/616-cha-miranda/src/Main.java
deleted file mode 100644
index e548482..0000000
--- a/test/616-cha-miranda/src/Main.java
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-interface Iface {
-  public void foo(int i);
-}
-
-abstract class Base implements Iface {
-  // Iface.foo(int) will be added as a miranda method.
-
-  void printError(String msg) {
-    System.out.println(msg);
-  }
-}
-
-class Main1 extends Base {
-  public void foo(int i) {
-    if (i != 1) {
-      printError("error1");
-    }
-  }
-}
-
-class Main2 extends Main1 {
-  public void foo(int i) {
-    if (i != 2) {
-      printError("error2");
-    }
-  }
-}
-
-public class Main {
-  static Base sMain1;
-  static Base sMain2;
-
-  static boolean sIsOptimizing = true;
-  static boolean sHasJIT = true;
-  static volatile boolean sOtherThreadStarted;
-
-  private static void assertSingleImplementation(Class<?> clazz, String method_name, boolean b) {
-    if (hasSingleImplementation(clazz, method_name) != b) {
-      System.out.println(clazz + "." + method_name +
-          " doesn't have single implementation value of " + b);
-    }
-  }
-
-  // sMain1.foo() will be always be Main1.foo() before Main2 is loaded/linked.
-  // So sMain1.foo() can be devirtualized to Main1.foo() and be inlined.
-  // After Dummy.createMain2() which links in Main2, live testOverride() on stack
-  // should be deoptimized.
-  static void testOverride(boolean createMain2, boolean wait, boolean setHasJIT) {
-    if (setHasJIT) {
-      if (isInterpreted()) {
-        sHasJIT = false;
-      }
-      return;
-    }
-
-    if (createMain2 && (sIsOptimizing || sHasJIT)) {
-      assertIsManaged();
-    }
-
-    sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2);
-
-    if (createMain2) {
-      // Wait for the other thread to start.
-      while (!sOtherThreadStarted);
-      // Create an Main2 instance and assign it to sMain2.
-      // sMain1 is kept the same.
-      sMain2 = Dummy.createMain2();
-      // Wake up the other thread.
-      synchronized(Main.class) {
-        Main.class.notify();
-      }
-    } else if (wait) {
-      // This is the other thread.
-      synchronized(Main.class) {
-        sOtherThreadStarted = true;
-        // Wait for Main2 to be linked and deoptimization is triggered.
-        try {
-          Main.class.wait();
-        } catch (Exception e) {
-        }
-      }
-    }
-
-    // There should be a deoptimization here right after Main2 is linked by
-    // calling Dummy.createMain2(), even though sMain1 didn't change.
-    // The behavior here would be different if inline-cache is used, which
-    // doesn't deoptimize since sMain1 still hits the type cache.
-    sMain1.foo(sMain1.getClass() == Main1.class ? 1 : 2);
-    if ((createMain2 || wait) && sHasJIT && !sIsOptimizing) {
-      // This method should be deoptimized right after Main2 is created.
-      assertIsInterpreted();
-    }
-
-    if (sMain2 != null) {
-      sMain2.foo(sMain2.getClass() == Main1.class ? 1 : 2);
-    }
-  }
-
-  // Test scenarios under which CHA-based devirtualization happens,
-  // and class loading that overrides a method can invalidate compiled code.
-  public static void main(String[] args) {
-    System.loadLibrary(args[0]);
-
-    if (isInterpreted()) {
-      sIsOptimizing = false;
-    }
-
-    // sMain1 is an instance of Main1. Main2 hasn't bee loaded yet.
-    sMain1 = new Main1();
-
-    ensureJitCompiled(Main.class, "testOverride");
-    testOverride(false, false, true);
-
-    if (sHasJIT && !sIsOptimizing) {
-      assertSingleImplementation(Base.class, "foo", true);
-      assertSingleImplementation(Main1.class, "foo", true);
-    } else {
-      // Main2 is verified ahead-of-time so it's linked in already.
-    }
-
-    // Create another thread that also calls sMain1.foo().
-    // Try to test suspend and deopt another thread.
-    new Thread() {
-      public void run() {
-        testOverride(false, true, false);
-      }
-    }.start();
-
-    // This will create Main2 instance in the middle of testOverride().
-    testOverride(true, false, false);
-    assertSingleImplementation(Base.class, "foo", false);
-    assertSingleImplementation(Main1.class, "foo", false);
-  }
-
-  private static native void ensureJitCompiled(Class<?> itf, String method_name);
-  private static native void assertIsInterpreted();
-  private static native void assertIsManaged();
-  private static native boolean isInterpreted();
-  private static native boolean hasSingleImplementation(Class<?> clazz, String method_name);
-}
-
-// Put createMain2() in another class to avoid class loading due to verifier.
-class Dummy {
-  static Main1 createMain2() {
-    return new Main2();
-  }
-}