Ensure shared enum unboxing utility methods
Bug: 190098858
Change-Id: I58203702d011db39179d512523c410a342895fdc
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
index fe3049f..98d016d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -62,7 +62,6 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.function.Function;
public class EnumUnboxingRewriter {
@@ -79,12 +78,6 @@
private final Map<DexMethod, DexEncodedMethod> utilityMethods = new ConcurrentHashMap<>();
- private final DexMethod ordinalUtilityMethod;
- private final DexMethod equalsUtilityMethod;
- private final DexMethod compareToUtilityMethod;
- private final DexMethod zeroCheckMethod;
- private final DexMethod zeroCheckMessageMethod;
-
EnumUnboxingRewriter(
AppView<AppInfoWithLiveness> appView,
IRConverter converter,
@@ -98,35 +91,6 @@
this.enumUnboxingLens = enumUnboxingLens;
this.unboxedEnumsData = unboxedEnumsInstanceFieldData;
this.utilityClasses = utilityClasses;
-
- // Custom methods for java.lang.Enum methods ordinal, equals and compareTo.
- DexType sharedEnumUnboxingUtilityType = utilityClasses.getSharedUtilityClass().getType();
- this.ordinalUtilityMethod =
- factory.createMethod(
- sharedEnumUnboxingUtilityType,
- factory.createProto(factory.intType, factory.intType),
- ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "ordinal");
- this.equalsUtilityMethod =
- factory.createMethod(
- sharedEnumUnboxingUtilityType,
- factory.createProto(factory.booleanType, factory.intType, factory.intType),
- ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "equals");
- this.compareToUtilityMethod =
- factory.createMethod(
- sharedEnumUnboxingUtilityType,
- factory.createProto(factory.intType, factory.intType, factory.intType),
- ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "compareTo");
- // Custom methods for Object#getClass without outValue and Objects.requireNonNull.
- this.zeroCheckMethod =
- factory.createMethod(
- sharedEnumUnboxingUtilityType,
- factory.createProto(factory.voidType, factory.intType),
- ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "zeroCheck");
- this.zeroCheckMessageMethod =
- factory.createMethod(
- sharedEnumUnboxingUtilityType,
- factory.createProto(factory.voidType, factory.intType, factory.stringType),
- ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "zeroCheckMessage");
}
private LocalEnumUnboxingUtilityClass getLocalUtilityClass(DexType enumType) {
@@ -171,50 +135,57 @@
// - toString is non-final, implemented in java.lang.Object, java.lang.Enum and possibly
// also in the unboxed enum class.
if (instruction.isInvokeMethodWithReceiver()) {
- InvokeMethodWithReceiver invokeMethod = instruction.asInvokeMethodWithReceiver();
- DexType enumType = getEnumTypeOrNull(invokeMethod.getReceiver(), convertedEnums);
- DexMethod invokedMethod = invokeMethod.getInvokedMethod();
+ InvokeMethodWithReceiver invoke = instruction.asInvokeMethodWithReceiver();
+ DexType enumType = getEnumTypeOrNull(invoke.getReceiver(), convertedEnums);
+ DexMethod invokedMethod = invoke.getInvokedMethod();
if (enumType != null) {
if (invokedMethod == factory.enumMembers.ordinalMethod
|| invokedMethod.match(factory.enumMembers.hashCode)) {
replaceEnumInvoke(
- iterator, invokeMethod, ordinalUtilityMethod, m -> synthesizeOrdinalMethod());
+ iterator,
+ invoke,
+ getSharedUtilityClass().ensureOrdinalMethod(appView, converter, methodProcessor));
continue;
} else if (invokedMethod.match(factory.enumMembers.equals)) {
replaceEnumInvoke(
- iterator, invokeMethod, equalsUtilityMethod, m -> synthesizeEqualsMethod());
+ iterator,
+ invoke,
+ getSharedUtilityClass().ensureEqualsMethod(appView, converter, methodProcessor));
continue;
} else if (invokedMethod == factory.enumMembers.compareTo
|| invokedMethod == factory.enumMembers.compareToWithObject) {
replaceEnumInvoke(
iterator,
- invokeMethod,
+ invoke,
getSharedUtilityClass()
.ensureCompareToMethod(appView, converter, methodProcessor));
continue;
} else if (invokedMethod == factory.enumMembers.nameMethod) {
- rewriteNameMethod(iterator, invokeMethod, enumType);
+ rewriteNameMethod(iterator, invoke, enumType);
continue;
} else if (invokedMethod.match(factory.enumMembers.toString)) {
DexMethod lookupMethod = enumUnboxingLens.lookupMethod(invokedMethod);
// If the lookupMethod is different, then a toString method was on the enumType
// class, which was moved, and the lens code rewriter will rewrite the invoke to
// that method.
- if (invokeMethod.isInvokeSuper() || lookupMethod == invokedMethod) {
- rewriteNameMethod(iterator, invokeMethod, enumType);
+ if (invoke.isInvokeSuper() || lookupMethod == invokedMethod) {
+ rewriteNameMethod(iterator, invoke, enumType);
continue;
}
} else if (invokedMethod == factory.objectMembers.getClass) {
- assert !invokeMethod.hasOutValue() || !invokeMethod.outValue().hasAnyUsers();
+ assert !invoke.hasOutValue() || !invoke.outValue().hasAnyUsers();
replaceEnumInvoke(
- iterator, invokeMethod, zeroCheckMethod, m -> synthesizeZeroCheckMethod());
+ iterator,
+ invoke,
+ getSharedUtilityClass()
+ .ensureCheckNotZeroMethod(appView, converter, methodProcessor));
continue;
}
} else if (invokedMethod == factory.stringBuilderMethods.appendObject
|| invokedMethod == factory.stringBufferMethods.appendObject) {
// Rewrites stringBuilder.append(enumInstance) as if it was
// stringBuilder.append(String.valueOf(unboxedEnumInstance));
- Value enumArg = invokeMethod.getArgument(1);
+ Value enumArg = invoke.getArgument(1);
DexType enumArgType = getEnumTypeOrNull(enumArg, convertedEnums);
if (enumArgType != null) {
DexMethod stringValueOfMethod = computeStringValueOfUtilityMethod(enumArgType);
@@ -223,17 +194,17 @@
.setMethod(stringValueOfMethod)
.setSingleArgument(enumArg)
.setFreshOutValue(appView, code)
- .setPosition(invokeMethod)
+ .setPosition(invoke)
.build();
DexMethod newAppendMethod =
invokedMethod == factory.stringBuilderMethods.appendObject
? factory.stringBuilderMethods.appendString
: factory.stringBufferMethods.appendString;
List<Value> arguments =
- ImmutableList.of(invokeMethod.getReceiver(), toStringInvoke.outValue());
+ ImmutableList.of(invoke.getReceiver(), toStringInvoke.outValue());
InvokeVirtual invokeAppendString =
- new InvokeVirtual(newAppendMethod, invokeMethod.clearOutValue(), arguments);
- invokeAppendString.setPosition(invokeMethod.getPosition());
+ new InvokeVirtual(newAppendMethod, invoke.clearOutValue(), arguments);
+ invokeAppendString.setPosition(invoke.getPosition());
iterator.replaceCurrentInstruction(toStringInvoke);
if (block.hasCatchHandlers()) {
iterator
@@ -248,7 +219,13 @@
}
} else if (instruction.isInvokeStatic()) {
rewriteInvokeStatic(
- instruction.asInvokeStatic(), code, context, convertedEnums, iterator, affectedPhis);
+ instruction.asInvokeStatic(),
+ code,
+ context,
+ convertedEnums,
+ iterator,
+ affectedPhis,
+ methodProcessor);
}
if (instruction.isStaticGet()) {
StaticGet staticGet = instruction.asStaticGet();
@@ -301,7 +278,8 @@
InstanceGet instanceGet = instruction.asInstanceGet();
DexType holder = instanceGet.getField().holder;
if (unboxedEnumsData.isUnboxedEnum(holder)) {
- DexMethod fieldMethod = computeInstanceFieldMethod(instanceGet.getField());
+ DexMethod fieldMethod =
+ computeInstanceFieldMethod(instanceGet.getField(), methodProcessor);
Value rewrittenOutValue =
code.createValue(
TypeElement.fromDexType(
@@ -350,7 +328,8 @@
ProgramMethod context,
Map<Instruction, DexType> convertedEnums,
InstructionListIterator instructionIterator,
- Set<Phi> affectedPhis) {
+ Set<Phi> affectedPhis,
+ MethodProcessor methodProcessor) {
DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
if (singleTarget == null) {
return;
@@ -394,7 +373,10 @@
DexType enumType = getEnumTypeOrNull(argument, convertedEnums);
if (enumType != null) {
replaceEnumInvoke(
- instructionIterator, invoke, zeroCheckMethod, m -> synthesizeZeroCheckMethod());
+ instructionIterator,
+ invoke,
+ getSharedUtilityClass()
+ .ensureCheckNotZeroMethod(appView, converter, methodProcessor));
}
} else if (invokedMethod == factory.objectsMethods.requireNonNullWithMessage) {
assert invoke.arguments().size() == 2;
@@ -404,8 +386,8 @@
replaceEnumInvoke(
instructionIterator,
invoke,
- zeroCheckMessageMethod,
- m -> synthesizeZeroCheckMessageMethod());
+ getSharedUtilityClass()
+ .ensureCheckNotZeroWithMessageMethod(appView, converter, methodProcessor));
}
}
return;
@@ -496,32 +478,24 @@
return iterator.insertConstIntInstruction(code, options, 0);
}
- private DexMethod computeInstanceFieldMethod(DexField field) {
+ private DexMethod computeInstanceFieldMethod(DexField field, MethodProcessor methodProcessor) {
EnumInstanceFieldKnownData enumFieldKnownData =
unboxedEnumsData.getInstanceFieldData(field.holder, field);
if (enumFieldKnownData.isOrdinal()) {
- utilityMethods.computeIfAbsent(ordinalUtilityMethod, m -> synthesizeOrdinalMethod());
- return ordinalUtilityMethod;
+ return getSharedUtilityClass()
+ .ensureOrdinalMethod(appView, converter, methodProcessor)
+ .getReference();
}
return computeInstanceFieldUtilityMethod(field.holder, field);
}
private void replaceEnumInvoke(
InstructionListIterator iterator, InvokeMethod invoke, ProgramMethod method) {
- replaceEnumInvoke(iterator, invoke, method.getReference(), null);
- }
-
- private void replaceEnumInvoke(
- InstructionListIterator iterator,
- InvokeMethod invoke,
- DexMethod method,
- Function<DexMethod, DexEncodedMethod> synthesizor) {
- if (synthesizor != null) {
- utilityMethods.computeIfAbsent(method, synthesizor);
- }
InvokeStatic replacement =
new InvokeStatic(
- method, invoke.hasUnusedOutValue() ? null : invoke.outValue(), invoke.arguments());
+ method.getReference(),
+ invoke.hasUnusedOutValue() ? null : invoke.outValue(),
+ invoke.arguments());
assert !replacement.hasOutValue()
|| !replacement.getInvokedMethod().getReturnType().isVoidType();
iterator.replaceCurrentInstruction(replacement);
@@ -696,38 +670,6 @@
return synthesizeUtilityMethod(cfCode, method);
}
- private DexEncodedMethod synthesizeZeroCheckMethod() {
- CfCode cfCode =
- EnumUnboxingCfMethods.EnumUnboxingMethods_zeroCheck(appView.options(), zeroCheckMethod);
- return synthesizeUtilityMethod(cfCode, zeroCheckMethod);
- }
-
- private DexEncodedMethod synthesizeZeroCheckMessageMethod() {
- CfCode cfCode =
- EnumUnboxingCfMethods.EnumUnboxingMethods_zeroCheckMessage(
- appView.options(), zeroCheckMessageMethod);
- return synthesizeUtilityMethod(cfCode, zeroCheckMessageMethod);
- }
-
- private DexEncodedMethod synthesizeOrdinalMethod() {
- CfCode cfCode =
- EnumUnboxingCfMethods.EnumUnboxingMethods_ordinal(appView.options(), ordinalUtilityMethod);
- return synthesizeUtilityMethod(cfCode, ordinalUtilityMethod);
- }
-
- private DexEncodedMethod synthesizeEqualsMethod() {
- CfCode cfCode =
- EnumUnboxingCfMethods.EnumUnboxingMethods_equals(appView.options(), equalsUtilityMethod);
- return synthesizeUtilityMethod(cfCode, equalsUtilityMethod);
- }
-
- private DexEncodedMethod synthesizeCompareToMethod() {
- CfCode cfCode =
- EnumUnboxingCfMethods.EnumUnboxingMethods_compareTo(
- appView.options(), compareToUtilityMethod);
- return synthesizeUtilityMethod(cfCode, compareToUtilityMethod);
- }
-
private DexEncodedMethod synthesizeUtilityMethod(CfCode cfCode, DexMethod method) {
return new DexEncodedMethod(
method,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
index 3e556e6..8fac402 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/SharedEnumUnboxingUtilityClass.java
@@ -25,6 +25,8 @@
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
@@ -39,6 +41,7 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
+import com.android.tools.r8.synthesis.SyntheticMethodBuilder.SyntheticCodeGenerator;
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.utils.ConsumerUtils;
import com.google.common.collect.ImmutableList;
@@ -72,11 +75,87 @@
appView, enumDataMap, enumsToUnbox, fieldAccessInfoCollectionModifierBuilder);
}
+ public ProgramMethod ensureCheckNotZeroMethod(
+ AppView<AppInfoWithLiveness> appView,
+ IRConverter converter,
+ MethodProcessor methodProcessor) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ return internalEnsureMethod(
+ appView,
+ converter,
+ methodProcessor,
+ dexItemFactory.createString("checkNotZero"),
+ dexItemFactory.createProto(dexItemFactory.voidType, dexItemFactory.intType),
+ method -> EnumUnboxingCfMethods.EnumUnboxingMethods_zeroCheck(appView.options(), method));
+ }
+
+ public ProgramMethod ensureCheckNotZeroWithMessageMethod(
+ AppView<AppInfoWithLiveness> appView,
+ IRConverter converter,
+ MethodProcessor methodProcessor) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ return internalEnsureMethod(
+ appView,
+ converter,
+ methodProcessor,
+ dexItemFactory.createString("checkNotZero"),
+ dexItemFactory.createProto(
+ dexItemFactory.voidType, dexItemFactory.intType, dexItemFactory.stringType),
+ method ->
+ EnumUnboxingCfMethods.EnumUnboxingMethods_zeroCheckMessage(appView.options(), method));
+ }
+
public ProgramMethod ensureCompareToMethod(
AppView<AppInfoWithLiveness> appView,
IRConverter converter,
MethodProcessor methodProcessor) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
+ return internalEnsureMethod(
+ appView,
+ converter,
+ methodProcessor,
+ dexItemFactory.enumMembers.compareTo.getName(),
+ dexItemFactory.createProto(
+ dexItemFactory.intType, dexItemFactory.intType, dexItemFactory.intType),
+ method -> EnumUnboxingCfMethods.EnumUnboxingMethods_compareTo(appView.options(), method));
+ }
+
+ public ProgramMethod ensureEqualsMethod(
+ AppView<AppInfoWithLiveness> appView,
+ IRConverter converter,
+ MethodProcessor methodProcessor) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ return internalEnsureMethod(
+ appView,
+ converter,
+ methodProcessor,
+ dexItemFactory.enumMembers.equals.getName(),
+ dexItemFactory.createProto(
+ dexItemFactory.booleanType, dexItemFactory.intType, dexItemFactory.intType),
+ method -> EnumUnboxingCfMethods.EnumUnboxingMethods_equals(appView.options(), method));
+ }
+
+ public ProgramMethod ensureOrdinalMethod(
+ AppView<AppInfoWithLiveness> appView,
+ IRConverter converter,
+ MethodProcessor methodProcessor) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ return internalEnsureMethod(
+ appView,
+ converter,
+ methodProcessor,
+ dexItemFactory.enumMembers.ordinalMethod.getName(),
+ dexItemFactory.createProto(dexItemFactory.intType, dexItemFactory.intType),
+ method -> EnumUnboxingCfMethods.EnumUnboxingMethods_ordinal(appView.options(), method));
+ }
+
+ private ProgramMethod internalEnsureMethod(
+ AppView<AppInfoWithLiveness> appView,
+ IRConverter converter,
+ MethodProcessor methodProcessor,
+ DexString methodName,
+ DexProto methodProto,
+ SyntheticCodeGenerator codeGenerator) {
// TODO(b/191957637): Consider creating free flowing static methods instead. The synthetic
// infrastructure needs to be augmented with a new method ensureFixedMethod() or
// ensureFixedFreeFlowingMethod() for this, if we want to create only one utility method (and
@@ -84,9 +163,8 @@
return appView
.getSyntheticItems()
.ensureFixedClassMethod(
- dexItemFactory.enumMembers.compareTo.getName(),
- dexItemFactory.createProto(
- dexItemFactory.intType, dexItemFactory.intType, dexItemFactory.intType),
+ methodName,
+ methodProto,
SyntheticKind.ENUM_UNBOXING_SHARED_UTILITY_CLASS,
synthesizingContext,
appView,
@@ -94,10 +172,7 @@
methodBuilder ->
methodBuilder
.setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
- .setCode(
- method ->
- EnumUnboxingCfMethods.EnumUnboxingMethods_compareTo(
- appView.options(), method))
+ .setCode(codeGenerator)
.setClassFileVersion(CfVersion.V1_6),
newMethod ->
converter.processDesugaredMethod(