Extend instance initializer info with argument initialization info
Change-Id: I998e25e50fde7f68ad8d7dff1d9112e3645cdb73
Bug: 147652121
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 9f7b4cf..3ce7b0a 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
import com.android.tools.r8.ir.optimize.CallSiteOptimizationInfoPropagator;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoFactory;
import com.android.tools.r8.ir.optimize.library.LibraryMethodOptimizer;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
@@ -45,6 +46,8 @@
private final InternalOptions options;
private RootSet rootSet;
private final AbstractValueFactory abstractValueFactory = new AbstractValueFactory();
+ private final InstanceFieldInitializationInfoFactory instanceFieldInitializationInfoFactory =
+ new InstanceFieldInitializationInfoFactory();
// Desugared library prefix rewriter.
public final PrefixRewritingMapper rewritePrefix;
@@ -125,6 +128,10 @@
return abstractValueFactory;
}
+ public InstanceFieldInitializationInfoFactory instanceFieldInitializationInfoFactory() {
+ return instanceFieldInitializationInfoFactory;
+ }
+
public T appInfo() {
return appInfo;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
index 29dc41b..2289a28 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
@@ -275,7 +275,7 @@
return true;
}
- private void updateFieldOptimizationInfo(DexEncodedField field, Value value) {
+ void updateFieldOptimizationInfo(DexEncodedField field, Value value) {
// Abstract value.
Value root = value.getAliasedValue();
AbstractValue abstractValue = computeAbstractValue(root);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
index d636715..6c1fe58 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
@@ -5,15 +5,29 @@
package com.android.tools.r8.ir.analysis.fieldvalueanalysis;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.ir.code.Argument;
import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.optimize.ClassInitializerDefaultsOptimization.ClassInitializerDefaultsResult;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
+import com.android.tools.r8.ir.optimize.info.field.EmptyInstanceFieldInitializationInfoCollection;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoFactory;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
public class InstanceFieldValueAnalysis extends FieldValueAnalysis {
+ // Information about how this instance constructor initializes the fields on the newly created
+ // instance.
+ private final InstanceFieldInitializationInfoCollection.Builder builder =
+ InstanceFieldInitializationInfoCollection.builder();
+
+ private final InstanceFieldInitializationInfoFactory factory;
+
private InstanceFieldValueAnalysis(
AppView<AppInfoWithLiveness> appView,
IRCode code,
@@ -21,9 +35,14 @@
DexProgramClass clazz,
DexEncodedMethod method) {
super(appView, code, feedback, clazz, method);
+ factory = appView.instanceFieldInitializationInfoFactory();
}
- public static void run(
+ /**
+ * Returns information about how this instance constructor initializes the fields on the newly
+ * created instance.
+ */
+ public static InstanceFieldInitializationInfoCollection run(
AppView<?> appView,
IRCode code,
ClassInitializerDefaultsResult classInitializerDefaultsResult,
@@ -34,16 +53,32 @@
assert method.isInstanceInitializer();
DexProgramClass clazz = appView.definitionFor(method.method.holder).asProgramClass();
if (!appView.options().enableValuePropagationForInstanceFields) {
- return;
+ return EmptyInstanceFieldInitializationInfoCollection.getInstance();
}
DexEncodedMethod otherInstanceInitializer =
clazz.lookupDirectMethod(other -> other.isInstanceInitializer() && other != method);
if (otherInstanceInitializer != null) {
// Conservatively bail out.
// TODO(b/125282093): Handle multiple instance initializers on the same class.
- return;
+ return EmptyInstanceFieldInitializationInfoCollection.getInstance();
}
- new InstanceFieldValueAnalysis(appView.withLiveness(), code, feedback, clazz, method)
- .computeFieldOptimizationInfo(classInitializerDefaultsResult);
+ InstanceFieldValueAnalysis analysis =
+ new InstanceFieldValueAnalysis(appView.withLiveness(), code, feedback, clazz, method);
+ analysis.computeFieldOptimizationInfo(classInitializerDefaultsResult);
+ return analysis.builder.build();
+ }
+
+ @Override
+ void updateFieldOptimizationInfo(DexEncodedField field, Value value) {
+ super.updateFieldOptimizationInfo(field, value);
+
+ // If this instance field is initialized with an argument, then record this in the instance
+ // field initialization info.
+ Value root = value.getAliasedValue();
+ if (root.isDefinedByInstructionSatisfying(Instruction::isArgument)) {
+ Argument argument = root.definition.asArgument();
+ builder.recordInitializationInfo(
+ field, factory.createArgumentInitializationInfo(argument.getArgumentIndex()));
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Argument.java b/src/main/java/com/android/tools/r8/ir/code/Argument.java
index 93c39ec..046af1b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Argument.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Argument.java
@@ -29,6 +29,20 @@
outValue.markAsArgument();
}
+ public int getArgumentIndex() {
+ int index = 0;
+ InstructionIterator instructionIterator = getBlock().iterator();
+ while (instructionIterator.hasNext()) {
+ Instruction instruction = instructionIterator.next();
+ assert instruction.isArgument();
+ if (instruction == this) {
+ break;
+ }
+ index++;
+ }
+ return index;
+ }
+
@Override
public int opcode() {
return Opcodes.ARGUMENT;
diff --git a/src/main/java/com/android/tools/r8/ir/code/Phi.java b/src/main/java/com/android/tools/r8/ir/code/Phi.java
index eecf8c3..95c2608 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Phi.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Phi.java
@@ -30,6 +30,7 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.function.Predicate;
public class Phi extends Value implements InstructionOrPhi {
@@ -62,6 +63,11 @@
}
@Override
+ public boolean isDefinedByInstructionSatisfying(Predicate<Instruction> predicate) {
+ return false;
+ }
+
+ @Override
public boolean isPhi() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index 8e75d62..e46aca6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -893,6 +893,10 @@
return root.definition.getAbstractValue(appView, context);
}
+ public boolean isDefinedByInstructionSatisfying(Predicate<Instruction> predicate) {
+ return predicate.test(definition);
+ }
+
public boolean isPhi() {
return false;
}
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 94df8fb..5c76d71 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
@@ -77,6 +77,7 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
import com.android.tools.r8.ir.optimize.lambda.LambdaMerger;
import com.android.tools.r8.ir.optimize.staticizer.ClassStaticizer;
import com.android.tools.r8.ir.optimize.string.StringBuilderOptimizer;
@@ -1563,18 +1564,19 @@
return;
}
- methodOptimizationInfoCollector
- .collectMethodOptimizationInfo(code.method, code, feedback, dynamicTypeOptimization);
-
+ InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos = null;
if (method.isInitializer()) {
if (method.isClassInitializer()) {
StaticFieldValueAnalysis.run(
appView, code, classInitializerDefaultsResult, feedback, code.method);
} else {
- InstanceFieldValueAnalysis.run(
- appView, code, classInitializerDefaultsResult, feedback, code.method);
+ instanceFieldInitializationInfos =
+ InstanceFieldValueAnalysis.run(
+ appView, code, classInitializerDefaultsResult, feedback, code.method);
}
}
+ methodOptimizationInfoCollector.collectMethodOptimizationInfo(
+ code.method, code, feedback, dynamicTypeOptimization, instanceFieldInitializationInfos);
}
public void removeDeadCodeAndFinalizeIR(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index d1a6c3a..b9345e9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -84,6 +84,7 @@
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerReceiverAnalysis;
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsageBuilder;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
import com.android.tools.r8.ir.optimize.info.initializer.DefaultInstanceInitializerInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
import com.android.tools.r8.ir.optimize.info.initializer.NonTrivialInstanceInitializerInfo;
@@ -120,7 +121,8 @@
DexEncodedMethod method,
IRCode code,
OptimizationFeedback feedback,
- DynamicTypeOptimization dynamicTypeOptimization) {
+ DynamicTypeOptimization dynamicTypeOptimization,
+ InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos) {
identifyClassInlinerEligibility(method, code, feedback);
identifyParameterUsages(method, code, feedback);
identifyReturnsArgument(method, code, feedback);
@@ -129,7 +131,7 @@
}
computeDynamicReturnType(dynamicTypeOptimization, feedback, method, code);
computeInitializedClassesOnNormalExit(feedback, method, code);
- computeInstanceInitializerInfo(method, code, feedback);
+ computeInstanceInitializerInfo(method, code, feedback, instanceFieldInitializationInfos);
computeMayHaveSideEffects(feedback, method, code);
computeReturnValueOnlyDependsOnArguments(feedback, method, code);
computeNonNullParamOrThrow(feedback, method, code);
@@ -354,13 +356,18 @@
}
private void computeInstanceInitializerInfo(
- DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
+ DexEncodedMethod method,
+ IRCode code,
+ OptimizationFeedback feedback,
+ InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos) {
assert !appView.appInfo().isPinned(method.method);
if (!method.isInstanceInitializer()) {
return;
}
+ assert instanceFieldInitializationInfos != null;
+
if (method.accessFlags.isNative()) {
return;
}
@@ -375,7 +382,10 @@
return;
}
- InstanceInitializerInfo instanceInitializerInfo = analyzeInstanceInitializer(code, clazz);
+ NonTrivialInstanceInitializerInfo.Builder builder =
+ NonTrivialInstanceInitializerInfo.builder(instanceFieldInitializationInfos);
+ InstanceInitializerInfo instanceInitializerInfo =
+ analyzeInstanceInitializer(code, clazz, builder);
feedback.setInstanceInitializerInfo(
method,
instanceInitializerInfo != null
@@ -398,13 +408,13 @@
// ** Assigns arguments or non-throwing constants to fields of this class.
//
// (Note that this initializer does not have to have zero arguments.)
- private InstanceInitializerInfo analyzeInstanceInitializer(IRCode code, DexClass clazz) {
+ private InstanceInitializerInfo analyzeInstanceInitializer(
+ IRCode code, DexClass clazz, NonTrivialInstanceInitializerInfo.Builder builder) {
if (clazz.definesFinalizer(options.itemFactory)) {
// Defining a finalize method can observe the side-effect of Object.<init> GC registration.
return null;
}
- NonTrivialInstanceInitializerInfo.Builder builder = NonTrivialInstanceInitializerInfo.builder();
Value receiver = code.getThis();
boolean hasCatchHandler = false;
for (BasicBlock block : code.blocks) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java
new file mode 100644
index 0000000..54a50fe
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/EmptyInstanceFieldInitializationInfoCollection.java
@@ -0,0 +1,34 @@
+// Copyright (c) 2020, 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.info.field;
+
+import com.android.tools.r8.graph.DexEncodedField;
+
+/**
+ * Represents that no information is known about the way a constructor initializes the instance
+ * fields of the newly created instance.
+ */
+public class EmptyInstanceFieldInitializationInfoCollection
+ extends InstanceFieldInitializationInfoCollection {
+
+ private static final EmptyInstanceFieldInitializationInfoCollection INSTANCE =
+ new EmptyInstanceFieldInitializationInfoCollection();
+
+ private EmptyInstanceFieldInitializationInfoCollection() {}
+
+ public static EmptyInstanceFieldInitializationInfoCollection getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public InstanceFieldInitializationInfo get(DexEncodedField field) {
+ return UnknownInstanceFieldInitializationInfo.getInstance();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java
new file mode 100644
index 0000000..c56c562
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldArgumentInitializationInfo.java
@@ -0,0 +1,33 @@
+// Copyright (c) 2020, 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.info.field;
+
+/**
+ * Used to represent that a constructor initializes an instance field on the newly created instance
+ * with argument number {@link #argumentIndex} from the constructor's argument list.
+ */
+public class InstanceFieldArgumentInitializationInfo extends InstanceFieldInitializationInfo {
+
+ private final int argumentIndex;
+
+ /** Intentionally package private, use {@link InstanceFieldInitializationInfoFactory} instead. */
+ InstanceFieldArgumentInitializationInfo(int argumentIndex) {
+ this.argumentIndex = argumentIndex;
+ }
+
+ public int getArgumentIndex() {
+ return argumentIndex;
+ }
+
+ @Override
+ public boolean isArgumentInitializationInfo() {
+ return true;
+ }
+
+ @Override
+ public InstanceFieldArgumentInitializationInfo asArgumentInitializationInfo() {
+ return this;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java
new file mode 100644
index 0000000..312d7a0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfo.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2020, 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.info.field;
+
+/**
+ * Information about the way a constructor initializes an instance field on the newly created
+ * instance.
+ *
+ * <p>For example, this can be used to represent that a constructor always initializes a particular
+ * instance field with a constant, or with an argument from the constructor's argument list.
+ */
+public abstract class InstanceFieldInitializationInfo {
+
+ public boolean isArgumentInitializationInfo() {
+ return false;
+ }
+
+ public InstanceFieldArgumentInitializationInfo asArgumentInitializationInfo() {
+ return null;
+ }
+
+ public boolean isUnknown() {
+ return false;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java
new file mode 100644
index 0000000..4912d46
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoCollection.java
@@ -0,0 +1,46 @@
+// Copyright (c) 2020, 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.info.field;
+
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexField;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+/**
+ * A mapping from instance fields of a class to information about how a particular constructor
+ * initializes these instance fields.
+ *
+ * <p>Returns {@link UnknownInstanceFieldInitializationInfo} if no information is known about the
+ * initialization of a given instance field.
+ */
+public abstract class InstanceFieldInitializationInfoCollection {
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public abstract InstanceFieldInitializationInfo get(DexEncodedField field);
+
+ public abstract boolean isEmpty();
+
+ public static class Builder {
+
+ Map<DexField, InstanceFieldInitializationInfo> infos = new IdentityHashMap<>();
+
+ public void recordInitializationInfo(
+ DexEncodedField field, InstanceFieldInitializationInfo info) {
+ assert !infos.containsKey(field.field);
+ infos.put(field.field, info);
+ }
+
+ public InstanceFieldInitializationInfoCollection build() {
+ if (infos.isEmpty()) {
+ return EmptyInstanceFieldInitializationInfoCollection.getInstance();
+ }
+ return new NonTrivialInstanceFieldInitializationInfoCollection(infos);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoFactory.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoFactory.java
new file mode 100644
index 0000000..42209b4
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldInitializationInfoFactory.java
@@ -0,0 +1,19 @@
+// Copyright (c) 2020, 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.info.field;
+
+import java.util.concurrent.ConcurrentHashMap;
+
+public class InstanceFieldInitializationInfoFactory {
+
+ private ConcurrentHashMap<Integer, InstanceFieldArgumentInitializationInfo>
+ argumentInitializationInfos = new ConcurrentHashMap<>();
+
+ public InstanceFieldArgumentInitializationInfo createArgumentInitializationInfo(
+ int argumentIndex) {
+ return argumentInitializationInfos.computeIfAbsent(
+ argumentIndex, InstanceFieldArgumentInitializationInfo::new);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
new file mode 100644
index 0000000..bdaaf78
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/NonTrivialInstanceFieldInitializationInfoCollection.java
@@ -0,0 +1,33 @@
+// Copyright (c) 2020, 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.info.field;
+
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexField;
+import java.util.Map;
+
+/** See {@link InstanceFieldArgumentInitializationInfo}. */
+public class NonTrivialInstanceFieldInitializationInfoCollection
+ extends InstanceFieldInitializationInfoCollection {
+
+ private final Map<DexField, InstanceFieldInitializationInfo> infos;
+
+ NonTrivialInstanceFieldInitializationInfoCollection(
+ Map<DexField, InstanceFieldInitializationInfo> infos) {
+ assert !infos.isEmpty();
+ assert infos.values().stream().noneMatch(InstanceFieldInitializationInfo::isUnknown);
+ this.infos = infos;
+ }
+
+ @Override
+ public InstanceFieldInitializationInfo get(DexEncodedField field) {
+ return infos.getOrDefault(field.field, UnknownInstanceFieldInitializationInfo.getInstance());
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java
new file mode 100644
index 0000000..66e882e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/UnknownInstanceFieldInitializationInfo.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2020, 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.info.field;
+
+/**
+ * Represents that no information is known about the way a particular constructor initializes an
+ * instance field of the newly created instance.
+ */
+public class UnknownInstanceFieldInitializationInfo extends InstanceFieldInitializationInfo {
+
+ private static final UnknownInstanceFieldInitializationInfo INSTANCE =
+ new UnknownInstanceFieldInitializationInfo();
+
+ private UnknownInstanceFieldInitializationInfo() {}
+
+ public static UnknownInstanceFieldInitializationInfo getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public boolean isUnknown() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java
index ef3ca08..20aff53 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/DefaultInstanceInitializerInfo.java
@@ -7,6 +7,8 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.UnknownFieldSet;
+import com.android.tools.r8.ir.optimize.info.field.EmptyInstanceFieldInitializationInfoCollection;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
public class DefaultInstanceInitializerInfo extends InstanceInitializerInfo {
@@ -30,6 +32,11 @@
}
@Override
+ public InstanceFieldInitializationInfoCollection fieldInitializationInfos() {
+ return EmptyInstanceFieldInitializationInfoCollection.getInstance();
+ }
+
+ @Override
public AbstractFieldSet readSet() {
return UnknownFieldSet.getInstance();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java
index 5452bce..b27888e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/InstanceInitializerInfo.java
@@ -6,11 +6,14 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.AbstractFieldSet;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
public abstract class InstanceInitializerInfo {
public abstract DexMethod getParent();
+ public abstract InstanceFieldInitializationInfoCollection fieldInitializationInfos();
+
/**
* Returns an abstraction of the set of fields that may be as a result of executing this
* initializer.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java
index 70017cc..4e19cef 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/initializer/NonTrivialInstanceInitializerInfo.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.ConcreteMutableFieldSet;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.EmptyFieldSet;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.UnknownFieldSet;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
public final class NonTrivialInstanceInitializerInfo extends InstanceInitializerInfo {
@@ -18,12 +19,18 @@
private static final int RECEIVER_NEVER_ESCAPE_OUTSIDE_CONSTRUCTOR_CHAIN = 1 << 2;
private final int data;
+ private final InstanceFieldInitializationInfoCollection fieldInitializationInfos;
private final AbstractFieldSet readSet;
private final DexMethod parent;
- private NonTrivialInstanceInitializerInfo(int data, AbstractFieldSet readSet, DexMethod parent) {
+ private NonTrivialInstanceInitializerInfo(
+ int data,
+ InstanceFieldInitializationInfoCollection fieldInitializationInfos,
+ AbstractFieldSet readSet,
+ DexMethod parent) {
assert verifyNoUnknownBits(data);
this.data = data;
+ this.fieldInitializationInfos = fieldInitializationInfos;
this.readSet = readSet;
this.parent = parent;
}
@@ -37,8 +44,9 @@
return true;
}
- public static Builder builder() {
- return new Builder();
+ public static Builder builder(
+ InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos) {
+ return new Builder(instanceFieldInitializationInfos);
}
@Override
@@ -47,6 +55,11 @@
}
@Override
+ public InstanceFieldInitializationInfoCollection fieldInitializationInfos() {
+ return fieldInitializationInfos;
+ }
+
+ @Override
public AbstractFieldSet readSet() {
return readSet;
}
@@ -68,6 +81,8 @@
public static class Builder {
+ private final InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos;
+
private int data =
INSTANCE_FIELD_INITIALIZATION_INDEPENDENT_OF_ENVIRONMENT
| NO_OTHER_SIDE_EFFECTS_THAN_INSTANCE_FIELD_ASSIGNMENTS
@@ -75,8 +90,15 @@
private AbstractFieldSet readSet = EmptyFieldSet.getInstance();
private DexMethod parent;
+ public Builder(InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos) {
+ this.instanceFieldInitializationInfos = instanceFieldInitializationInfos;
+ }
+
private boolean isTrivial() {
- return data == 0 && readSet.isTop() && parent == null;
+ return instanceFieldInitializationInfos.isEmpty()
+ && data == 0
+ && readSet.isTop()
+ && parent == null;
}
public Builder markFieldAsRead(DexEncodedField field) {
@@ -158,7 +180,8 @@
public InstanceInitializerInfo build() {
return isTrivial()
? DefaultInstanceInitializerInfo.getInstance()
- : new NonTrivialInstanceInitializerInfo(data, readSet, parent);
+ : new NonTrivialInstanceInitializerInfo(
+ data, instanceFieldInitializationInfos, readSet, parent);
}
}
}