Fix enum merging with single enum instance
Bug: b/297158103
Change-Id: I83ae40ec48020787c02d44cc277f2e51a9f0b43e
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
index a0d4d36..bcaf48b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -664,6 +664,7 @@
}
if (superMethod == null || subimplementations.isEmpty()) {
// No emulated dispatch is required, just move everything.
+ // If an abstract method with no implementors is found, effectively don't do anything.
if (superMethod != null && !superMethod.getAccessFlags().isAbstract()) {
assert superMethod.isProgramMethod();
directMoveAndMap(localUtilityClass, localUtilityMethods, superMethod.asProgramMethod());
@@ -673,6 +674,13 @@
}
return;
}
+ if (superMethod.getDefinition().isAbstract() && subimplementations.size() == 1) {
+ // No emulated dispatch is required, just forward everything to the unique implementation.
+ ProgramMethod override = subimplementations.iterator().next();
+ DexMethod uniqueUtility = directMoveAndMap(localUtilityClass, localUtilityMethods, override);
+ lensBuilder.mapToDispatch(superMethod.getReference(), uniqueUtility);
+ return;
+ }
// These methods require emulated dispatch.
emulatedDispatchMoveAndMap(
localUtilityClass, localUtilityMethods, superMethod, subimplementations);
@@ -736,7 +744,7 @@
}
}
- private void directMoveAndMap(
+ private DexMethod directMoveAndMap(
LocalEnumUnboxingUtilityClass localUtilityClass,
Map<DexMethod, DexEncodedMethod> localUtilityMethods,
ProgramMethod method) {
@@ -745,6 +753,7 @@
installLocalUtilityMethod(localUtilityClass, localUtilityMethods, method);
assert utilityMethod != null;
lensBuilder.moveAndMap(method.getReference(), utilityMethod, method.getDefinition().isStatic());
+ return utilityMethod;
}
public void recordEmulatedDispatch(DexMethod from, DexMethod move, DexMethod dispatch) {
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/enummerging/AbstractEnumMergingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/enummerging/AbstractEnumMergingTest.java
index be3e6b3..e2103e4 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/enummerging/AbstractEnumMergingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/enummerging/AbstractEnumMergingTest.java
@@ -37,15 +37,16 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addKeepRules(enumKeepRules.getKeepRules())
- .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class))
+ .addEnumUnboxingInspector(
+ inspector -> inspector.assertUnboxed(MyEnum2Cases.class, MyEnum1Case.class))
.enableInliningAnnotations()
.addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
.setMinApi(parameters)
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("336", "74", "96", "44");
+ .assertSuccessWithOutputLines("336", "74", "96", "44", "336", "56");
}
- enum MyEnum {
+ enum MyEnum2Cases {
A(8) {
@NeverInline
@Override
@@ -62,7 +63,24 @@
};
final long num;
- MyEnum(long num) {
+ MyEnum2Cases(long num) {
+ this.num = num;
+ }
+
+ public abstract long operate(long another);
+ }
+
+ enum MyEnum1Case {
+ A(8) {
+ @NeverInline
+ @Override
+ public long operate(long another) {
+ return num * another;
+ }
+ };
+ final long num;
+
+ MyEnum1Case(long num) {
this.num = num;
}
@@ -72,15 +90,23 @@
static class Main {
public static void main(String[] args) {
- System.out.println(MyEnum.A.operate(42));
- System.out.println(MyEnum.B.operate(42));
- System.out.println(indirect(MyEnum.A));
- System.out.println(indirect(MyEnum.B));
+ System.out.println(MyEnum2Cases.A.operate(42));
+ System.out.println(MyEnum2Cases.B.operate(42));
+ System.out.println(indirect(MyEnum2Cases.A));
+ System.out.println(indirect(MyEnum2Cases.B));
+
+ System.out.println(MyEnum1Case.A.operate(42));
+ System.out.println(indirect(MyEnum1Case.A));
}
@NeverInline
- public static long indirect(MyEnum e) {
+ public static long indirect(MyEnum2Cases e) {
return e.operate(12);
}
+
+ @NeverInline
+ public static long indirect(MyEnum1Case e) {
+ return e.operate(7);
+ }
}
}