Account for constructor inlining in proto builder optimization
Change-Id: Ie895cd0147275c7d598f8a6f6ea7adad2187dae3
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
index 2ff901b..c6658c4 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
@@ -43,11 +43,11 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerWorklist;
+import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.ObjectUtils;
import com.android.tools.r8.utils.PredicateSet;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
-import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.IdentityHashMap;
@@ -220,11 +220,8 @@
assert builder.superType == references.generatedMessageLiteBuilderType
|| builder.superType == references.generatedMessageLiteExtendableBuilderType;
- DexField defaultInstanceField = references.getDefaultInstanceField(dynamicMethod.getHolder());
Value builderValue =
code.createValue(ClassTypeElement.create(builder.superType, definitelyNotNull(), appView));
- Value defaultInstanceValue =
- code.createValue(ClassTypeElement.create(defaultInstanceField.type, maybeNull(), appView));
// Replace `new Message.Builder()` by `new GeneratedMessageLite.Builder()`
// (or `new GeneratedMessageLite.ExtendableBuilder()`).
@@ -239,23 +236,47 @@
//
// We may also see an accessibility bridge constructor, because the Builder constructor is
// private. The accessibility bridge takes null as an argument.
+ DexField defaultInstanceField = references.getDefaultInstanceField(dynamicMethod.getHolder());
+ Box<Value> existingDefaultInstanceValue = new Box<>();
InvokeDirect constructorInvoke =
instructionIterator.nextUntil(
instruction -> {
+ // After constructor inlining we may see a load of the DEFAULT_INSTANCE field.
+ if (instruction.isStaticGet()) {
+ StaticGet staticGet = instruction.asStaticGet();
+ if (staticGet.getField() == defaultInstanceField) {
+ existingDefaultInstanceValue.set(staticGet.outValue());
+ return false;
+ }
+ }
assert instruction.isInvokeDirect() || instruction.isConstNumber();
return instruction.isInvokeDirect();
});
assert constructorInvoke != null;
- instructionIterator.replaceCurrentInstruction(
- new StaticGet(defaultInstanceValue, defaultInstanceField));
- instructionIterator.setInsertionPosition(constructorInvoke.getPosition());
- instructionIterator.add(
- new InvokeDirect(
- builder.superType == references.generatedMessageLiteBuilderType
- ? references.generatedMessageLiteBuilderMethods.constructorMethod
- : references.generatedMessageLiteExtendableBuilderMethods.constructorMethod,
- null,
- ImmutableList.of(builderValue, defaultInstanceValue)));
+
+ DexMethod constructorMethod =
+ builder.superType == references.generatedMessageLiteBuilderType
+ ? references.generatedMessageLiteBuilderMethods.constructorMethod
+ : references.generatedMessageLiteExtendableBuilderMethods.constructorMethod;
+ if (existingDefaultInstanceValue.isSet()) {
+ instructionIterator.replaceCurrentInstruction(
+ InvokeDirect.builder()
+ .setArguments(builderValue, existingDefaultInstanceValue.get())
+ .setMethod(constructorMethod)
+ .build());
+ } else {
+ Value defaultInstanceValue =
+ code.createValue(
+ ClassTypeElement.create(defaultInstanceField.type, maybeNull(), appView));
+ instructionIterator.replaceCurrentInstruction(
+ new StaticGet(defaultInstanceValue, defaultInstanceField));
+ instructionIterator.setInsertionPosition(constructorInvoke.getPosition());
+ instructionIterator.add(
+ InvokeDirect.builder()
+ .setArguments(builderValue, defaultInstanceValue)
+ .setMethod(constructorMethod)
+ .build());
+ }
converter.removeDeadCodeAndFinalizeIR(
code, OptimizationFeedbackSimple.getInstance(), Timing.empty());
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index b7a8fae..1871e96 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -37,6 +37,7 @@
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.List;
@@ -282,6 +283,10 @@
protected DexMethod method;
protected List<Value> arguments = Collections.emptyList();
+ public B setArguments(Value... arguments) {
+ return setArguments(Arrays.asList(arguments));
+ }
+
public B setArguments(List<Value> arguments) {
assert arguments != null;
this.arguments = arguments;