Fix bug in virtual method merging of preoptimized methods
Bug: 163311975
Change-Id: I83aa9108aacd45e29c5788849e73fea596dbaf95
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index 0f9fdc1..b26d2ea 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -154,12 +154,12 @@
}
// Use the first of the original methods as the original method for the merged constructor.
+ DexMethod templateReference = methods.iterator().next().getReference();
DexMethod originalMethodReference =
- appView.graphLens().getOriginalMethodSignature(methods.iterator().next().getReference());
+ appView.graphLens().getOriginalMethodSignature(templateReference);
DexMethod newMethodReference =
- dexItemFactory.createMethod(
- target.type, originalMethodReference.proto, originalMethodReference.name);
+ dexItemFactory.createMethod(target.type, templateReference.proto, templateReference.name);
AbstractSynthesizedCode synthesizedCode =
new VirtualMethodEntryPointSynthesizedCode(
classIdToMethodMap,
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticalMergingPreoptimizedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticalMergingPreoptimizedTest.java
new file mode 100644
index 0000000..7731d5e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticalMergingPreoptimizedTest.java
@@ -0,0 +1,99 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.classmerging.horizontal;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNot.not;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.TestParameters;
+import org.junit.Test;
+
+public class VerticalMergingPreoptimizedTest extends HorizontalClassMergingTestBase {
+
+ public VerticalMergingPreoptimizedTest(
+ TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .enableNoHorizontalClassMergingAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(
+ "changed", "print a", "foo", "print b", "foo", "unused argument")
+ .inspect(
+ codeInspector -> {
+ assertThat(codeInspector.clazz(Parent.class), not(isPresent()));
+ assertThat(codeInspector.clazz(Changed.class), isPresent());
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(
+ codeInspector.clazz(B.class), notIf(isPresent(), enableHorizontalClassMerging));
+ });
+ }
+
+ @NeverClassInline
+ @NoHorizontalClassMerging
+ public static class Parent {
+ @NeverInline
+ public void foo() {
+ System.out.println("foo");
+ }
+ }
+
+ @NeverClassInline
+ @NoHorizontalClassMerging
+ public static class Changed extends Parent {
+ public Changed() {
+ System.out.println("changed");
+ }
+ }
+
+ @NeverClassInline
+ public static class A {
+ @NeverInline
+ public void print(Parent p) {
+ System.out.println("print a");
+ p.foo();
+ }
+ }
+
+ @NeverClassInline
+ public static class B {
+ @NeverInline
+ public void print(Parent p) {
+ System.out.println("print b");
+ p.foo();
+ }
+
+ @NeverInline
+ public void unusedArgument(Parent p) {
+ System.out.println("unused argument");
+ }
+ }
+
+ public static class Main {
+ public static void main(String[] args) {
+ Parent p = new Changed();
+ A a = new A();
+ B b = new B();
+ a.print(p);
+ b.print(p);
+ b.unusedArgument(p);
+ }
+ }
+}