Revert "Reland "Fix enum merging with abstract method error""
This reverts commit 67951b6fb8db259454c110f1294e75a57cdc11ee.
Reason for revert: Breaks bots
Change-Id: I8c8cdfb32d0566b0738ef5fb406756a37d6563b3
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 2db3697..32f0cbd 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -327,8 +327,6 @@
createString("Ljava/lang/IllegalAccessError;");
public final DexString illegalArgumentExceptionDescriptor =
createString("Ljava/lang/IllegalArgumentException;");
- public final DexString abstractMethodErrorDescriptor =
- createString("Ljava/lang/AbstractMethodError;");
public final DexString icceDescriptor = createString("Ljava/lang/IncompatibleClassChangeError;");
public final DexString exceptionInInitializerErrorDescriptor =
createString("Ljava/lang/ExceptionInInitializerError;");
@@ -575,8 +573,6 @@
createStaticallyKnownType(illegalAccessErrorDescriptor);
public final DexType illegalArgumentExceptionType =
createStaticallyKnownType(illegalArgumentExceptionDescriptor);
- public final DexType abstractMethodErrorType =
- createStaticallyKnownType(abstractMethodErrorDescriptor);
public final DexType icceType = createStaticallyKnownType(icceDescriptor);
public final DexType exceptionInInitializerErrorType =
createStaticallyKnownType(exceptionInInitializerErrorDescriptor);
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 7449cee..6ba6ad1 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
@@ -7,7 +7,6 @@
import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
import static com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl.ordinalToUnboxedInt;
-import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.contexts.CompilationContext.ProcessorContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
@@ -61,9 +60,8 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
-import com.android.tools.r8.ir.synthetic.EnumUnboxingCfCodeProvider.CfCodeWithLens;
import com.android.tools.r8.ir.synthetic.EnumUnboxingCfCodeProvider.EnumUnboxingMethodDispatchCfCodeProvider;
-import com.android.tools.r8.ir.synthetic.ThrowCfCodeProvider;
+import com.android.tools.r8.ir.synthetic.EnumUnboxingCfCodeProvider.EnumUnboxingMethodDispatchCfCodeProvider.CfCodeWithLens;
import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ImmutableArrayUtils;
@@ -656,13 +654,10 @@
// and at least one override.
DexMethod reference = nonPrivateVirtualMethod.withHolder(unboxedEnum.getType(), factory);
ProgramMethodSet subimplementations = ProgramMethodSet.create();
- boolean allImplements = true;
for (DexProgramClass subEnum : subEnums) {
ProgramMethod subMethod = subEnum.lookupProgramMethod(reference);
if (subMethod != null) {
subimplementations.add(subMethod);
- } else {
- allImplements = false;
}
}
DexClassAndMethod superMethod = unboxedEnum.lookupProgramMethod(reference);
@@ -671,73 +666,60 @@
superMethod = appView.appInfo().lookupSuperTarget(reference, unboxedEnum, appView);
assert superMethod == null || superMethod.getReference() == factory.enumMembers.toString;
}
- if (superMethod == null) {
- // No effective virtual dispatch is required, just move each subimplementation.
+ 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());
+ }
for (ProgramMethod override : subimplementations) {
- assert !override.getAccessFlags().isAbstract();
directMoveAndMap(localUtilityClass, localUtilityMethods, override);
}
return;
}
- if (superMethod.getAccessFlags().isAbstract()) {
- if (subimplementations.isEmpty()) {
- // Abstract method with no implementors: rewrite to abstract method error.
- directMoveAndMap(
- localUtilityClass, localUtilityMethods, superMethod.asProgramMethod(), true);
- } else if (!allImplements) {
- // The abstract method is missing implementors, so we need to remap all missing
- // implementation to an abstract method error.
- emulatedDispatchMoveAndMap(
- localUtilityClass, localUtilityMethods, superMethod, subimplementations, true);
- } else if (subimplementations.size() == 1) {
- // Single implementor, no emulated dispatch is required, just forward everything to the
- // unique implementation.
- assert allImplements;
- ProgramMethod override = subimplementations.iterator().next();
- DexMethod uniqueUtility =
- directMoveAndMap(localUtilityClass, localUtilityMethods, override);
- lensBuilder.mapToDispatch(superMethod.getReference(), uniqueUtility);
- } else {
- // Multiple implementors, the abstract method is entirely implemented, no need to
- // introduce the call to the abstract method error.
- emulatedDispatchMoveAndMap(
- localUtilityClass, localUtilityMethods, superMethod, subimplementations, false);
- }
+ 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;
}
- assert !superMethod.getAccessFlags().isAbstract();
- // No override, no effective virtual dispatch, just forward to the unique implementation.
- if (subimplementations.isEmpty()) {
- assert superMethod.isProgramMethod();
- directMoveAndMap(localUtilityClass, localUtilityMethods, superMethod.asProgramMethod());
- return;
- }
- // Emulated dispatch with a default case on the super enum.
+ // These methods require emulated dispatch.
emulatedDispatchMoveAndMap(
- localUtilityClass, localUtilityMethods, superMethod, subimplementations, false);
+ localUtilityClass, localUtilityMethods, superMethod, subimplementations);
}
private void emulatedDispatchMoveAndMap(
LocalEnumUnboxingUtilityClass localUtilityClass,
Map<DexMethod, DexEncodedMethod> localUtilityMethods,
DexClassAndMethod superMethod,
- ProgramMethodSet unorderedSubimplementations,
- boolean needsAbstractMethodErrorCase) {
+ ProgramMethodSet unorderedSubimplementations) {
assert !unorderedSubimplementations.isEmpty();
DexMethod superUtilityMethod;
List<ProgramMethod> sortedSubimplementations = new ArrayList<>(unorderedSubimplementations);
sortedSubimplementations.sort(Comparator.comparing(ProgramMethod::getHolderType));
- superUtilityMethod =
- computeSuperUtilityMethod(
- localUtilityClass,
- localUtilityMethods,
- superMethod,
- sortedSubimplementations,
- needsAbstractMethodErrorCase);
+ if (superMethod.isProgramMethod()) {
+ superUtilityMethod =
+ installLocalUtilityMethod(
+ localUtilityClass, localUtilityMethods, superMethod.asProgramMethod());
+ } else {
+ // All methods but toString() are final or non-virtual.
+ // We could support other cases by setting correctly the superUtilityMethod here.
+ assert superMethod.getReference().match(factory.enumMembers.toString);
+ ProgramMethod toString = localUtilityClass.ensureToStringMethod(appView);
+ superUtilityMethod = toString.getReference();
+ for (ProgramMethod context : sortedSubimplementations) {
+ // If the utility method is used only from the dispatch method, we have to process it and
+ // add it to the ArtProfile.
+ methodsToProcess.add(toString);
+ profileCollectionAdditions.addMethodIfContextIsInProfile(toString, context);
+ }
+ }
Map<DexMethod, DexMethod> overrideToUtilityMethods = new IdentityHashMap<>();
for (ProgramMethod subMethod : sortedSubimplementations) {
DexMethod subEnumLocalUtilityMethod =
- installLocalUtilityMethod(localUtilityClass, localUtilityMethods, subMethod, false);
+ installLocalUtilityMethod(localUtilityClass, localUtilityMethods, subMethod);
assert subEnumLocalUtilityMethod != null;
overrideToUtilityMethods.put(subMethod.getReference(), subEnumLocalUtilityMethod);
}
@@ -766,58 +748,13 @@
}
}
- private DexMethod computeSuperUtilityMethod(
- LocalEnumUnboxingUtilityClass localUtilityClass,
- Map<DexMethod, DexEncodedMethod> localUtilityMethods,
- DexClassAndMethod superMethod,
- List<ProgramMethod> sortedSubimplementations,
- boolean needsAbstractMethodErrorCase) {
- DexMethod superUtilityMethod;
- if (superMethod.isProgramMethod()) {
- if (needsAbstractMethodErrorCase) {
- assert superMethod.getAccessFlags().isAbstract();
- superUtilityMethod =
- installLocalUtilityMethod(
- localUtilityClass, localUtilityMethods, superMethod.asProgramMethod(), true);
- } else if (!superMethod.getAccessFlags().isAbstract()) {
- superUtilityMethod =
- installLocalUtilityMethod(
- localUtilityClass, localUtilityMethods, superMethod.asProgramMethod(), false);
- } else {
- assert superMethod.getAccessFlags().isAbstract();
- superUtilityMethod = null;
- }
- } else {
- // All methods but toString() are final or non-virtual.
- // We could support other cases by setting correctly the superUtilityMethod here.
- assert superMethod.getReference().match(factory.enumMembers.toString);
- ProgramMethod toString = localUtilityClass.ensureToStringMethod(appView);
- superUtilityMethod = toString.getReference();
- for (ProgramMethod context : sortedSubimplementations) {
- // If the utility method is used only from the dispatch method, we have to process it and
- // add it to the ArtProfile.
- methodsToProcess.add(toString);
- profileCollectionAdditions.addMethodIfContextIsInProfile(toString, context);
- }
- }
- return superUtilityMethod;
- }
-
private DexMethod directMoveAndMap(
LocalEnumUnboxingUtilityClass localUtilityClass,
Map<DexMethod, DexEncodedMethod> localUtilityMethods,
ProgramMethod method) {
- return directMoveAndMap(localUtilityClass, localUtilityMethods, method, false);
- }
-
- private DexMethod directMoveAndMap(
- LocalEnumUnboxingUtilityClass localUtilityClass,
- Map<DexMethod, DexEncodedMethod> localUtilityMethods,
- ProgramMethod method,
- boolean abstractMethodError) {
+ assert !method.getAccessFlags().isAbstract();
DexMethod utilityMethod =
- installLocalUtilityMethod(
- localUtilityClass, localUtilityMethods, method, abstractMethodError);
+ installLocalUtilityMethod(localUtilityClass, localUtilityMethods, method);
assert utilityMethod != null;
lensBuilder.moveAndMap(method.getReference(), utilityMethod, method.getDefinition().isStatic());
return utilityMethod;
@@ -892,15 +829,15 @@
private DexMethod installLocalUtilityMethod(
LocalEnumUnboxingUtilityClass localUtilityClass,
Map<DexMethod, DexEncodedMethod> localUtilityMethods,
- ProgramMethod method,
- boolean abstractMethodError) {
- assert abstractMethodError || !method.getAccessFlags().isAbstract();
- Predicate<DexMethod> isFresh =
- newMethodSignature -> !localUtilityMethods.containsKey(newMethodSignature);
+ ProgramMethod method) {
+ if (method.getAccessFlags().isAbstract()) {
+ return null;
+ }
DexEncodedMethod newLocalUtilityMethod =
- abstractMethodError
- ? createAbstractMethodErrorLocalUtilityMethod(method, localUtilityClass, isFresh)
- : createLocalUtilityMethod(method, localUtilityClass, isFresh);
+ createLocalUtilityMethod(
+ method,
+ localUtilityClass,
+ newMethodSignature -> !localUtilityMethods.containsKey(newMethodSignature));
assert !localUtilityMethods.containsKey(newLocalUtilityMethod.getReference());
localUtilityMethods.put(newLocalUtilityMethod.getReference(), newLocalUtilityMethod);
return newLocalUtilityMethod.getReference();
@@ -910,78 +847,40 @@
ProgramMethod method,
LocalEnumUnboxingUtilityClass localUtilityClass,
Predicate<DexMethod> availableMethodSignatures) {
- assert !method.getAccessFlags().isAbstract();
+ DexMethod methodReference = method.getReference();
+
+ // Create a new, fresh method signature on the local utility class. We prefix the method by "_"
+ // such that this does not collide with the utility methods we synthesize for unboxing.
DexMethod newMethod =
- createFreshMethodSignature(
- method, localUtilityClass, availableMethodSignatures, method.getReference());
+ method.getDefinition().isClassInitializer()
+ ? factory.createClassInitializer(localUtilityClass.getType())
+ : factory.createFreshMethodNameWithoutHolder(
+ "_" + method.getName().toString(),
+ fixupProto(
+ method.getAccessFlags().isStatic()
+ ? method.getProto()
+ : factory.prependHolderToProto(methodReference)),
+ localUtilityClass.getType(),
+ availableMethodSignatures);
+
return method
.getDefinition()
.toTypeSubstitutedMethod(
newMethod,
builder ->
- transformMethodForLocalUtility(builder, method)
- .setCompilationState(method.getDefinition().getCompilationState()));
- }
-
- private DexEncodedMethod createAbstractMethodErrorLocalUtilityMethod(
- ProgramMethod method,
- LocalEnumUnboxingUtilityClass localUtilityClass,
- Predicate<DexMethod> availableMethodSignatures) {
- assert method.getAccessFlags().isAbstract();
- DexMethod newMethod =
- createFreshMethodSignature(
- method, localUtilityClass, availableMethodSignatures, method.getReference());
- DexEncodedMethod dexEncodedMethod =
- method
- .getDefinition()
- .toTypeSubstitutedMethod(
- newMethod,
- builder ->
- transformMethodForLocalUtility(builder, method)
- .modifyAccessFlags(MethodAccessFlags::unsetAbstract)
- .setCode(
- new ThrowCfCodeProvider(
- appView, newMethod, factory.abstractMethodErrorType)
- .generateCfCode())
- .setClassFileVersion(CfVersion.V1_8)
- .setApiLevelForDefinition(appView.computedMinApiLevel())
- .setApiLevelForCode(appView.computedMinApiLevel()));
- methodsToProcess.add(new ProgramMethod(localUtilityClass.getDefinition(), dexEncodedMethod));
- return dexEncodedMethod;
- }
-
- private DexEncodedMethod.Builder transformMethodForLocalUtility(
- DexEncodedMethod.Builder builder, ProgramMethod method) {
- builder
- .clearAllAnnotations()
- .modifyAccessFlags(
- accessFlags -> {
- if (method.getDefinition().isClassInitializer()) {
- assert accessFlags.isStatic();
- } else {
- accessFlags.promoteToPublic();
- accessFlags.promoteToStatic();
- }
- })
- .unsetIsLibraryMethodOverride();
- return builder;
- }
-
- private DexMethod createFreshMethodSignature(
- ProgramMethod method,
- LocalEnumUnboxingUtilityClass localUtilityClass,
- Predicate<DexMethod> availableMethodSignatures,
- DexMethod methodReference) {
- return method.getDefinition().isClassInitializer()
- ? factory.createClassInitializer(localUtilityClass.getType())
- : factory.createFreshMethodNameWithoutHolder(
- "_" + method.getName().toString(),
- fixupProto(
- method.getAccessFlags().isStatic()
- ? method.getProto()
- : factory.prependHolderToProto(methodReference)),
- localUtilityClass.getType(),
- availableMethodSignatures);
+ builder
+ .clearAllAnnotations()
+ .modifyAccessFlags(
+ accessFlags -> {
+ if (method.getDefinition().isClassInitializer()) {
+ assert accessFlags.isStatic();
+ } else {
+ accessFlags.promoteToPublic();
+ accessFlags.promoteToStatic();
+ }
+ })
+ .setCompilationState(method.getDefinition().getCompilationState())
+ .unsetIsLibraryMethodOverride());
}
private boolean isPrunedAfterEnumUnboxing(ProgramField field, EnumData enumData) {
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
index f60fe64..112ffdd 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
@@ -169,6 +169,25 @@
? new CfReturnVoid()
: new CfReturn(ValueType.fromDexType(method.getReturnType())));
}
+
+ public static class CfCodeWithLens extends CfCode {
+ private GraphLens codeLens;
+
+ public void setCodeLens(GraphLens codeLens) {
+ this.codeLens = codeLens;
+ }
+
+ public CfCodeWithLens(
+ DexType originalHolder, int maxStack, int maxLocals, List<CfInstruction> instructions) {
+ super(originalHolder, maxStack, maxLocals, instructions);
+ }
+
+ @Override
+ public GraphLens getCodeLens(AppView<?> appView) {
+ assert codeLens != null;
+ return codeLens;
+ }
+ }
}
public static class EnumUnboxingInstanceFieldCfCodeProvider extends EnumUnboxingCfCodeProvider {
@@ -303,24 +322,4 @@
return standardCfCodeFromInstructions(instructions);
}
}
-
- public static class CfCodeWithLens extends CfCode {
-
- private GraphLens codeLens;
-
- public void setCodeLens(GraphLens codeLens) {
- this.codeLens = codeLens;
- }
-
- public CfCodeWithLens(
- DexType originalHolder, int maxStack, int maxLocals, List<CfInstruction> instructions) {
- super(originalHolder, maxStack, maxLocals, instructions);
- }
-
- @Override
- public GraphLens getCodeLens(AppView<?> appView) {
- assert codeLens != null;
- return codeLens;
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/ThrowCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/ThrowCfCodeProvider.java
deleted file mode 100644
index becf6d3..0000000
--- a/src/main/java/com/android/tools/r8/ir/synthetic/ThrowCfCodeProvider.java
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2023, 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.ir.synthetic;
-
-import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
-
-import com.android.tools.r8.cf.code.CfInstruction;
-import com.android.tools.r8.cf.code.CfInvoke;
-import com.android.tools.r8.cf.code.CfNew;
-import com.android.tools.r8.cf.code.CfStackInstruction;
-import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
-import com.android.tools.r8.cf.code.CfThrow;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Generates a method that just throws a exception with empty <init></init> with *any* signature
- * passed, so the method can be inserted in a hierarchy and be called with normal virtual dispatch.
- */
-public class ThrowCfCodeProvider extends SyntheticCfCodeProvider {
-
- private final DexMethod method;
- private final DexType exceptionType;
-
- public ThrowCfCodeProvider(AppView<?> appView, DexMethod method, DexType exceptionType) {
- super(appView, method.getHolderType());
- this.method = method;
- this.exceptionType = exceptionType;
- }
-
- @Override
- public CfCode generateCfCode() {
- List<CfInstruction> instructions = new ArrayList<>();
- instructions.add(new CfNew(exceptionType));
- instructions.add(new CfStackInstruction(Opcode.Dup));
- DexMethod init = appView.dexItemFactory().createInstanceInitializer(exceptionType);
- instructions.add(new CfInvoke(INVOKESPECIAL, init, false));
- instructions.add(new CfThrow());
- return standardCfCodeFromInstructions(instructions);
- }
-}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/enummerging/AbstractMethodErrorEnumMergingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/enummerging/AbstractMethodErrorEnumMergingTest.java
deleted file mode 100644
index 7937ef7..0000000
--- a/src/test/java/com/android/tools/r8/enumunboxing/enummerging/AbstractMethodErrorEnumMergingTest.java
+++ /dev/null
@@ -1,174 +0,0 @@
-// Copyright (c) 2023, 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.enumunboxing.enummerging;
-
-import static com.android.tools.r8.ToolHelper.getClassFilesForInnerClasses;
-import static org.junit.Assert.assertEquals;
-
-import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.enumunboxing.EnumUnboxingTestBase;
-import com.android.tools.r8.utils.StringUtils;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class AbstractMethodErrorEnumMergingTest extends EnumUnboxingTestBase {
-
- private final TestParameters parameters;
- private final boolean enumValueOptimization;
- private final EnumKeepRules enumKeepRules;
- private final String EXPECTED_RESULT =
- StringUtils.lines(
- "class java.lang.AbstractMethodError",
- "74",
- "class java.lang.AbstractMethodError",
- "44",
- "class java.lang.AbstractMethodError",
- "class java.lang.AbstractMethodError");
-
- @Parameters(name = "{0} valueOpt: {1} keep: {2}")
- public static List<Object[]> data() {
- return enumUnboxingTestParameters();
- }
-
- public AbstractMethodErrorEnumMergingTest(
- TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) {
- this.parameters = parameters;
- this.enumValueOptimization = enumValueOptimization;
- this.enumKeepRules = enumKeepRules;
- }
-
- @Test
- public void testReference() throws Exception {
- testForD8(parameters.getBackend())
- .addProgramClassFileData(inputProgram())
- .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
- .setMinApi(parameters)
- .run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutput(EXPECTED_RESULT);
- }
-
- @Test
- public void testEnumUnboxing() throws Exception {
- testForR8(parameters.getBackend())
- .addProgramClassFileData(inputProgram())
- .addKeepMainRule(Main.class)
- .addKeepRules(enumKeepRules.getKeepRules())
- .addEnumUnboxingInspector(
- inspector -> inspector.assertUnboxed(MyEnum2Cases.class, MyEnum1Case.class))
- .enableInliningAnnotations()
- .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
- .setMinApi(parameters)
- .run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutput(EXPECTED_RESULT);
- }
-
- private List<byte[]> inputProgram() throws Exception {
- Collection<Path> files = getClassFilesForInnerClasses(getClass());
- List<byte[]> result = new ArrayList<>();
- int changed = 0;
- for (Path file : files) {
- String fileName = file.getFileName().toString();
- if (fileName.equals("AbstractMethodErrorEnumMergingTest$MyEnum1Case$1.class")
- || fileName.equals("AbstractMethodErrorEnumMergingTest$MyEnum2Cases$1.class")) {
- result.add(transformer(file, null).removeMethodsWithName("operate").transform());
- changed++;
- } else {
- result.add(Files.readAllBytes(file));
- }
- }
- assertEquals(2, changed);
- return result;
- }
-
- enum MyEnum2Cases {
- A(8) {
- // Will be removed by transformation before compilation.
- @NeverInline
- @Override
- public long operate(long another) {
- throw new RuntimeException("Should have been removed");
- }
- },
- B(32) {
- @NeverInline
- @Override
- public long operate(long another) {
- return num + another;
- }
- };
- final long num;
-
- MyEnum2Cases(long num) {
- this.num = num;
- }
-
- public abstract long operate(long another);
- }
-
- enum MyEnum1Case {
- A(8) {
- // Will be removed by transformation before compilation.
- @NeverInline
- @Override
- public long operate(long another) {
- throw new RuntimeException("Should have been removed");
- }
- };
- final long num;
-
- MyEnum1Case(long num) {
- this.num = num;
- }
-
- public abstract long operate(long another);
- }
-
- static class Main {
-
- public static void main(String[] args) {
- try {
- System.out.println(MyEnum2Cases.A.operate(42));
- } catch (Throwable t) {
- System.out.println(t.getClass());
- }
- System.out.println(MyEnum2Cases.B.operate(42));
- try {
- System.out.println(indirect(MyEnum2Cases.A));
- } catch (Throwable t) {
- System.out.println(t.getClass());
- }
- System.out.println(indirect(MyEnum2Cases.B));
-
- try {
- System.out.println(MyEnum1Case.A.operate(42));
- } catch (Throwable t) {
- System.out.println(t.getClass());
- }
- try {
- System.out.println(indirect(MyEnum1Case.A));
- } catch (Throwable t) {
- System.out.println(t.getClass());
- }
- }
-
- @NeverInline
- public static long indirect(MyEnum2Cases e) {
- return e.operate(12);
- }
-
- @NeverInline
- public static long indirect(MyEnum1Case e) {
- return e.operate(7);
- }
- }
-}