Account for T::new expressions in default field value joiner
Bug: b/397737234
Change-Id: Iea344f54fa5a8ac40739a51da5d7e6679d5964b8
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/DefaultFieldValueJoiner.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/DefaultFieldValueJoiner.java
index 3a14982..2724406 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/DefaultFieldValueJoiner.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/propagation/DefaultFieldValueJoiner.java
@@ -32,11 +32,13 @@
import com.android.tools.r8.optimize.argumentpropagation.codescanner.NonEmptyValueState;
import com.android.tools.r8.optimize.argumentpropagation.codescanner.ValueState;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.MapUtils;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.collections.ProgramFieldSet;
+import com.google.common.collect.Iterables;
import it.unimi.dsi.fastutil.objects.Reference2BooleanMap;
import it.unimi.dsi.fastutil.objects.Reference2BooleanOpenHashMap;
import java.util.ArrayDeque;
@@ -64,6 +66,7 @@
private final FieldStateCollection fieldStates;
private final List<FlowGraph> flowGraphs;
private final ImmediateProgramSubtypingInfo immediateSubtypingInfo;
+ private final InternalOptions options;
public DefaultFieldValueJoiner(
AppView<AppInfoWithLiveness> appView,
@@ -77,6 +80,7 @@
this.fieldStates = fieldStates;
this.flowGraphs = flowGraphs;
this.immediateSubtypingInfo = immediateSubtypingInfo;
+ this.options = appView.options();
}
public Map<FlowGraph, Deque<FlowGraphNode>> joinDefaultFieldValuesForFieldsWithReadBeforeWrite(
@@ -178,7 +182,7 @@
}
private boolean isKeptDirectly(DexProgramClass clazz) {
- return appView.getKeepInfo(clazz).isPinned(appView.options());
+ return appView.getKeepInfo(clazz).isPinned(options);
}
private Map<DexProgramClass, List<ProgramField>> getFieldsOfInterest() {
@@ -213,7 +217,7 @@
Map<DexProgramClass, List<ProgramField>> fieldsSubjectToInitializerAnalysis) {
// When there is no constructor inlining, we can always analyze the initializers.
Map<DexType, ProgramFieldSet> fieldsNotSubjectToInitializerAnalysis = new ConcurrentHashMap<>();
- if (!appView.options().canInitNewInstanceUsingSuperclassConstructor()) {
+ if (!options.canInitNewInstanceUsingSuperclassConstructor()) {
return fieldsNotSubjectToInitializerAnalysis;
}
if (classesWithSingleCallerInlinedInstanceInitializers != null
@@ -265,7 +269,7 @@
analyzeInstanceInitializerAssignments(
clazz, instanceFieldsWithLiveDefaultValue, concurrentLiveDefaultValueConsumer);
},
- appView.options().getThreadingModule(),
+ options.getThreadingModule(),
executorService);
}
@@ -338,8 +342,17 @@
DexProgramClass holder = fields.iterator().next().getHolder();
// If the class is kept it could be instantiated directly, in which case all default field
// values could be live.
- if (appView.getKeepInfo(holder).isPinned(appView.options())
- || serviceImplementations.contains(holder.getType())) {
+ if (isKeptDirectly(holder) || serviceImplementations.contains(holder.getType())) {
+ fields.forEach(liveDefaultValueConsumer);
+ return true;
+ }
+ // If we are compiling to class files and there is a T::new lambda method handle, then
+ // abort, since the analysis performed by this method assumes that the given classes are
+ // only instantiated via new-instance instructions.
+ if (options.isGeneratingClassFiles()
+ && Iterables.any(
+ holder.programInstanceInitializers(),
+ method -> !appView.getKeepInfo(method).isClosedWorldReasoningAllowed(options))) {
fields.forEach(liveDefaultValueConsumer);
return true;
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/DefaultFieldValueJoinerWithLambdaAllocationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/DefaultFieldValueJoinerWithLambdaAllocationTest.java
index 77c48954..b54d384 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/DefaultFieldValueJoinerWithLambdaAllocationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/DefaultFieldValueJoinerWithLambdaAllocationTest.java
@@ -42,10 +42,7 @@
.setMinApi(parameters)
.compile()
.run(parameters.getRuntime(), Main.class)
- .applyIf(
- parameters.isCfRuntime(),
- rr -> rr.assertSuccessWithOutputLines("1", "1", "2", "2"),
- rr -> rr.assertSuccessWithOutputLines("0", "1", "0", "2"));
+ .assertSuccessWithOutputLines("0", "1", "0", "2");
}
public interface A {