Generalize ArtProfileAdditions to work on abstract profile
Bug: b/271822426
Change-Id: I4f42c5639f930a1292d8e8a7d7cc1ed819601e60
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
index 67a2116..fe54f24 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfile.java
@@ -110,9 +110,8 @@
MissingStartupProfileItemsDiagnostic.Builder missingItemsDiagnosticBuilder =
new MissingStartupProfileItemsDiagnostic.Builder(definitions)
.setOrigin(startupProfileProvider.getOrigin());
- NonEmptyStartupProfile.Builder startupProfileBuilder =
- NonEmptyStartupProfile.builder(
- options, missingItemsDiagnosticBuilder, startupProfileProvider);
+ StartupProfile.Builder startupProfileBuilder =
+ StartupProfile.builder(options, missingItemsDiagnosticBuilder, startupProfileProvider);
startupProfileProvider.getStartupProfile(startupProfileBuilder);
startupProfiles.add(startupProfileBuilder.build());
if (missingItemsDiagnosticBuilder.hasMissingStartupItems()) {
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java
index a815ecb..c5ec563 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupProfileProviderUtils.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.utils.ConsumerUtils.emptyConsumer;
-import com.android.tools.r8.experimental.startup.profile.NonEmptyStartupProfile;
import com.android.tools.r8.experimental.startup.profile.StartupItem;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
@@ -54,9 +53,8 @@
// Do not report missing items.
MissingStartupProfileItemsDiagnostic.Builder missingItemsDiagnosticBuilder =
MissingStartupProfileItemsDiagnostic.Builder.nop();
- NonEmptyStartupProfile.Builder startupProfileBuilder =
- NonEmptyStartupProfile.builder(
- options, missingItemsDiagnosticBuilder, startupProfileProvider);
+ StartupProfile.Builder startupProfileBuilder =
+ StartupProfile.builder(options, missingItemsDiagnosticBuilder, startupProfileProvider);
// Do not report warnings for lines that cannot be parsed.
startupProfileBuilder.setIgnoreWarnings();
// Populate the startup profile builder.
diff --git a/src/main/java/com/android/tools/r8/profile/AbstractProfile.java b/src/main/java/com/android/tools/r8/profile/AbstractProfile.java
new file mode 100644
index 0000000..8265aa2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/AbstractProfile.java
@@ -0,0 +1,41 @@
+// 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;
+
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.ThrowingConsumer;
+
+public interface AbstractProfile<
+ ClassRule extends AbstractProfileClassRule, MethodRule extends AbstractProfileMethodRule> {
+
+ boolean containsClassRule(DexType type);
+
+ boolean containsMethodRule(DexMethod method);
+
+ <E1 extends Exception, E2 extends Exception> void forEachRule(
+ ThrowingConsumer<ClassRule, E1> classRuleConsumer,
+ ThrowingConsumer<MethodRule, E2> methodRuleConsumer)
+ throws E1, E2;
+
+ ClassRule getClassRule(DexType type);
+
+ MethodRule getMethodRule(DexMethod method);
+
+ interface Builder<
+ ClassRule extends AbstractProfileClassRule,
+ MethodRule extends AbstractProfileMethodRule,
+ Profile extends AbstractProfile<ClassRule, MethodRule>,
+ ProfileBuilder extends Builder<ClassRule, MethodRule, Profile, ProfileBuilder>> {
+
+ ProfileBuilder addRule(AbstractProfileRule profileRule);
+
+ ProfileBuilder addClassRule(ClassRule classRule);
+
+ ProfileBuilder addMethodRule(MethodRule methodRule);
+
+ Profile build();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/AbstractProfileClassRule.java b/src/main/java/com/android/tools/r8/profile/AbstractProfileClassRule.java
new file mode 100644
index 0000000..d948afb
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/AbstractProfileClassRule.java
@@ -0,0 +1,17 @@
+// 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;
+
+import com.android.tools.r8.graph.DexType;
+
+public interface AbstractProfileClassRule extends AbstractProfileRule {
+
+ DexType getReference();
+
+ interface Builder<ClassRule extends AbstractProfileClassRule> {
+
+ ClassRule build();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/AbstractProfileMethodRule.java b/src/main/java/com/android/tools/r8/profile/AbstractProfileMethodRule.java
new file mode 100644
index 0000000..ddb1225
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/AbstractProfileMethodRule.java
@@ -0,0 +1,27 @@
+// 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;
+
+import com.android.tools.r8.graph.DexMethod;
+
+public interface AbstractProfileMethodRule extends AbstractProfileRule {
+
+ DexMethod getReference();
+
+ interface Builder<
+ MethodRule extends AbstractProfileMethodRule,
+ MethodRuleBuilder extends Builder<MethodRule, MethodRuleBuilder>> {
+
+ boolean isGreaterThanOrEqualTo(MethodRuleBuilder methodRuleBuilder);
+
+ MethodRuleBuilder join(MethodRule methodRule);
+
+ MethodRuleBuilder join(MethodRuleBuilder methodRuleBuilder);
+
+ MethodRuleBuilder setMethod(DexMethod method);
+
+ MethodRule build();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/profile/AbstractProfileRule.java b/src/main/java/com/android/tools/r8/profile/AbstractProfileRule.java
new file mode 100644
index 0000000..c9f0d4c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/AbstractProfileRule.java
@@ -0,0 +1,15 @@
+// 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;
+
+import com.android.tools.r8.profile.art.ArtProfileRule;
+
+public interface AbstractProfileRule {
+
+ @SuppressWarnings("unchecked")
+ default ArtProfileRule asArtProfileRule() {
+ return (ArtProfileRule) this;
+ }
+}
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 8fb11ef..a1761ec 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
@@ -19,6 +19,8 @@
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxingLens;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.profile.AbstractProfile;
+import com.android.tools.r8.profile.AbstractProfileRule;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.ThrowingConsumer;
@@ -33,7 +35,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
-public class ArtProfile {
+public class ArtProfile implements AbstractProfile<ArtProfileClassRule, ArtProfileMethodRule> {
private final Map<DexReference, ArtProfileRule> rules;
@@ -50,10 +52,12 @@
return new Builder(artProfileProvider, options);
}
+ @Override
public boolean containsClassRule(DexType type) {
return rules.containsKey(type);
}
+ @Override
public boolean containsMethodRule(DexMethod method) {
return rules.containsKey(method);
}
@@ -65,6 +69,7 @@
}
}
+ @Override
public <E1 extends Exception, E2 extends Exception> void forEachRule(
ThrowingConsumer<ArtProfileClassRule, E1> classRuleConsumer,
ThrowingConsumer<ArtProfileMethodRule, E2> methodRuleConsumer)
@@ -74,10 +79,12 @@
}
}
+ @Override
public ArtProfileClassRule getClassRule(DexType type) {
return (ArtProfileClassRule) rules.get(type);
}
+ @Override
public ArtProfileMethodRule getMethodRule(DexMethod method) {
return (ArtProfileMethodRule) rules.get(method);
}
@@ -259,7 +266,9 @@
methodRule.getMethodReference(), methodRule.getMethodRuleInfo()));
}
- public static class Builder implements ArtProfileBuilder {
+ public static class Builder
+ implements ArtProfileBuilder,
+ AbstractProfile.Builder<ArtProfileClassRule, ArtProfileMethodRule, ArtProfile, Builder> {
private final ArtProfileProvider artProfileProvider;
private final DexItemFactory dexItemFactory;
@@ -281,19 +290,34 @@
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));
+ @Override
+ public Builder addRule(AbstractProfileRule rule) {
+ if (rule instanceof ArtProfileClassRule) {
+ return addClassRule((ArtProfileClassRule) rule);
+ } else {
+ assert rule instanceof ArtProfileMethodRule;
+ return addMethodRule((ArtProfileMethodRule) rule);
+ }
+ }
+
+ @Override
+ public Builder addClassRule(ArtProfileClassRule classRule) {
+ assert !rules.containsKey(classRule.getReference());
+ rules.put(classRule.getType(), classRule);
return this;
}
- public Builder addRules(Collection<ArtProfileRule> rules) {
- rules.forEach(this::addRule);
+ @Override
+ public Builder addMethodRule(ArtProfileMethodRule methodRule) {
+ assert !rules.containsKey(methodRule.getReference());
+ rules.put(methodRule.getMethod(), methodRule);
return this;
}
+ public Builder addRule(ArtProfileRule rule) {
+ return rule.apply(this::addClassRule, this::addMethodRule);
+ }
+
public Builder addRuleBuilders(Collection<ArtProfileRule.Builder> ruleBuilders) {
ruleBuilders.forEach(ruleBuilder -> addRule(ruleBuilder.build()));
return this;
@@ -303,14 +327,14 @@
public Builder addClassRule(Consumer<ArtProfileClassRuleBuilder> classRuleBuilderConsumer) {
ArtProfileClassRule.Builder classRuleBuilder = ArtProfileClassRule.builder(dexItemFactory);
classRuleBuilderConsumer.accept(classRuleBuilder);
- return addRule(classRuleBuilder.build());
+ return addClassRule(classRuleBuilder.build());
}
@Override
public Builder addMethodRule(Consumer<ArtProfileMethodRuleBuilder> methodRuleBuilderConsumer) {
ArtProfileMethodRule.Builder methodRuleBuilder = ArtProfileMethodRule.builder(dexItemFactory);
methodRuleBuilderConsumer.accept(methodRuleBuilder);
- return addRule(methodRuleBuilder.build());
+ return addMethodRule(methodRuleBuilder.build());
}
@Override
@@ -328,6 +352,7 @@
return this;
}
+ @Override
public ArtProfile build() {
return new ArtProfile(rules);
}
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 283e22b..625d92f 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,15 +5,16 @@
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.profile.AbstractProfileClassRule;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.ThrowingConsumer;
+import com.android.tools.r8.utils.ThrowingFunction;
import java.io.IOException;
import java.io.OutputStreamWriter;
-public class ArtProfileClassRule extends ArtProfileRule {
+public class ArtProfileClassRule extends ArtProfileRule implements AbstractProfileClassRule {
private final DexType type;
@@ -37,6 +38,14 @@
classRuleConsumer.accept(this);
}
+ @Override
+ public <T, E1 extends Exception, E2 extends Exception> T apply(
+ ThrowingFunction<ArtProfileClassRule, T, E1> classRuleFunction,
+ ThrowingFunction<ArtProfileMethodRule, T, E2> methodRuleFunction)
+ throws E1 {
+ return classRuleFunction.apply(this);
+ }
+
public ClassReference getClassReference() {
return Reference.classFromDescriptor(type.toDescriptorString());
}
@@ -46,7 +55,7 @@
}
@Override
- public DexReference getReference() {
+ public DexType getReference() {
return getType();
}
@@ -55,16 +64,6 @@
}
@Override
- public boolean isClassRule() {
- return true;
- }
-
- @Override
- public ArtProfileClassRule asClassRule() {
- return this;
- }
-
- @Override
public void writeHumanReadableRuleString(OutputStreamWriter writer) throws IOException {
writer.write(type.toDescriptorString());
}
@@ -91,7 +90,8 @@
return type.toDescriptorString();
}
- public static class Builder extends ArtProfileRule.Builder implements ArtProfileClassRuleBuilder {
+ public static class Builder extends ArtProfileRule.Builder
+ implements ArtProfileClassRuleBuilder, AbstractProfileClassRule.Builder<ArtProfileClassRule> {
private final DexItemFactory dexItemFactory;
private DexType type;
@@ -105,11 +105,6 @@
}
@Override
- public boolean isClassRuleBuilder() {
- return true;
- }
-
- @Override
Builder asClassRuleBuilder() {
return 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
index 9eb9a1c..0a256ba 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
@@ -48,10 +48,11 @@
private static ArtProfile createCompleteArtProfile(AppInfo appInfo) {
ArtProfile.Builder artProfileBuilder = ArtProfile.builder();
for (DexProgramClass clazz : appInfo.classesWithDeterministicOrder()) {
- artProfileBuilder.addRule(ArtProfileClassRule.builder().setType(clazz.getType()).build());
+ artProfileBuilder.addClassRule(
+ ArtProfileClassRule.builder().setType(clazz.getType()).build());
clazz.forEachMethod(
method ->
- artProfileBuilder.addRule(
+ artProfileBuilder.addMethodRule(
ArtProfileMethodRule.builder().setMethod(method.getReference()).build()));
}
return artProfileBuilder.build();
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 fe7bd78..1440b8b 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
@@ -6,14 +6,16 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.profile.AbstractProfileMethodRule;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.utils.MethodReferenceUtils;
import com.android.tools.r8.utils.ThrowingConsumer;
+import com.android.tools.r8.utils.ThrowingFunction;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.util.function.Consumer;
-public class ArtProfileMethodRule extends ArtProfileRule {
+public class ArtProfileMethodRule extends ArtProfileRule implements AbstractProfileMethodRule {
private final DexMethod method;
private final ArtProfileMethodRuleInfoImpl info;
@@ -39,6 +41,14 @@
methodRuleConsumer.accept(this);
}
+ @Override
+ public <T, E1 extends Exception, E2 extends Exception> T apply(
+ ThrowingFunction<ArtProfileClassRule, T, E1> classRuleFunction,
+ ThrowingFunction<ArtProfileMethodRule, T, E2> methodRuleFunction)
+ throws E2 {
+ return methodRuleFunction.apply(this);
+ }
+
public DexMethod getMethod() {
return method;
}
@@ -57,16 +67,6 @@
}
@Override
- public boolean isMethodRule() {
- return true;
- }
-
- @Override
- public ArtProfileMethodRule asMethodRule() {
- return this;
- }
-
- @Override
public void writeHumanReadableRuleString(OutputStreamWriter writer) throws IOException {
info.writeHumanReadableFlags(writer);
writer.write(method.toSmaliString());
@@ -97,7 +97,8 @@
}
public static class Builder extends ArtProfileRule.Builder
- implements ArtProfileMethodRuleBuilder {
+ implements ArtProfileMethodRuleBuilder,
+ AbstractProfileMethodRule.Builder<ArtProfileMethodRule, Builder> {
private final DexItemFactory dexItemFactory;
@@ -118,8 +119,8 @@
}
@Override
- public boolean isMethodRuleBuilder() {
- return true;
+ public boolean isGreaterThanOrEqualTo(Builder builder) {
+ return methodRuleInfoBuilder.isGreaterThanOrEqualTo(builder.methodRuleInfoBuilder);
}
@Override
@@ -128,11 +129,24 @@
}
@Override
+ public Builder join(Builder builder) {
+ methodRuleInfoBuilder.joinFlags(builder);
+ return this;
+ }
+
+ @Override
+ public Builder join(ArtProfileMethodRule methodRule) {
+ methodRuleInfoBuilder.joinFlags(methodRule.getMethodRuleInfo());
+ return this;
+ }
+
+ @Override
public Builder setMethodReference(MethodReference methodReference) {
assert dexItemFactory != null;
return setMethod(MethodReferenceUtils.toDexMethod(methodReference, dexItemFactory));
}
+ @Override
public Builder setMethod(DexMethod method) {
this.method = method;
return this;
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 cb482d8..d91553e 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
@@ -105,6 +105,10 @@
return flags;
}
+ public boolean isGreaterThanOrEqualTo(Builder builder) {
+ return flags == (flags | builder.flags);
+ }
+
public Builder merge(ArtProfileMethodRuleInfo methodRuleInfo) {
if (methodRuleInfo.isHot()) {
setIsHot();
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 8d6eefd..bb0bcc1 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
@@ -5,17 +5,24 @@
package com.android.tools.r8.profile.art;
import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.profile.AbstractProfileRule;
import com.android.tools.r8.utils.ThrowingConsumer;
+import com.android.tools.r8.utils.ThrowingFunction;
import java.io.IOException;
import java.io.OutputStreamWriter;
-public abstract class ArtProfileRule implements Comparable<ArtProfileRule> {
+public abstract class ArtProfileRule implements Comparable<ArtProfileRule>, AbstractProfileRule {
public abstract <E1 extends Exception, E2 extends Exception> void accept(
ThrowingConsumer<ArtProfileClassRule, E1> classRuleConsumer,
ThrowingConsumer<ArtProfileMethodRule, E2> methodRuleConsumer)
throws E1, E2;
+ public abstract <T, E1 extends Exception, E2 extends Exception> T apply(
+ ThrowingFunction<ArtProfileClassRule, T, E1> classRuleFunction,
+ ThrowingFunction<ArtProfileMethodRule, T, E2> methodRuleFunction)
+ throws E1, E2;
+
@Override
public final int compareTo(ArtProfileRule rule) {
return getReference().compareTo(rule.getReference());
@@ -23,38 +30,14 @@
public abstract DexReference getReference();
- public boolean isClassRule() {
- return false;
- }
-
- public ArtProfileClassRule asClassRule() {
- return null;
- }
-
- public boolean isMethodRule() {
- return false;
- }
-
- public ArtProfileMethodRule asMethodRule() {
- return null;
- }
-
public abstract void writeHumanReadableRuleString(OutputStreamWriter writer) throws IOException;
public abstract static class Builder {
- public boolean isClassRuleBuilder() {
- return false;
- }
-
ArtProfileClassRule.Builder asClassRuleBuilder() {
return null;
}
- public boolean isMethodRuleBuilder() {
- return false;
- }
-
ArtProfileMethodRule.Builder asMethodRuleBuilder() {
return null;
}
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
index f4400c7..6207388 100644
--- 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
@@ -4,306 +4,57 @@
package com.android.tools.r8.profile.art.rewriting;
-import static com.android.tools.r8.utils.MapUtils.ignoreKey;
-
-import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramDefinition;
-import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.profile.AbstractProfileRule;
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.ArtProfileMethodRuleInfoImpl;
import com.android.tools.r8.profile.art.ArtProfileRule;
-import com.android.tools.r8.utils.WorkList;
-import com.google.common.collect.Sets;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Consumer;
-import java.util.function.Function;
-import java.util.stream.Collectors;
+import java.util.Comparator;
-/** Mutable extension of an existing ArtProfile. */
-public class ArtProfileAdditions {
+public class ArtProfileAdditions
+ extends ProfileAdditions<
+ ArtProfileAdditions,
+ ArtProfileClassRule,
+ ArtProfileClassRule.Builder,
+ ArtProfileMethodRule,
+ ArtProfileMethodRule.Builder,
+ ArtProfileRule,
+ ArtProfile,
+ ArtProfile.Builder> {
- public interface ArtProfileAdditionsBuilder {
-
- default ArtProfileAdditionsBuilder addRule(ProgramDefinition definition) {
- return addRule(definition.getReference());
- }
-
- default ArtProfileAdditionsBuilder addRule(DexReference reference) {
- if (reference.isDexType()) {
- return addClassRule(reference.asDexType());
- } else {
- assert reference.isDexMethod();
- return addMethodRule(reference.asDexMethod());
- }
- }
-
- ArtProfileAdditionsBuilder addClassRule(DexType type);
-
- ArtProfileAdditionsBuilder addMethodRule(DexMethod method);
-
- default ArtProfileAdditionsBuilder removeMovedMethodRule(
- ProgramMethod oldMethod, ProgramMethod newMethod) {
- return removeMovedMethodRule(oldMethod.getReference(), newMethod);
- }
-
- ArtProfileAdditionsBuilder removeMovedMethodRule(DexMethod oldMethod, ProgramMethod newMethod);
+ ArtProfileAdditions(ArtProfile profile) {
+ super(profile);
}
- private ArtProfile artProfile;
-
- private final Map<DexType, ArtProfileClassRule.Builder> classRuleAdditions =
- new ConcurrentHashMap<>();
- private final Map<DexMethod, ArtProfileMethodRule.Builder> methodRuleAdditions =
- new ConcurrentHashMap<>();
- private final Set<DexMethod> methodRuleRemovals = Sets.newConcurrentHashSet();
-
- private final NestedMethodRuleAdditionsGraph nestedMethodRuleAdditionsGraph =
- new NestedMethodRuleAdditionsGraph();
-
- ArtProfileAdditions(ArtProfile artProfile) {
- this.artProfile = artProfile;
+ @Override
+ public ArtProfileAdditions create() {
+ return new ArtProfileAdditions(profile);
}
- void applyIfContextIsInProfile(DexType context, Consumer<ArtProfileAdditions> fn) {
- if (artProfile.containsClassRule(context) || classRuleAdditions.containsKey(context)) {
- fn.accept(this);
- }
+ @Override
+ public ArtProfileClassRule.Builder createClassRuleBuilder(DexType type) {
+ return ArtProfileClassRule.builder().setType(type);
}
- void applyIfContextIsInProfile(
- DexMethod context, Consumer<ArtProfileAdditionsBuilder> builderConsumer) {
- ArtProfileMethodRule contextMethodRule = artProfile.getMethodRule(context);
- if (contextMethodRule != null) {
- builderConsumer.accept(
- new ArtProfileAdditionsBuilder() {
-
- @Override
- public ArtProfileAdditionsBuilder addClassRule(DexType type) {
- ArtProfileAdditions.this.addClassRule(type);
- return this;
- }
-
- @Override
- public ArtProfileAdditionsBuilder addMethodRule(DexMethod method) {
- ArtProfileAdditions.this.addMethodRuleFromContext(
- method,
- methodRuleInfoBuilder ->
- methodRuleInfoBuilder.joinFlags(contextMethodRule.getMethodRuleInfo()));
- return this;
- }
-
- @Override
- public ArtProfileAdditionsBuilder removeMovedMethodRule(
- DexMethod oldMethod, ProgramMethod newMethod) {
- ArtProfileAdditions.this.removeMovedMethodRule(oldMethod, newMethod);
- return this;
- }
- });
- } else if (methodRuleAdditions.containsKey(context)) {
- builderConsumer.accept(
- new ArtProfileAdditionsBuilder() {
-
- @Override
- public ArtProfileAdditionsBuilder addClassRule(DexType type) {
- ArtProfileAdditions.this.addClassRule(type);
- return this;
- }
-
- @Override
- public ArtProfileAdditionsBuilder addMethodRule(DexMethod method) {
- ArtProfileMethodRule.Builder contextRuleBuilder = methodRuleAdditions.get(context);
- ArtProfileAdditions.this.addMethodRuleFromContext(
- method,
- methodRuleInfoBuilder -> methodRuleInfoBuilder.joinFlags(contextRuleBuilder));
- nestedMethodRuleAdditionsGraph.recordMethodRuleInfoFlagsLargerThan(method, context);
- return this;
- }
-
- @Override
- public ArtProfileAdditionsBuilder removeMovedMethodRule(
- DexMethod oldMethod, ProgramMethod newMethod) {
- ArtProfileAdditions.this.removeMovedMethodRule(oldMethod, newMethod);
- return this;
- }
- });
- }
+ @Override
+ public ArtProfileMethodRule.Builder createMethodRuleBuilder(DexMethod method) {
+ return ArtProfileMethodRule.builder().setMethod(method);
}
- public ArtProfileAdditions addClassRule(DexClass clazz) {
- addClassRule(clazz.getType());
+ @Override
+ public ArtProfile.Builder createProfileBuilder() {
+ return ArtProfile.builder();
+ }
+
+ @Override
+ public Comparator<AbstractProfileRule> getRuleComparator() {
+ return Comparator.comparing(AbstractProfileRule::asArtProfileRule);
+ }
+
+ @Override
+ public ArtProfileAdditions self() {
return this;
}
-
- public void addClassRule(DexType type) {
- if (artProfile.containsClassRule(type)) {
- return;
- }
-
- // Create profile rule for class.
- classRuleAdditions.computeIfAbsent(type, key -> ArtProfileClassRule.builder().setType(key));
- }
-
- private void addMethodRuleFromContext(
- DexMethod method,
- Consumer<ArtProfileMethodRuleInfoImpl.Builder> methodRuleInfoBuilderConsumer) {
- addMethodRule(method, methodRuleInfoBuilderConsumer);
- }
-
- public ArtProfileAdditions addMethodRule(
- DexClassAndMethod method,
- Consumer<ArtProfileMethodRuleInfoImpl.Builder> methodRuleInfoBuilderConsumer) {
- return addMethodRule(method.getReference(), methodRuleInfoBuilderConsumer);
- }
-
- public ArtProfileAdditions addMethodRule(
- DexMethod method,
- Consumer<ArtProfileMethodRuleInfoImpl.Builder> methodRuleInfoBuilderConsumer) {
- // Create profile rule for method.
- ArtProfileMethodRule.Builder methodRuleBuilder =
- methodRuleAdditions.computeIfAbsent(
- method, methodReference -> ArtProfileMethodRule.builder().setMethod(method));
-
- // Setup the rule.
- synchronized (methodRuleBuilder) {
- methodRuleBuilder.acceptMethodRuleInfoBuilder(methodRuleInfoBuilderConsumer);
- }
-
- return this;
- }
-
- void removeMovedMethodRule(DexMethod oldMethod, ProgramMethod newMethod) {
- assert artProfile.containsMethodRule(oldMethod) || methodRuleAdditions.containsKey(oldMethod);
- assert methodRuleAdditions.containsKey(newMethod.getReference());
- methodRuleRemovals.add(oldMethod);
- }
-
- ArtProfile createNewArtProfile() {
- if (!hasAdditions()) {
- assert !hasRemovals();
- return artProfile;
- }
-
- nestedMethodRuleAdditionsGraph.propagateMethodRuleInfoFlags(methodRuleAdditions);
-
- // Add existing rules to new profile.
- ArtProfile.Builder artProfileBuilder = ArtProfile.builder();
- artProfile.forEachRule(
- artProfileBuilder::addRule,
- methodRule -> {
- if (methodRuleRemovals.contains(methodRule.getMethod())) {
- return;
- }
- ArtProfileMethodRule.Builder methodRuleBuilder =
- methodRuleAdditions.remove(methodRule.getReference());
- if (methodRuleBuilder != null) {
- ArtProfileMethodRule newMethodRule =
- methodRuleBuilder
- .acceptMethodRuleInfoBuilder(
- methodRuleInfoBuilder ->
- methodRuleInfoBuilder.joinFlags(methodRule.getMethodRuleInfo()))
- .build();
- artProfileBuilder.addRule(newMethodRule);
- } else {
- artProfileBuilder.addRule(methodRule);
- }
- });
-
- // 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();
- }
-
- private boolean hasRemovals() {
- return !methodRuleRemovals.isEmpty();
- }
-
- ArtProfileAdditions rewriteMethodReferences(Function<DexMethod, DexMethod> methodFn) {
- ArtProfileAdditions rewrittenAdditions = new ArtProfileAdditions(artProfile);
- assert methodRuleRemovals.isEmpty();
- rewrittenAdditions.classRuleAdditions.putAll(classRuleAdditions);
- methodRuleAdditions.forEach(
- (method, methodRuleBuilder) -> {
- DexMethod newMethod = methodFn.apply(method);
- ArtProfileMethodRule.Builder existingMethodRuleBuilder =
- rewrittenAdditions.methodRuleAdditions.put(
- newMethod, methodRuleBuilder.setMethod(newMethod));
- assert existingMethodRuleBuilder == null;
- });
- return rewrittenAdditions;
- }
-
- void setArtProfile(ArtProfile artProfile) {
- this.artProfile = artProfile;
- }
-
- private static class NestedMethodRuleAdditionsGraph {
-
- private final Map<DexMethod, Set<DexMethod>> successors = new ConcurrentHashMap<>();
- private final Map<DexMethod, Set<DexMethod>> predecessors = new ConcurrentHashMap<>();
-
- void recordMethodRuleInfoFlagsLargerThan(DexMethod largerFlags, DexMethod smallerFlags) {
- predecessors
- .computeIfAbsent(largerFlags, ignoreKey(Sets::newConcurrentHashSet))
- .add(smallerFlags);
- successors
- .computeIfAbsent(smallerFlags, ignoreKey(Sets::newConcurrentHashSet))
- .add(largerFlags);
- }
-
- void propagateMethodRuleInfoFlags(
- Map<DexMethod, ArtProfileMethodRule.Builder> methodRuleAdditions) {
- List<DexMethod> leaves =
- successors.keySet().stream()
- .filter(method -> predecessors.getOrDefault(method, Collections.emptySet()).isEmpty())
- .collect(Collectors.toList());
- WorkList<DexMethod> worklist = WorkList.newIdentityWorkList(leaves);
- while (worklist.hasNext()) {
- DexMethod method = worklist.next();
- ArtProfileMethodRule.Builder methodRuleBuilder = methodRuleAdditions.get(method);
- for (DexMethod successor : successors.getOrDefault(method, Collections.emptySet())) {
- methodRuleAdditions
- .get(successor)
- .acceptMethodRuleInfoBuilder(
- methodRuleInfoBuilder -> {
- int oldFlags = methodRuleInfoBuilder.getFlags();
- methodRuleInfoBuilder.joinFlags(methodRuleBuilder);
- // If this assertion fails, that means we have synthetics with multiple
- // synthesizing contexts, which are not guaranteed to be processed before the
- // synthetic itself. In that case this assertion should simply be removed.
- assert methodRuleInfoBuilder.getFlags() == oldFlags;
- });
- // Note: no need to addIgnoringSeenSet() since the graph will not have cycles. Indeed, it
- // should never be the case that a method m2(), which is synthesized from method context
- // m1(), would itself be a synthesizing context for m1().
- worklist.addIfNotSeen(successor);
- }
- }
- }
- }
}
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
index 5198d05..11df596 100644
--- 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
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.profile.art.ArtProfileCollection;
-import com.android.tools.r8.profile.art.rewriting.ArtProfileAdditions.ArtProfileAdditionsBuilder;
+import com.android.tools.r8.profile.art.rewriting.ProfileAdditions.ProfileAdditionsBuilder;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -38,7 +38,7 @@
public abstract void addMethodIfContextIsInProfile(ProgramMethod method, ProgramMethod context);
public abstract void applyIfContextIsInProfile(
- DexMethod context, Consumer<ArtProfileAdditionsBuilder> builderConsumer);
+ DexMethod context, Consumer<ProfileAdditionsBuilder> builderConsumer);
public abstract void commit(AppView<?> appView);
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
index 1d1a897..0e6011d 100644
--- 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
@@ -15,7 +15,7 @@
import com.android.tools.r8.profile.art.ArtProfileCollection;
import com.android.tools.r8.profile.art.ArtProfileMethodRuleInfoImpl;
import com.android.tools.r8.profile.art.NonEmptyArtProfileCollection;
-import com.android.tools.r8.profile.art.rewriting.ArtProfileAdditions.ArtProfileAdditionsBuilder;
+import com.android.tools.r8.profile.art.rewriting.ProfileAdditions.ProfileAdditionsBuilder;
import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.Iterator;
@@ -56,7 +56,11 @@
} else {
apply(
artProfileAdditions ->
- artProfileAdditions.addMethodRule(method, methodRuleInfoBuilderConsumer));
+ artProfileAdditions.addMethodRule(
+ method,
+ methodRuleBuilder ->
+ methodRuleBuilder.acceptMethodRuleInfoBuilder(
+ methodRuleInfoBuilderConsumer)));
}
}
@@ -74,7 +78,7 @@
void applyIfContextIsInProfile(
ProgramDefinition context,
Consumer<ArtProfileAdditions> additionsConsumer,
- Consumer<ArtProfileAdditionsBuilder> additionsBuilderConsumer) {
+ Consumer<ProfileAdditionsBuilder> additionsBuilderConsumer) {
if (context.isProgramClass()) {
applyIfContextIsInProfile(context.asProgramClass(), additionsConsumer);
} else {
@@ -95,13 +99,13 @@
}
public void applyIfContextIsInProfile(
- ProgramMethod context, Consumer<ArtProfileAdditionsBuilder> builderConsumer) {
+ ProgramMethod context, Consumer<ProfileAdditionsBuilder> builderConsumer) {
applyIfContextIsInProfile(context.getReference(), builderConsumer);
}
@Override
public void applyIfContextIsInProfile(
- DexMethod context, Consumer<ArtProfileAdditionsBuilder> builderConsumer) {
+ DexMethod context, Consumer<ProfileAdditionsBuilder> builderConsumer) {
for (ArtProfileAdditions artProfileAdditions : additionsCollection) {
artProfileAdditions.applyIfContextIsInProfile(context, builderConsumer);
}
@@ -125,7 +129,7 @@
assert hasAdditions();
List<ArtProfile> newArtProfiles = new ArrayList<>(additionsCollection.size());
for (ArtProfileAdditions additions : additionsCollection) {
- newArtProfiles.add(additions.createNewArtProfile());
+ newArtProfiles.add(additions.createNewProfile());
}
return new NonEmptyArtProfileCollection(newArtProfiles);
}
@@ -151,7 +155,7 @@
assert artProfileCollection.isNonEmpty();
Iterator<ArtProfile> artProfileIterator = artProfileCollection.asNonEmpty().iterator();
for (ArtProfileAdditions additions : additionsCollection) {
- additions.setArtProfile(artProfileIterator.next());
+ additions.setProfile(artProfileIterator.next());
}
return this;
}
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
index 8bfd4a6..9d87d65 100644
--- 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
@@ -8,7 +8,7 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.profile.art.ArtProfileCollection;
-import com.android.tools.r8.profile.art.rewriting.ArtProfileAdditions.ArtProfileAdditionsBuilder;
+import com.android.tools.r8.profile.art.rewriting.ProfileAdditions.ProfileAdditionsBuilder;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -30,7 +30,7 @@
@Override
public void applyIfContextIsInProfile(
- DexMethod context, Consumer<ArtProfileAdditionsBuilder> builderConsumer) {
+ DexMethod context, Consumer<ProfileAdditionsBuilder> builderConsumer) {
// Intentionally empty.
}
diff --git a/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileAdditions.java b/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileAdditions.java
new file mode 100644
index 0000000..195963e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/profile/art/rewriting/ProfileAdditions.java
@@ -0,0 +1,309 @@
+// 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 static com.android.tools.r8.utils.MapUtils.ignoreKey;
+
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramDefinition;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.profile.AbstractProfile;
+import com.android.tools.r8.profile.AbstractProfileClassRule;
+import com.android.tools.r8.profile.AbstractProfileMethodRule;
+import com.android.tools.r8.profile.AbstractProfileRule;
+import com.android.tools.r8.utils.WorkList;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/** Mutable extension of an existing profile. */
+public abstract class ProfileAdditions<
+ Additions extends
+ ProfileAdditions<
+ Additions,
+ ClassRule,
+ ClassRuleBuilder,
+ MethodRule,
+ MethodRuleBuilder,
+ ProfileRule,
+ Profile,
+ ProfileBuilder>,
+ ClassRule extends AbstractProfileClassRule,
+ ClassRuleBuilder extends AbstractProfileClassRule.Builder<ClassRule>,
+ MethodRule extends AbstractProfileMethodRule,
+ MethodRuleBuilder extends AbstractProfileMethodRule.Builder<MethodRule, MethodRuleBuilder>,
+ ProfileRule extends AbstractProfileRule,
+ Profile extends AbstractProfile<ClassRule, MethodRule>,
+ ProfileBuilder extends
+ AbstractProfile.Builder<ClassRule, MethodRule, Profile, ProfileBuilder>> {
+
+ public interface ProfileAdditionsBuilder {
+
+ default ProfileAdditionsBuilder addRule(ProgramDefinition definition) {
+ return addRule(definition.getReference());
+ }
+
+ default ProfileAdditionsBuilder addRule(DexReference reference) {
+ if (reference.isDexType()) {
+ return addClassRule(reference.asDexType());
+ } else {
+ assert reference.isDexMethod();
+ return addMethodRule(reference.asDexMethod());
+ }
+ }
+
+ ProfileAdditionsBuilder addClassRule(DexType type);
+
+ ProfileAdditionsBuilder addMethodRule(DexMethod method);
+
+ default void removeMovedMethodRule(ProgramMethod oldMethod, ProgramMethod newMethod) {
+ removeMovedMethodRule(oldMethod.getReference(), newMethod);
+ }
+
+ void removeMovedMethodRule(DexMethod oldMethod, ProgramMethod newMethod);
+ }
+
+ Profile profile;
+
+ final Map<DexType, ClassRuleBuilder> classRuleAdditions = new ConcurrentHashMap<>();
+ final Map<DexMethod, MethodRuleBuilder> methodRuleAdditions = new ConcurrentHashMap<>();
+ private final Set<DexMethod> methodRuleRemovals = Sets.newConcurrentHashSet();
+
+ private final NestedMethodRuleAdditionsGraph nestedMethodRuleAdditionsGraph =
+ new NestedMethodRuleAdditionsGraph();
+
+ ProfileAdditions(Profile profile) {
+ this.profile = profile;
+ }
+
+ void applyIfContextIsInProfile(DexType context, Consumer<Additions> fn) {
+ if (profile.containsClassRule(context) || classRuleAdditions.containsKey(context)) {
+ fn.accept(self());
+ }
+ }
+
+ void applyIfContextIsInProfile(
+ DexMethod context, Consumer<ProfileAdditionsBuilder> builderConsumer) {
+ MethodRule contextMethodRule = profile.getMethodRule(context);
+ if (contextMethodRule != null) {
+ builderConsumer.accept(
+ new ProfileAdditionsBuilder() {
+
+ @Override
+ public ProfileAdditionsBuilder addClassRule(DexType type) {
+ ProfileAdditions.this.addClassRule(type);
+ return this;
+ }
+
+ @Override
+ public ProfileAdditionsBuilder addMethodRule(DexMethod method) {
+ ProfileAdditions.this.addMethodRule(
+ method, methodRuleBuilder -> methodRuleBuilder.join(contextMethodRule));
+ return this;
+ }
+
+ @Override
+ public void removeMovedMethodRule(DexMethod oldMethod, ProgramMethod newMethod) {
+ ProfileAdditions.this.removeMovedMethodRule(oldMethod, newMethod);
+ }
+ });
+ } else if (methodRuleAdditions.containsKey(context)) {
+ builderConsumer.accept(
+ new ProfileAdditionsBuilder() {
+
+ @Override
+ public ProfileAdditionsBuilder addClassRule(DexType type) {
+ ProfileAdditions.this.addClassRule(type);
+ return this;
+ }
+
+ @Override
+ public ProfileAdditionsBuilder addMethodRule(DexMethod method) {
+ MethodRuleBuilder contextRuleBuilder = methodRuleAdditions.get(context);
+ ProfileAdditions.this.addMethodRule(
+ method, methodRuleBuilder -> methodRuleBuilder.join(contextRuleBuilder));
+ nestedMethodRuleAdditionsGraph.recordMethodRuleInfoFlagsLargerThan(method, context);
+ return this;
+ }
+
+ @Override
+ public void removeMovedMethodRule(DexMethod oldMethod, ProgramMethod newMethod) {
+ ProfileAdditions.this.removeMovedMethodRule(oldMethod, newMethod);
+ }
+ });
+ }
+ }
+
+ public Additions addClassRule(DexClass clazz) {
+ addClassRule(clazz.getType());
+ return self();
+ }
+
+ public void addClassRule(DexType type) {
+ if (profile.containsClassRule(type)) {
+ return;
+ }
+
+ // Create profile rule for class.
+ classRuleAdditions.computeIfAbsent(type, this::createClassRuleBuilder);
+ }
+
+ public Additions addMethodRule(
+ DexClassAndMethod method, Consumer<MethodRuleBuilder> methodRuleBuilderConsumer) {
+ return addMethodRule(method.getReference(), methodRuleBuilderConsumer);
+ }
+
+ public Additions addMethodRule(
+ DexMethod method, Consumer<MethodRuleBuilder> methodRuleBuilderConsumer) {
+ // Create profile rule for method.
+ MethodRuleBuilder methodRuleBuilder =
+ methodRuleAdditions.computeIfAbsent(method, this::createMethodRuleBuilder);
+
+ // Setup the rule.
+ synchronized (methodRuleBuilder) {
+ methodRuleBuilderConsumer.accept(methodRuleBuilder);
+ }
+
+ return self();
+ }
+
+ void removeMovedMethodRule(DexMethod oldMethod, ProgramMethod newMethod) {
+ assert profile.containsMethodRule(oldMethod) || methodRuleAdditions.containsKey(oldMethod);
+ assert methodRuleAdditions.containsKey(newMethod.getReference());
+ methodRuleRemovals.add(oldMethod);
+ }
+
+ Profile createNewProfile() {
+ if (!hasAdditions()) {
+ assert !hasRemovals();
+ return profile;
+ }
+
+ nestedMethodRuleAdditionsGraph.propagateMethodRuleInfoFlags(methodRuleAdditions);
+
+ // Add existing rules to new profile.
+ ProfileBuilder profileBuilder = createProfileBuilder();
+ profile.forEachRule(
+ profileBuilder::addClassRule,
+ methodRule -> {
+ if (methodRuleRemovals.contains(methodRule.getReference())) {
+ return;
+ }
+ MethodRuleBuilder methodRuleBuilder =
+ methodRuleAdditions.remove(methodRule.getReference());
+ if (methodRuleBuilder != null) {
+ MethodRule newMethodRule = methodRuleBuilder.join(methodRule).build();
+ profileBuilder.addMethodRule(newMethodRule);
+ } else {
+ profileBuilder.addMethodRule(methodRule);
+ }
+ });
+
+ // Sort and add additions to new profile. Sorting is needed since the additions to this
+ // collection may be concurrent.
+ List<AbstractProfileRule> 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(getRuleComparator());
+ ruleAdditionsSorted.forEach(profileBuilder::addRule);
+
+ return profileBuilder.build();
+ }
+
+ boolean hasAdditions() {
+ return !classRuleAdditions.isEmpty() || !methodRuleAdditions.isEmpty();
+ }
+
+ private boolean hasRemovals() {
+ return !methodRuleRemovals.isEmpty();
+ }
+
+ Additions rewriteMethodReferences(Function<DexMethod, DexMethod> methodFn) {
+ Additions rewrittenAdditions = create();
+ assert methodRuleRemovals.isEmpty();
+ rewrittenAdditions.classRuleAdditions.putAll(classRuleAdditions);
+ methodRuleAdditions.forEach(
+ (method, methodRuleBuilder) -> {
+ DexMethod newMethod = methodFn.apply(method);
+ MethodRuleBuilder existingMethodRuleBuilder =
+ rewrittenAdditions.methodRuleAdditions.put(
+ newMethod, methodRuleBuilder.setMethod(newMethod));
+ assert existingMethodRuleBuilder == null;
+ });
+ return rewrittenAdditions;
+ }
+
+ public abstract Additions create();
+
+ public abstract ClassRuleBuilder createClassRuleBuilder(DexType type);
+
+ public abstract MethodRuleBuilder createMethodRuleBuilder(DexMethod method);
+
+ public abstract ProfileBuilder createProfileBuilder();
+
+ public abstract Comparator<AbstractProfileRule> getRuleComparator();
+
+ public abstract Additions self();
+
+ void setProfile(Profile profile) {
+ this.profile = profile;
+ }
+
+ private class NestedMethodRuleAdditionsGraph {
+
+ private final Map<DexMethod, Set<DexMethod>> successors = new ConcurrentHashMap<>();
+ private final Map<DexMethod, Set<DexMethod>> predecessors = new ConcurrentHashMap<>();
+
+ void recordMethodRuleInfoFlagsLargerThan(DexMethod largerFlags, DexMethod smallerFlags) {
+ predecessors
+ .computeIfAbsent(largerFlags, ignoreKey(Sets::newConcurrentHashSet))
+ .add(smallerFlags);
+ successors
+ .computeIfAbsent(smallerFlags, ignoreKey(Sets::newConcurrentHashSet))
+ .add(largerFlags);
+ }
+
+ void propagateMethodRuleInfoFlags(Map<DexMethod, MethodRuleBuilder> methodRuleAdditions) {
+ List<DexMethod> leaves =
+ successors.keySet().stream()
+ .filter(method -> predecessors.getOrDefault(method, Collections.emptySet()).isEmpty())
+ .collect(Collectors.toList());
+ WorkList<DexMethod> worklist = WorkList.newIdentityWorkList(leaves);
+ while (worklist.hasNext()) {
+ DexMethod method = worklist.next();
+ MethodRuleBuilder methodRuleBuilder = methodRuleAdditions.get(method);
+ for (DexMethod successor : successors.getOrDefault(method, Collections.emptySet())) {
+ MethodRuleBuilder successorMethodRuleBuilder = methodRuleAdditions.get(successor);
+ // If this assertion fails, that means we have synthetics with multiple
+ // synthesizing contexts, which are not guaranteed to be processed before the
+ // synthetic itself. In that case this assertion should simply be removed.
+ assert successorMethodRuleBuilder.isGreaterThanOrEqualTo(methodRuleBuilder);
+ successorMethodRuleBuilder.join(methodRuleBuilder);
+ // Note: no need to addIgnoringSeenSet() since the graph will not have cycles. Indeed, it
+ // should never be the case that a method m2(), which is synthesized from method context
+ // m1(), would itself be a synthesizing context for m1().
+ worklist.addIfNotSeen(successor);
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/D8CommandTest.java b/src/test/java/com/android/tools/r8/D8CommandTest.java
index b4c8475..901629a 100644
--- a/src/test/java/com/android/tools/r8/D8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/D8CommandTest.java
@@ -22,7 +22,6 @@
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.experimental.startup.StartupProfile;
-import com.android.tools.r8.experimental.startup.profile.NonEmptyStartupProfile;
import com.android.tools.r8.experimental.startup.profile.StartupItem;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.origin.Origin;
@@ -806,8 +805,8 @@
MissingStartupProfileItemsDiagnostic.Builder missingStartupProfileItemsDiagnosticBuilder =
MissingStartupProfileItemsDiagnostic.Builder.nop();
StartupProfileProvider startupProfileProvider = startupProfileProviders.get(0);
- NonEmptyStartupProfile.Builder startupProfileBuilder =
- NonEmptyStartupProfile.builder(
+ StartupProfile.Builder startupProfileBuilder =
+ StartupProfile.builder(
options, missingStartupProfileItemsDiagnosticBuilder, startupProfileProvider);
startupProfileProvider.getStartupProfile(startupProfileBuilder);