Support for adding static synthetic methods to profile
Bug: b/265729283
Change-Id: I33ec266c5b57492abb1924249a2b4a9df6774913
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
index 42b36ff..edead3e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -29,6 +29,7 @@
import com.android.tools.r8.ir.desugar.records.RecordDesugaringEventConsumer.RecordInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.twr.TwrCloseResourceDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.varhandle.VarHandleDesugaringEventConsumer;
+import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
import com.android.tools.r8.profile.art.rewriting.ArtProfileRewritingCfInstructionDesugaringEventConsumer;
import com.android.tools.r8.shaking.Enqueuer.SyntheticAdditions;
import com.android.tools.r8.shaking.KeepMethodInfo.Joiner;
@@ -71,11 +72,16 @@
CfInstructionDesugaringEventConsumer eventConsumer =
new D8CfInstructionDesugaringEventConsumer(
appView, classConverterResultBuilder, methodProcessor);
- return ArtProfileRewritingCfInstructionDesugaringEventConsumer.attachIfNeeded(eventConsumer);
+ // TODO(b/265729283): Also include synthetics in the baseline profile in D8.
+ ArtProfileCollectionAdditions artProfileCollectionAdditions =
+ ArtProfileCollectionAdditions.nop();
+ return ArtProfileRewritingCfInstructionDesugaringEventConsumer.attach(
+ artProfileCollectionAdditions, eventConsumer);
}
public static CfInstructionDesugaringEventConsumer createForR8(
AppView<? extends AppInfoWithClassHierarchy> appView,
+ ArtProfileCollectionAdditions artProfileCollectionAdditions,
BiConsumer<LambdaClass, ProgramMethod> lambdaClassConsumer,
BiConsumer<ConstantDynamicClass, ProgramMethod> constantDynamicClassConsumer,
BiConsumer<ProgramMethod, ProgramMethod> twrCloseResourceMethodConsumer,
@@ -89,7 +95,8 @@
twrCloseResourceMethodConsumer,
additions,
companionMethodConsumer);
- return ArtProfileRewritingCfInstructionDesugaringEventConsumer.attachIfNeeded(eventConsumer);
+ return ArtProfileRewritingCfInstructionDesugaringEventConsumer.attach(
+ artProfileCollectionAdditions, eventConsumer);
}
public abstract List<ProgramMethod> finalizeDesugaring();
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
index f3d4f1d..55d7ef6 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfile.java
@@ -17,13 +17,12 @@
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
-import com.google.common.collect.ImmutableList;
+import com.android.tools.r8.utils.ThrowingConsumer;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UncheckedIOException;
-import java.util.ArrayList;
+import java.util.Collection;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@@ -31,16 +30,53 @@
public class ArtProfile {
- private final List<ArtProfileRule> rules;
+ private final Map<DexReference, ArtProfileRule> rules;
- ArtProfile(List<ArtProfileRule> rules) {
+ ArtProfile(Map<DexReference, ArtProfileRule> rules) {
this.rules = rules;
}
- public static Builder builder(ArtProfileProvider artProfileProvider, InternalOptions options) {
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static Builder builderForInitialArtProfile(
+ ArtProfileProvider artProfileProvider, InternalOptions options) {
return new Builder(artProfileProvider, options);
}
+ public boolean containsClassRule(DexType type) {
+ return rules.containsKey(type);
+ }
+
+ public boolean containsMethodRule(DexMethod method) {
+ return rules.containsKey(method);
+ }
+
+ public <E extends Exception> void forEachRule(ThrowingConsumer<ArtProfileRule, E> ruleConsumer)
+ throws E {
+ for (ArtProfileRule rule : rules.values()) {
+ ruleConsumer.accept(rule);
+ }
+ }
+
+ public <E1 extends Exception, E2 extends Exception> void forEachRule(
+ ThrowingConsumer<ArtProfileClassRule, E1> classRuleConsumer,
+ ThrowingConsumer<ArtProfileMethodRule, E2> methodRuleConsumer)
+ throws E1, E2 {
+ for (ArtProfileRule rule : rules.values()) {
+ rule.accept(classRuleConsumer, methodRuleConsumer);
+ }
+ }
+
+ public ArtProfileClassRule getClassRule(DexType type) {
+ return (ArtProfileClassRule) rules.get(type);
+ }
+
+ public ArtProfileMethodRule getMethodRule(DexMethod method) {
+ return (ArtProfileMethodRule) rules.get(method);
+ }
+
public ArtProfile rewrittenWithLens(GraphLens lens) {
return transform(
(classRule, builderFactory) -> builderFactory.accept(lens.lookupType(classRule.getType())),
@@ -88,37 +124,32 @@
BiConsumer<ArtProfileMethodRule, Function<DexMethod, ArtProfileMethodRule.Builder>>
methodTransformation) {
Map<DexReference, ArtProfileRule.Builder> ruleBuilders = new LinkedHashMap<>();
- for (ArtProfileRule rule : rules) {
- if (rule.isClassRule()) {
+ forEachRule(
// Supply a factory method for creating a builder. If the current rule should be included in
// the rewritten profile, the caller should call the provided builder factory method to
// create a class rule builder. If two rules are mapped to the same reference, the same rule
// builder is reused so that the two rules are merged into a single rule (with their flags
// merged).
- classTransformation.accept(
- rule.asClassRule(),
- newType ->
- ruleBuilders
- .computeIfAbsent(
- newType, ignoreKey(() -> ArtProfileClassRule.builder().setType(newType)))
- .asClassRuleBuilder());
- } else {
+ classRule ->
+ classTransformation.accept(
+ classRule,
+ newType ->
+ ruleBuilders
+ .computeIfAbsent(
+ newType,
+ ignoreKey(() -> ArtProfileClassRule.builder().setType(newType)))
+ .asClassRuleBuilder()),
// As above.
- assert rule.isMethodRule();
- methodTransformation.accept(
- rule.asMethodRule(),
- newMethod ->
- ruleBuilders
- .computeIfAbsent(
- newMethod,
- ignoreKey(() -> ArtProfileMethodRule.builder().setMethod(newMethod)))
- .asMethodRuleBuilder());
- }
- }
- ImmutableList.Builder<ArtProfileRule> newRules =
- ImmutableList.builderWithExpectedSize(ruleBuilders.size());
- ruleBuilders.values().forEach(ruleBuilder -> newRules.add(ruleBuilder.build()));
- return new ArtProfile(newRules.build());
+ methodRule ->
+ methodTransformation.accept(
+ methodRule,
+ newMethod ->
+ ruleBuilders
+ .computeIfAbsent(
+ newMethod,
+ ignoreKey(() -> ArtProfileMethodRule.builder().setMethod(newMethod)))
+ .asMethodRuleBuilder()));
+ return builder().addRuleBuilders(ruleBuilders.values()).build();
}
public void supplyConsumer(ArtProfileConsumer consumer, Reporter reporter) {
@@ -140,10 +171,11 @@
try (OutputStreamWriter outputStreamWriter =
new OutputStreamWriter(
textOutputStream.getOutputStream(), textOutputStream.getCharset())) {
- for (ArtProfileRule rule : rules) {
- rule.writeHumanReadableRuleString(outputStreamWriter);
- outputStreamWriter.write('\n');
- }
+ forEachRule(
+ rule -> {
+ rule.writeHumanReadableRuleString(outputStreamWriter);
+ outputStreamWriter.write('\n');
+ });
}
} catch (IOException e) {
throw new UncheckedIOException(e);
@@ -151,15 +183,13 @@
}
private void supplyRuleConsumer(ArtProfileRuleConsumer ruleConsumer) {
- for (ArtProfileRule rule : rules) {
- rule.accept(
- classRule ->
- ruleConsumer.acceptClassRule(
- classRule.getClassReference(), classRule.getClassRuleInfo()),
- methodRule ->
- ruleConsumer.acceptMethodRule(
- methodRule.getMethodReference(), methodRule.getMethodRuleInfo()));
- }
+ forEachRule(
+ classRule ->
+ ruleConsumer.acceptClassRule(
+ classRule.getClassReference(), classRule.getClassRuleInfo()),
+ methodRule ->
+ ruleConsumer.acceptMethodRule(
+ methodRule.getMethodReference(), methodRule.getMethodRuleInfo()));
}
public static class Builder implements ArtProfileBuilder {
@@ -167,34 +197,57 @@
private final ArtProfileProvider artProfileProvider;
private final DexItemFactory dexItemFactory;
private Reporter reporter;
- private final List<ArtProfileRule> rules = new ArrayList<>();
+ private final Map<DexReference, ArtProfileRule> rules = new LinkedHashMap<>();
+ Builder() {
+ this.artProfileProvider = null;
+ this.dexItemFactory = null;
+ this.reporter = null;
+ }
+
+ // Constructor for building the initial ART profile. The input is based on the Reference API, so
+ // access to the DexItemFactory is needed for conversion into the internal DexReference.
+ // Moreover, access to the Reporter is needed for diagnostics reporting.
Builder(ArtProfileProvider artProfileProvider, InternalOptions options) {
this.artProfileProvider = artProfileProvider;
this.dexItemFactory = options.dexItemFactory();
this.reporter = options.reporter;
}
+ public Builder addRule(ArtProfileRule rule) {
+ assert !rules.containsKey(rule.getReference());
+ rule.accept(
+ classRule -> rules.put(classRule.getType(), classRule),
+ methodRule -> rules.put(methodRule.getMethod(), methodRule));
+ return this;
+ }
+
+ public Builder addRules(Collection<ArtProfileRule> rules) {
+ rules.forEach(this::addRule);
+ return this;
+ }
+
+ public Builder addRuleBuilders(Collection<ArtProfileRule.Builder> ruleBuilders) {
+ ruleBuilders.forEach(ruleBuilder -> addRule(ruleBuilder.build()));
+ return this;
+ }
+
@Override
- public ArtProfileBuilder addClassRule(
- Consumer<ArtProfileClassRuleBuilder> classRuleBuilderConsumer) {
+ public Builder addClassRule(Consumer<ArtProfileClassRuleBuilder> classRuleBuilderConsumer) {
ArtProfileClassRule.Builder classRuleBuilder = ArtProfileClassRule.builder(dexItemFactory);
classRuleBuilderConsumer.accept(classRuleBuilder);
- rules.add(classRuleBuilder.build());
- return this;
+ return addRule(classRuleBuilder.build());
}
@Override
- public ArtProfileBuilder addMethodRule(
- Consumer<ArtProfileMethodRuleBuilder> methodRuleBuilderConsumer) {
+ public Builder addMethodRule(Consumer<ArtProfileMethodRuleBuilder> methodRuleBuilderConsumer) {
ArtProfileMethodRule.Builder methodRuleBuilder = ArtProfileMethodRule.builder(dexItemFactory);
methodRuleBuilderConsumer.accept(methodRuleBuilder);
- rules.add(methodRuleBuilder.build());
- return this;
+ return addRule(methodRuleBuilder.build());
}
@Override
- public ArtProfileBuilder addHumanReadableArtProfile(
+ public Builder addHumanReadableArtProfile(
TextInputStream textInputStream,
Consumer<HumanReadableArtProfileParserBuilder> parserBuilderConsumer) {
HumanReadableArtProfileParser.Builder parserBuilder =
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
index 932ecb8..283e22b 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileClassRule.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileClassRule.java
@@ -5,12 +5,13 @@
package com.android.tools.r8.profile.art;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.ThrowingConsumer;
import java.io.IOException;
import java.io.OutputStreamWriter;
-import java.util.function.Consumer;
public class ArtProfileClassRule extends ArtProfileRule {
@@ -29,9 +30,10 @@
}
@Override
- public void accept(
- Consumer<ArtProfileClassRule> classRuleConsumer,
- Consumer<ArtProfileMethodRule> methodRuleConsumer) {
+ public <E1 extends Exception, E2 extends Exception> void accept(
+ ThrowingConsumer<ArtProfileClassRule, E1> classRuleConsumer,
+ ThrowingConsumer<ArtProfileMethodRule, E2> methodRuleConsumer)
+ throws E1 {
classRuleConsumer.accept(this);
}
@@ -43,6 +45,11 @@
return ArtProfileClassRuleInfoImpl.empty();
}
+ @Override
+ public DexReference getReference() {
+ return getType();
+ }
+
public DexType getType() {
return type;
}
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
index 3a885d9..2cdb3e0 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCollection.java
@@ -30,7 +30,8 @@
for (ArtProfileForRewriting artProfileForRewriting :
options.getArtProfileOptions().getArtProfilesForRewriting()) {
ArtProfileProvider artProfileProvider = artProfileForRewriting.getArtProfileProvider();
- ArtProfile.Builder artProfileBuilder = ArtProfile.builder(artProfileProvider, options);
+ ArtProfile.Builder artProfileBuilder =
+ ArtProfile.builderForInitialArtProfile(artProfileProvider, options);
artProfileForRewriting.getArtProfileProvider().getArtProfile(artProfileBuilder);
artProfiles.add(artProfileBuilder.build());
}
@@ -45,6 +46,10 @@
return PassthroughArtProfileCollection.getInstance();
}
+ public abstract boolean isNonEmpty();
+
+ public abstract NonEmptyArtProfileCollection asNonEmpty();
+
public abstract ArtProfileCollection rewrittenWithLens(GraphLens lens);
public abstract ArtProfileCollection rewrittenWithLens(
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
index f9380b8..df469c9 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileMethodRule.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileMethodRule.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.utils.MethodReferenceUtils;
+import com.android.tools.r8.utils.ThrowingConsumer;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.function.Consumer;
@@ -31,9 +32,10 @@
}
@Override
- public void accept(
- Consumer<ArtProfileClassRule> classRuleConsumer,
- Consumer<ArtProfileMethodRule> methodRuleConsumer) {
+ public <E1 extends Exception, E2 extends Exception> void accept(
+ ThrowingConsumer<ArtProfileClassRule, E1> classRuleConsumer,
+ ThrowingConsumer<ArtProfileMethodRule, E2> methodRuleConsumer)
+ throws E2 {
methodRuleConsumer.accept(this);
}
@@ -45,11 +47,16 @@
return method.asMethodReference();
}
- public ArtProfileMethodRuleInfo getMethodRuleInfo() {
+ public ArtProfileMethodRuleInfoImpl getMethodRuleInfo() {
return info;
}
@Override
+ public DexMethod getReference() {
+ return getMethod();
+ }
+
+ @Override
public boolean isMethodRule() {
return true;
}
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 86d4c84..252cdac 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
@@ -140,6 +140,11 @@
return this;
}
+ public Builder joinFlags(ArtProfileMethodRuleInfoImpl methodRuleInfo) {
+ flags |= methodRuleInfo.flags;
+ return this;
+ }
+
public ArtProfileMethodRuleInfoImpl build() {
return new ArtProfileMethodRuleInfoImpl(flags);
}
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
index f05167c..8d6eefd 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileRule.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileRule.java
@@ -4,15 +4,24 @@
package com.android.tools.r8.profile.art;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.utils.ThrowingConsumer;
import java.io.IOException;
import java.io.OutputStreamWriter;
-import java.util.function.Consumer;
-public abstract class ArtProfileRule {
+public abstract class ArtProfileRule implements Comparable<ArtProfileRule> {
- public abstract void accept(
- Consumer<ArtProfileClassRule> classRuleConsumer,
- Consumer<ArtProfileMethodRule> methodRuleConsumer);
+ public abstract <E1 extends Exception, E2 extends Exception> void accept(
+ ThrowingConsumer<ArtProfileClassRule, E1> classRuleConsumer,
+ ThrowingConsumer<ArtProfileMethodRule, E2> methodRuleConsumer)
+ throws E1, E2;
+
+ @Override
+ public final int compareTo(ArtProfileRule rule) {
+ return getReference().compareTo(rule.getReference());
+ }
+
+ public abstract DexReference getReference();
public boolean isClassRule() {
return false;
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
index f0313ef..0540aa4 100644
--- a/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java
+++ b/src/main/java/com/android/tools/r8/profile/art/EmptyArtProfileCollection.java
@@ -21,6 +21,16 @@
}
@Override
+ public boolean isNonEmpty() {
+ return false;
+ }
+
+ @Override
+ public NonEmptyArtProfileCollection asNonEmpty() {
+ return null;
+ }
+
+ @Override
public ArtProfileCollection rewrittenWithLens(GraphLens lens) {
return this;
}
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
index e3cbaf7..b196906 100644
--- a/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
+++ b/src/main/java/com/android/tools/r8/profile/art/NonEmptyArtProfileCollection.java
@@ -15,15 +15,31 @@
import java.util.Iterator;
import java.util.function.Function;
-public class NonEmptyArtProfileCollection extends ArtProfileCollection {
+public class NonEmptyArtProfileCollection extends ArtProfileCollection
+ implements Iterable<ArtProfile> {
private final Collection<ArtProfile> artProfiles;
- NonEmptyArtProfileCollection(Collection<ArtProfile> artProfiles) {
+ public NonEmptyArtProfileCollection(Collection<ArtProfile> artProfiles) {
this.artProfiles = artProfiles;
}
@Override
+ public boolean isNonEmpty() {
+ return true;
+ }
+
+ @Override
+ public NonEmptyArtProfileCollection asNonEmpty() {
+ return this;
+ }
+
+ @Override
+ public Iterator<ArtProfile> iterator() {
+ return artProfiles.iterator();
+ }
+
+ @Override
public NonEmptyArtProfileCollection rewrittenWithLens(GraphLens lens) {
return map(artProfile -> artProfile.rewrittenWithLens(lens));
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/PassthroughArtProfileCollection.java b/src/main/java/com/android/tools/r8/profile/art/PassthroughArtProfileCollection.java
index 2198da6..ac92f64 100644
--- a/src/main/java/com/android/tools/r8/profile/art/PassthroughArtProfileCollection.java
+++ b/src/main/java/com/android/tools/r8/profile/art/PassthroughArtProfileCollection.java
@@ -30,6 +30,16 @@
}
@Override
+ public boolean isNonEmpty() {
+ return false;
+ }
+
+ @Override
+ public NonEmptyArtProfileCollection asNonEmpty() {
+ return null;
+ }
+
+ @Override
public ArtProfileCollection rewrittenWithLens(GraphLens lens) {
return this;
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileAdditions.java
new file mode 100644
index 0000000..9427a5a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileAdditions.java
@@ -0,0 +1,105 @@
+// Copyright (c) 2023, 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.rewriting;
+
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.profile.art.ArtProfile;
+import com.android.tools.r8.profile.art.ArtProfileClassRule;
+import com.android.tools.r8.profile.art.ArtProfileMethodRule;
+import com.android.tools.r8.profile.art.ArtProfileRule;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/** Mutable extension of an existing ArtProfile. */
+class ArtProfileAdditions {
+
+ private final ArtProfile artProfile;
+
+ private final Map<DexType, ArtProfileClassRule.Builder> classRuleAdditions =
+ new ConcurrentHashMap<>();
+ private final Map<DexMethod, ArtProfileMethodRule.Builder> methodRuleAdditions =
+ new ConcurrentHashMap<>();
+
+ ArtProfileAdditions(ArtProfile artProfile) {
+ this.artProfile = artProfile;
+ }
+
+ void addClassRule(DexProgramClass clazz) {
+ if (artProfile.containsClassRule(clazz.getType())) {
+ return;
+ }
+
+ // Create profile rule for class.
+ classRuleAdditions.computeIfAbsent(
+ clazz.getType(), type -> ArtProfileClassRule.builder().setType(type));
+ }
+
+ boolean addMethodRuleIfContextIsInProfile(ProgramMethod method, ProgramMethod context) {
+ return addMethodRuleIfContextIsInProfile(
+ method, context, MethodRuleAdditionConfig.getDefault());
+ }
+
+ /**
+ * Adds the given {@param method} to the ART profile if {@param context} is live (i.e., present in
+ * the baseline profile).
+ *
+ * @return true if {@param context} is live.
+ */
+ boolean addMethodRuleIfContextIsInProfile(
+ ProgramMethod method, ProgramMethod context, MethodRuleAdditionConfig config) {
+ assert !artProfile.containsMethodRule(method.getReference());
+
+ ArtProfileMethodRule contextMethodRule = artProfile.getMethodRule(context.getReference());
+ if (contextMethodRule == null) {
+ return false;
+ }
+
+ // Create profile rule for method.
+ ArtProfileMethodRule.Builder methodRuleBuilder =
+ methodRuleAdditions.computeIfAbsent(
+ method.getReference(),
+ methodReference -> ArtProfileMethodRule.builder().setMethod(method.getReference()));
+
+ // Setup the rule.
+ methodRuleBuilder.acceptMethodRuleInfoBuilder(
+ methodRuleInfoBuilder ->
+ config.configureMethodRuleInfo(methodRuleInfoBuilder, contextMethodRule));
+ return true;
+ }
+
+ ArtProfile createNewArtProfile() {
+ if (!hasAdditions()) {
+ return artProfile;
+ }
+
+ // Add existing rules to new profile.
+ ArtProfile.Builder artProfileBuilder = ArtProfile.builder();
+ artProfile.forEachRule(artProfileBuilder::addRule);
+
+ // Sort and add additions to new profile. Sorting is needed since the additions to this
+ // collection may be concurrent.
+ List<ArtProfileRule> ruleAdditionsSorted =
+ new ArrayList<>(classRuleAdditions.size() + methodRuleAdditions.size());
+ classRuleAdditions
+ .values()
+ .forEach(classRuleBuilder -> ruleAdditionsSorted.add(classRuleBuilder.build()));
+ methodRuleAdditions
+ .values()
+ .forEach(methodRuleBuilder -> ruleAdditionsSorted.add(methodRuleBuilder.build()));
+ ruleAdditionsSorted.sort(ArtProfileRule::compareTo);
+ artProfileBuilder.addRules(ruleAdditionsSorted);
+
+ return artProfileBuilder.build();
+ }
+
+ boolean hasAdditions() {
+ return !classRuleAdditions.isEmpty() || !methodRuleAdditions.isEmpty();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileCollectionAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileCollectionAdditions.java
new file mode 100644
index 0000000..f4ea621
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileCollectionAdditions.java
@@ -0,0 +1,42 @@
+// Copyright (c) 2023, 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.rewriting;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.profile.art.ArtProfileCollection;
+
+/**
+ * Interface for adding (synthetic) items to an existing ArtProfileCollection.
+ *
+ * <p>The interface will be implemented by {@link NopArtProfileCollectionAdditions} when the
+ * compilation does not contain any ART profiles, for minimal performance overhead.
+ *
+ * <p>When one or more ART profiles are present, this is implemented by {@link
+ * ConcreteArtProfileCollectionAdditions}.
+ */
+public abstract class ArtProfileCollectionAdditions {
+
+ public static ArtProfileCollectionAdditions create(AppView<?> appView) {
+ ArtProfileCollection artProfileCollection = appView.getArtProfileCollection();
+ if (artProfileCollection.isNonEmpty()) {
+ return new ConcreteArtProfileCollectionAdditions(artProfileCollection.asNonEmpty());
+ }
+ return nop();
+ }
+
+ public static NopArtProfileCollectionAdditions nop() {
+ return NopArtProfileCollectionAdditions.getInstance();
+ }
+
+ public abstract void commit(AppView<?> appView);
+
+ boolean isNop() {
+ return false;
+ }
+
+ ConcreteArtProfileCollectionAdditions asConcrete() {
+ return null;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfInstructionDesugaringEventConsumer.java
index 2386676..58a8a1e 100644
--- a/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ArtProfileRewritingCfInstructionDesugaringEventConsumer.java
@@ -17,17 +17,24 @@
public class ArtProfileRewritingCfInstructionDesugaringEventConsumer
extends CfInstructionDesugaringEventConsumer {
+ private final ConcreteArtProfileCollectionAdditions additionsCollection;
private final CfInstructionDesugaringEventConsumer parent;
- public ArtProfileRewritingCfInstructionDesugaringEventConsumer(
+ private ArtProfileRewritingCfInstructionDesugaringEventConsumer(
+ ConcreteArtProfileCollectionAdditions additionsCollection,
CfInstructionDesugaringEventConsumer parent) {
+ this.additionsCollection = additionsCollection;
this.parent = parent;
}
- public static CfInstructionDesugaringEventConsumer attachIfNeeded(
+ public static CfInstructionDesugaringEventConsumer attach(
+ ArtProfileCollectionAdditions artProfileCollectionAdditions,
CfInstructionDesugaringEventConsumer eventConsumer) {
- // TODO(b/265729283): Attach this wrapper when there is a baseline profile that needs rewriting.
- return eventConsumer;
+ if (artProfileCollectionAdditions.isNop()) {
+ return eventConsumer;
+ }
+ return new ArtProfileRewritingCfInstructionDesugaringEventConsumer(
+ artProfileCollectionAdditions.asConcrete(), eventConsumer);
}
@Override
@@ -123,6 +130,7 @@
@Override
public void acceptOutlinedMethod(ProgramMethod outlinedMethod, ProgramMethod context) {
+ additionsCollection.addMethodRuleIfContextIsInProfile(outlinedMethod, context);
parent.acceptOutlinedMethod(outlinedMethod, context);
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteArtProfileCollectionAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteArtProfileCollectionAdditions.java
new file mode 100644
index 0000000..7b1b1c6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ConcreteArtProfileCollectionAdditions.java
@@ -0,0 +1,59 @@
+// Copyright (c) 2023, 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.rewriting;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.profile.art.ArtProfile;
+import com.android.tools.r8.profile.art.ArtProfileCollection;
+import com.android.tools.r8.profile.art.NonEmptyArtProfileCollection;
+import com.google.common.collect.Iterables;
+import java.util.ArrayList;
+import java.util.List;
+
+public class ConcreteArtProfileCollectionAdditions extends ArtProfileCollectionAdditions {
+
+ private final List<ArtProfileAdditions> additionsCollection = new ArrayList<>();
+
+ ConcreteArtProfileCollectionAdditions(NonEmptyArtProfileCollection artProfileCollection) {
+ for (ArtProfile artProfile : artProfileCollection) {
+ additionsCollection.add(new ArtProfileAdditions(artProfile));
+ }
+ assert !additionsCollection.isEmpty();
+ }
+
+ void addMethodRuleIfContextIsInProfile(ProgramMethod method, ProgramMethod context) {
+ for (ArtProfileAdditions artProfileAdditions : additionsCollection) {
+ if (artProfileAdditions.addMethodRuleIfContextIsInProfile(method, context)) {
+ artProfileAdditions.addClassRule(method.getHolder());
+ }
+ }
+ }
+
+ @Override
+ ConcreteArtProfileCollectionAdditions asConcrete() {
+ return this;
+ }
+
+ @Override
+ public void commit(AppView<?> appView) {
+ if (hasAdditions()) {
+ appView.setArtProfileCollection(createNewArtProfileCollection());
+ }
+ }
+
+ private ArtProfileCollection createNewArtProfileCollection() {
+ assert hasAdditions();
+ List<ArtProfile> newArtProfiles = new ArrayList<>(additionsCollection.size());
+ for (ArtProfileAdditions additions : additionsCollection) {
+ newArtProfiles.add(additions.createNewArtProfile());
+ }
+ return new NonEmptyArtProfileCollection(newArtProfiles);
+ }
+
+ private boolean hasAdditions() {
+ return Iterables.any(additionsCollection, ArtProfileAdditions::hasAdditions);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/MethodRuleAdditionConfig.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/MethodRuleAdditionConfig.java
new file mode 100644
index 0000000..5f4f17f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/MethodRuleAdditionConfig.java
@@ -0,0 +1,38 @@
+// Copyright (c) 2023, 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.rewriting;
+
+import com.android.tools.r8.profile.art.ArtProfileMethodRule;
+import com.android.tools.r8.profile.art.ArtProfileMethodRuleInfoImpl;
+
+public abstract class MethodRuleAdditionConfig {
+
+ public static MethodRuleAdditionConfig getDefault() {
+ return DefaultMethodRuleAdditionConfig.getInstance();
+ }
+
+ public abstract void configureMethodRuleInfo(
+ ArtProfileMethodRuleInfoImpl.Builder methodRuleInfoBuilder,
+ ArtProfileMethodRule contextMethodRule);
+
+ private static class DefaultMethodRuleAdditionConfig extends MethodRuleAdditionConfig {
+
+ private static final DefaultMethodRuleAdditionConfig INSTANCE =
+ new DefaultMethodRuleAdditionConfig();
+
+ private DefaultMethodRuleAdditionConfig() {}
+
+ static DefaultMethodRuleAdditionConfig getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public void configureMethodRuleInfo(
+ ArtProfileMethodRuleInfoImpl.Builder methodRuleInfoBuilder,
+ ArtProfileMethodRule contextMethodRule) {
+ methodRuleInfoBuilder.joinFlags(contextMethodRule.getMethodRuleInfo());
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/NopArtProfileCollectionAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/NopArtProfileCollectionAdditions.java
new file mode 100644
index 0000000..c26a098
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/NopArtProfileCollectionAdditions.java
@@ -0,0 +1,29 @@
+// Copyright (c) 2023, 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.rewriting;
+
+import com.android.tools.r8.graph.AppView;
+
+public class NopArtProfileCollectionAdditions extends ArtProfileCollectionAdditions {
+
+ private static final NopArtProfileCollectionAdditions INSTANCE =
+ new NopArtProfileCollectionAdditions();
+
+ private NopArtProfileCollectionAdditions() {}
+
+ public static NopArtProfileCollectionAdditions getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public void commit(AppView<?> appView) {
+ // Intentionally empty.
+ }
+
+ @Override
+ boolean isNop() {
+ return true;
+ }
+}
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 ea03644..11a9fb6 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -126,6 +126,7 @@
import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringLookupResult;
import com.android.tools.r8.naming.identifiernamestring.IdentifierNameStringTypeLookupResult;
import com.android.tools.r8.position.Position;
+import com.android.tools.r8.profile.art.rewriting.ArtProfileCollectionAdditions;
import com.android.tools.r8.shaking.AnnotationMatchResult.MatchedAnnotation;
import com.android.tools.r8.shaking.DelayedRootSetActionItem.InterfaceMethodSyntheticBridgeAction;
import com.android.tools.r8.shaking.EnqueuerEvent.ClassEnqueuerEvent;
@@ -469,6 +470,8 @@
private final Thread mainThreadForTesting = Thread.currentThread();
+ private final ArtProfileCollectionAdditions artProfileCollectionAdditions;
+
Enqueuer(
AppView<? extends AppInfoWithClassHierarchy> appView,
ExecutorService executorService,
@@ -479,6 +482,7 @@
InternalOptions options = appView.options();
this.appInfo = appView.appInfo();
this.appView = appView.withClassHierarchy();
+ this.artProfileCollectionAdditions = ArtProfileCollectionAdditions.create(appView);
this.deferredTracing = EnqueuerDeferredTracing.create(appView, this, mode);
this.executorService = executorService;
this.subtypingInfo = subtypingInfo;
@@ -3673,6 +3677,7 @@
}
timing.begin("Create result");
EnqueuerResult result = createEnqueuerResult(appInfo, timing);
+ artProfileCollectionAdditions.commit(appView);
timing.end();
return result;
}
@@ -4086,6 +4091,7 @@
CfInstructionDesugaringEventConsumer eventConsumer =
CfInstructionDesugaringEventConsumer.createForR8(
appView,
+ artProfileCollectionAdditions,
lambdaCallback,
this::recordConstantDynamicSynthesizingContext,
this::recordTwrCloseResourceMethodSynthesizingContext,
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/ApiOutlineProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/ApiOutlineProfileRewritingTest.java
index f5959e8..599d9c9 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/ApiOutlineProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/ApiOutlineProfileRewritingTest.java
@@ -109,10 +109,14 @@
MethodSubject apiOutlineMethodSubject = apiOutlineClassSubject.uniqueMethod();
assertThat(apiOutlineMethodSubject, notIf(isPresent(), isLibraryClassAlwaysPresent()));
- // TODO(b/265729283): When outlining the residual profile should include the outline method and
- // its holder.
+ // Verify the residual profile contains the outline method and its holder when present.
profileInspector
.assertContainsMethodRule(MethodReferenceUtils.mainMethod(Main.class))
+ .applyIf(
+ !isLibraryClassAlwaysPresent(),
+ i ->
+ i.assertContainsClassRule(apiOutlineClassSubject)
+ .assertContainsMethodRule(apiOutlineMethodSubject))
.assertContainsNoOtherRules();
}
diff --git a/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileInspector.java b/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileInspector.java
index 507dd67..d498e18 100644
--- a/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileInspector.java
+++ b/src/test/java/com/android/tools/r8/profile/art/utils/ArtProfileInspector.java
@@ -30,6 +30,13 @@
this.artProfile = artProfile;
}
+ public ArtProfileInspector applyIf(boolean condition, Consumer<ArtProfileInspector> fn) {
+ if (condition) {
+ fn.accept(this);
+ }
+ return this;
+ }
+
public ArtProfileInspector assertEmpty() {
assertEquals(0, artProfile.size());
return this;