Get string builder optimizations to trigger on D8 again.
It was implemented in the setting of R8 and therefore had
assumptions about library methods being present. They are not
when running D8.
R=sgjesse@google.com
Bug:
Change-Id: I676de738b55a552da9455891699900d013288b6b
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 3cd40f7..68051fd 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -38,8 +38,8 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
-import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@@ -89,8 +89,7 @@
this.graphLense = graphLense != null ? graphLense : GraphLense.getIdentityLense();
this.options = options;
this.printer = printer;
- Set<DexType> libraryClassesWithOptimizationInfo = markLibraryMethodsReturningReceiver();
- this.codeRewriter = new CodeRewriter(appInfo, libraryClassesWithOptimizationInfo);
+ this.codeRewriter = new CodeRewriter(appInfo, libraryMethodsReturningReceiver());
this.lambdaRewriter = enableDesugaring ? new LambdaRewriter(this) : null;
this.interfaceMethodRewriter =
(enableDesugaring && enableInterfaceMethodDesugaring())
@@ -183,18 +182,12 @@
throw new Unreachable();
}
- private Set<DexType> markLibraryMethodsReturningReceiver() {
+ private Set<DexMethod> libraryMethodsReturningReceiver() {
+ Set<DexMethod> methods = new HashSet<>();
DexItemFactory dexItemFactory = appInfo.dexItemFactory;
- dexItemFactory.stringBuilderMethods.forEachAppendMethod(this::markReturnsReceiver);
- dexItemFactory.stringBufferMethods.forEachAppendMethod(this::markReturnsReceiver);
- return ImmutableSet.of(dexItemFactory.stringBuilderType, dexItemFactory.stringBufferType);
- }
-
- private void markReturnsReceiver(DexMethod method) {
- DexEncodedMethod definition = appInfo.definitionFor(method);
- if (definition != null) {
- definition.markReturnsArgument(0);
- }
+ dexItemFactory.stringBufferMethods.forEachAppendMethod(methods::add);
+ dexItemFactory.stringBuilderMethods.forEachAppendMethod(methods::add);
+ return methods;
}
private void removeLambdaDeserializationMethods() {
@@ -512,7 +505,7 @@
}
printMethod(code, "Final IR (non-SSA)");
- // After all the optimizations have take place, we compute whether method should be inlined.
+ // After all the optimizations have take place, we compute whether method should be inlinedex.
Constraint state;
if (!options.inlineAccessors || inliner == null) {
state = Constraint.NEVER;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index eab1dfa..0f328c2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -96,12 +97,12 @@
private final AppInfo appInfo;
private final DexItemFactory dexItemFactory;
- private final Set<DexType> libraryClassesWithOptimizationInfo;
+ private final Set<DexMethod> libraryMethodsReturningReceiver;
- public CodeRewriter(AppInfo appInfo, Set<DexType> libraryClassesWithOptimizationInfo) {
+ public CodeRewriter(AppInfo appInfo, Set<DexMethod> libraryMethodsReturningReceiver) {
this.appInfo = appInfo;
this.dexItemFactory = appInfo.dexItemFactory;
- this.libraryClassesWithOptimizationInfo = libraryClassesWithOptimizationInfo;
+ this.libraryMethodsReturningReceiver = libraryMethodsReturningReceiver;
}
/**
@@ -517,37 +518,39 @@
// Replace result uses for methods where something is known about what is returned.
public void rewriteMoveResult(IRCode code) {
- if (!appInfo.hasSubtyping()) {
- return;
- }
+ AppInfoWithSubtyping appInfoWithSubtyping = appInfo.withSubtyping();
InstructionIterator iterator = code.instructionIterator();
while (iterator.hasNext()) {
Instruction current = iterator.next();
if (current.isInvokeMethod()) {
InvokeMethod invoke = current.asInvokeMethod();
if (invoke.outValue() != null && invoke.outValue().getLocalInfo() == null) {
- DexEncodedMethod target = invoke.computeSingleTarget(appInfo.withSubtyping());
- // We have a set of library classes with optimization information - consider those
- // as well.
- if ((target == null) &&
- libraryClassesWithOptimizationInfo.contains(invoke.getInvokedMethod().getHolder())) {
- target = appInfo.definitionFor(invoke.getInvokedMethod());
- }
- if (target != null) {
- DexMethod invokedMethod = target.method;
- // Check if the invoked method is known to return one of its arguments.
- DexEncodedMethod definition = appInfo.definitionFor(invokedMethod);
- if (definition != null && definition.getOptimizationInfo().returnsArgument()) {
- int argumentIndex = definition.getOptimizationInfo().getReturnedArgument();
- // Replace the out value of the invoke with the argument and ignore the out value.
- if (argumentIndex != -1 && checkArgumentType(invoke, target.method, argumentIndex)) {
- Value argument = invoke.arguments().get(argumentIndex);
- assert (invoke.outType() == argument.outType()) ||
- (invoke.outType() == MoveType.OBJECT
- && argument.outType() == MoveType.SINGLE
- && argument.getConstInstruction().asConstNumber().isZero());
- invoke.outValue().replaceUsers(argument);
- invoke.setOutValue(null);
+ boolean isLibraryMethodReturningReceiver =
+ libraryMethodsReturningReceiver.contains(invoke.getInvokedMethod());
+ if (isLibraryMethodReturningReceiver) {
+ if (checkArgumentType(invoke, invoke.getInvokedMethod(), 0)) {
+ invoke.outValue().replaceUsers(invoke.arguments().get(0));
+ invoke.setOutValue(null);
+ }
+ } else if (appInfoWithSubtyping != null) {
+ DexEncodedMethod target = invoke.computeSingleTarget(appInfoWithSubtyping);
+ if (target != null) {
+ DexMethod invokedMethod = target.method;
+ // Check if the invoked method is known to return one of its arguments.
+ DexEncodedMethod definition = appInfo.definitionFor(invokedMethod);
+ if (definition != null && definition.getOptimizationInfo().returnsArgument()) {
+ int argumentIndex = definition.getOptimizationInfo().getReturnedArgument();
+ // Replace the out value of the invoke with the argument and ignore the out value.
+ if (argumentIndex != -1 && checkArgumentType(invoke, target.method,
+ argumentIndex)) {
+ Value argument = invoke.arguments().get(argumentIndex);
+ assert (invoke.outType() == argument.outType()) ||
+ (invoke.outType() == MoveType.OBJECT
+ && argument.outType() == MoveType.SINGLE
+ && argument.getConstInstruction().asConstNumber().isZero());
+ invoke.outValue().replaceUsers(argument);
+ invoke.setOutValue(null);
+ }
}
}
}