Record that singleton fields from lambda merger are definitely-not-null
Change-Id: I01d73730c6dcf0af6a1536000560680dd96d5bfd
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
index ae5e066..f7d423e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
@@ -13,9 +13,9 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.lambda.CodeProcessor.Strategy;
import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThrowingConsumer;
import com.google.common.collect.Lists;
import com.google.common.io.BaseEncoding;
@@ -163,19 +163,22 @@
protected abstract String getGroupSuffix();
- final DexProgramClass synthesizeClass(InternalOptions options) {
+ final DexProgramClass synthesizeClass(
+ AppView<? extends AppInfoWithSubtyping> appView, OptimizationFeedback feedback) {
assert classType == null;
assert verifyLambdaIds(true);
List<LambdaInfo> lambdas = Lists.newArrayList(this.lambdas.values());
classType =
- options.itemFactory.createType(
- "L"
- + getTypePackage()
- + "-$$LambdaGroup$"
- + getGroupSuffix()
- + createHash(lambdas)
- + ";");
- return getBuilder(options.itemFactory).synthesizeClass(options);
+ appView
+ .dexItemFactory()
+ .createType(
+ "L"
+ + getTypePackage()
+ + "-$$LambdaGroup$"
+ + getGroupSuffix()
+ + createHash(lambdas)
+ + ";");
+ return getBuilder(appView.dexItemFactory()).synthesizeClass(appView, feedback);
}
protected abstract LambdaGroupClassBuilder getBuilder(DexItemFactory factory);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
index e569714..2c4315c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroupClassBuilder.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.ir.optimize.lambda;
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexEncodedField;
@@ -14,8 +16,8 @@
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.InnerClassAttribute;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.origin.SynthesizedOrigin;
-import com.android.tools.r8.utils.InternalOptions;
import java.util.Collections;
import java.util.List;
@@ -32,7 +34,8 @@
this.origin = origin;
}
- public final DexProgramClass synthesizeClass(InternalOptions options) {
+ public final DexProgramClass synthesizeClass(
+ AppView<? extends AppInfoWithSubtyping> appView, OptimizationFeedback feedback) {
DexType groupClassType = group.getGroupClassType();
DexType superClassType = getSuperClassType();
DexProgramClass programClass =
@@ -49,7 +52,7 @@
buildEnclosingMethodAttribute(),
buildInnerClasses(),
buildAnnotations(),
- buildStaticFields(),
+ buildStaticFields(appView, feedback),
buildInstanceFields(),
buildDirectMethods(),
buildVirtualMethods(),
@@ -75,7 +78,8 @@
protected abstract DexEncodedField[] buildInstanceFields();
- protected abstract DexEncodedField[] buildStaticFields();
+ protected abstract DexEncodedField[] buildStaticFields(
+ AppView<? extends AppInfoWithSubtyping> appView, OptimizationFeedback feedback);
protected abstract DexTypeList buildInterfaces();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index 3bb09ce..9981290 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -326,7 +326,7 @@
// Remove invalidated lambdas, compact groups to ensure
// sequential lambda ids, create group lambda classes.
- BiMap<LambdaGroup, DexProgramClass> lambdaGroupsClasses = finalizeLambdaGroups();
+ BiMap<LambdaGroup, DexProgramClass> lambdaGroupsClasses = finalizeLambdaGroups(feedback);
// Fixup optimization info to ensure that the optimization info does not refer to any merged
// lambdas.
@@ -388,7 +388,7 @@
ThreadUtils.awaitFutures(futures);
}
- private BiMap<LambdaGroup, DexProgramClass> finalizeLambdaGroups() {
+ private BiMap<LambdaGroup, DexProgramClass> finalizeLambdaGroups(OptimizationFeedback feedback) {
for (DexType lambda : invalidatedLambdas) {
LambdaGroup group = lambdas.get(lambda);
assert group != null;
@@ -405,7 +405,7 @@
for (LambdaGroup group : groups.values()) {
assert !group.isTrivial() : "No trivial group is expected here.";
group.compact();
- DexProgramClass lambdaGroupClass = group.synthesizeClass(appView.options());
+ DexProgramClass lambdaGroupClass = group.synthesizeClass(appView, feedback);
result.put(group, lambdaGroupClass);
}
return result;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupClassBuilder.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupClassBuilder.java
index 15d4160..74a5236 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupClassBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupClassBuilder.java
@@ -4,11 +4,16 @@
package com.android.tools.r8.ir.optimize.lambda.kotlin;
+import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
+
+import com.android.tools.r8.graph.AppInfoWithSubtyping;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
@@ -20,7 +25,9 @@
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.ir.analysis.type.ClassTypeLatticeElement;
import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.lambda.LambdaGroupClassBuilder;
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
@@ -212,18 +219,30 @@
}
@Override
- protected DexEncodedField[] buildStaticFields() {
+ protected DexEncodedField[] buildStaticFields(
+ AppView<? extends AppInfoWithSubtyping> appView, OptimizationFeedback feedback) {
if (!group.isStateless()) {
return DexEncodedField.EMPTY_ARRAY;
}
// One field for each singleton lambda in the group.
List<DexEncodedField> result = new ArrayList<>(group.size());
- group.forEachLambda(info -> {
- if (group.isSingletonLambda(info.clazz.type)) {
- result.add(new DexEncodedField(group.getSingletonInstanceField(factory, info.id),
- SINGLETON_FIELD_FLAGS, DexAnnotationSet.empty(), DexValueNull.NULL));
- }
- });
+ group.forEachLambda(
+ info -> {
+ if (group.isSingletonLambda(info.clazz.type)) {
+ DexField field = group.getSingletonInstanceField(factory, info.id);
+ DexEncodedField encodedField =
+ new DexEncodedField(
+ field, SINGLETON_FIELD_FLAGS, DexAnnotationSet.empty(), DexValueNull.NULL);
+ result.add(encodedField);
+
+ // Record that the field is definitely not null. It is guaranteed to be assigned in the
+ // class initializer of the enclosing class before it is read.
+ ClassTypeLatticeElement exactType =
+ ClassTypeLatticeElement.create(field.type, definitelyNotNull(), appView);
+ feedback.markFieldHasDynamicLowerBoundType(encodedField, exactType);
+ feedback.markFieldHasDynamicUpperBoundType(encodedField, exactType);
+ }
+ });
assert result.isEmpty() == !group.hasAnySingletons();
return result.toArray(DexEncodedField.EMPTY_ARRAY);
}