[KeepAnno] Make keep annotations available to the enqueuer
Bug: b/323816623
Change-Id: I986f2322dc3ab7f7d6eeb2a274eb9270e57d98db
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
index 01d57c7..85f651f 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeReader.java
@@ -529,7 +529,7 @@
}
}
- private static class ExtractedAnnotationsVisitor extends AnnotationVisitorBase {
+ public static class ExtractedAnnotationsVisitor extends AnnotationVisitorBase {
private final Parent<KeepDeclaration> parent;
private List<KeepDeclaration> declarations = new ArrayList<>();
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
index a0a98c7..7f8bdde 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/asm/KeepEdgeWriter.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.keepanno.ast.KeepAnnotationPattern;
import com.android.tools.r8.keepanno.ast.KeepBindingReference;
import com.android.tools.r8.keepanno.ast.KeepBindings;
+import com.android.tools.r8.keepanno.ast.KeepCheck;
import com.android.tools.r8.keepanno.ast.KeepClassItemPattern;
import com.android.tools.r8.keepanno.ast.KeepClassItemReference;
import com.android.tools.r8.keepanno.ast.KeepConsequences;
@@ -149,26 +150,25 @@
KeepEdgeMetaInfo metaInfo = decl.getMetaInfo();
visitor.visit(ExtractedAnnotation.version, metaInfo.getVersion().toVersionString());
visitor.visit(ExtractedAnnotation.context, metaInfo.getContextDescriptorString());
- decl.match(
- edge -> {
- withNewVisitor(
- visitor.visitAnnotation(ExtractedAnnotation.edge, Edge.DESCRIPTOR),
- v -> new KeepEdgeWriter().writeEdge(edge, v));
- return null;
- },
- check -> {
- switch (check.getKind()) {
- case REMOVED:
- visitor.visit(ExtractedAnnotation.checkRemoved, true);
- break;
- case OPTIMIZED_OUT:
- visitor.visit(ExtractedAnnotation.checkOptimizedOut, true);
- break;
- default:
- throw new KeepEdgeException("Unexpected keep check kind: " + check.getKind());
- }
- return null;
- });
+ if (decl.isKeepEdge()) {
+ KeepEdge edge = decl.asKeepEdge();
+ withNewVisitor(
+ visitor.visitAnnotation(ExtractedAnnotation.edge, Edge.DESCRIPTOR),
+ v -> new KeepEdgeWriter().writeEdge(edge, v));
+ return;
+ }
+ assert decl.isKeepCheck();
+ KeepCheck check = decl.asKeepCheck();
+ switch (check.getKind()) {
+ case REMOVED:
+ visitor.visit(ExtractedAnnotation.checkRemoved, true);
+ break;
+ case OPTIMIZED_OUT:
+ visitor.visit(ExtractedAnnotation.checkOptimizedOut, true);
+ break;
+ default:
+ throw new KeepEdgeException("Unexpected keep check kind: " + check.getKind());
+ }
}
private void writeEdge(KeepEdge edge, AnnotationVisitor visitor) {
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 3e3c0ca..0b8ab6c 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -59,6 +59,7 @@
import com.android.tools.r8.ir.optimize.templates.CfUtilityMethodsForCodeOptimizations;
import com.android.tools.r8.jar.CfApplicationWriter;
import com.android.tools.r8.keepanno.annotations.KeepForApi;
+import com.android.tools.r8.keepanno.ast.KeepDeclaration;
import com.android.tools.r8.kotlin.KotlinMetadataRewriter;
import com.android.tools.r8.kotlin.KotlinMetadataUtils;
import com.android.tools.r8.naming.IdentifierMinifier;
@@ -281,10 +282,12 @@
timing.end();
try {
AppView<AppInfoWithClassHierarchy> appView;
+ List<KeepDeclaration> keepDeclarations;
{
timing.begin("Read app");
ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing);
LazyLoadedDexApplication lazyLoaded = applicationReader.read(executorService);
+ keepDeclarations = lazyLoaded.getKeepDeclarations();
timing.begin("To direct app");
DirectMappedDexApplication application = lazyLoaded.toDirect();
timing.end();
@@ -389,7 +392,8 @@
appView,
profileCollectionAdditions,
subtypingInfo,
- initialRuntimeTypeCheckInfoBuilder);
+ initialRuntimeTypeCheckInfoBuilder,
+ keepDeclarations);
timing.end();
timing.begin("After enqueuer");
assert appView.rootSet().verifyKeptFieldsAreAccessedAndLive(appViewWithLiveness);
@@ -1108,12 +1112,14 @@
AppView<AppInfoWithClassHierarchy> appView,
ProfileCollectionAdditions profileCollectionAdditions,
SubtypingInfo subtypingInfo,
- RuntimeTypeCheckInfo.Builder classMergingEnqueuerExtensionBuilder)
+ RuntimeTypeCheckInfo.Builder classMergingEnqueuerExtensionBuilder,
+ List<KeepDeclaration> keepDeclarations)
throws ExecutionException {
timing.begin("Set up enqueuer");
Enqueuer enqueuer =
EnqueuerFactory.createForInitialTreeShaking(
appView, profileCollectionAdditions, executorService, subtypingInfo);
+ enqueuer.setKeepDeclarations(keepDeclarations);
enqueuer.setAnnotationRemoverBuilder(annotationRemoverBuilder);
if (appView.options().enableInitializedClassesInInstanceMethodsAnalysis) {
enqueuer.registerAnalysis(new InitializedClassesInInstanceMethodsAnalysis(appView));
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index e3d2f78..04ff802 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -503,6 +503,9 @@
if (libraryClassProvider != null) {
builder.setLibraryClassCollection(new LibraryClassCollection(libraryClassProvider));
}
+
+ // Transfer the keep declarations found during reading.
+ builder.setKeepDeclarations(application.getKeepDeclarations());
}
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java b/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
index 2c4ce38..d6c5bdf 100644
--- a/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
@@ -6,8 +6,10 @@
import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
import com.android.tools.r8.ir.desugar.records.RecordDesugaring;
import com.android.tools.r8.ir.desugar.varhandle.VarHandleDesugaring;
+import com.android.tools.r8.keepanno.ast.KeepDeclaration;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.objectweb.asm.Type;
@@ -27,6 +29,7 @@
private final ConcurrentHashMap<String, DexString> stringCache = new ConcurrentHashMap<>();
private final ApplicationReaderMap applicationReaderMap;
private final DexApplicationReadFlags.Builder readFlagsBuilder;
+ private final List<KeepDeclaration> keepDeclarations = new ArrayList<>();
public JarApplicationReader(
InternalOptions options, DexApplicationReadFlags.Builder readFlagsBuilder) {
@@ -39,6 +42,16 @@
this(options, DexApplicationReadFlags.builder());
}
+ public void addKeepDeclaration(KeepDeclaration declaration) {
+ synchronized (keepDeclarations) {
+ keepDeclarations.add(declaration);
+ }
+ }
+
+ public List<KeepDeclaration> getKeepDeclarations() {
+ return keepDeclarations;
+ }
+
public Type getAsmObjectType(String name) {
return asmObjectTypeCache.computeIfAbsent(name, Type::getObjectType);
}
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 05c265a..978932d 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -35,6 +35,9 @@
import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.jar.CfApplicationWriter;
+import com.android.tools.r8.keepanno.asm.KeepEdgeReader.ExtractedAnnotationsVisitor;
+import com.android.tools.r8.keepanno.ast.AnnotationConstants.ExtractedAnnotations;
+import com.android.tools.r8.keepanno.ast.ParsingContext.ClassParsingContext;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.synthesis.SyntheticMarker;
import com.android.tools.r8.utils.AsmUtils;
@@ -452,6 +455,17 @@
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ if (!visible && ExtractedAnnotations.DESCRIPTOR.equals(desc)) {
+ if (!application.options.testing.enableExtractedKeepAnnotations) {
+ return null;
+ }
+ if (classKind != ClassKind.PROGRAM) {
+ return null;
+ }
+ return new ExtractedAnnotationsVisitor(
+ new ClassParsingContext(type.getName()).annotation(desc),
+ application::addKeepDeclaration);
+ }
return createAnnotationVisitor(
desc, visible, getAnnotations(), application, DexAnnotation::new);
}
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
index 897d908..0fc1f96 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.DataResourceProvider;
import com.android.tools.r8.dex.ApplicationReader.ProgramClassConflictResolver;
+import com.android.tools.r8.keepanno.ast.KeepDeclaration;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.ClasspathClassCollection;
import com.android.tools.r8.utils.InternalOptions;
@@ -17,6 +18,7 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -30,6 +32,7 @@
private final ProgramClassCollection programClasses;
private final ClasspathClassCollection classpathClasses;
private final LibraryClassCollection libraryClasses;
+ private final List<KeepDeclaration> keepDeclarations;
/** Constructor should only be invoked by the DexApplication.Builder. */
private LazyLoadedDexApplication(
@@ -39,12 +42,18 @@
ImmutableList<DataResourceProvider> dataResourceProviders,
ClasspathClassCollection classpathClasses,
LibraryClassCollection libraryClasses,
+ List<KeepDeclaration> keepDeclarations,
InternalOptions options,
Timing timing) {
super(proguardMap, flags, dataResourceProviders, options, timing);
this.programClasses = programClasses;
this.classpathClasses = classpathClasses;
this.libraryClasses = libraryClasses;
+ this.keepDeclarations = keepDeclarations;
+ }
+
+ public List<KeepDeclaration> getKeepDeclarations() {
+ return keepDeclarations;
}
@Override
@@ -252,6 +261,7 @@
private ClasspathClassCollection classpathClasses;
private LibraryClassCollection libraryClasses;
+ private List<KeepDeclaration> keepDeclarations = Collections.emptyList();
Builder(InternalOptions options, Timing timing) {
super(options, timing);
@@ -280,6 +290,11 @@
return this;
}
+ public Builder setKeepDeclarations(List<KeepDeclaration> declarations) {
+ this.keepDeclarations = declarations;
+ return this;
+ }
+
@Override
public void addProgramClassPotentiallyOverridingNonProgramClass(DexProgramClass clazz) {
addProgramClass(clazz);
@@ -300,6 +315,7 @@
ImmutableList.copyOf(dataResourceProviders),
classpathClasses,
libraryClasses,
+ keepDeclarations,
options,
timing);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 34cb2ec..3fa01e0 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -29,6 +29,7 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.code.CfOrDexInstruction;
import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
+import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.features.IsolatedFeatureSplitsChecker;
@@ -129,6 +130,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.itf.InterfaceMethodProcessorFacade;
import com.android.tools.r8.ir.desugar.itf.InterfaceProcessor;
+import com.android.tools.r8.keepanno.ast.KeepDeclaration;
import com.android.tools.r8.kotlin.KotlinMetadataEnqueuerExtension;
import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringLookupResult;
import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringTypeLookupResult;
@@ -289,6 +291,8 @@
private final Set<DexMember<?, ?>> identifierNameStrings = Sets.newIdentityHashSet();
+ private List<KeepDeclaration> keepDeclarations = Collections.emptyList();
+
/**
* Tracks the dependency between a method and the super-method it calls, if any. Used to make
* super methods become live when they become reachable from a live sub-method.
@@ -642,6 +646,13 @@
.registerNewInstanceAnalysis(analysis);
}
+ public void setKeepDeclarations(List<KeepDeclaration> keepDeclarations) {
+ // Keep declarations are used during initial tree shaking. Re-runs use the rule instance sets.
+ assert mode.isInitialTreeShaking();
+ assert keepDeclarations != null;
+ this.keepDeclarations = keepDeclarations;
+ }
+
public void setAnnotationRemoverBuilder(AnnotationRemover.Builder annotationRemoverBuilder) {
this.annotationRemoverBuilder = annotationRemoverBuilder;
}
@@ -3700,6 +3711,9 @@
rootSet.pendingMethodMoveInverse.forEach(pendingMethodMoveInverse::put);
// Translate the result of root-set computation into enqueuer actions.
timing.begin("Register analysis");
+ // TODO(b/323816623): This check does not include presence of keep declarations.
+ // The non-presense of PG config seems like a exeedingly rare corner case so maybe just
+ // make this conditional on tree shaking and the specific option flag.
if (mode.isTreeShaking()
&& appView.options().hasProguardConfiguration()
&& !options.kotlinOptimizationOptions().disableKotlinSpecificOptimizations) {
@@ -3707,6 +3721,9 @@
new KotlinMetadataEnqueuerExtension(
appView, enqueuerDefinitionSupplier, initialPrunedTypes));
}
+ // TODO(b/323816623): This check does not include presence of keep declarations.
+ // We should consider if we should always run the signature analysis and just not emit them
+ // in the end?
if (appView.options().getProguardConfiguration() != null
&& appView.options().getProguardConfiguration().getKeepAttributes().signature) {
registerAnalysis(new GenericSignatureEnqueuerAnalysis(enqueuerDefinitionSupplier));
@@ -3722,6 +3739,10 @@
timing.end();
if (mode.isInitialTreeShaking()) {
+ // TODO(b/323816623): Start native interpretation here...
+ if (!keepDeclarations.isEmpty()) {
+ throw new Unimplemented("Native support for keep annotaitons pending");
+ }
// Amend library methods with covariant return types.
timing.begin("Model library");
modelLibraryMethodsWithCovariantReturnTypes(appView);
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index c120ac1..f116aef 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -2175,6 +2175,8 @@
public static class TestingOptions {
+ public boolean enableExtractedKeepAnnotations = false;
+
public boolean enableNumberUnboxer = false;
public boolean printNumberUnboxed = false;
public boolean roundtripThroughLir = false;