Initial support for rewriting baseline profiles in R8
Bug: b/237043695
Change-Id: Ib7d355d674222ee24a5fca0664897f199f7c79bc
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 3bd5968..093b08d 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -64,6 +64,7 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OriginalSourceFiles;
import com.android.tools.r8.utils.PredicateUtils;
+import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ThreadUtils;
@@ -594,16 +595,21 @@
public static void supplyAdditionalConsumers(AppView<?> appView) {
InternalOptions options = appView.options();
+ Reporter reporter = options.reporter;
+ if (appView.hasClassHierarchy()) {
+ appView.appInfoWithClassHierarchy().getArtProfiles().supplyConsumers(appView);
+ }
if (options.configurationConsumer != null) {
ExceptionUtils.withConsumeResourceHandler(
- options.reporter, options.configurationConsumer,
+ reporter,
+ options.configurationConsumer,
options.getProguardConfiguration().getParsedConfiguration());
- ExceptionUtils.withFinishedResourceHandler(options.reporter, options.configurationConsumer);
+ ExceptionUtils.withFinishedResourceHandler(reporter, options.configurationConsumer);
}
if (options.mainDexListConsumer != null) {
ExceptionUtils.withConsumeResourceHandler(
- options.reporter, options.mainDexListConsumer, writeMainDexList(appView));
- ExceptionUtils.withFinishedResourceHandler(options.reporter, options.mainDexListConsumer);
+ reporter, options.mainDexListConsumer, writeMainDexList(appView));
+ ExceptionUtils.withFinishedResourceHandler(reporter, options.mainDexListConsumer);
}
KotlinModuleSynthesizer kotlinModuleSynthesizer = new KotlinModuleSynthesizer(appView);
@@ -642,13 +648,13 @@
.getBytes(),
AppServices.SERVICE_DIRECTORY_NAME + serviceName,
Origin.unknown()),
- options.reporter);
+ reporter);
});
}
// Rewrite/synthesize kotlin_module files
kotlinModuleSynthesizer
.synthesizeKotlinModuleFiles()
- .forEach(file -> dataResourceConsumer.accept(file, options.reporter));
+ .forEach(file -> dataResourceConsumer.accept(file, reporter));
}
if (options.featureSplitConfiguration != null) {
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java
index 01f91e0..531c50e 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupOptions.java
@@ -7,7 +7,6 @@
import static com.android.tools.r8.utils.SystemPropertyUtils.parseSystemPropertyForDevelopmentOrDefault;
import com.android.tools.r8.startup.StartupProfileProvider;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.SystemPropertyUtils;
import com.google.common.collect.ImmutableList;
import java.nio.file.Paths;
@@ -54,7 +53,7 @@
private Collection<StartupProfileProvider> startupProfileProviders;
- public StartupOptions(InternalOptions options) {
+ public StartupOptions() {
this.startupProfileProviders =
SystemPropertyUtils.applySystemProperty(
"com.android.tools.r8.startup.profile",
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
index b891c89..a1622f5 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.ir.analysis.type.InterfaceCollection;
import com.android.tools.r8.ir.analysis.type.InterfaceCollection.Builder;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
+import com.android.tools.r8.profile.art.ArtProfileCollection;
import com.android.tools.r8.shaking.MainDexInfo;
import com.android.tools.r8.shaking.MissingClasses;
import com.android.tools.r8.synthesis.CommittedItems;
@@ -48,18 +49,21 @@
public static AppInfoWithClassHierarchy createInitialAppInfoWithClassHierarchy(
DexApplication application,
+ ArtProfileCollection artProfiles,
ClassToFeatureSplitMap classToFeatureSplitMap,
MainDexInfo mainDexInfo,
GlobalSyntheticsStrategy globalSyntheticsStrategy,
StartupOrder startupOrder) {
return new AppInfoWithClassHierarchy(
SyntheticItems.createInitialSyntheticItems(application, globalSyntheticsStrategy),
+ artProfiles,
classToFeatureSplitMap,
mainDexInfo,
MissingClasses.empty(),
startupOrder);
}
+ private final ArtProfileCollection artProfiles;
private final ClassToFeatureSplitMap classToFeatureSplitMap;
private final StartupOrder startupOrder;
@@ -70,11 +74,13 @@
// For AppInfoWithLiveness subclass.
protected AppInfoWithClassHierarchy(
CommittedItems committedItems,
+ ArtProfileCollection artProfiles,
ClassToFeatureSplitMap classToFeatureSplitMap,
MainDexInfo mainDexInfo,
MissingClasses missingClasses,
StartupOrder startupOrder) {
super(committedItems, mainDexInfo);
+ this.artProfiles = artProfiles;
this.classToFeatureSplitMap = classToFeatureSplitMap;
this.missingClasses = missingClasses;
this.startupOrder = startupOrder;
@@ -83,6 +89,7 @@
// For desugaring.
private AppInfoWithClassHierarchy(CreateDesugaringViewOnAppInfo witness, AppInfo appInfo) {
super(witness, appInfo);
+ this.artProfiles = ArtProfileCollection.empty();
this.classToFeatureSplitMap = ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap();
// TODO(b/175659048): Migrate the reporting of missing classes in D8 desugar to MissingClasses,
// and use the missing classes from AppInfo instead of MissingClasses.empty().
@@ -98,6 +105,7 @@
public final AppInfoWithClassHierarchy rebuildWithClassHierarchy(CommittedItems commit) {
return new AppInfoWithClassHierarchy(
commit,
+ getArtProfiles(),
getClassToFeatureSplitMap(),
getMainDexInfo(),
getMissingClasses(),
@@ -109,6 +117,7 @@
assert checkIfObsolete();
return new AppInfoWithClassHierarchy(
getSyntheticItems().commit(fn.apply(app())),
+ getArtProfiles(),
getClassToFeatureSplitMap(),
getMainDexInfo(),
getMissingClasses(),
@@ -121,6 +130,7 @@
assert checkIfObsolete();
return new AppInfoWithClassHierarchy(
getSyntheticItems().commit(app()),
+ getArtProfiles(),
getClassToFeatureSplitMap(),
mainDexInfo,
getMissingClasses(),
@@ -138,12 +148,17 @@
}
return new AppInfoWithClassHierarchy(
getSyntheticItems().commitPrunedItems(prunedItems),
+ getArtProfiles().withoutPrunedItems(prunedItems),
getClassToFeatureSplitMap().withoutPrunedItems(prunedItems),
getMainDexInfo().withoutPrunedItems(prunedItems),
getMissingClasses(),
getStartupOrder().withoutPrunedItems(prunedItems, getSyntheticItems()));
}
+ public ArtProfileCollection getArtProfiles() {
+ return artProfiles;
+ }
+
public ClassToFeatureSplitMap getClassToFeatureSplitMap() {
return classToFeatureSplitMap;
}
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 3633506..95baf65 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -34,6 +34,7 @@
import com.android.tools.r8.naming.SeedMapper;
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
import com.android.tools.r8.optimize.interfaces.collection.OpenClosedInterfacesCollection;
+import com.android.tools.r8.profile.art.ArtProfileCollection;
import com.android.tools.r8.retrace.internal.RetraceUtils;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.AssumeInfoCollection;
@@ -206,12 +207,15 @@
public static AppView<AppInfoWithClassHierarchy> createForR8(
DexApplication application, MainDexInfo mainDexInfo) {
+ ArtProfileCollection artProfiles =
+ ArtProfileCollection.createInitialArtProfileCollection(application.options);
ClassToFeatureSplitMap classToFeatureSplitMap =
ClassToFeatureSplitMap.createInitialClassToFeatureSplitMap(application.options);
StartupOrder startupOrder = StartupOrder.createInitialStartupOrderForR8(application);
AppInfoWithClassHierarchy appInfo =
AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
application,
+ artProfiles,
classToFeatureSplitMap,
mainDexInfo,
GlobalSyntheticsStrategy.forSingleOutputMode(),
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java
new file mode 100644
index 0000000..8cf52c5
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java
@@ -0,0 +1,117 @@
+// Copyright (c) 2022, 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.profile.art;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.Reporter;
+import com.google.common.collect.ImmutableList;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.UnaryOperator;
+
+public class ArtProfile {
+
+ private final List<ArtProfileRule> rules;
+
+ ArtProfile(List<ArtProfileRule> rules) {
+ this.rules = rules;
+ }
+
+ public static Builder builder(DexItemFactory dexItemFactory) {
+ return new Builder(dexItemFactory);
+ }
+
+ public ArtProfile rewrittenWithLens(GraphLens lens) {
+ return transform(rule -> rule.rewrittenWithLens(lens));
+ }
+
+ public ArtProfile rewrittenWithLens(NamingLens lens, DexItemFactory dexItemFactory) {
+ assert !lens.isIdentityLens();
+ return transform(rule -> rule.rewrittenWithLens(dexItemFactory, lens));
+ }
+
+ public ArtProfile withoutPrunedItems(PrunedItems prunedItems) {
+ return transform(
+ rule -> {
+ if (rule.isClassRule()) {
+ if (prunedItems.isRemoved(rule.asClassRule().getType())) {
+ return null;
+ }
+ } else {
+ assert rule.isMethodRule();
+ if (prunedItems.isRemoved(rule.asMethodRule().getMethod())) {
+ return null;
+ }
+ }
+ return rule;
+ });
+ }
+
+ private ArtProfile transform(UnaryOperator<ArtProfileRule> transformation) {
+ ImmutableList.Builder<ArtProfileRule> newRules =
+ ImmutableList.builderWithExpectedSize(rules.size());
+ for (ArtProfileRule rule : rules) {
+ ArtProfileRule transformedRule = transformation.apply(rule);
+ if (transformedRule != null) {
+ newRules.add(transformedRule);
+ }
+ }
+ return new ArtProfile(newRules.build());
+ }
+
+ public void supplyConsumer(ResidualArtProfileConsumer consumer, Reporter reporter) {
+ if (consumer != null) {
+ ResidualArtProfileRuleConsumer ruleConsumer = consumer.getRuleConsumer();
+ if (ruleConsumer != null) {
+ for (ArtProfileRule rule : rules) {
+ rule.accept(
+ classRule ->
+ ruleConsumer.acceptClassRule(
+ classRule.getClassReference(), classRule.getClassRuleInfo()),
+ methodRule ->
+ ruleConsumer.acceptMethodRule(
+ methodRule.getMethodReference(), methodRule.getMethodRuleInfo()));
+ }
+ }
+ consumer.finished(reporter);
+ }
+ }
+
+ public static class Builder implements ArtProfileBuilder {
+
+ private final DexItemFactory dexItemFactory;
+ private final List<ArtProfileRule> rules = new ArrayList<>();
+
+ Builder(DexItemFactory dexItemFactory) {
+ this.dexItemFactory = dexItemFactory;
+ }
+
+ @Override
+ public ArtProfileBuilder addClassRule(
+ Consumer<ArtProfileClassRuleBuilder> classRuleBuilderConsumer) {
+ ArtProfileClassRule.Builder classRuleBuilder = ArtProfileClassRule.builder(dexItemFactory);
+ classRuleBuilderConsumer.accept(classRuleBuilder);
+ rules.add(classRuleBuilder.build());
+ return this;
+ }
+
+ @Override
+ public ArtProfileBuilder addMethodRule(
+ Consumer<ArtProfileMethodRuleBuilder> methodRuleBuilderConsumer) {
+ ArtProfileMethodRule.Builder methodRuleBuilder = ArtProfileMethodRule.builder(dexItemFactory);
+ methodRuleBuilderConsumer.accept(methodRuleBuilder);
+ rules.add(methodRuleBuilder.build());
+ return this;
+ }
+
+ public ArtProfile build() {
+ return new ArtProfile(rules);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileBuilderUtils.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileBuilderUtils.java
index 3426e7b..44de1a8 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileBuilderUtils.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileBuilderUtils.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.startup.StartupProfileBuilder;
+import java.util.function.Consumer;
public class ArtProfileBuilderUtils {
@@ -72,15 +73,19 @@
return new ArtProfileBuilder() {
@Override
- public void addClassRule(
- ClassReference classReference, ArtProfileClassRuleInfo classRuleInfo) {
- if (rulePredicate.testClassRule(classReference, classRuleInfo)) {
+ public ArtProfileBuilder addClassRule(
+ Consumer<ArtProfileClassRuleBuilder> classRuleBuilderConsumer) {
+ MutableArtProfileClassRule classRule = new MutableArtProfileClassRule();
+ classRuleBuilderConsumer.accept(classRule);
+ if (rulePredicate.testClassRule(
+ classRule.getClassReference(), classRule.getClassRuleInfo())) {
ClassReference syntheticContextReference =
syntheticToSyntheticContextGeneralization.getSyntheticContextReference(
- classReference);
+ classRule.getClassReference());
if (syntheticContextReference == null) {
startupProfileBuilder.addStartupClass(
- startupClassBuilder -> startupClassBuilder.setClassReference(classReference));
+ startupClassBuilder ->
+ startupClassBuilder.setClassReference(classRule.getClassReference()));
} else {
startupProfileBuilder.addSyntheticStartupMethod(
syntheticStartupMethodBuilder ->
@@ -88,18 +93,23 @@
syntheticContextReference));
}
}
+ return this;
}
@Override
- public void addMethodRule(
- MethodReference methodReference, ArtProfileMethodRuleInfo methodRuleInfo) {
- if (rulePredicate.testMethodRule(methodReference, methodRuleInfo)) {
+ public ArtProfileBuilder addMethodRule(
+ Consumer<ArtProfileMethodRuleBuilder> methodRuleBuilderConsumer) {
+ MutableArtProfileMethodRule methodRule = new MutableArtProfileMethodRule();
+ methodRuleBuilderConsumer.accept(methodRule);
+ if (rulePredicate.testMethodRule(
+ methodRule.getMethodReference(), methodRule.getMethodRuleInfo())) {
ClassReference syntheticContextReference =
syntheticToSyntheticContextGeneralization.getSyntheticContextReference(
- methodReference.getHolderClass());
+ methodRule.getMethodReference().getHolderClass());
if (syntheticContextReference == null) {
startupProfileBuilder.addStartupMethod(
- startupMethodBuilder -> startupMethodBuilder.setMethodReference(methodReference));
+ startupMethodBuilder ->
+ startupMethodBuilder.setMethodReference(methodRule.getMethodReference()));
} else {
startupProfileBuilder.addSyntheticStartupMethod(
syntheticStartupMethodBuilder ->
@@ -107,7 +117,61 @@
syntheticContextReference));
}
}
+ return this;
}
};
}
+
+ private static class MutableArtProfileClassRule implements ArtProfileClassRuleBuilder {
+
+ private ClassReference classReference;
+
+ MutableArtProfileClassRule() {}
+
+ public ClassReference getClassReference() {
+ return classReference;
+ }
+
+ @Override
+ public ArtProfileClassRuleBuilder setClassReference(ClassReference classReference) {
+ this.classReference = classReference;
+ return this;
+ }
+
+ public ArtProfileClassRuleInfo getClassRuleInfo() {
+ return ArtProfileClassRuleInfoImpl.empty();
+ }
+ }
+
+ private static class MutableArtProfileMethodRule implements ArtProfileMethodRuleBuilder {
+
+ private MethodReference methodReference;
+ private ArtProfileMethodRuleInfo methodRuleInfo = ArtProfileMethodRuleInfoImpl.empty();
+
+ MutableArtProfileMethodRule() {}
+
+ public MethodReference getMethodReference() {
+ return methodReference;
+ }
+
+ public ArtProfileMethodRuleInfo getMethodRuleInfo() {
+ return methodRuleInfo;
+ }
+
+ @Override
+ public ArtProfileMethodRuleBuilder setMethodReference(MethodReference methodReference) {
+ this.methodReference = methodReference;
+ return this;
+ }
+
+ @Override
+ public ArtProfileMethodRuleBuilder setMethodRuleInfo(
+ Consumer<ArtProfileMethodRuleInfoBuilder> methodRuleInfoBuilderConsumer) {
+ ArtProfileMethodRuleInfoImpl.Builder methodRuleInfoBuilder =
+ ArtProfileMethodRuleInfoImpl.builder();
+ methodRuleInfoBuilderConsumer.accept(methodRuleInfoBuilder);
+ methodRuleInfo = methodRuleInfoBuilder.build();
+ return this;
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileClassRule.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileClassRule.java
new file mode 100644
index 0000000..be3a39e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileClassRule.java
@@ -0,0 +1,107 @@
+// Copyright (c) 2022, 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.profile.art;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
+import java.util.function.Consumer;
+
+public class ArtProfileClassRule extends ArtProfileRule {
+
+ private final DexType type;
+
+ ArtProfileClassRule(DexType type) {
+ this.type = type;
+ }
+
+ public static Builder builder(DexItemFactory dexItemFactory) {
+ return new Builder(dexItemFactory);
+ }
+
+ @Override
+ public void accept(
+ Consumer<ArtProfileClassRule> classRuleConsumer,
+ Consumer<ArtProfileMethodRule> methodRuleConsumer) {
+ classRuleConsumer.accept(this);
+ }
+
+ public ClassReference getClassReference() {
+ return Reference.classFromDescriptor(type.toDescriptorString());
+ }
+
+ public ArtProfileClassRuleInfo getClassRuleInfo() {
+ return ArtProfileClassRuleInfoImpl.empty();
+ }
+
+ public DexType getType() {
+ return type;
+ }
+
+ @Override
+ public boolean isClassRule() {
+ return true;
+ }
+
+ @Override
+ public ArtProfileClassRule asClassRule() {
+ return this;
+ }
+
+ @Override
+ public ArtProfileClassRule rewrittenWithLens(GraphLens lens) {
+ return new ArtProfileClassRule(lens.lookupType(type));
+ }
+
+ @Override
+ public ArtProfileRule rewrittenWithLens(DexItemFactory dexItemFactory, NamingLens lens) {
+ return new ArtProfileClassRule(lens.lookupType(type, dexItemFactory));
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ArtProfileClassRule that = (ArtProfileClassRule) o;
+ return type == that.type;
+ }
+
+ @Override
+ public int hashCode() {
+ return type.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return type.toSmaliString();
+ }
+
+ public static class Builder implements ArtProfileClassRuleBuilder {
+
+ private final DexItemFactory dexItemFactory;
+ private DexType type;
+
+ Builder(DexItemFactory dexItemFactory) {
+ this.dexItemFactory = dexItemFactory;
+ }
+
+ @Override
+ public ArtProfileClassRuleBuilder setClassReference(ClassReference classReference) {
+ this.type = dexItemFactory.createType(classReference.getDescriptor());
+ return this;
+ }
+
+ public ArtProfileClassRule build() {
+ return new ArtProfileClassRule(type);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileClassRuleInfoImpl.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileClassRuleInfoImpl.java
index 7be8869..9fa3001 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileClassRuleInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileClassRuleInfoImpl.java
@@ -13,4 +13,14 @@
public static ArtProfileClassRuleInfoImpl empty() {
return INSTANCE;
}
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
new file mode 100644
index 0000000..bba8705
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
@@ -0,0 +1,43 @@
+// Copyright (c) 2022, 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.profile.art;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.InternalOptions;
+import java.util.ArrayList;
+import java.util.List;
+
+public abstract class ArtProfileCollection {
+
+ public static ArtProfileCollection createInitialArtProfileCollection(InternalOptions options) {
+ List<ArtProfile> artProfiles = new ArrayList<>();
+ for (ArtProfileInput input : options.getArtProfileOptions().getArtProfileInputs()) {
+ ArtProfile.Builder artProfileBuilder = ArtProfile.builder(options.dexItemFactory());
+ input.getArtProfile(artProfileBuilder);
+ artProfiles.add(artProfileBuilder.build());
+ }
+ if (artProfiles.isEmpty()) {
+ return empty();
+ }
+ return new NonEmptyArtProfileCollection(artProfiles);
+ }
+
+ public static EmptyArtProfileCollection empty() {
+ return EmptyArtProfileCollection.getInstance();
+ }
+
+ public abstract ArtProfileCollection rewrittenWithLens(GraphLens lens);
+
+ public abstract ArtProfileCollection rewrittenWithLens(
+ NamingLens lens, DexItemFactory dexItemFactory);
+
+ public abstract void supplyConsumers(AppView<?> appView);
+
+ public abstract ArtProfileCollection withoutPrunedItems(PrunedItems prunedItems);
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileMethodRule.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileMethodRule.java
new file mode 100644
index 0000000..521e359
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileMethodRule.java
@@ -0,0 +1,123 @@
+// Copyright (c) 2022, 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.profile.art;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import java.util.function.Consumer;
+
+public class ArtProfileMethodRule extends ArtProfileRule {
+
+ private final DexMethod method;
+ private final ArtProfileMethodRuleInfo info;
+
+ ArtProfileMethodRule(DexMethod method, ArtProfileMethodRuleInfo info) {
+ this.method = method;
+ this.info = info;
+ }
+
+ public static Builder builder(DexItemFactory dexItemFactory) {
+ return new Builder(dexItemFactory);
+ }
+
+ @Override
+ public void accept(
+ Consumer<ArtProfileClassRule> classRuleConsumer,
+ Consumer<ArtProfileMethodRule> methodRuleConsumer) {
+ methodRuleConsumer.accept(this);
+ }
+
+ public DexMethod getMethod() {
+ return method;
+ }
+
+ public MethodReference getMethodReference() {
+ return method.asMethodReference();
+ }
+
+ public ArtProfileMethodRuleInfo getMethodRuleInfo() {
+ return info;
+ }
+
+ @Override
+ public boolean isMethodRule() {
+ return true;
+ }
+
+ @Override
+ public ArtProfileMethodRule asMethodRule() {
+ return this;
+ }
+
+ @Override
+ public ArtProfileMethodRule rewrittenWithLens(GraphLens lens) {
+ return new ArtProfileMethodRule(lens.getRenamedMethodSignature(method), info);
+ }
+
+ @Override
+ public ArtProfileRule rewrittenWithLens(DexItemFactory dexItemFactory, NamingLens lens) {
+ return new ArtProfileMethodRule(lens.lookupMethod(method, dexItemFactory), info);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ArtProfileMethodRule that = (ArtProfileMethodRule) o;
+ return method.equals(that.method) && info.equals(that.info);
+ }
+
+ @Override
+ public int hashCode() {
+ // A profile does not have two rules with the same reference but different flags, so no need to
+ // include the flags in the hash.
+ return method.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return info.toString() + method.toSmaliString();
+ }
+
+ public static class Builder implements ArtProfileMethodRuleBuilder {
+
+ private final DexItemFactory dexItemFactory;
+
+ private DexMethod method;
+ private ArtProfileMethodRuleInfo methodRuleInfo = ArtProfileMethodRuleInfoImpl.empty();
+
+ Builder(DexItemFactory dexItemFactory) {
+ this.dexItemFactory = dexItemFactory;
+ }
+
+ @Override
+ public ArtProfileMethodRuleBuilder setMethodReference(MethodReference methodReference) {
+ this.method = MethodReferenceUtils.toDexMethod(methodReference, dexItemFactory);
+ return this;
+ }
+
+ @Override
+ public ArtProfileMethodRuleBuilder setMethodRuleInfo(
+ Consumer<ArtProfileMethodRuleInfoBuilder> methodRuleInfoBuilderConsumer) {
+ ArtProfileMethodRuleInfoImpl.Builder methodRuleInfoBuilder =
+ ArtProfileMethodRuleInfoImpl.builder();
+ methodRuleInfoBuilderConsumer.accept(methodRuleInfoBuilder);
+ methodRuleInfo = methodRuleInfoBuilder.build();
+ return this;
+ }
+
+ public ArtProfileMethodRule build() {
+ return new ArtProfileMethodRule(method, methodRuleInfo);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileMethodRuleFlagsUtils.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileMethodRuleFlagsUtils.java
new file mode 100644
index 0000000..31f9b10
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileMethodRuleFlagsUtils.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2022, 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.profile.art;
+
+public class ArtProfileMethodRuleFlagsUtils {
+
+ private static final int FLAG_HOT = 1;
+ private static final int FLAG_STARTUP = 2;
+ private static final int FLAG_POST_STARTUP = 4;
+
+ // Getters.
+
+ public static boolean isHot(int flags) {
+ return isFlagSet(flags, FLAG_HOT);
+ }
+
+ public static boolean isStartup(int flags) {
+ return isFlagSet(flags, FLAG_STARTUP);
+ }
+
+ public static boolean isPostStartup(int flags) {
+ return isFlagSet(flags, FLAG_POST_STARTUP);
+ }
+
+ private static boolean isFlagSet(int flags, int flag) {
+ return (flags & flag) != 0;
+ }
+
+ // Setters.
+
+ public static int setIsHot(int flags, boolean isHot) {
+ return isHot ? setFlag(flags, FLAG_HOT) : unsetFlag(flags, FLAG_HOT);
+ }
+
+ public static int setIsStartup(int flags, boolean isStartup) {
+ return isStartup ? setFlag(flags, FLAG_STARTUP) : unsetFlag(flags, FLAG_STARTUP);
+ }
+
+ public static int setIsPostStartup(int flags, boolean isPostStartup) {
+ return isPostStartup ? setFlag(flags, FLAG_POST_STARTUP) : unsetFlag(flags, FLAG_POST_STARTUP);
+ }
+
+ private static int setFlag(int flags, int flag) {
+ return flags | flag;
+ }
+
+ private static int unsetFlag(int flags, int flag) {
+ return flags & ~flag;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileMethodRuleInfoImpl.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileMethodRuleInfoImpl.java
index ca2d241..4ec56b6 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileMethodRuleInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileMethodRuleInfoImpl.java
@@ -6,9 +6,7 @@
public class ArtProfileMethodRuleInfoImpl implements ArtProfileMethodRuleInfo {
- private static final int FLAG_HOT = 1;
- private static final int FLAG_STARTUP = 2;
- private static final int FLAG_POST_STARTUP = 4;
+ private static final ArtProfileMethodRuleInfoImpl EMPTY = new ArtProfileMethodRuleInfoImpl(0);
private final int flags;
@@ -20,41 +18,92 @@
return new Builder();
}
+ public static ArtProfileMethodRuleInfoImpl empty() {
+ return EMPTY;
+ }
+
public boolean isEmpty() {
return flags == 0;
}
@Override
public boolean isHot() {
- return (flags & FLAG_HOT) != 0;
+ return ArtProfileMethodRuleFlagsUtils.isHot(flags);
}
@Override
public boolean isStartup() {
- return (flags & FLAG_STARTUP) != 0;
+ return ArtProfileMethodRuleFlagsUtils.isStartup(flags);
}
@Override
public boolean isPostStartup() {
- return (flags & FLAG_POST_STARTUP) != 0;
+ return ArtProfileMethodRuleFlagsUtils.isPostStartup(flags);
}
- public static class Builder {
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ ArtProfileMethodRuleInfoImpl that = (ArtProfileMethodRuleInfoImpl) o;
+ return flags == that.flags;
+ }
+
+ @Override
+ public int hashCode() {
+ return flags;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (isHot()) {
+ builder.append('H');
+ }
+ if (isStartup()) {
+ builder.append('S');
+ }
+ if (isPostStartup()) {
+ builder.append('P');
+ }
+ return builder.toString();
+ }
+
+ public static class Builder implements ArtProfileMethodRuleInfoBuilder {
private int flags;
- public Builder setHot() {
- flags |= FLAG_HOT;
+ public Builder setIsHot() {
+ return setIsHot(true);
+ }
+
+ @Override
+ public Builder setIsHot(boolean isHot) {
+ flags = ArtProfileMethodRuleFlagsUtils.setIsHot(flags, isHot);
return this;
}
- public Builder setStartup() {
- flags |= FLAG_STARTUP;
+ public Builder setIsStartup() {
+ return setIsStartup(true);
+ }
+
+ @Override
+ public Builder setIsStartup(boolean isStartup) {
+ flags = ArtProfileMethodRuleFlagsUtils.setIsStartup(flags, isStartup);
return this;
}
- public Builder setPostStartup() {
- flags |= FLAG_POST_STARTUP;
+ public Builder setIsPostStartup() {
+ return setIsPostStartup(true);
+ }
+
+ @Override
+ public Builder setIsPostStartup(boolean isPostStartup) {
+ flags = ArtProfileMethodRuleFlagsUtils.setIsPostStartup(flags, isPostStartup);
return this;
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileOptions.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileOptions.java
new file mode 100644
index 0000000..5f5ae7f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileOptions.java
@@ -0,0 +1,24 @@
+// Copyright (c) 2022, 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.profile.art;
+
+import java.util.Collection;
+import java.util.Collections;
+
+public class ArtProfileOptions {
+
+ private Collection<ArtProfileInput> inputs = Collections.emptyList();
+
+ public ArtProfileOptions() {}
+
+ public Collection<ArtProfileInput> getArtProfileInputs() {
+ return inputs;
+ }
+
+ public ArtProfileOptions setArtProfileInputs(Collection<ArtProfileInput> inputs) {
+ this.inputs = inputs;
+ return this;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileRule.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileRule.java
new file mode 100644
index 0000000..15260ef
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileRule.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2022, 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.profile.art;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import java.util.function.Consumer;
+
+public abstract class ArtProfileRule {
+
+ public abstract void accept(
+ Consumer<ArtProfileClassRule> classRuleConsumer,
+ Consumer<ArtProfileMethodRule> methodRuleConsumer);
+
+ public boolean isClassRule() {
+ return false;
+ }
+
+ public ArtProfileClassRule asClassRule() {
+ return null;
+ }
+
+ public boolean isMethodRule() {
+ return false;
+ }
+
+ public ArtProfileMethodRule asMethodRule() {
+ return null;
+ }
+
+ public abstract ArtProfileRule rewrittenWithLens(GraphLens lens);
+
+ public abstract ArtProfileRule rewrittenWithLens(
+ DexItemFactory dexItemFactory, NamingLens namingLens);
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java b/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java
new file mode 100644
index 0000000..c3b420c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java
@@ -0,0 +1,42 @@
+// Copyright (c) 2022, 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.profile.art;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.naming.NamingLens;
+
+public class EmptyArtProfileCollection extends ArtProfileCollection {
+
+ private static final EmptyArtProfileCollection INSTANCE = new EmptyArtProfileCollection();
+
+ private EmptyArtProfileCollection() {}
+
+ static EmptyArtProfileCollection getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public ArtProfileCollection rewrittenWithLens(GraphLens lens) {
+ return this;
+ }
+
+ @Override
+ public ArtProfileCollection rewrittenWithLens(NamingLens lens, DexItemFactory dexItemFactory) {
+ return this;
+ }
+
+ @Override
+ public void supplyConsumers(AppView<?> appView) {
+ assert appView.options().getArtProfileOptions().getArtProfileInputs().isEmpty();
+ }
+
+ @Override
+ public ArtProfileCollection withoutPrunedItems(PrunedItems prunedItems) {
+ return this;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/HumanReadableArtProfileParser.java b/src/main/java/com/android/tools/r8/profile/art/HumanReadableArtProfileParser.java
index 5f0c92b..7b7a09c 100644
--- a/src/main/java/com/android/tools/r8/profile/art/HumanReadableArtProfileParser.java
+++ b/src/main/java/com/android/tools/r8/profile/art/HumanReadableArtProfileParser.java
@@ -64,9 +64,9 @@
public boolean parseRule(String rule) {
ArtProfileMethodRuleInfoImpl.Builder methodRuleInfoBuilder =
ArtProfileMethodRuleInfoImpl.builder();
- rule = parseFlag(rule, 'H', methodRuleInfoBuilder::setHot);
- rule = parseFlag(rule, 'S', methodRuleInfoBuilder::setStartup);
- rule = parseFlag(rule, 'P', methodRuleInfoBuilder::setPostStartup);
+ rule = parseFlag(rule, 'H', methodRuleInfoBuilder::setIsHot);
+ rule = parseFlag(rule, 'S', methodRuleInfoBuilder::setIsStartup);
+ rule = parseFlag(rule, 'P', methodRuleInfoBuilder::setIsPostStartup);
return parseClassOrMethodDescriptor(rule, methodRuleInfoBuilder.build());
}
@@ -95,7 +95,8 @@
if (classReference == null) {
return false;
}
- profileBuilder.addClassRule(classReference, ArtProfileClassRuleInfoImpl.empty());
+ profileBuilder.addClassRule(
+ classRuleBuilder -> classRuleBuilder.setClassReference(classReference));
return true;
}
@@ -106,7 +107,16 @@
if (methodReference == null) {
return false;
}
- profileBuilder.addMethodRule(methodReference, methodRuleInfo);
+ profileBuilder.addMethodRule(
+ methodRuleBuilder ->
+ methodRuleBuilder
+ .setMethodReference(methodReference)
+ .setMethodRuleInfo(
+ methodRuleInfoBuilder ->
+ methodRuleInfoBuilder
+ .setIsHot(methodRuleInfo.isHot())
+ .setIsStartup(methodRuleInfo.isStartup())
+ .setIsPostStartup(methodRuleInfo.isPostStartup())));
return true;
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java b/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
new file mode 100644
index 0000000..56c9683
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
@@ -0,0 +1,68 @@
+// Copyright (c) 2022, 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.profile.art;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.PrunedItems;
+import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.function.Function;
+
+public class NonEmptyArtProfileCollection extends ArtProfileCollection {
+
+ private final Collection<ArtProfile> artProfiles;
+
+ NonEmptyArtProfileCollection(Collection<ArtProfile> artProfiles) {
+ this.artProfiles = artProfiles;
+ }
+
+ @Override
+ public NonEmptyArtProfileCollection rewrittenWithLens(GraphLens lens) {
+ return map(artProfile -> artProfile.rewrittenWithLens(lens));
+ }
+
+ @Override
+ public NonEmptyArtProfileCollection rewrittenWithLens(
+ NamingLens lens, DexItemFactory dexItemFactory) {
+ assert !lens.isIdentityLens();
+ return map(artProfile -> artProfile.rewrittenWithLens(lens, dexItemFactory));
+ }
+
+ @Override
+ public void supplyConsumers(AppView<?> appView) {
+ NonEmptyArtProfileCollection collection =
+ appView.getNamingLens().isIdentityLens()
+ ? this
+ : rewrittenWithLens(appView.getNamingLens(), appView.dexItemFactory());
+ InternalOptions options = appView.options();
+ Collection<ArtProfileInput> inputs = options.getArtProfileOptions().getArtProfileInputs();
+ assert !inputs.isEmpty();
+ assert collection.artProfiles.size() == inputs.size();
+ Iterator<ArtProfileInput> inputIterator = inputs.iterator();
+ for (ArtProfile artProfile : collection.artProfiles) {
+ ArtProfileInput input = inputIterator.next();
+ artProfile.supplyConsumer(input.getArtProfileConsumer(), options.reporter);
+ }
+ }
+
+ @Override
+ public NonEmptyArtProfileCollection withoutPrunedItems(PrunedItems prunedItems) {
+ return map(artProfile -> artProfile.withoutPrunedItems(prunedItems));
+ }
+
+ private NonEmptyArtProfileCollection map(Function<ArtProfile, ArtProfile> fn) {
+ ImmutableList.Builder<ArtProfile> newArtProfiles =
+ ImmutableList.builderWithExpectedSize(artProfiles.size());
+ for (ArtProfile artProfile : artProfiles) {
+ newArtProfiles.add(fn.apply(artProfile));
+ }
+ return new NonEmptyArtProfileCollection(newArtProfiles.build());
+ }
+}
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 f4e27a1..3112e48 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -57,6 +57,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringSyntheticHelper;
import com.android.tools.r8.naming.SeedMapper;
+import com.android.tools.r8.profile.art.ArtProfileCollection;
import com.android.tools.r8.shaking.KeepInfo.Joiner;
import com.android.tools.r8.synthesis.CommittedItems;
import com.android.tools.r8.utils.CollectionUtils;
@@ -199,6 +200,7 @@
// TODO(zerny): Clean up the constructors so we have just one.
AppInfoWithLiveness(
CommittedItems committedItems,
+ ArtProfileCollection artProfiles,
ClassToFeatureSplitMap classToFeatureSplitMap,
MainDexInfo mainDexInfo,
MissingClasses missingClasses,
@@ -234,7 +236,13 @@
Set<DexType> lockCandidates,
Map<DexType, Visibility> initClassReferences,
Set<DexMethod> recordFieldValuesReferences) {
- super(committedItems, classToFeatureSplitMap, mainDexInfo, missingClasses, startupOrder);
+ super(
+ committedItems,
+ artProfiles,
+ classToFeatureSplitMap,
+ mainDexInfo,
+ missingClasses,
+ startupOrder);
this.deadProtoTypes = deadProtoTypes;
this.liveTypes = liveTypes;
this.targetedMethods = targetedMethods;
@@ -272,6 +280,7 @@
private AppInfoWithLiveness(AppInfoWithLiveness previous, CommittedItems committedItems) {
this(
committedItems,
+ previous.getArtProfiles(),
previous.getClassToFeatureSplitMap(),
previous.getMainDexInfo(),
previous.getMissingClasses(),
@@ -316,6 +325,7 @@
List<Future<?>> futures) {
this(
previous.getSyntheticItems().commitPrunedItems(prunedItems),
+ previous.getArtProfiles().withoutPrunedItems(prunedItems),
previous.getClassToFeatureSplitMap().withoutPrunedItems(prunedItems),
previous.getMainDexInfo().withoutPrunedItems(prunedItems),
previous.getMissingClasses(),
@@ -520,6 +530,7 @@
public AppInfoWithLiveness rebuildWithMainDexInfo(MainDexInfo mainDexInfo) {
return new AppInfoWithLiveness(
getSyntheticItems().commit(app()),
+ getArtProfiles(),
getClassToFeatureSplitMap(),
mainDexInfo,
getMissingClasses(),
@@ -598,6 +609,7 @@
AppInfoWithLiveness previous, Map<DexField, Int2ReferenceMap<DexField>> switchMaps) {
super(
previous.getSyntheticItems().commit(previous.app()),
+ previous.getArtProfiles(),
previous.getClassToFeatureSplitMap(),
previous.getMainDexInfo(),
previous.getMissingClasses(),
@@ -1183,6 +1195,7 @@
committedItems.getApplication().getDefinitionsSupplier(committedItems);
return new AppInfoWithLiveness(
committedItems,
+ getArtProfiles().rewrittenWithLens(lens),
getClassToFeatureSplitMap().rewrittenWithLens(lens),
getMainDexInfo().rewrittenWithLens(getSyntheticItems(), lens),
getMissingClasses(),
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 90b9dfb..9cbe49f 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -4191,6 +4191,7 @@
AppInfoWithLiveness appInfoWithLiveness =
new AppInfoWithLiveness(
appInfo.getSyntheticItems().commit(app),
+ appInfo.getArtProfiles(),
appInfo.getClassToFeatureSplitMap(),
appInfo.getMainDexInfo(),
mode.isInitialTreeShaking()
diff --git a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
index 97c4499..11b610a 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/Tracer.java
@@ -37,6 +37,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
+import com.android.tools.r8.profile.art.ArtProfileCollection;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.MethodReference;
@@ -73,6 +74,7 @@
AppView.createForTracer(
AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
new ApplicationReader(inputApp, options, Timing.empty()).read().toDirect(),
+ ArtProfileCollection.empty(),
ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
MainDexInfo.none(),
GlobalSyntheticsStrategy.forSingleOutputMode(),
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 a7841fc..9c2c3b1 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -72,6 +72,7 @@
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorEventConsumer;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
+import com.android.tools.r8.profile.art.ArtProfileOptions;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.MethodReference;
@@ -819,7 +820,8 @@
new KotlinOptimizationOptions();
private final ApiModelTestingOptions apiModelTestingOptions = new ApiModelTestingOptions();
private final DesugarSpecificOptions desugarSpecificOptions = new DesugarSpecificOptions();
- private final StartupOptions startupOptions = new StartupOptions(this);
+ private final ArtProfileOptions artProfileOptions = new ArtProfileOptions();
+ private final StartupOptions startupOptions = new StartupOptions();
private final StartupInstrumentationOptions startupInstrumentationOptions =
new StartupInstrumentationOptions();
public final TestingOptions testing = new TestingOptions();
@@ -881,6 +883,10 @@
return openClosedInterfacesOptions;
}
+ public ArtProfileOptions getArtProfileOptions() {
+ return artProfileOptions;
+ }
+
public StartupOptions getStartupOptions() {
return startupOptions;
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 4f8181d..ab3a2a9 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -46,6 +46,7 @@
import com.android.tools.r8.jasmin.JasminBuilder;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
+import com.android.tools.r8.profile.art.ArtProfileCollection;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.MethodReference;
@@ -775,6 +776,7 @@
throws Exception {
return AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
readApplicationForDexOutput(app, new InternalOptions()),
+ ArtProfileCollection.empty(),
ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
MainDexInfo.none(),
GlobalSyntheticsStrategy.forSingleOutputMode(),
diff --git a/src/test/java/com/android/tools/r8/profile/art/ArtProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/ArtProfileRewritingTest.java
new file mode 100644
index 0000000..860d603
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/profile/art/ArtProfileRewritingTest.java
@@ -0,0 +1,169 @@
+// Copyright (c) 2022, 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.profile.art;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.Lists;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ArtProfileRewritingTest extends TestBase {
+
+ private static final ClassReference mainClassReference = Reference.classFromClass(Main.class);
+ private static final MethodReference mainMethodReference =
+ MethodReferenceUtils.mainMethod(Main.class);
+
+ private static final ClassReference greeterClassReference =
+ Reference.classFromClass(Greeter.class);
+ private static final MethodReference greetMethodReference =
+ MethodReferenceUtils.methodFromMethod(Greeter.class, "greet");
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ MyArtProfileInput artProfileInput = new MyArtProfileInput();
+ testForR8(Backend.DEX)
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options ->
+ options
+ .getArtProfileOptions()
+ .setArtProfileInputs(Collections.singleton(artProfileInput)))
+ .enableInliningAnnotations()
+ .setMinApi(AndroidApiLevel.LATEST)
+ .compile()
+ .inspect(inspector -> inspect(inspector, artProfileInput));
+ }
+
+ private void inspect(CodeInspector inspector, MyArtProfileInput artProfileInput) {
+ ClassSubject greeterClassSubject = inspector.clazz(Greeter.class);
+ assertThat(greeterClassSubject, isPresentAndRenamed());
+
+ MethodSubject greetMethodSubject = greeterClassSubject.uniqueMethodWithName("greet");
+ assertThat(greetMethodSubject, isPresentAndRenamed());
+
+ assertTrue(artProfileInput.finished);
+ assertEquals(
+ Lists.newArrayList(
+ mainClassReference,
+ mainMethodReference,
+ greeterClassSubject.getFinalReference(),
+ greetMethodSubject.getFinalReference()),
+ artProfileInput.references);
+ assertEquals(
+ Lists.newArrayList(
+ ArtProfileClassRuleInfoImpl.empty(),
+ ArtProfileMethodRuleInfoImpl.builder().setIsStartup().build(),
+ ArtProfileClassRuleInfoImpl.empty(),
+ ArtProfileMethodRuleInfoImpl.builder().setIsHot().setIsPostStartup().build()),
+ artProfileInput.infos);
+ }
+
+ static class MyArtProfileInput implements ArtProfileInput {
+
+ boolean finished;
+ List<Object> references = new ArrayList<>();
+ List<Object> infos = new ArrayList<>();
+
+ @Override
+ public ResidualArtProfileConsumer getArtProfileConsumer() {
+ return new ResidualArtProfileConsumer() {
+
+ @Override
+ public ResidualArtProfileRuleConsumer getRuleConsumer() {
+ return new ResidualArtProfileRuleConsumer() {
+
+ @Override
+ public void acceptClassRule(
+ ClassReference classReference, ArtProfileClassRuleInfo classRuleInfo) {
+ references.add(classReference);
+ infos.add(classRuleInfo);
+ }
+
+ @Override
+ public void acceptMethodRule(
+ MethodReference methodReference, ArtProfileMethodRuleInfo methodRuleInfo) {
+ references.add(methodReference);
+ infos.add(methodRuleInfo);
+ }
+ };
+ }
+
+ @Override
+ public void finished(DiagnosticsHandler handler) {
+ finished = true;
+ }
+ };
+ }
+
+ @Override
+ public void getArtProfile(ArtProfileBuilder profileBuilder) {
+ profileBuilder
+ .addClassRule(classRuleBuilder -> classRuleBuilder.setClassReference(mainClassReference))
+ .addMethodRule(
+ methodRuleBuilder ->
+ methodRuleBuilder
+ .setMethodReference(mainMethodReference)
+ .setMethodRuleInfo(
+ methodRuleInfoBuilder -> methodRuleInfoBuilder.setIsStartup(true)))
+ .addClassRule(
+ classRuleBuilder -> classRuleBuilder.setClassReference(greeterClassReference))
+ .addMethodRule(
+ methodRuleBuilder ->
+ methodRuleBuilder
+ .setMethodReference(greetMethodReference)
+ .setMethodRuleInfo(
+ methodRuleInfoBuilder ->
+ methodRuleInfoBuilder.setIsHot(true).setIsPostStartup(true)));
+ }
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ Greeter.greet();
+ }
+ }
+
+ static class Greeter {
+
+ @NeverInline
+ static void greet() {
+ System.out.println("Hello, world!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
index e3855b0..aeeb8f4 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.naming.MemberNaming.Signature;
+import com.android.tools.r8.references.MethodReference;
import java.util.List;
public class AbsentMethodSubject extends MethodSubject {
@@ -82,6 +83,11 @@
}
@Override
+ public MethodReference getFinalReference() {
+ throw new Unreachable("Cannot get the final reference for an absent method");
+ }
+
+ @Override
public TypeSubject getParameter(int index) {
throw new Unreachable("Cannot get the parameter for an absent method");
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 533fa55..3e28a56 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -134,6 +134,11 @@
}
@Override
+ public MethodReference getFinalReference() {
+ return dexMethod.getReference().asMethodReference();
+ }
+
+ @Override
public TypeSubject getParameter(int index) {
return new TypeSubject(codeInspector, getMethod().getParameter(index));
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index a083636..ccc63b0 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
+import com.android.tools.r8.references.MethodReference;
import com.google.common.collect.Streams;
import java.util.Iterator;
import java.util.List;
@@ -54,6 +55,8 @@
public abstract DexEncodedMethod getMethod();
+ public abstract MethodReference getFinalReference();
+
public abstract TypeSubject getParameter(int index);
public abstract List<TypeSubject> getParameters();