Collect missing class references from D8 part of R8 partial
The missing class references are only collected when assertions are enabled.
Bug: b/391572031
Change-Id: Idf4af12bf2702b21d8f6501ac6ce1ff10fe063a7
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java b/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
index a5cd867..5ea8d60 100644
--- a/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
@@ -24,7 +24,6 @@
import com.android.tools.r8.profile.art.ArtProfileCollection;
import com.android.tools.r8.profile.art.ArtProfileMethodRule;
import com.android.tools.r8.profile.startup.profile.StartupProfile;
-import com.android.tools.r8.shaking.MissingClasses;
import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.MapUtils;
@@ -36,6 +35,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
public abstract class R8PartialSubCompilationConfiguration {
@@ -187,6 +187,14 @@
private List<KeepDeclaration> keepDeclarations;
private StartupProfile startupProfile;
+ // Stores the missing class references from the D8 compilation unit in R8 partial.
+ // We use this to ensure that calling AppInfoWithLiveness#definitionFor does not fail
+ // when looking up a missing class type from the D8 part (which happens during library
+ // desugaring).
+ //
+ // Always empty when assertions are disabled.
+ public final Set<DexType> d8MissingClasses = ConcurrentHashMap.newKeySet();
+
public R8PartialR8SubCompilationConfiguration(
ArtProfileCollection artProfiles,
ClassToFeatureSplitMap classToFeatureSplitMap,
@@ -255,7 +263,6 @@
.addProgramClasses(dexingOutputClasses.values())
.build();
appView.rebuildAppInfo(newApp);
- assert amendMissingClasses(appView);
}
public void uncommitDexingOutputClasses(AppView<? extends AppInfoWithClassHierarchy> appView) {
@@ -272,7 +279,6 @@
.addClasspathClasses(newClasspathClasses)
.build();
appView.rebuildAppInfo(newApp);
- assert amendMissingClasses(appView);
}
public boolean hasD8DefinitionFor(DexReference reference) {
@@ -289,24 +295,6 @@
return hasD8DefinitionFor(definition.getReference());
}
- private boolean amendMissingClasses(AppView<? extends AppInfoWithClassHierarchy> appView) {
- if (appView.hasLiveness()) {
- MissingClasses.Builder missingClassesBuilder =
- appView.appInfo().getMissingClasses().builder();
- for (DexProgramClass clazz : dexingOutputClasses.values()) {
- clazz.forEachImmediateSuperClassMatching(
- appView.app(),
- (supertype, superclass) -> superclass == null,
- (supertype, superclass) ->
- missingClassesBuilder.addNewMissingClass(supertype, clazz));
- }
- appView
- .appInfoWithLiveness()
- .setMissingClasses(missingClassesBuilder.ignoreMissingClasses());
- }
- return true;
- }
-
@Override
public boolean isR8() {
return true;
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialUseCollector.java b/src/main/java/com/android/tools/r8/partial/R8PartialUseCollector.java
index bb8af7d..a871664 100644
--- a/src/main/java/com/android/tools/r8/partial/R8PartialUseCollector.java
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialUseCollector.java
@@ -116,7 +116,7 @@
@Override
public void acceptType(TracedClass tracedClass, DiagnosticsHandler handler) {
- assert tracedClass.isMissingDefinition();
+ assert false;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index d98e17f..110abf1 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -56,6 +56,7 @@
import com.android.tools.r8.ir.code.InvokeType;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
import com.android.tools.r8.naming.SeedMapper;
+import com.android.tools.r8.partial.R8PartialSubCompilationConfiguration;
import com.android.tools.r8.repackaging.RepackagingUtils;
import com.android.tools.r8.shaking.KeepInfo.Joiner;
import com.android.tools.r8.synthesis.CommittedItems;
@@ -523,11 +524,15 @@
@Override
public DexClass definitionFor(DexType type) {
DexClass definition = super.definitionFor(type);
+ R8PartialSubCompilationConfiguration subCompilationConfiguration =
+ options().partialSubCompilationConfiguration;
assert definition != null
|| deadProtoTypes.contains(type)
|| getMissingClasses().contains(type)
// TODO(b/150736225): Not sure how to remove these.
|| isVivifiedType(type)
+ || (subCompilationConfiguration != null
+ && subCompilationConfiguration.asR8().d8MissingClasses.contains(type))
: "Failed lookup of non-missing type: " + type;
return definition;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 6eec044..5eab51c 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -9,6 +9,7 @@
import static java.util.Collections.emptyMap;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.diagnostic.DefinitionContext;
import com.android.tools.r8.errors.AssumeNoSideEffectsRuleForObjectMembersDiagnostic;
import com.android.tools.r8.errors.AssumeValuesMissingStaticFieldDiagnostic;
import com.android.tools.r8.errors.InlinableStaticFinalFieldPreconditionDiagnostic;
@@ -258,6 +259,20 @@
rootLibraryTypes.add(definition.getContextType());
}
}
+
+ @Override
+ protected void notifyMissingClass(DexType type, DefinitionContext referencedFrom) {
+ assert recordMissingClassWhenAssertionsEnabled(type);
+ }
+
+ private boolean recordMissingClassWhenAssertionsEnabled(DexType type) {
+ // Record missing class references from the D8 compilation unit in R8 partial.
+ // We use this to ensure that calling AppInfoWithLiveness#definitionFor does not fail
+ // when looking up a missing class type from the D8 part (which happens during library
+ // desugaring).
+ options.partialSubCompilationConfiguration.asR8().d8MissingClasses.add(type);
+ return true;
+ }
};
useCollector.run(executorService);
diff --git a/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java b/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
index 6bcaf98..257ff73 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/UseCollector.java
@@ -113,6 +113,12 @@
consumer.acceptType(tracedClass, diagnostics);
}
+ protected void notifyMissingClass(DexType type, DefinitionContext referencedFrom) {
+ TracedClassImpl missingClass = new TracedClassImpl(type, referencedFrom);
+ collectMissingClass(missingClass);
+ consumer.acceptType(missingClass, diagnostics);
+ }
+
protected void notifyPresentField(DexClassAndField field, DefinitionContext referencedFrom) {
TracedFieldImpl tracedField = new TracedFieldImpl(field, referencedFrom);
consumer.acceptField(tracedField, diagnostics);
@@ -176,9 +182,7 @@
if (result.hasClassResolutionResult()) {
result.forEachClassResolutionResult(resolvedClassesConsumer);
} else {
- TracedClassImpl missingClass = new TracedClassImpl(type, referencedFrom);
- collectMissingClass(missingClass);
- consumer.acceptType(missingClass, diagnostics);
+ notifyMissingClass(type, referencedFrom);
}
}
@@ -630,9 +634,7 @@
}
});
} else {
- TracedClassImpl missingClass = new TracedClassImpl(interfaceType, referencedFrom);
- collectMissingClass(missingClass);
- consumer.acceptType(missingClass, diagnostics);
+ notifyMissingClass(interfaceType, referencedFrom);
}
}
}