Extend profile rewriting to enum unboxing
Bug: b/265729283
Bug: b/267592755
Change-Id: Ia6cf885d7ed424256767e357f3279be2e22a040a
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 0cb6881..22d3978 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -339,6 +339,12 @@
return toProgramMethodOrNull(getClassInitializer());
}
+ public void acceptProgramClassInitializer(Consumer<ProgramMethod> consumer) {
+ if (hasClassInitializer()) {
+ consumer.accept(getProgramClassInitializer());
+ }
+ }
+
public ProgramMethod getProgramDefaultInitializer() {
return getProgramInitializer(DexType.EMPTY_ARRAY);
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessorEventConsumer.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessorEventConsumer.java
index b6031d8..d002cd5 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessorEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodProcessorEventConsumer.java
@@ -7,11 +7,13 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizationsEventConsumer;
import com.android.tools.r8.ir.optimize.api.InstanceInitializerOutlinerEventConsumer;
+import com.android.tools.r8.ir.optimize.enums.EnumUnboxerMethodProcessorEventConsumer;
import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
import com.android.tools.r8.profile.art.rewriting.ArtProfileRewritingMethodProcessorEventConsumer;
public abstract class MethodProcessorEventConsumer
- implements InstanceInitializerOutlinerEventConsumer,
+ implements EnumUnboxerMethodProcessorEventConsumer,
+ InstanceInitializerOutlinerEventConsumer,
UtilityMethodsForCodeOptimizationsEventConsumer {
public static MethodProcessorEventConsumer create(
@@ -36,6 +38,23 @@
}
@Override
+ public void acceptEnumUnboxerCheckNotZeroContext(ProgramMethod method, ProgramMethod context) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void acceptEnumUnboxerLocalUtilityClassMethodContext(
+ ProgramMethod method, ProgramMethod context) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void acceptEnumUnboxerSharedUtilityClassMethodContext(
+ ProgramMethod method, ProgramMethod context) {
+ // Intentionally empty.
+ }
+
+ @Override
public void acceptInstanceInitializerOutline(ProgramMethod method, ProgramMethod context) {
// Intentionally empty.
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerMethodProcessorEventConsumer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerMethodProcessorEventConsumer.java
new file mode 100644
index 0000000..e24fcd3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerMethodProcessorEventConsumer.java
@@ -0,0 +1,17 @@
+// 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.optimize.enums;
+
+import com.android.tools.r8.graph.ProgramMethod;
+
+public interface EnumUnboxerMethodProcessorEventConsumer {
+
+ void acceptEnumUnboxerCheckNotZeroContext(ProgramMethod method, ProgramMethod context);
+
+ void acceptEnumUnboxerLocalUtilityClassMethodContext(ProgramMethod method, ProgramMethod context);
+
+ void acceptEnumUnboxerSharedUtilityClassMethodContext(
+ ProgramMethod method, ProgramMethod context);
+}
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 d0db72d..c9f6a96 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
@@ -123,6 +123,7 @@
}
assert code.isConsistentSSABeforeTypesAreCorrect(appView);
ProgramMethod context = code.context();
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer = methodProcessor.getEventConsumer();
Map<Instruction, DexType> convertedEnums = createInitialConvertedEnums(code, prototypeChanges);
Set<Phi> affectedPhis = Sets.newIdentityHashSet();
BasicBlockIterator blocks = code.listIterator();
@@ -186,19 +187,25 @@
if (invokedMethod == factory.enumMembers.ordinalMethod
|| invokedMethod.match(factory.enumMembers.hashCode)) {
replaceEnumInvoke(
- iterator, invoke, getSharedUtilityClass().ensureOrdinalMethod(appView));
+ iterator,
+ invoke,
+ getSharedUtilityClass().ensureOrdinalMethod(appView, context, eventConsumer));
continue;
} else if (invokedMethod.match(factory.enumMembers.equals)) {
replaceEnumInvoke(
- iterator, invoke, getSharedUtilityClass().ensureEqualsMethod(appView));
+ iterator,
+ invoke,
+ getSharedUtilityClass().ensureEqualsMethod(appView, context, eventConsumer));
continue;
} else if (invokedMethod == factory.enumMembers.compareTo
|| invokedMethod == factory.enumMembers.compareToWithObject) {
replaceEnumInvoke(
- iterator, invoke, getSharedUtilityClass().ensureCompareToMethod(appView));
+ iterator,
+ invoke,
+ getSharedUtilityClass().ensureCompareToMethod(appView, context, eventConsumer));
continue;
} else if (invokedMethod == factory.enumMembers.nameMethod) {
- rewriteNameMethod(iterator, invoke, enumType, methodProcessor);
+ rewriteNameMethod(iterator, invoke, enumType, context, eventConsumer);
continue;
} else if (invokedMethod.match(factory.enumMembers.toString)) {
DexMethod lookupMethod = enumUnboxingLens.lookupMethod(invokedMethod);
@@ -206,11 +213,11 @@
// class, which was moved, and the lens code rewriter will rewrite the invoke to
// that method.
if (invoke.isInvokeSuper() || lookupMethod == invokedMethod) {
- rewriteNameMethod(iterator, invoke, enumType, methodProcessor);
+ rewriteNameMethod(iterator, invoke, enumType, context, eventConsumer);
continue;
}
} else if (invokedMethod == factory.objectMembers.getClass) {
- rewriteNullCheck(iterator, invoke);
+ rewriteNullCheck(iterator, invoke, context, eventConsumer);
continue;
}
} else if (invokedMethod == factory.stringBuilderMethods.appendObject
@@ -221,7 +228,8 @@
DexType enumArgType = getEnumClassTypeOrNull(enumArg, convertedEnums);
if (enumArgType != null) {
ProgramMethod stringValueOfMethod =
- getLocalUtilityClass(enumArgType).ensureStringValueOfMethod(appView);
+ getLocalUtilityClass(enumArgType)
+ .ensureStringValueOfMethod(appView, context, eventConsumer);
InvokeStatic toStringInvoke =
InvokeStatic.builder()
.setMethod(stringValueOfMethod)
@@ -258,7 +266,7 @@
convertedEnums,
iterator,
affectedPhis,
- methodProcessor);
+ eventConsumer);
}
if (instruction.isStaticGet()) {
StaticGet staticGet = instruction.asStaticGet();
@@ -283,7 +291,7 @@
// Replace Enum.$VALUES by a call to: int[] SharedUtilityClass.values(int size).
InvokeStatic invoke =
InvokeStatic.builder()
- .setMethod(getSharedUtilityClass().getValuesMethod())
+ .setMethod(getSharedUtilityClass().getValuesMethod(context, eventConsumer))
.setFreshOutValue(appView, code)
.setSingleArgument(sizeValue)
.build();
@@ -312,7 +320,7 @@
DexType holder = instanceGet.getField().holder;
if (unboxedEnumsData.isUnboxedEnum(holder)) {
ProgramMethod fieldMethod =
- ensureInstanceFieldMethod(instanceGet.getField(), methodProcessor);
+ ensureInstanceFieldMethod(instanceGet.getField(), context, eventConsumer);
Value rewrittenOutValue =
code.createValue(
TypeElement.fromDexType(fieldMethod.getReturnType(), maybeNull(), appView));
@@ -363,7 +371,7 @@
Map<Instruction, DexType> convertedEnums,
InstructionListIterator instructionIterator,
Set<Phi> affectedPhis,
- MethodProcessor methodProcessor) {
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
if (singleTarget == null) {
return;
@@ -381,7 +389,8 @@
if (!unboxedEnumsData.isUnboxedEnum(enumType)) {
return;
}
- ProgramMethod valueOfMethod = getLocalUtilityClass(enumType).ensureValueOfMethod(appView);
+ ProgramMethod valueOfMethod =
+ getLocalUtilityClass(enumType).ensureValueOfMethod(appView, context, eventConsumer);
Value outValue = invoke.outValue();
Value rewrittenOutValue = null;
if (outValue != null) {
@@ -406,7 +415,7 @@
Value argument = invoke.getFirstArgument();
DexType enumType = getEnumClassTypeOrNull(argument, convertedEnums);
if (enumType != null) {
- rewriteNullCheck(instructionIterator, invoke);
+ rewriteNullCheck(instructionIterator, invoke, context, eventConsumer);
}
} else if (invokedMethod == factory.objectsMethods.requireNonNullWithMessage) {
assert invoke.arguments().size() == 2;
@@ -416,7 +425,8 @@
replaceEnumInvoke(
instructionIterator,
invoke,
- getSharedUtilityClass().ensureCheckNotZeroWithMessageMethod(appView));
+ getSharedUtilityClass()
+ .ensureCheckNotZeroWithMessageMethod(appView, context, eventConsumer));
}
}
return;
@@ -430,7 +440,8 @@
DexType enumType = getEnumClassTypeOrNull(argument, convertedEnums);
if (enumType != null) {
ProgramMethod stringValueOfMethod =
- getLocalUtilityClass(enumType).ensureStringValueOfMethod(appView);
+ getLocalUtilityClass(enumType)
+ .ensureStringValueOfMethod(appView, context, eventConsumer);
instructionIterator.replaceCurrentInstruction(
new InvokeStatic(
stringValueOfMethod.getReference(), invoke.outValue(), invoke.arguments()));
@@ -481,6 +492,7 @@
.build();
instructionIterator.replaceCurrentInstruction(replacement);
convertedEnums.put(replacement, enumType);
+ eventConsumer.acceptEnumUnboxerCheckNotZeroContext(checkNotZeroMethod, context);
}
} else {
assert false;
@@ -491,9 +503,16 @@
}
}
- public void rewriteNullCheck(InstructionListIterator iterator, InvokeMethod invoke) {
+ public void rewriteNullCheck(
+ InstructionListIterator iterator,
+ InvokeMethod invoke,
+ ProgramMethod context,
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
assert !invoke.hasOutValue() || !invoke.outValue().hasAnyUsers();
- replaceEnumInvoke(iterator, invoke, getSharedUtilityClass().ensureCheckNotZeroMethod(appView));
+ replaceEnumInvoke(
+ iterator,
+ invoke,
+ getSharedUtilityClass().ensureCheckNotZeroMethod(appView, context, eventConsumer));
}
private void removeRedundantValuesArrayCloning(
@@ -520,10 +539,12 @@
InstructionListIterator iterator,
InvokeMethodWithReceiver invoke,
DexType enumType,
- MethodProcessor methodProcessor) {
+ ProgramMethod context,
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
ProgramMethod toStringMethod =
getLocalUtilityClass(enumType)
- .ensureGetInstanceFieldMethod(appView, factory.enumMembers.nameField);
+ .ensureGetInstanceFieldMethod(
+ appView, factory.enumMembers.nameField, context, eventConsumer);
iterator.replaceCurrentInstruction(
new InvokeStatic(toStringMethod.getReference(), invoke.outValue(), invoke.arguments()));
}
@@ -553,13 +574,17 @@
return iterator.insertConstIntInstruction(code, options, 0);
}
- private ProgramMethod ensureInstanceFieldMethod(DexField field, MethodProcessor methodProcessor) {
+ private ProgramMethod ensureInstanceFieldMethod(
+ DexField field,
+ ProgramMethod context,
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
EnumInstanceFieldKnownData enumFieldKnownData =
unboxedEnumsData.getInstanceFieldData(field.holder, field);
if (enumFieldKnownData.isOrdinal()) {
- return getSharedUtilityClass().ensureOrdinalMethod(appView);
+ return getSharedUtilityClass().ensureOrdinalMethod(appView, context, eventConsumer);
}
- return getLocalUtilityClass(field.getHolderType()).ensureGetInstanceFieldMethod(appView, field);
+ return getLocalUtilityClass(field.getHolderType())
+ .ensureGetInstanceFieldMethod(appView, field, context, eventConsumer);
}
private void replaceEnumInvoke(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/LocalEnumUnboxingUtilityClass.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/LocalEnumUnboxingUtilityClass.java
index 6741924..4e7e556 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/LocalEnumUnboxingUtilityClass.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/LocalEnumUnboxingUtilityClass.java
@@ -59,7 +59,16 @@
public ProgramMethod ensureGetInstanceFieldMethod(
AppView<AppInfoWithLiveness> appView,
- DexField field) {
+ DexField field,
+ ProgramMethod context,
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
+ ProgramMethod method = ensureGetInstanceFieldMethod(appView, field);
+ eventConsumer.acceptEnumUnboxerLocalUtilityClassMethodContext(method, context);
+ return method;
+ }
+
+ private ProgramMethod ensureGetInstanceFieldMethod(
+ AppView<AppInfoWithLiveness> appView, DexField field) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
String fieldName = field.getName().toString();
DexString methodName;
@@ -82,7 +91,16 @@
.generateCfCode());
}
- public ProgramMethod ensureStringValueOfMethod(AppView<AppInfoWithLiveness> appView) {
+ public ProgramMethod ensureStringValueOfMethod(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
+ ProgramMethod method = ensureStringValueOfMethod(appView);
+ eventConsumer.acceptEnumUnboxerLocalUtilityClassMethodContext(method, context);
+ return method;
+ }
+
+ private ProgramMethod ensureStringValueOfMethod(AppView<AppInfoWithLiveness> appView) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
AbstractValue defaultValue =
appView.abstractValueFactory().createSingleStringValue(dexItemFactory.createString("null"));
@@ -96,7 +114,16 @@
.generateCfCode());
}
- public ProgramMethod ensureValueOfMethod(AppView<AppInfoWithLiveness> appView) {
+ public ProgramMethod ensureValueOfMethod(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
+ ProgramMethod method = ensureValueOfMethod(appView);
+ eventConsumer.acceptEnumUnboxerLocalUtilityClassMethodContext(method, context);
+ return method;
+ }
+
+ private ProgramMethod ensureValueOfMethod(AppView<AppInfoWithLiveness> appView) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
return internalEnsureMethod(
appView,
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 c24a972..fb0c4d8 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
@@ -75,7 +75,16 @@
ensureOrdinalMethod(appView);
}
- public ProgramMethod ensureCheckNotZeroMethod(AppView<AppInfoWithLiveness> appView) {
+ public ProgramMethod ensureCheckNotZeroMethod(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
+ ProgramMethod method = ensureCheckNotZeroMethod(appView);
+ eventConsumer.acceptEnumUnboxerSharedUtilityClassMethodContext(method, context);
+ return method;
+ }
+
+ private ProgramMethod ensureCheckNotZeroMethod(AppView<AppInfoWithLiveness> appView) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
return internalEnsureMethod(
appView,
@@ -84,7 +93,16 @@
method -> EnumUnboxingCfMethods.EnumUnboxingMethods_zeroCheck(dexItemFactory, method));
}
- public ProgramMethod ensureCheckNotZeroWithMessageMethod(AppView<AppInfoWithLiveness> appView) {
+ public ProgramMethod ensureCheckNotZeroWithMessageMethod(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
+ ProgramMethod method = ensureCheckNotZeroWithMessageMethod(appView);
+ eventConsumer.acceptEnumUnboxerSharedUtilityClassMethodContext(method, context);
+ return method;
+ }
+
+ private ProgramMethod ensureCheckNotZeroWithMessageMethod(AppView<AppInfoWithLiveness> appView) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
return internalEnsureMethod(
appView,
@@ -95,7 +113,16 @@
EnumUnboxingCfMethods.EnumUnboxingMethods_zeroCheckMessage(dexItemFactory, method));
}
- public ProgramMethod ensureCompareToMethod(AppView<AppInfoWithLiveness> appView) {
+ public ProgramMethod ensureCompareToMethod(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
+ ProgramMethod method = ensureCompareToMethod(appView);
+ eventConsumer.acceptEnumUnboxerSharedUtilityClassMethodContext(method, context);
+ return method;
+ }
+
+ private ProgramMethod ensureCompareToMethod(AppView<AppInfoWithLiveness> appView) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
return internalEnsureMethod(
appView,
@@ -105,7 +132,16 @@
method -> EnumUnboxingCfMethods.EnumUnboxingMethods_compareTo(dexItemFactory, method));
}
- public ProgramMethod ensureEqualsMethod(AppView<AppInfoWithLiveness> appView) {
+ public ProgramMethod ensureEqualsMethod(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
+ ProgramMethod method = ensureEqualsMethod(appView);
+ eventConsumer.acceptEnumUnboxerSharedUtilityClassMethodContext(method, context);
+ return method;
+ }
+
+ private ProgramMethod ensureEqualsMethod(AppView<AppInfoWithLiveness> appView) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
return internalEnsureMethod(
appView,
@@ -115,7 +151,16 @@
method -> EnumUnboxingCfMethods.EnumUnboxingMethods_equals(dexItemFactory, method));
}
- public ProgramMethod ensureOrdinalMethod(AppView<AppInfoWithLiveness> appView) {
+ public ProgramMethod ensureOrdinalMethod(
+ AppView<AppInfoWithLiveness> appView,
+ ProgramMethod context,
+ EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
+ ProgramMethod method = ensureOrdinalMethod(appView);
+ eventConsumer.acceptEnumUnboxerSharedUtilityClassMethodContext(method, context);
+ return method;
+ }
+
+ private ProgramMethod ensureOrdinalMethod(AppView<AppInfoWithLiveness> appView) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
return internalEnsureMethod(
appView,
@@ -156,7 +201,9 @@
return sharedUtilityClass;
}
- public ProgramMethod getValuesMethod() {
+ public ProgramMethod getValuesMethod(
+ ProgramMethod context, EnumUnboxerMethodProcessorEventConsumer eventConsumer) {
+ eventConsumer.acceptEnumUnboxerSharedUtilityClassMethodContext(valuesMethod, context);
return valuesMethod;
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingMethodProcessorEventConsumer.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingMethodProcessorEventConsumer.java
index 38005e2..325422e 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingMethodProcessorEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingMethodProcessorEventConsumer.java
@@ -30,6 +30,33 @@
}
@Override
+ public void acceptEnumUnboxerCheckNotZeroContext(ProgramMethod method, ProgramMethod context) {
+ additionsCollection.applyIfContextIsInProfile(
+ context, additionsBuilder -> additionsBuilder.addRule(method));
+ parent.acceptEnumUnboxerCheckNotZeroContext(method, context);
+ }
+
+ @Override
+ public void acceptEnumUnboxerLocalUtilityClassMethodContext(
+ ProgramMethod method, ProgramMethod context) {
+ additionsCollection.applyIfContextIsInProfile(
+ context, additionsBuilder -> additionsBuilder.addRule(method).addRule(method.getHolder()));
+ parent.acceptEnumUnboxerLocalUtilityClassMethodContext(method, context);
+ }
+
+ @Override
+ public void acceptEnumUnboxerSharedUtilityClassMethodContext(
+ ProgramMethod method, ProgramMethod context) {
+ additionsCollection.applyIfContextIsInProfile(
+ context,
+ additionsBuilder -> {
+ additionsBuilder.addRule(method).addRule(method.getHolder());
+ method.getHolder().acceptProgramClassInitializer(additionsBuilder::addRule);
+ });
+ parent.acceptEnumUnboxerSharedUtilityClassMethodContext(method, context);
+ }
+
+ @Override
public void acceptInstanceInitializerOutline(ProgramMethod method, ProgramMethod context) {
additionsCollection.applyIfContextIsInProfile(
context, additionsBuilder -> additionsBuilder.addRule(method).addRule(method.getHolder()));