Merge commit 'fa022880caa3b073b638754aea63a435c0becac4' into dev-release
Change-Id: Id43bf4460065aaae02337fc999b994d306969be3
diff --git a/.gitignore b/.gitignore
index 1c8e875..2f6bfaa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -287,6 +287,8 @@
third_party/r8-releases/2.0.74.tar.gz
third_party/r8-releases/3.2.54
third_party/r8-releases/3.2.54.tar.gz
+third_party/r8-releases/8.0.46
+third_party/r8-releases/8.0.46.tar.gz
third_party/r8mappings
third_party/r8mappings.tar.gz
third_party/remapper
diff --git a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
index 56562ac..fe9bd92 100644
--- a/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
+++ b/d8_r8/commonBuildSrc/src/main/kotlin/DependenciesPlugin.kt
@@ -584,6 +584,10 @@
"r8-v3-2-54",
Paths.get("third_party", "r8-releases","3.2.54").toFile(),
Paths.get("third_party", "r8-releases", "3.2.54.tar.gz.sha1").toFile())
+ val r8v8_0_46 = ThirdPartyDependency(
+ "r8-v8-0-46",
+ Paths.get("third_party", "r8-releases","8.0.46").toFile(),
+ Paths.get("third_party", "r8-releases", "8.0.46.tar.gz.sha1").toFile())
val retraceBenchmark = ThirdPartyDependency(
"retrace-benchmark",
Paths.get("third_party", "retrace_benchmark").toFile(),
@@ -692,7 +696,12 @@
}
fun getThirdPartyProguards() : List<ThirdPartyDependency> {
- return listOf("proguard5.2.1", "proguard6.0.1", "proguard-7.0.0", "proguard-7.3.2")
+ return listOf(
+ "proguard5.2.1",
+ "proguard6.0.1",
+ "proguard-7.0.0",
+ "proguard-7.3.2",
+ "proguard-7.4.1")
.map { ThirdPartyDependency(
it,
Paths.get("third_party", "proguard", it).toFile(),
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepForApi.java b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepForApi.java
index 91934e0..aac3246 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepForApi.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/annotations/KeepForApi.java
@@ -44,12 +44,14 @@
/**
* Specify the kind of this item pattern.
*
- * <p>Default kind is CLASS_AND_MEMBERS , meaning the annotated class and/or member is to be kept.
- * When annotating a class this can be set to ONLY_CLASS to avoid patterns on any members. That
- * can be useful when the API members are themselves explicitly annotated.
+ * <p>Default kind is {@link KeepItemKind#CLASS_AND_MEMBERS}, meaning the annotated class and/or
+ * member is to be kept. When annotating a class this can be set to {@link
+ * KeepItemKind#ONLY_CLASS} to avoid patterns on any members. That can be useful when the API
+ * members are themselves explicitly annotated.
*
- * <p>It is not possible to use ONLY_CLASS if annotating a member. Also, it is never valid to use
- * kind ONLY_MEMBERS as the API surface must keep the class if any member is to be accessible.
+ * <p>It is not possible to use {@link KeepItemKind#ONLY_CLASS} if annotating a member. Also, it
+ * is never valid to use kind {@link KeepItemKind#ONLY_MEMBERS} as the API surface must keep the
+ * class if any member is to be accessible.
*
* @return The kind for this pattern.
*/
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/ast/AnnotationConstants.java b/src/keepanno/java/com/android/tools/r8/keepanno/ast/AnnotationConstants.java
index 239dd0e..18b2784 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/ast/AnnotationConstants.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/ast/AnnotationConstants.java
@@ -172,16 +172,6 @@
public static final String CLASS_OPEN_HIERARCHY = "CLASS_OPEN_HIERARCHY";
}
- public static final class Option {
- public static final String DESCRIPTOR =
- "Lcom/android/tools/r8/keepanno/annotations/KeepOption;";
- public static final String SHRINKING = "SHRINKING";
- public static final String OPTIMIZATION = "OPTIMIZATION";
- public static final String OBFUSCATION = "OBFUSCATION";
- public static final String ACCESS_MODIFICATION = "ACCESS_MODIFICATION";
- public static final String ANNOTATION_REMOVAL = "ANNOTATION_REMOVAL";
- }
-
public static final class MemberAccess {
public static final String DESCRIPTOR =
"Lcom/android/tools/r8/keepanno/annotations/MemberAccessFlags;";
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
index 815f6ba..c5d43c5 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractor.java
@@ -49,16 +49,17 @@
/** Extract the PG keep rules that over-approximate a keep edge. */
public class KeepRuleExtractor {
- private final KeepRuleExtractorOptions options;
+ private final KeepRuleExtractorOptions extractorOptions;
private final Consumer<String> ruleConsumer;
public KeepRuleExtractor(Consumer<String> ruleConsumer) {
this(ruleConsumer, KeepRuleExtractorOptions.getR8Options());
}
- public KeepRuleExtractor(Consumer<String> ruleConsumer, KeepRuleExtractorOptions options) {
+ public KeepRuleExtractor(
+ Consumer<String> ruleConsumer, KeepRuleExtractorOptions extractorOptions) {
this.ruleConsumer = ruleConsumer;
- this.options = options;
+ this.extractorOptions = extractorOptions;
}
public void extract(KeepDeclaration declaration) {
@@ -66,7 +67,7 @@
PgRule.groupByKinds(rules);
StringBuilder builder = new StringBuilder();
for (PgRule rule : rules) {
- rule.printRule(builder, options);
+ rule.printRule(builder, extractorOptions);
builder.append("\n");
}
ruleConsumer.accept(builder.toString());
@@ -80,7 +81,7 @@
}
private List<PgRule> generateCheckRules(KeepCheck check) {
- if (!options.hasCheckDiscardSupport()) {
+ if (!extractorOptions.hasCheckDiscardSupport()) {
return Collections.emptyList();
}
KeepItemPattern itemPattern = check.getItemPattern();
@@ -114,7 +115,8 @@
KeepOptions.keepAll(),
memberPatterns,
targetMembers,
- TargetKeepKind.CHECK_DISCARD));
+ TargetKeepKind.CHECK_DISCARD,
+ extractorOptions));
// If the check declaration is to ensure full removal we generate a soft-pin rule to disallow
// moving/inlining the items.
if (isRemovedPattern) {
@@ -130,7 +132,8 @@
allowShrinking,
Collections.singletonMap(memberSymbol, KeepMemberPattern.allMembers()),
Collections.singletonList(memberSymbol),
- TargetKeepKind.CLASS_OR_MEMBERS));
+ TargetKeepKind.CLASS_OR_MEMBERS,
+ extractorOptions));
} else {
// A check removal on members just soft-pins the members.
rules.add(
@@ -141,7 +144,8 @@
memberPatterns,
Collections.emptyList(),
targetMembers,
- TargetKeepKind.JUST_MEMBERS));
+ TargetKeepKind.JUST_MEMBERS,
+ extractorOptions));
}
}
return rules;
@@ -255,7 +259,7 @@
}
@SuppressWarnings("UnnecessaryParentheses")
- private static List<PgRule> doSplit(KeepEdge edge) {
+ private List<PgRule> doSplit(KeepEdge edge) {
List<PgRule> rules = new ArrayList<>();
// Collection for all attribute constraints required for this edge.
Set<KeepAttribute> allAttributeConstraints = new HashSet<>();
@@ -287,7 +291,8 @@
// Generate at most one `-keepattributes` rule for the edge if needed.
if (!allAttributeConstraints.isEmpty()) {
- rules.add(new PgKeepAttributeRule(edge.getMetaInfo(), allAttributeConstraints));
+ rules.add(
+ new PgKeepAttributeRule(edge.getMetaInfo(), allAttributeConstraints, extractorOptions));
}
bindingUsers.forEach(
@@ -400,7 +405,7 @@
callback.accept(newTargetHolder, memberPatterns, targetMembers, finalKeepKind));
}
- private static void createUnconditionalRules(
+ private void createUnconditionalRules(
List<PgRule> rules,
Holder holder,
KeepEdgeMetaInfo metaInfo,
@@ -423,7 +428,8 @@
memberPatterns,
Collections.emptyList(),
targetMembers,
- targetKeepKind));
+ targetKeepKind,
+ extractorOptions));
} else {
rules.add(
new PgUnconditionalRule(
@@ -432,12 +438,13 @@
options,
memberPatterns,
targetMembers,
- targetKeepKind));
+ targetKeepKind,
+ extractorOptions));
}
});
}
- private static void createConditionalRules(
+ private void createConditionalRules(
List<PgRule> rules,
KeepEdgeMetaInfo metaInfo,
Holder conditionHolder,
@@ -472,10 +479,11 @@
memberPatterns,
conditionMembers,
targetMembers,
- targetKeepKind)));
+ targetKeepKind,
+ extractorOptions)));
}
- private static void createDependentRules(
+ private void createDependentRules(
List<PgRule> rules,
Holder initialHolder,
KeepEdgeMetaInfo metaInfo,
@@ -510,7 +518,8 @@
copyWithMethod,
conditionMembers,
Collections.singletonList(targetMember),
- targetKeepKind));
+ targetKeepKind,
+ extractorOptions));
HashMap<KeepBindingSymbol, KeepMemberPattern> copyWithField =
new HashMap<>(memberPatterns);
copyWithField.put(targetMember, copyFieldFromMember(memberPattern));
@@ -522,7 +531,8 @@
copyWithField,
conditionMembers,
Collections.singletonList(targetMember),
- targetKeepKind));
+ targetKeepKind,
+ extractorOptions));
} else {
nonAllMemberTargets.add(targetMember);
}
@@ -538,7 +548,8 @@
memberPatterns,
conditionMembers,
nonAllMemberTargets,
- targetKeepKind));
+ targetKeepKind,
+ extractorOptions));
});
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractorOptions.java b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractorOptions.java
index c30b430..f155852 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractorOptions.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/KeepRuleExtractorOptions.java
@@ -6,12 +6,86 @@
import com.android.tools.r8.keepanno.ast.KeepOptions.KeepOption;
-public class KeepRuleExtractorOptions {
+public abstract class KeepRuleExtractorOptions {
private static final KeepRuleExtractorOptions PG_OPTIONS =
- new KeepRuleExtractorOptions(false, false);
+ new KeepRuleExtractorOptions() {
+ @Override
+ public boolean hasCheckDiscardSupport() {
+ return false;
+ }
+
+ @Override
+ public boolean hasAllowAccessModificationOptionSupport() {
+ return false;
+ }
+
+ @Override
+ public boolean hasAllowAnnotationRemovalOptionSupport() {
+ return false;
+ }
+
+ @Override
+ public boolean hasFieldTypeBackReference() {
+ return false;
+ }
+
+ @Override
+ public boolean hasMethodReturnTypeBackReference() {
+ return false;
+ }
+
+ @Override
+ public boolean hasMethodParameterTypeBackReference() {
+ return false;
+ }
+
+ @Override
+ public boolean hasMethodParameterListBackReference() {
+ return false;
+ }
+ };
+
private static final KeepRuleExtractorOptions R8_OPTIONS =
- new KeepRuleExtractorOptions(true, true);
+ new KeepRuleExtractorOptions() {
+ @Override
+ public boolean hasCheckDiscardSupport() {
+ return true;
+ }
+
+ @Override
+ public boolean hasAllowAccessModificationOptionSupport() {
+ return true;
+ }
+
+ @Override
+ public boolean hasAllowAnnotationRemovalOptionSupport() {
+ // Allow annotation removal is currently a testing only option.
+ return false;
+ }
+
+ @Override
+ public boolean hasFieldTypeBackReference() {
+ return true;
+ }
+
+ @Override
+ public boolean hasMethodReturnTypeBackReference() {
+ return true;
+ }
+
+ @Override
+ public boolean hasMethodParameterTypeBackReference() {
+ return true;
+ }
+
+ @Override
+ public boolean hasMethodParameterListBackReference() {
+ // TODO(b/265892343): R8 does not support backrefs for `(...)`.
+ // When resolving this the options need to be split in legacy R8 and current R8.
+ return false;
+ }
+ };
public static KeepRuleExtractorOptions getPgOptions() {
return PG_OPTIONS;
@@ -21,27 +95,21 @@
return R8_OPTIONS;
}
- private final boolean allowCheckDiscard;
- private final boolean allowAccessModificationOption;
- private final boolean allowAnnotationRemovalOption = false;
+ private KeepRuleExtractorOptions() {}
- private KeepRuleExtractorOptions(
- boolean allowCheckDiscard, boolean allowAccessModificationOption) {
- this.allowCheckDiscard = allowCheckDiscard;
- this.allowAccessModificationOption = allowAccessModificationOption;
- }
+ public abstract boolean hasCheckDiscardSupport();
- public boolean hasCheckDiscardSupport() {
- return allowCheckDiscard;
- }
+ public abstract boolean hasAllowAccessModificationOptionSupport();
- private boolean hasAllowAccessModificationOptionSupport() {
- return allowAccessModificationOption;
- }
+ public abstract boolean hasAllowAnnotationRemovalOptionSupport();
- private boolean hasAllowAnnotationRemovalOptionSupport() {
- return allowAnnotationRemovalOption;
- }
+ public abstract boolean hasFieldTypeBackReference();
+
+ public abstract boolean hasMethodReturnTypeBackReference();
+
+ public abstract boolean hasMethodParameterTypeBackReference();
+
+ public abstract boolean hasMethodParameterListBackReference();
public boolean isKeepOptionSupported(KeepOption keepOption) {
switch (keepOption) {
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/PgRule.java b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/PgRule.java
index 75ea20c..328b6ca 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/PgRule.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/PgRule.java
@@ -94,16 +94,23 @@
private final KeepEdgeMetaInfo metaInfo;
private final KeepOptions options;
+ private final KeepRuleExtractorOptions extractorOptions;
- private PgRule(KeepEdgeMetaInfo metaInfo, KeepOptions options) {
+ private PgRule(
+ KeepEdgeMetaInfo metaInfo, KeepOptions options, KeepRuleExtractorOptions extractorOptions) {
this.metaInfo = metaInfo;
this.options = options;
+ this.extractorOptions = extractorOptions;
}
public KeepEdgeMetaInfo getMetaInfo() {
return metaInfo;
}
+ public KeepRuleExtractorOptions getExtractorOptions() {
+ return extractorOptions;
+ }
+
// Helper to print the class-name pattern in a class-item.
public static BiConsumer<StringBuilder, KeepQualifiedClassNamePattern> classNamePrinter(
KeepQualifiedClassNamePattern classNamePattern) {
@@ -203,8 +210,9 @@
KeepOptions options,
Map<KeepBindingSymbol, KeepMemberPattern> memberPatterns,
List<KeepBindingSymbol> targetMembers,
- TargetKeepKind targetKeepKind) {
- super(metaInfo, options);
+ TargetKeepKind targetKeepKind,
+ KeepRuleExtractorOptions extractorOptions) {
+ super(metaInfo, options, extractorOptions);
assert !targetKeepKind.equals(TargetKeepKind.JUST_MEMBERS);
this.holderNamePattern = holder.getNamePattern();
this.holderPattern = holder.getClassItemPattern();
@@ -234,7 +242,8 @@
@Override
void printTargetMember(StringBuilder builder, KeepBindingSymbol memberReference) {
KeepMemberPattern memberPattern = memberPatterns.get(memberReference);
- printMemberClause(memberPattern, RulePrinter.withoutBackReferences(builder));
+ printMemberClause(
+ memberPattern, RulePrinter.withoutBackReferences(builder), getExtractorOptions());
}
}
@@ -242,8 +251,11 @@
private final Set<KeepAttribute> attributes;
- public PgKeepAttributeRule(KeepEdgeMetaInfo metaInfo, Set<KeepAttribute> attributes) {
- super(metaInfo, null);
+ public PgKeepAttributeRule(
+ KeepEdgeMetaInfo metaInfo,
+ Set<KeepAttribute> attributes,
+ KeepRuleExtractorOptions extractorOptions) {
+ super(metaInfo, null, extractorOptions);
assert !attributes.isEmpty();
this.attributes = attributes;
}
@@ -308,8 +320,9 @@
Map<KeepBindingSymbol, KeepMemberPattern> memberPatterns,
List<KeepBindingSymbol> memberConditions,
List<KeepBindingSymbol> memberTargets,
- TargetKeepKind keepKind) {
- super(metaInfo, options);
+ TargetKeepKind keepKind,
+ KeepRuleExtractorOptions extractorOptions) {
+ super(metaInfo, options, extractorOptions);
this.classCondition = classCondition.getClassItemPattern();
this.classTarget = classTarget.getClassItemPattern();
this.memberPatterns = memberPatterns;
@@ -336,7 +349,8 @@
@Override
void printConditionMember(StringBuilder builder, KeepBindingSymbol member) {
KeepMemberPattern memberPattern = memberPatterns.get(member);
- printMemberClause(memberPattern, RulePrinter.withoutBackReferences(builder));
+ printMemberClause(
+ memberPattern, RulePrinter.withoutBackReferences(builder), getExtractorOptions());
}
@Override
@@ -360,7 +374,8 @@
@Override
void printTargetMember(StringBuilder builder, KeepBindingSymbol member) {
KeepMemberPattern memberPattern = memberPatterns.get(member);
- printMemberClause(memberPattern, RulePrinter.withoutBackReferences(builder));
+ printMemberClause(
+ memberPattern, RulePrinter.withoutBackReferences(builder), getExtractorOptions());
}
private void printClassName(StringBuilder builder, KeepQualifiedClassNamePattern clazzName) {
@@ -402,8 +417,9 @@
Map<KeepBindingSymbol, KeepMemberPattern> memberPatterns,
List<KeepBindingSymbol> memberConditions,
List<KeepBindingSymbol> memberTargets,
- TargetKeepKind keepKind) {
- super(metaInfo, options);
+ TargetKeepKind keepKind,
+ KeepRuleExtractorOptions extractorOptions) {
+ super(metaInfo, options, extractorOptions);
this.holderNamePattern = holder.getNamePattern();
this.holderPattern = holder.getClassItemPattern();
this.memberPatterns = memberPatterns;
@@ -458,7 +474,7 @@
KeepMemberPattern memberPattern = memberPatterns.get(member);
BackReferencePrinter printer =
RulePrinter.withBackReferences(builder, this::getNextBackReferenceNumber);
- printMemberClause(memberPattern, printer);
+ printMemberClause(memberPattern, printer, getExtractorOptions());
membersBackReferencePatterns.put(member, printer.getBackReference());
}
@@ -492,7 +508,8 @@
}
}
KeepMemberPattern memberPattern = memberPatterns.get(member);
- printMemberClause(memberPattern, RulePrinter.withoutBackReferences(builder));
+ printMemberClause(
+ memberPattern, RulePrinter.withoutBackReferences(builder), getExtractorOptions());
}
}
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/RulePrinter.java b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/RulePrinter.java
index 518eeba..78513c6 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/RulePrinter.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/RulePrinter.java
@@ -22,6 +22,10 @@
this.builder = builder;
}
+ public RulePrinter allowBackReferencesIf(boolean isBackReferenceSupported) {
+ return this;
+ }
+
public RulePrinter append(String str) {
assert !str.contains("*");
assert !str.contains("(...)");
@@ -102,7 +106,51 @@
@Override
public RulePrinter appendAnyParameters() {
- // TODO(b/265892343): R8 does not yet support back reference to `...`.
+ return addBackRef("(...)");
+ }
+
+ @Override
+ public RulePrinter allowBackReferencesIf(boolean isBackReferenceSupported) {
+ return isBackReferenceSupported ? this : new SkipBackreferencePrinter(this);
+ }
+ }
+
+ private static class SkipBackreferencePrinter extends RulePrinter {
+ final BackReferencePrinter printer;
+
+ private SkipBackreferencePrinter(BackReferencePrinter printer) {
+ super(((RulePrinter) printer).builder);
+ this.printer = printer;
+ }
+
+ @Override
+ public RulePrinter appendWithoutBackReferenceAssert(String str) {
+ printer.appendWithoutBackReferenceAssert(str);
+ return this;
+ }
+
+ @Override
+ public RulePrinter appendStar() {
+ return appendWithoutBackReferenceAssert("*");
+ }
+
+ @Override
+ public RulePrinter appendDoubleStar() {
+ return appendWithoutBackReferenceAssert("**");
+ }
+
+ @Override
+ public RulePrinter appendTripleStar() {
+ return appendWithoutBackReferenceAssert("***");
+ }
+
+ @Override
+ public RulePrinter appendPercent() {
+ return appendWithoutBackReferenceAssert("%");
+ }
+
+ @Override
+ public RulePrinter appendAnyParameters() {
return appendWithoutBackReferenceAssert("(...)");
}
}
diff --git a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/RulePrintingUtils.java b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/RulePrintingUtils.java
index 636dbfc..07c7c9b 100644
--- a/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/RulePrintingUtils.java
+++ b/src/keepanno/java/com/android/tools/r8/keepanno/keeprules/RulePrintingUtils.java
@@ -115,7 +115,8 @@
return builder;
}
- public static RulePrinter printMemberClause(KeepMemberPattern member, RulePrinter printer) {
+ public static RulePrinter printMemberClause(
+ KeepMemberPattern member, RulePrinter printer, KeepRuleExtractorOptions options) {
if (member.isAllMembers()) {
// Note: the rule language does not allow backref to a full member. A rule matching all
// members via a binding must be split in two up front: one for methods and one for fields.
@@ -127,10 +128,10 @@
printer.append(" ");
}
if (member.isMethod()) {
- return printMethod(member.asMethod(), printer);
+ return printMethod(member.asMethod(), printer, options);
}
if (member.isField()) {
- return printField(member.asField(), printer);
+ return printField(member.asField(), printer, options);
}
// The pattern is a restricted member pattern, e.g., it must apply to fields and methods
// without any specifics not common to both. For now that is annotated-by and access patterns.
@@ -139,27 +140,37 @@
return printer.appendWithoutBackReferenceAssert("*").append(";");
}
- private static RulePrinter printField(KeepFieldPattern fieldPattern, RulePrinter printer) {
+ private static RulePrinter printField(
+ KeepFieldPattern fieldPattern, RulePrinter printer, KeepRuleExtractorOptions options) {
printFieldAccess(printer, fieldPattern.getAccessPattern());
- printType(printer, fieldPattern.getTypePattern().asType());
+ printType(
+ printer.allowBackReferencesIf(options.hasFieldTypeBackReference()),
+ fieldPattern.getTypePattern().asType());
printer.append(" ");
printFieldName(printer, fieldPattern.getNamePattern());
return printer.append(";");
}
- private static RulePrinter printMethod(KeepMethodPattern methodPattern, RulePrinter printer) {
+ private static RulePrinter printMethod(
+ KeepMethodPattern methodPattern, RulePrinter printer, KeepRuleExtractorOptions options) {
printMethodAccess(printer, methodPattern.getAccessPattern());
- printReturnType(printer, methodPattern.getReturnTypePattern());
+ printReturnType(
+ printer.allowBackReferencesIf(options.hasMethodReturnTypeBackReference()),
+ methodPattern.getReturnTypePattern());
printer.append(" ");
printMethodName(printer, methodPattern.getNamePattern());
- printParameters(printer, methodPattern.getParametersPattern());
+ printParameters(printer, methodPattern.getParametersPattern(), options);
return printer.append(";");
}
private static RulePrinter printParameters(
- RulePrinter builder, KeepMethodParametersPattern parametersPattern) {
+ RulePrinter builder,
+ KeepMethodParametersPattern parametersPattern,
+ KeepRuleExtractorOptions options) {
if (parametersPattern.isAny()) {
- return builder.appendAnyParameters();
+ return builder
+ .allowBackReferencesIf(options.hasMethodParameterListBackReference())
+ .appendAnyParameters();
}
builder.append("(");
List<KeepTypePattern> patterns = parametersPattern.asList();
@@ -167,7 +178,9 @@
if (i > 0) {
builder.append(", ");
}
- printType(builder, patterns.get(i));
+ printType(
+ builder.allowBackReferencesIf(options.hasMethodParameterTypeBackReference()),
+ patterns.get(i));
}
return builder.append(")");
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 24f0c28..f9694e5 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -728,39 +728,44 @@
// already have been leveraged.
OptimizationInfoRemover.run(appView, executorService);
- // Perform repackaging.
- if (appView.hasLiveness()) {
- if (options.isRepackagingEnabled()) {
- new Repackaging(appView.withLiveness()).run(executorService, timing);
+ GenericSignatureContextBuilder genericContextBuilderBeforeFinalMerging = null;
+ if (appView.hasCfByteCodePassThroughMethods()) {
+ LirConverter.finalizeLirToOutputFormat(appView, timing, executorService);
+ } else {
+ // Perform repackaging.
+ if (appView.hasLiveness()) {
+ if (options.isRepackagingEnabled()) {
+ new Repackaging(appView.withLiveness()).run(executorService, timing);
+ }
+ assert Repackaging.verifyIdentityRepackaging(appView.withLiveness(), executorService);
}
- assert Repackaging.verifyIdentityRepackaging(appView.withLiveness(), executorService);
+
+ // Rewrite LIR with lens to allow building IR from LIR in class mergers.
+ LirConverter.rewriteLirWithLens(appView, timing, executorService);
+ appView.clearCodeRewritings(executorService, timing);
+
+ if (appView.hasLiveness()) {
+ VerticalClassMerger.createForFinalClassMerging(appView.withLiveness())
+ .runIfNecessary(executorService, timing);
+ }
+
+ // TODO(b/225838009): Move further down.
+ LirConverter.finalizeLirToOutputFormat(appView, timing, executorService);
+ assert appView.dexItemFactory().verifyNoCachedTypeElements();
+
+ genericContextBuilderBeforeFinalMerging = GenericSignatureContextBuilder.create(appView);
+
+ // Run horizontal class merging. This runs even if shrinking is disabled to ensure
+ // synthetics are always merged.
+ HorizontalClassMerger.createForFinalClassMerging(appView)
+ .runIfNecessary(
+ executorService,
+ timing,
+ finalRuntimeTypeCheckInfoBuilder != null
+ ? finalRuntimeTypeCheckInfoBuilder.build(appView.graphLens())
+ : null);
}
- // Rewrite LIR with lens to allow building IR from LIR in class mergers.
- LirConverter.rewriteLirWithLens(appView, timing, executorService);
-
- if (appView.hasLiveness()) {
- VerticalClassMerger.createForFinalClassMerging(appView.withLiveness())
- .runIfNecessary(executorService, timing);
- }
-
- // TODO(b/225838009): Move further down.
- LirConverter.finalizeLirToOutputFormat(appView, timing, executorService);
- assert appView.dexItemFactory().verifyNoCachedTypeElements();
-
- GenericSignatureContextBuilder genericContextBuilderBeforeFinalMerging =
- GenericSignatureContextBuilder.create(appView);
-
- // Run horizontal class merging. This runs even if shrinking is disabled to ensure synthetics
- // are always merged.
- HorizontalClassMerger.createForFinalClassMerging(appView)
- .runIfNecessary(
- executorService,
- timing,
- finalRuntimeTypeCheckInfoBuilder != null
- ? finalRuntimeTypeCheckInfoBuilder.build(appView.graphLens())
- : null);
-
// Perform minification.
if (options.getProguardConfiguration().hasApplyMappingFile()) {
timing.begin("apply-mapping");
@@ -823,8 +828,10 @@
new KotlinMetadataRewriter(appView).runForR8(executorService);
timing.end();
- new GenericSignatureRewriter(appView, genericContextBuilderBeforeFinalMerging)
- .run(appView.appInfo().classes(), executorService);
+ if (genericContextBuilderBeforeFinalMerging != null) {
+ new GenericSignatureRewriter(appView, genericContextBuilderBeforeFinalMerging)
+ .run(appView.appInfo().classes(), executorService);
+ }
assert appView.checkForTesting(
() ->
@@ -921,7 +928,9 @@
LegacyResourceShrinker shrinker = resourceShrinkerBuilder.build();
ShrinkerResult shrinkerResult;
if (options.resourceShrinkerConfiguration.isOptimizedShrinking()) {
- shrinkerResult = shrinker.shrinkModel(appView.getResourceAnalysisResult().getModel(), true);
+ shrinkerResult =
+ shrinker.shrinkModel(
+ appView.getResourceShrinkerState().getR8ResourceShrinkerModel(), true);
} else {
shrinkerResult = shrinker.run();
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
index b407f34..e9c6f6b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -18,8 +17,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -211,12 +208,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forBinop();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState state, AppView<?> appView, CfAnalysisConfig config) {
// ..., value1, value2 →
// ..., result
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
index 068d034..fd9586f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -16,8 +15,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -82,12 +79,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forArrayLength();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., arrayref →
// ..., length
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index a97e1ea..a0662ad 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.lens.GraphLens;
@@ -19,8 +18,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -97,12 +94,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forArrayGet();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., arrayref, index →
// ..., value
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
index 0cad424..f7cb0c5 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.lens.GraphLens;
@@ -17,8 +16,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -97,12 +94,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forArrayPut();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., arrayref, index, value →
// ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
index 091aa57..9e23bd0 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -19,8 +18,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -133,12 +130,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forCheckCast(type, context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., objectref →
// ..., objectref
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
index 6ca820e..a18c05a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -20,8 +19,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -131,12 +128,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forBinop();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., value1, value2 →
// ..., result
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConditionalJumpInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfConditionalJumpInstruction.java
index def3dd4..9d4f58d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConditionalJumpInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConditionalJumpInstruction.java
@@ -4,12 +4,8 @@
package com.android.tools.r8.cf.code;
-import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.IfType;
import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
public abstract class CfConditionalJumpInstruction extends CfJumpInstruction {
@@ -29,12 +25,6 @@
}
@Override
- public final ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forJumpInstruction();
- }
-
- @Override
public final boolean isConditionalJump() {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index 151be2a..0d0838e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -19,8 +18,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -150,12 +147,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forConstClass(type, context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ... →
// ..., value
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
index d47a830..c16eae4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
@@ -8,9 +8,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unimplemented;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -28,8 +26,6 @@
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.desugar.constantdynamic.ConstantDynamicReference;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -217,12 +213,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- throw new Unreachable();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ... →
// ..., value
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
index 9c59d83..25cb808 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -19,8 +18,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -104,12 +101,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forConstMethodHandle();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ... →
// ..., value
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
index b9f5d88..2f0fb30 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -18,8 +17,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -102,12 +99,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forConstMethodType();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ... →
// ..., value
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
index 5e6485a..09d9f3c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -16,8 +15,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -74,12 +71,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forConstInstruction();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ... →
// ..., value
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
index 991ed9d..9246c77 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -17,8 +16,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -231,12 +228,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forConstInstruction();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ... →
// ..., value
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
index d60203a..064ee4c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
@@ -16,8 +15,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -105,12 +102,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forConstInstruction();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ... →
// ..., value
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
index b350e1f..6280303 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -19,8 +18,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
@@ -124,12 +121,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forDexItemBasedConstString(item, context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ... →
// ..., value
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
index c8308b4..62a8f65 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.cf.code.frame.PreciseFrameType;
import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -23,8 +22,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -309,12 +306,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return ConstraintWithTarget.ALWAYS;
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
return frame.check(config, this);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
index 29dd22a..cabbeeb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -15,8 +14,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -109,12 +106,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forJumpInstruction();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
return frame;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
index 7a4ba0a..533657e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -17,8 +16,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -99,12 +96,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return ConstraintWithTarget.ALWAYS;
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
return frame.readLocal(
appView, config, getLocalIndex(), ValueType.INT, FunctionUtils::getFirst);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
index 21608ae..4fa09ff 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
@@ -19,8 +18,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -117,12 +114,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forInitClass(clazz, context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., →
// ..., value
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
index 09ec0f5..1a7c2af 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
@@ -6,17 +6,13 @@
import com.android.tools.r8.dex.code.CfOrDexInstanceFieldRead;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import java.util.ListIterator;
@@ -70,12 +66,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forInstanceGet(getField(), context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., objectref →
// ..., value
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
index 594f126..1f8e193 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
@@ -8,17 +8,13 @@
import com.android.tools.r8.cf.code.frame.PreciseFrameType;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import com.android.tools.r8.optimize.interfaces.analysis.ErroneousCfFrameState;
@@ -74,12 +70,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forInstancePut(getField(), context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., objectref, value →
// ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index ec34784..da879bd 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -18,8 +17,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -127,12 +124,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forInstanceOf(type, context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., objectref →
// ..., result
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index ff95325..985fbc9 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.dex.code.DexInstruction;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.ClasspathMethod;
import com.android.tools.r8.graph.DexClassAndMethod;
@@ -21,8 +20,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -420,9 +417,6 @@
return true;
}
- public abstract ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context);
-
public abstract CfFrameState evaluate(
CfFrameState frame, AppView<?> appView, CfAnalysisConfig config);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index bcbe536..fc2e576 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -7,11 +7,8 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
@@ -28,8 +25,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -285,68 +280,6 @@
}
@Override
- @SuppressWarnings("ReferenceEquality")
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- GraphLens graphLens = inliningConstraints.getGraphLens();
- AppView<?> appView = inliningConstraints.getAppView();
- DexMethod target = method;
- // Find the DEX invocation type.
- InvokeType type;
- switch (opcode) {
- case Opcodes.INVOKEINTERFACE:
- // Could have changed to an invoke-virtual instruction due to vertical class merging
- // (if an interface is merged into a class).
- type =
- graphLens.lookupMethod(target, context.getReference(), InvokeType.INTERFACE).getType();
- assert type == InvokeType.INTERFACE || type == InvokeType.VIRTUAL;
- break;
-
- case Opcodes.INVOKESPECIAL:
- {
- InvokeType actualInvokeType =
- computeInvokeTypeForInvokeSpecial(appView, method, context, code.getOriginalHolder());
- type = graphLens.lookupMethod(target, context.getReference(), actualInvokeType).getType();
- }
- break;
-
- case Opcodes.INVOKESTATIC:
- {
- // Static invokes may have changed as a result of horizontal class merging.
- MethodLookupResult lookup =
- graphLens.lookupMethod(target, context.getReference(), InvokeType.STATIC);
- target = lookup.getReference();
- type = lookup.getType();
- }
- break;
-
- case Opcodes.INVOKEVIRTUAL:
- {
- type = InvokeType.VIRTUAL;
- // Instructions that target a private method in the same class translates to
- // invoke-direct.
- if (target.holder == context.getHolderType()) {
- DexClass clazz = appView.definitionFor(target.holder);
- if (clazz != null && clazz.lookupDirectMethod(target) != null) {
- type = InvokeType.DIRECT;
- }
- }
-
- // Virtual invokes may have changed to interface invokes as a result of member rebinding.
- MethodLookupResult lookup = graphLens.lookupMethod(target, context.getReference(), type);
- target = lookup.getReference();
- type = lookup.getType();
- }
- break;
-
- default:
- throw new Unreachable("Unexpected opcode " + opcode);
- }
-
- return inliningConstraints.forInvoke(target, type, context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., objectref, [arg1, [arg2 ...]] →
// ... [ returnType ]
@@ -370,41 +303,4 @@
}
return frame.push(config, method.getReturnType());
}
-
- @SuppressWarnings("ReferenceEquality")
- private InvokeType computeInvokeTypeForInvokeSpecial(
- AppView<?> appView, DexMethod method, ProgramMethod context, DexType originalHolder) {
- if (appView.dexItemFactory().isConstructor(method)) {
- return InvokeType.DIRECT;
- }
- if (originalHolder != method.getHolderType()) {
- return InvokeType.SUPER;
- }
- return invokeTypeForInvokeSpecialToNonInitMethodOnHolder(context, appView.graphLens());
- }
-
- private InvokeType invokeTypeForInvokeSpecialToNonInitMethodOnHolder(
- ProgramMethod context, GraphLens graphLens) {
- MethodLookupResult lookupResult =
- graphLens.lookupMethod(method, context.getReference(), InvokeType.DIRECT);
- DexEncodedMethod definition = context.getHolder().lookupMethod(lookupResult.getReference());
- if (definition == null) {
- return InvokeType.SUPER;
- }
-
- if (context.getHolder().isInterface()) {
- // On interfaces invoke-special should be mapped to invoke-super if the invoke-special
- // instruction is used to target a default interface method.
- if (definition.belongsToVirtualPool()) {
- return InvokeType.SUPER;
- }
- } else {
- // Due to desugaring of invoke-special instructions that target virtual methods, this invoke
- // should only target a virtual method if the method has been publicized in R8 (in which case
- // the invoke instruction has a pending rewrite to invoke-virtual).
- assert definition.isPrivate() || lookupResult.getType().isVirtual();
- }
-
- return InvokeType.DIRECT;
- }
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
index 79ba7f9..a36f61b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClassAndMethod;
@@ -24,8 +23,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -168,12 +165,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forInvokeCustom();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., [arg1, [arg2 ...]] →
// ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
index 7ab3052..d0efa3c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -16,8 +15,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -84,12 +81,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- throw error();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
return CfFrameState.error("Unexpected JSR/RET instruction");
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
index 29701e6..008b905 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -15,8 +14,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -97,12 +94,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return ConstraintWithTarget.ALWAYS;
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
return frame;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
index a0b7fdc..0af1153 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -19,8 +18,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -129,12 +126,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forLoad();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ... →
// ..., objectref
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
index 14f30b1..97c4dce 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -18,8 +17,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -182,12 +179,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forBinop();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., value1, value2 →
// ..., result
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
index d7ef8ee..6821e61 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -17,8 +16,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -95,12 +92,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forMonitor();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., objectref →
// ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
index 85f09af..449bdcb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -18,8 +17,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -130,12 +127,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forInvokeMultiNewArray(type, context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., count1, [count2, ...] →
// ..., arrayref
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
index 61216c1..9b047f8 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -18,8 +17,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -120,12 +117,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forUnop();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., value →
// ..., result
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
index 9e0af9c..f574223 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -19,8 +18,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -143,12 +140,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forNewInstance(type, context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ... →
// ..., objectref
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
index 943252d..f131164 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -20,8 +19,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -170,12 +167,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forNewArrayEmpty(type, context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., count →
// ..., arrayref
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
index 11efcd1..11cab35 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -19,8 +18,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -118,12 +115,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forNewUnboxedEnumInstance(type, context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ... →
// ..., objectref
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNop.java b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
index fd5d76c..7706a69 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -15,8 +14,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -78,12 +75,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return ConstraintWithTarget.ALWAYS;
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
return frame;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
index 32a1d4f..cadead1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -18,8 +17,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -191,12 +188,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forUnop();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., value →
// ..., result
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
index 9e4bae3..b52cb87 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -16,8 +15,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -112,12 +109,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return ConstraintWithTarget.ALWAYS;
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
return frame;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
index c34d876..ce358df 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
@@ -19,8 +18,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -111,12 +108,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forRecordFieldValues();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
for (DexField ignored : fields) {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
index 725acb1..a99482d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -18,8 +17,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -124,12 +121,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forReturn();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
assert !config.getCurrentContext().getReturnType().isVoidType();
return frame
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
index 0197fc2..5b16578 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -15,8 +14,6 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -93,12 +90,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forReturn();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
return frame.clear();
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
index 7679a02..c5c8f6e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -19,8 +18,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -355,12 +352,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return ConstraintWithTarget.ALWAYS;
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
switch (opcode) {
case Pop:
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
index 73d6349..f7ae0ff 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
@@ -6,16 +6,12 @@
import com.android.tools.r8.dex.code.CfOrDexStaticFieldRead;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import java.util.ListIterator;
@@ -63,12 +59,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forStaticGet(getField(), context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., →
// ..., value
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
index c904d10..01d9bed 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
@@ -5,17 +5,13 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
import java.util.ListIterator;
@@ -69,12 +65,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forStaticPut(getField(), context);
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., value →
// ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
index f59bfb6..9e5449a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -18,8 +17,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -126,12 +123,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forStore();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., ref →
// ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
index f190ae4..31e7ff3 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -17,8 +16,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -176,12 +173,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forJumpInstruction();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., index/key →
// ...
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
index f59f162..4b81a79 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.ProgramMethod;
@@ -16,8 +15,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
@@ -100,12 +97,6 @@
}
@Override
- public ConstraintWithTarget inliningConstraint(
- InliningConstraints inliningConstraints, CfCode code, ProgramMethod context) {
- return inliningConstraints.forJumpInstruction();
- }
-
- @Override
public CfFrameState evaluate(CfFrameState frame, AppView<?> appView, CfAnalysisConfig config) {
// ..., objectref →
// objectref
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMergerSharedData.java b/src/main/java/com/android/tools/r8/classmerging/ClassMergerSharedData.java
similarity index 87%
rename from src/main/java/com/android/tools/r8/verticalclassmerging/ClassMergerSharedData.java
rename to src/main/java/com/android/tools/r8/classmerging/ClassMergerSharedData.java
index 7bc0e12..1948ef7 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMergerSharedData.java
+++ b/src/main/java/com/android/tools/r8/classmerging/ClassMergerSharedData.java
@@ -1,12 +1,11 @@
// Copyright (c) 2024, 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.verticalclassmerging;
+package com.android.tools.r8.classmerging;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import java.util.List;
@@ -17,7 +16,7 @@
// The collection of types that should be used to generate fresh constructor signatures.
private final List<Supplier<DexType>> extraUnusedArgumentTypes;
- public ClassMergerSharedData(AppView<AppInfoWithLiveness> appView) {
+ public ClassMergerSharedData(AppView<?> appView) {
DexItemFactory factory = appView.dexItemFactory();
extraUnusedArgumentTypes =
ImmutableList.<Supplier<DexType>>builder()
diff --git a/src/main/java/com/android/tools/r8/classmerging/ClassMergerTreeFixer.java b/src/main/java/com/android/tools/r8/classmerging/ClassMergerTreeFixer.java
index 198b611..fce660c 100644
--- a/src/main/java/com/android/tools/r8/classmerging/ClassMergerTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/classmerging/ClassMergerTreeFixer.java
@@ -21,11 +21,9 @@
import com.android.tools.r8.graph.classmerging.MergedClasses;
import com.android.tools.r8.graph.fixup.TreeFixerBase;
import com.android.tools.r8.horizontalclassmerging.SubtypingForrestForClasses;
-import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
import com.android.tools.r8.shaking.AnnotationFixer;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ArrayUtils;
-import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
@@ -50,8 +48,7 @@
protected final LB lensBuilder;
protected final MC mergedClasses;
- private final ProfileCollectionAdditions profileCollectionAdditions;
- private final SyntheticArgumentClass syntheticArgumentClass;
+ private final ClassMergerSharedData classMergerSharedData;
private final Map<DexProgramClass, DexType> originalSuperTypes = new IdentityHashMap<>();
@@ -61,15 +58,13 @@
public ClassMergerTreeFixer(
AppView<?> appView,
+ ClassMergerSharedData classMergerSharedData,
LB lensBuilder,
- MC mergedClasses,
- ProfileCollectionAdditions profileCollectionAdditions,
- SyntheticArgumentClass syntheticArgumentClass) {
+ MC mergedClasses) {
super(appView);
+ this.classMergerSharedData = classMergerSharedData;
this.lensBuilder = lensBuilder;
this.mergedClasses = mergedClasses;
- this.profileCollectionAdditions = profileCollectionAdditions;
- this.syntheticArgumentClass = syntheticArgumentClass;
}
public GL run(ExecutorService executorService, Timing timing) throws ExecutionException {
@@ -289,40 +284,18 @@
if (keptSignatures.contains(newMethodReference)
|| newMethodSignatures.containsValue(newMethodReference.getSignature())) {
// If the method collides with a direct method on the same class then rename it to a
- // globally
- // fresh name and record the signature.
+ // globally fresh name and record the signature.
if (method.isInstanceInitializer()) {
- // If the method is an instance initializer, then add extra nulls.
- Box<Set<DexType>> usedSyntheticArgumentClasses = new Box<>();
+ // If the method is an instance initializer, then add extra unused arguments.
newMethodReference =
dexItemFactory.createInstanceInitializerWithFreshProto(
newMethodReference,
- syntheticArgumentClass.getArgumentClasses(),
- tryMethod -> !newMethodSignatures.containsValue(tryMethod.getSignature()),
- usedSyntheticArgumentClasses::set);
+ classMergerSharedData.getExtraUnusedArgumentTypes(),
+ tryMethod -> !newMethodSignatures.containsValue(tryMethod.getSignature()));
lensBuilder.addExtraParameters(
originalMethodReference,
newMethodReference,
computeExtraUnusedParameters(originalMethodReference, newMethodReference));
-
- // Amend the art profile collection.
- if (usedSyntheticArgumentClasses.isSet()) {
- Set<DexMethod> previousMethodReferences =
- lensBuilder.getOriginalMethodReferences(originalMethodReference);
- if (previousMethodReferences.isEmpty()) {
- profileCollectionAdditions.applyIfContextIsInProfile(
- originalMethodReference,
- additionsBuilder ->
- usedSyntheticArgumentClasses.get().forEach(additionsBuilder::addRule));
- } else {
- for (DexMethod previousMethodReference : previousMethodReferences) {
- profileCollectionAdditions.applyIfContextIsInProfile(
- previousMethodReference,
- additionsBuilder ->
- usedSyntheticArgumentClasses.get().forEach(additionsBuilder::addRule));
- }
- }
- }
} else {
newMethodReference =
dexItemFactory.createFreshMethodNameWithoutHolder(
diff --git a/src/main/java/com/android/tools/r8/classmerging/Policy.java b/src/main/java/com/android/tools/r8/classmerging/Policy.java
index 7655762..6170933 100644
--- a/src/main/java/com/android/tools/r8/classmerging/Policy.java
+++ b/src/main/java/com/android/tools/r8/classmerging/Policy.java
@@ -89,10 +89,12 @@
}
assert previousNumberOfRemovedClasses >= newNumberOfRemovedClasses;
int change = previousNumberOfRemovedClasses - newNumberOfRemovedClasses;
- if (isInterfaceGroup) {
- numberOfRemovedInterfaces += change;
- } else {
- numberOfRemovedClasses += change;
+ synchronized (this) {
+ if (isInterfaceGroup) {
+ numberOfRemovedInterfaces += change;
+ } else {
+ numberOfRemovedClasses += change;
+ }
}
return true;
}
diff --git a/src/main/java/com/android/tools/r8/classmerging/SyntheticArgumentClass.java b/src/main/java/com/android/tools/r8/classmerging/SyntheticArgumentClass.java
deleted file mode 100644
index 54cdd43..0000000
--- a/src/main/java/com/android/tools/r8/classmerging/SyntheticArgumentClass.java
+++ /dev/null
@@ -1,98 +0,0 @@
-// 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.classmerging;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.horizontalclassmerging.HorizontalMergeGroup;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.synthesis.SyntheticItems.SyntheticKindSelector;
-import com.google.common.base.Suppliers;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.List;
-import java.util.function.Supplier;
-
-/**
- * Lets assume we are merging a class A that looks like:
- *
- * <pre>
- * class A {
- * A() { ... }
- * A(int) { ... }
- * }
- * </pre>
- *
- * If {@code A::<init>()} is merged with other constructors, then we need to prevent a conflict with
- * {@code A::<init>(int)}. To do this we introduce a synthetic class so that the new signature for
- * the merged constructor is {@code A::<init>(SyntheticClass, int)}, as this is guaranteed to be
- * unique.
- *
- * <p>This class generates a synthetic class in the package of the first class to be merged.
- */
-public class SyntheticArgumentClass {
-
- private final List<Supplier<DexType>> syntheticClassTypes;
-
- private SyntheticArgumentClass(List<Supplier<DexType>> syntheticClassTypes) {
- this.syntheticClassTypes = syntheticClassTypes;
- }
-
- public List<Supplier<DexType>> getArgumentClasses() {
- return syntheticClassTypes;
- }
-
- public static class Builder {
-
- private final AppView<AppInfoWithLiveness> appView;
-
- public Builder(AppView<AppInfoWithLiveness> appView) {
- this.appView = appView;
- }
-
- private DexProgramClass synthesizeClass(
- DexProgramClass context, SyntheticKindSelector syntheticKindSelector) {
- return appView
- .getSyntheticItems()
- .createFixedClass(syntheticKindSelector, context, appView, builder -> {});
- }
-
- public SyntheticArgumentClass build(Collection<HorizontalMergeGroup> mergeGroups) {
- return build(getDeterministicContext(mergeGroups));
- }
-
- public SyntheticArgumentClass build(DexProgramClass deterministicContext) {
- List<Supplier<DexType>> syntheticArgumentTypes = new ArrayList<>();
- syntheticArgumentTypes.add(
- Suppliers.memoize(
- () ->
- synthesizeClass(
- deterministicContext, kinds -> kinds.HORIZONTAL_INIT_TYPE_ARGUMENT_1)
- .getType()));
- syntheticArgumentTypes.add(
- Suppliers.memoize(
- () ->
- synthesizeClass(
- deterministicContext, kinds -> kinds.HORIZONTAL_INIT_TYPE_ARGUMENT_2)
- .getType()));
- syntheticArgumentTypes.add(
- Suppliers.memoize(
- () ->
- synthesizeClass(
- deterministicContext, kinds -> kinds.HORIZONTAL_INIT_TYPE_ARGUMENT_3)
- .getType()));
- return new SyntheticArgumentClass(syntheticArgumentTypes);
- }
-
- private static DexProgramClass getDeterministicContext(
- Collection<HorizontalMergeGroup> mergeGroups) {
- // Relies on the determinism of the merge groups.
- HorizontalMergeGroup mergeGroup = mergeGroups.iterator().next();
- assert mergeGroup.hasTarget();
- return mergeGroup.getTarget();
- }
- }
-}
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 c09b0fd..e3c04a8 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph;
+import com.android.build.shrinker.r8integration.R8ResourceShrinkerState;
import com.android.tools.r8.androidapi.AndroidApiLevelCompute;
import com.android.tools.r8.androidapi.ComputedApiLevel;
import com.android.tools.r8.classmerging.ClassMergerMode;
@@ -13,7 +14,6 @@
import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.DexValue.DexValueString;
import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis.InitializedClassesInInstanceMethods;
-import com.android.tools.r8.graph.analysis.ResourceAccessAnalysis.ResourceAnalysisResult;
import com.android.tools.r8.graph.classmerging.MergedClassesCollection;
import com.android.tools.r8.graph.lens.AppliedGraphLens;
import com.android.tools.r8.graph.lens.ClearCodeRewritingGraphLens;
@@ -154,7 +154,7 @@
private SeedMapper applyMappingSeedMapper;
- private ResourceAnalysisResult resourceAnalysisResult = null;
+ private R8ResourceShrinkerState resourceShrinkerState = null;
// When input has been (partially) desugared these are the classes which has been library
// desugared. This information is populated in the IR converter.
@@ -438,12 +438,15 @@
allCodeProcessed = true;
}
- public void clearCodeRewritings(ExecutorService executorService) throws ExecutionException {
+ public void clearCodeRewritings(ExecutorService executorService, Timing timing)
+ throws ExecutionException {
+ timing.begin("Clear code rewritings");
setGraphLens(new ClearCodeRewritingGraphLens(withClassHierarchy()));
MemberRebindingIdentityLens memberRebindingIdentityLens =
MemberRebindingIdentityLensFactory.rebuild(withClassHierarchy(), executorService);
setGraphLens(memberRebindingIdentityLens);
+ timing.end();
}
public void flattenGraphLenses() {
@@ -906,12 +909,12 @@
testing().unboxedEnumsConsumer.accept(dexItemFactory(), unboxedEnums);
}
- public void setResourceAnalysisResult(ResourceAnalysisResult resourceAnalysisResult) {
- this.resourceAnalysisResult = resourceAnalysisResult;
+ public R8ResourceShrinkerState getResourceShrinkerState() {
+ return resourceShrinkerState;
}
- public ResourceAnalysisResult getResourceAnalysisResult() {
- return resourceAnalysisResult;
+ public void setResourceShrinkerState(R8ResourceShrinkerState resourceShrinkerState) {
+ this.resourceShrinkerState = resourceShrinkerState;
}
public boolean validateUnboxedEnumsHaveBeenPruned() {
@@ -1006,9 +1009,6 @@
setProguardCompatibilityActions(
getProguardCompatibilityActions().withoutPrunedItems(prunedItems, timing));
}
- if (resourceAnalysisResult != null) {
- resourceAnalysisResult.withoutPrunedItems(prunedItems, timing);
- }
if (hasRootSet()) {
rootSet.pruneItems(prunedItems, timing);
}
@@ -1226,18 +1226,6 @@
new ThreadTask() {
@Override
public void run(Timing threadTiming) {
- appView.resourceAnalysisResult.rewrittenWithLens(
- lens, appliedLensInModifiedLens, threadTiming);
- }
-
- @Override
- public boolean shouldRun() {
- return appView.resourceAnalysisResult != null;
- }
- },
- new ThreadTask() {
- @Override
- public void run(Timing threadTiming) {
appView.setRootSet(appView.rootSet().rewrittenWithLens(lens, threadTiming));
}
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 1deb035..33b02b2 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -38,11 +38,7 @@
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -587,11 +583,10 @@
public IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
verifyFramesOrRemove(method, appView, getCodeLens(appView));
return internalBuildPossiblyWithLocals(
- method, method, appView, appView.codeLens(), null, null, origin, null, conversionOptions);
+ method, method, appView, appView.codeLens(), null, null, null, conversionOptions);
}
@Override
@@ -602,7 +597,6 @@
GraphLens codeLens,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
RewrittenPrototypeDescription protoChanges) {
assert valueNumberGenerator != null;
assert callerPosition != null;
@@ -615,7 +609,6 @@
codeLens,
valueNumberGenerator,
callerPosition,
- origin,
protoChanges,
MethodConversionOptions.nonConverting());
}
@@ -637,7 +630,6 @@
GraphLens codeLens,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
RewrittenPrototypeDescription protoChanges,
MutableMethodConversionOptions conversionOptions) {
if (!method.keepLocals(appView)) {
@@ -649,7 +641,6 @@
codeLens,
valueNumberGenerator,
callerPosition,
- origin,
protoChanges,
conversionOptions);
} else {
@@ -660,7 +651,6 @@
codeLens,
valueNumberGenerator,
callerPosition,
- origin,
protoChanges,
conversionOptions);
}
@@ -674,7 +664,6 @@
GraphLens codeLens,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
RewrittenPrototypeDescription protoChanges,
MutableMethodConversionOptions conversionOptions) {
try {
@@ -686,11 +675,10 @@
codeLens,
valueNumberGenerator,
callerPosition,
- origin,
protoChanges,
conversionOptions);
} catch (InvalidDebugInfoException e) {
- appView.options().warningInvalidDebugInfo(method, origin, e);
+ appView.options().warningInvalidDebugInfo(method, e);
return internalBuild(
Collections.emptyList(),
context,
@@ -699,7 +687,6 @@
codeLens,
valueNumberGenerator,
callerPosition,
- origin,
protoChanges,
conversionOptions);
}
@@ -714,7 +701,6 @@
GraphLens codeLens,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
RewrittenPrototypeDescription protoChanges,
MutableMethodConversionOptions conversionOptions) {
CfSourceCode source =
@@ -723,16 +709,15 @@
localVariables,
method,
callerPosition,
- origin,
appView);
IRBuilder builder;
if (valueNumberGenerator == null) {
assert protoChanges == null;
- builder = IRBuilder.create(method, appView, source, origin);
+ builder = IRBuilder.create(method, appView, source);
} else {
builder =
IRBuilder.createForInlining(
- method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges);
+ method, appView, codeLens, source, valueNumberGenerator, protoChanges);
}
return builder.build(context, conversionOptions);
}
@@ -861,25 +846,6 @@
return new CfPrinter(this, method, retracer).toString();
}
- @SuppressWarnings("ReferenceEquality")
- public ConstraintWithTarget computeInliningConstraint(
- AppView<AppInfoWithLiveness> appView,
- GraphLens graphLens,
- ProgramMethod context) {
- InliningConstraints inliningConstraints = new InliningConstraints(appView, graphLens);
- ConstraintWithTarget constraint = ConstraintWithTarget.ALWAYS;
- assert inliningConstraints.forMonitor().isAlways();
- for (CfInstruction insn : instructions) {
- constraint =
- ConstraintWithTarget.meet(
- constraint, insn.inliningConstraint(inliningConstraints, this, context), appView);
- if (constraint.isNever()) {
- return constraint;
- }
- }
- return constraint;
- }
-
void addFakeThisParameter(DexItemFactory factory) {
if (localVariables == null || localVariables.isEmpty()) {
// We have no debugging info in the code.
diff --git a/src/main/java/com/android/tools/r8/graph/CfCodeDiagnostics.java b/src/main/java/com/android/tools/r8/graph/CfCodeDiagnostics.java
index 8a664ec..1f0f01c 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCodeDiagnostics.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCodeDiagnostics.java
@@ -30,9 +30,9 @@
private final MethodPosition methodPosition;
private final String diagnosticMessage;
- public CfCodeDiagnostics(Origin origin, DexMethod method, String diagnosticMessage) {
- this.origin = origin;
- this.methodPosition = new MethodPosition(method.asMethodReference());
+ public CfCodeDiagnostics(ProgramMethod method, String diagnosticMessage) {
+ this.origin = method.getOrigin();
+ this.methodPosition = new MethodPosition(method.getMethodReference());
this.diagnosticMessage = diagnosticMessage;
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/CfCodeStackMapValidatingException.java b/src/main/java/com/android/tools/r8/graph/CfCodeStackMapValidatingException.java
index 0670aeb..f37bced 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCodeStackMapValidatingException.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCodeStackMapValidatingException.java
@@ -16,7 +16,7 @@
if (appView.enableWholeProgramOptimizations()) {
sb.append(" In later version of R8, the method may be assumed not reachable.");
}
- return new CfCodeDiagnostics(method.getOrigin(), method.getReference(), sb.toString());
+ return new CfCodeDiagnostics(method, sb.toString());
}
public static CfCodeDiagnostics multipleFramesForLabel(ProgramMethod method, AppView<?> appView) {
@@ -24,7 +24,7 @@
if (appView.enableWholeProgramOptimizations()) {
sb.append(" In later version of R8, the method may be assumed not reachable.");
}
- return new CfCodeDiagnostics(method.getOrigin(), method.getReference(), sb.toString());
+ return new CfCodeDiagnostics(method, sb.toString());
}
public static CfCodeDiagnostics noFramesForMethodWithJumps(
@@ -34,7 +34,7 @@
if (appView.enableWholeProgramOptimizations()) {
sb.append(" In later version of R8, the method may be assumed not reachable.");
}
- return new CfCodeDiagnostics(method.getOrigin(), method.getReference(), sb.toString());
+ return new CfCodeDiagnostics(method, sb.toString());
}
public static CfCodeDiagnostics invalidTryCatchRange(
@@ -48,7 +48,7 @@
if (appView.enableWholeProgramOptimizations()) {
sb.append(" In later version of R8, the method may be assumed not reachable.");
}
- return new CfCodeDiagnostics(method.getOrigin(), method.getReference(), sb.toString());
+ return new CfCodeDiagnostics(method, sb.toString());
}
public static CfCodeDiagnostics invalidStackMapForInstruction(
@@ -68,6 +68,6 @@
if (appView.enableWholeProgramOptimizations()) {
sb.append(" In later version of R8, the method may be assumed not reachable.");
}
- return new CfCodeDiagnostics(method.getOrigin(), method.getReference(), sb.toString());
+ return new CfCodeDiagnostics(method, sb.toString());
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/Code.java b/src/main/java/com/android/tools/r8/graph/Code.java
index dfc2117..ee87e8a 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -17,21 +17,19 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.lightir.LirCode;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.RetracerForCodePrinting;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import java.util.function.Consumer;
public abstract class Code extends CachedHashValueDexItem {
- public final IRCode buildIR(ProgramMethod method, AppView<?> appView, Origin origin) {
- return buildIR(method, appView, origin, MethodConversionOptions.forLirPhase(appView));
+ public final IRCode buildIR(ProgramMethod method, AppView<?> appView) {
+ return buildIR(method, appView, MethodConversionOptions.forLirPhase(appView));
}
public abstract IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions);
public IRCode buildInliningIR(
@@ -41,7 +39,6 @@
GraphLens codeLens,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
RewrittenPrototypeDescription protoChanges) {
throw new Unreachable("Unexpected attempt to build IR graph for inlining from: "
+ getClass().getCanonicalName());
diff --git a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
index f43f02e..9b11e7e 100644
--- a/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DefaultInstanceInitializerCode.java
@@ -38,7 +38,6 @@
import com.android.tools.r8.lightir.LirEncodingStrategy;
import com.android.tools.r8.lightir.LirStrategy;
import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.IteratorUtils;
import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.HashingVisitor;
@@ -167,12 +166,11 @@
public IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
DefaultInstanceInitializerSourceCode source =
new DefaultInstanceInitializerSourceCode(
method.getReference(), method.getDefinition().isD8R8Synthesized());
- return IRBuilder.create(method, appView, source, origin).build(method, conversionOptions);
+ return IRBuilder.create(method, appView, source).build(method, conversionOptions);
}
@Override
@@ -183,13 +181,12 @@
GraphLens codeLens,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
RewrittenPrototypeDescription protoChanges) {
DefaultInstanceInitializerSourceCode source =
new DefaultInstanceInitializerSourceCode(
method.getReference(), method.getDefinition().isD8R8Synthesized(), callerPosition);
return IRBuilder.createForInlining(
- method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges)
+ method, appView, codeLens, source, valueNumberGenerator, protoChanges)
.build(context, MethodConversionOptions.nonConverting());
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index 95d19ee..8232d93 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -39,7 +39,6 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.lightir.ByteUtils;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.DexDebugUtils.PositionInfo;
import com.android.tools.r8.utils.RetracerForCodePrinting;
@@ -531,7 +530,6 @@
public IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
DexSourceCode source =
new DexSourceCode(
@@ -539,7 +537,7 @@
method,
null,
appView.dexItemFactory());
- return IRBuilder.create(method, appView, source, origin).build(method, conversionOptions);
+ return IRBuilder.create(method, appView, source).build(method, conversionOptions);
}
@Override
@@ -551,7 +549,6 @@
GraphLens codeLens,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
RewrittenPrototypeDescription protoChanges) {
DexSourceCode source =
new DexSourceCode(
@@ -560,7 +557,7 @@
callerPosition,
appView.dexItemFactory());
return IRBuilder.createForInlining(
- method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges)
+ method, appView, codeLens, source, valueNumberGenerator, protoChanges)
.build(context, MethodConversionOptions.nonConverting());
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 3c3533a..79d8789 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1354,7 +1354,7 @@
DexClass newHolder = definitions.definitionFor(newMethodReference.getHolderType());
assert newHolder != null;
DexEncodedMethod newMethod = newHolder.lookupMethod(newMethodReference);
- assert newMethod != null;
+ assert newMethod != null : newMethodReference.toSourceString();
return newMethod;
}
diff --git a/src/main/java/com/android/tools/r8/graph/InvalidCode.java b/src/main/java/com/android/tools/r8/graph/InvalidCode.java
index ff2dc3d..2ce267b 100644
--- a/src/main/java/com/android/tools/r8/graph/InvalidCode.java
+++ b/src/main/java/com/android/tools/r8/graph/InvalidCode.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.RetracerForCodePrinting;
public class InvalidCode extends Code {
@@ -28,7 +27,6 @@
public IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index 0257cfd..2ad9817 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -260,9 +260,8 @@
public IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
- return asCfCode().buildIR(method, appView, origin, conversionOptions);
+ return asCfCode().buildIR(method, appView, conversionOptions);
}
@Override
@@ -273,7 +272,6 @@
GraphLens codeLens,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
RewrittenPrototypeDescription protoChanges) {
return asCfCode()
.buildInliningIR(
@@ -283,7 +281,6 @@
codeLens,
valueNumberGenerator,
callerPosition,
- origin,
protoChanges);
}
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index a86dbc8..0c85af8 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.kotlin.KotlinMethodLevelInfo;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
@@ -35,9 +34,7 @@
public IRCode buildIR(AppView<?> appView, MutableMethodConversionOptions conversionOptions) {
DexEncodedMethod method = getDefinition();
- return method.hasCode()
- ? method.getCode().buildIR(this, appView, getOrigin(), conversionOptions)
- : null;
+ return method.hasCode() ? method.getCode().buildIR(this, appView, conversionOptions) : null;
}
public IRCode buildInliningIR(
@@ -45,7 +42,6 @@
AppView<?> appView,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
MethodProcessor methodProcessor) {
Code code = getDefinition().getCode();
GraphLens codeLens = appView.graphLens();
@@ -61,7 +57,6 @@
codeLens,
valueNumberGenerator,
callerPosition,
- origin,
protoChanges);
}
diff --git a/src/main/java/com/android/tools/r8/graph/PrunedItems.java b/src/main/java/com/android/tools/r8/graph/PrunedItems.java
index 19ebb99..3e96a43 100644
--- a/src/main/java/com/android/tools/r8/graph/PrunedItems.java
+++ b/src/main/java/com/android/tools/r8/graph/PrunedItems.java
@@ -4,11 +4,14 @@
package com.android.tools.r8.graph;
+import com.android.tools.r8.utils.DequeUtils;
import com.android.tools.r8.utils.SetUtils;
import com.google.common.collect.Sets;
import java.util.Collection;
+import java.util.Deque;
import java.util.IdentityHashMap;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
@@ -255,6 +258,9 @@
}
public PrunedItems build() {
+ if (hasFullyInlinedMethods()) {
+ compressInliningPaths();
+ }
return new PrunedItems(
prunedApp,
additionalPinnedItems,
@@ -264,6 +270,38 @@
removedFields,
removedMethods);
}
+
+ private void compressInliningPaths() {
+ Map<DexMethod, ProgramMethod> fullyInlinedMethodsUpdate = new IdentityHashMap<>();
+ for (Entry<DexMethod, ProgramMethod> entry : fullyInlinedMethods.entrySet()) {
+ DexMethod innermostCallee = entry.getKey();
+ if (fullyInlinedMethodsUpdate.containsKey(innermostCallee)) {
+ // Already processed as a result of previously processing a callee of the current callee.
+ continue;
+ }
+ ProgramMethod innermostCaller = entry.getValue();
+ ProgramMethod outermostCaller = fullyInlinedMethods.get(innermostCaller.getReference());
+ if (outermostCaller == null) {
+ continue;
+ }
+ Deque<DexMethod> fullyInlinedMethodChain =
+ DequeUtils.newArrayDeque(innermostCallee, innermostCaller.getReference());
+ while (true) {
+ DexMethod currentCallee = outermostCaller.getReference();
+ ProgramMethod currentCaller = fullyInlinedMethods.get(currentCallee);
+ if (currentCaller == null) {
+ break;
+ }
+ fullyInlinedMethodChain.addLast(currentCallee);
+ outermostCaller = currentCaller;
+ }
+ assert !removedMethods.contains(outermostCaller.getReference());
+ for (DexMethod callee : fullyInlinedMethodChain) {
+ fullyInlinedMethodsUpdate.put(callee, outermostCaller);
+ }
+ }
+ fullyInlinedMethods.putAll(fullyInlinedMethodsUpdate);
+ }
}
public static class ConcurrentBuilder extends Builder {
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
index 7e359ec..63f24c2 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowExceptionCode.java
@@ -20,7 +20,6 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.HashingVisitor;
import java.nio.ShortBuffer;
@@ -53,7 +52,6 @@
public IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
throw new Unreachable("Should not be called");
}
@@ -66,7 +64,6 @@
GraphLens codeLens,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
RewrittenPrototypeDescription protoChanges) {
throw new Unreachable("Should not be called");
}
diff --git a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
index 48fe289..af96367 100644
--- a/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
+++ b/src/main/java/com/android/tools/r8/graph/ThrowNullCode.java
@@ -24,7 +24,6 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SyntheticStraightLineSourceCode;
import com.android.tools.r8.naming.NamingLens;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.google.common.collect.ImmutableList;
@@ -70,10 +69,9 @@
public IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
ThrowNullSourceCode source = new ThrowNullSourceCode(method);
- return IRBuilder.create(method, appView, source, origin).build(method, conversionOptions);
+ return IRBuilder.create(method, appView, source).build(method, conversionOptions);
}
@Override
@@ -84,11 +82,10 @@
GraphLens codeLens,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
RewrittenPrototypeDescription protoChanges) {
ThrowNullSourceCode source = new ThrowNullSourceCode(method, callerPosition);
return IRBuilder.createForInlining(
- method, appView, codeLens, source, origin, valueNumberGenerator, protoChanges)
+ method, appView, codeLens, source, valueNumberGenerator, protoChanges)
.build(context, MethodConversionOptions.nonConverting());
}
diff --git a/src/main/java/com/android/tools/r8/graph/UseRegistry.java b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
index 1d9e498..d7d1b0b 100644
--- a/src/main/java/com/android/tools/r8/graph/UseRegistry.java
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
@@ -158,6 +158,8 @@
registerTypeReference(type);
}
+ public void registerConstResourceNumber(int value) {}
+
public void registerCheckCast(DexType type, boolean ignoreCompatRules) {
registerTypeReference(type);
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ResourceAccessAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ResourceAccessAnalysis.java
index d9547d9..6b64f53 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ResourceAccessAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ResourceAccessAnalysis.java
@@ -5,10 +5,10 @@
package com.android.tools.r8.graph.analysis;
import com.android.build.shrinker.r8integration.R8ResourceShrinkerState;
-import com.android.build.shrinker.r8integration.R8ResourceShrinkerState.R8ResourceShrinkerModel;
import com.android.tools.r8.AndroidResourceInput;
import com.android.tools.r8.AndroidResourceInput.Kind;
import com.android.tools.r8.ResourceException;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedField;
@@ -19,8 +19,6 @@
import com.android.tools.r8.graph.FieldResolutionResult.SingleFieldResolutionResult;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.PrunedItems;
-import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.NewArrayEmpty;
@@ -29,14 +27,10 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerWorklist;
-import com.android.tools.r8.shaking.KeepFieldInfo;
import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.Timing;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import java.util.IdentityHashMap;
-import java.util.List;
import java.util.Map;
public class ResourceAccessAnalysis implements EnqueuerFieldAccessAnalysis {
@@ -66,21 +60,23 @@
public static void register(
AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
- if (enabled(appView)) {
+ if (enabled(appView, enqueuer)) {
enqueuer.registerFieldAccessAnalysis(new ResourceAccessAnalysis(appView, enqueuer));
}
}
@Override
public void done(Enqueuer enqueuer) {
- appView.setResourceAnalysisResult(
- new ResourceAnalysisResult(resourceShrinkerState, fieldToValueMapping));
EnqueuerFieldAccessAnalysis.super.done(enqueuer);
}
- private static boolean enabled(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ private static boolean enabled(
+ AppView<? extends AppInfoWithClassHierarchy> appView, Enqueuer enqueuer) {
return appView.options().androidResourceProvider != null
- && appView.options().resourceShrinkerConfiguration.isOptimizedShrinking();
+ && appView.options().resourceShrinkerConfiguration.isOptimizedShrinking()
+ // Only run this in the first round, we explicitly trace the resource values
+ // with ResourceConstNumber in the optimizing pipeline.
+ && enqueuer.getMode().isInitialTreeShaking();
}
@Override
@@ -101,8 +97,6 @@
assert fieldToValueMapping.containsKey(holderType);
RClassFieldToValueStore rClassFieldToValueStore = fieldToValueMapping.get(holderType);
IntList integers = rClassFieldToValueStore.valueMapping.get(field);
- enqueuer.applyMinimumKeepInfoWhenLive(
- resolvedField, KeepFieldInfo.newEmptyJoiner().disallowOptimization());
for (Integer integer : integers) {
resourceShrinkerState.trace(integer);
}
@@ -140,6 +134,8 @@
if (definition.isConstNumber()) {
values = new IntArrayList(1);
values.add(definition.asConstNumber().getIntValue());
+ } else if (definition.isResourceConstNumber()) {
+ throw new Unreachable("Only running ResourceAccessAnalysis in initial tree shaking");
} else if (definition.isNewArrayEmpty()) {
NewArrayEmpty newArrayEmpty = definition.asNewArrayEmpty();
values = new IntArrayList();
@@ -148,6 +144,8 @@
Value constValue = uniqueUser.asArrayPut().value();
if (constValue.isConstNumber()) {
values.add(constValue.getDefinition().asConstNumber().getIntValue());
+ } else if (constValue.isConstResourceNumber()) {
+ throw new Unreachable("Only running ResourceAccessAnalysis in initial tree shaking");
}
} else {
assert uniqueUser == staticPut;
@@ -162,6 +160,8 @@
Instruction valueDefinition = inValue.definition;
if (valueDefinition.isConstNumber()) {
values.add(valueDefinition.asConstNumber().getIntValue());
+ } else if (valueDefinition.isResourceConstNumber()) {
+ throw new Unreachable("Only running ResourceAccessAnalysis in initial tree shaking");
}
}
} else {
@@ -192,79 +192,11 @@
if (result != null) {
return result;
}
- String simpleClassName =
- DescriptorUtils.getSimpleClassNameFromDescriptor(holder.getType().toDescriptorString());
- List<String> split = StringUtils.split(simpleClassName, '$');
-
- if (split.size() < 2) {
- cachedClassLookups.put(holder, false);
- return false;
- }
- String type = split.get(split.size() - 1);
- String rClass = split.get(split.size() - 2);
- // We match on R if:
- // - The name of the Class is R$type - we allow R to be an inner class.
- // - The inner type should be with lower case
- boolean isRClass = Character.isLowerCase(type.charAt(0)) && rClass.equals("R");
+ boolean isRClass = DescriptorUtils.isRClassDescriptor(holder.getType().toDescriptorString());
cachedClassLookups.put(holder, isRClass);
return isRClass;
}
- public static class ResourceAnalysisResult {
-
- private final R8ResourceShrinkerState resourceShrinkerState;
- private Map<DexType, RClassFieldToValueStore> rClassFieldToValueStoreMap;
-
- private ResourceAnalysisResult(
- R8ResourceShrinkerState resourceShrinkerState,
- Map<DexType, RClassFieldToValueStore> rClassFieldToValueStoreMap) {
- this.resourceShrinkerState = resourceShrinkerState;
- this.rClassFieldToValueStoreMap = rClassFieldToValueStoreMap;
- }
-
- public R8ResourceShrinkerModel getModel() {
- return resourceShrinkerState.getR8ResourceShrinkerModel();
- }
-
- public void rewrittenWithLens(GraphLens lens, GraphLens appliedLens, Timing timing) {
- Map<DexType, DexType> changed = new IdentityHashMap<>();
- for (DexType dexType : rClassFieldToValueStoreMap.keySet()) {
- DexType rewritten = lens.lookupClassType(dexType, appliedLens);
- if (rewritten.isNotIdenticalTo(dexType)) {
- changed.put(dexType, rewritten);
- }
- }
- if (!changed.isEmpty()) {
- Map<DexType, RClassFieldToValueStore> rewrittenMap = new IdentityHashMap<>();
- rClassFieldToValueStoreMap.forEach(
- (type, map) -> {
- rewrittenMap.put(changed.getOrDefault(type, type), map);
- map.rewrittenWithLens(lens);
- });
- rClassFieldToValueStoreMap = rewrittenMap;
- }
- }
-
- public void withoutPrunedItems(PrunedItems prunedItems, Timing timing) {
- rClassFieldToValueStoreMap.keySet().removeIf(prunedItems::isRemoved);
- rClassFieldToValueStoreMap.values().forEach(store -> store.pruneItems(prunedItems));
- }
-
- public String getSingleStringValueForField(ProgramField programField) {
- RClassFieldToValueStore rClassFieldToValueStore =
- rClassFieldToValueStoreMap.get(programField.getHolderType());
- if (rClassFieldToValueStore == null) {
- return null;
- }
- if (!rClassFieldToValueStore.hasField(programField.getReference())) {
- return null;
- }
- return getModel()
- .getStringResourcesWithSingleValue()
- .get(rClassFieldToValueStore.getResourceId(programField.getReference()));
- }
- }
-
private static class RClassFieldToValueStore {
private Map<DexField, IntList> valueMapping;
@@ -272,40 +204,6 @@
this.valueMapping = valueMapping;
}
- boolean hasField(DexField field) {
- return valueMapping.containsKey(field);
- }
-
- void pruneItems(PrunedItems prunedItems) {
- valueMapping.keySet().removeIf(prunedItems::isRemoved);
- }
-
- int getResourceId(DexField field) {
- IntList integers = valueMapping.get(field);
- assert integers.size() == 1;
- return integers.get(0);
- }
-
- @SuppressWarnings("ReferenceEquality")
- public void rewrittenWithLens(GraphLens lens) {
- Map<DexField, DexField> changed = new IdentityHashMap<>();
- valueMapping
- .keySet()
- .forEach(
- dexField -> {
- DexField rewritten = lens.lookupField(dexField);
- if (rewritten != dexField) {
- changed.put(dexField, rewritten);
- }
- });
- if (changed.size() > 0) {
- Map<DexField, IntList> rewrittenMapping = new IdentityHashMap<>();
- valueMapping.forEach(
- (key, value) -> rewrittenMapping.put(changed.getOrDefault(key, key), value));
- valueMapping = rewrittenMapping;
- }
- }
-
public static class Builder {
private final Map<DexField, IntList> valueMapping = new IdentityHashMap<>();
diff --git a/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java b/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
index 96948b9..05bf1b7 100644
--- a/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/lens/GraphLens.java
@@ -401,6 +401,10 @@
return false;
}
+ public final boolean isClassMergerLens() {
+ return isHorizontalClassMergerGraphLens() || isVerticalClassMergerLens();
+ }
+
public boolean isClearCodeRewritingLens() {
return false;
}
@@ -447,10 +451,6 @@
return null;
}
- public boolean isPublicizerLens() {
- return false;
- }
-
public boolean isVerticalClassMergerLens() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index cb4af41..7139797 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.androidapi.ComputedApiLevel;
import com.android.tools.r8.classmerging.ClassMergerMode;
-import com.android.tools.r8.classmerging.SyntheticArgumentClass;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinition;
@@ -109,11 +109,11 @@
}
void mergeDirectMethods(
+ ClassMergerSharedData classMergerSharedData,
ProfileCollectionAdditions profileCollectionAdditions,
- SyntheticArgumentClass syntheticArgumentClass,
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder) {
mergeInstanceInitializers(
- profileCollectionAdditions, syntheticArgumentClass, syntheticInitializerConverterBuilder);
+ classMergerSharedData, profileCollectionAdditions, syntheticInitializerConverterBuilder);
mergeStaticClassInitializers(syntheticInitializerConverterBuilder);
group.forEach(this::mergeDirectMethods);
if (!classInitializerMerger.isEmpty() && classInitializerMerger.isTrivialMerge()) {
@@ -203,26 +203,26 @@
}
void mergeInstanceInitializers(
+ ClassMergerSharedData classMergerSharedData,
ProfileCollectionAdditions profileCollectionAdditions,
- SyntheticArgumentClass syntheticArgumentClass,
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder) {
instanceInitializerMergers.forEach(
merger ->
merger.merge(
+ classMergerSharedData,
profileCollectionAdditions,
classMethodsBuilder,
- syntheticArgumentClass,
syntheticInitializerConverterBuilder));
}
void mergeMethods(
+ ClassMergerSharedData classMergerSharedData,
ProfileCollectionAdditions profileCollectionAdditions,
- SyntheticArgumentClass syntheticArgumentClass,
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder,
Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
mergeVirtualMethods(profileCollectionAdditions, virtuallyMergedMethodsKeepInfoConsumer);
mergeDirectMethods(
- profileCollectionAdditions, syntheticArgumentClass, syntheticInitializerConverterBuilder);
+ classMergerSharedData, profileCollectionAdditions, syntheticInitializerConverterBuilder);
classMethodsBuilder.setClassMethods(group.getTarget());
}
@@ -352,9 +352,9 @@
}
public void mergeGroup(
+ ClassMergerSharedData classMergerSharedData,
ProfileCollectionAdditions profileCollectionAdditions,
PrunedItems.Builder prunedItemsBuilder,
- SyntheticArgumentClass syntheticArgumentClass,
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder,
Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
fixAccessFlags();
@@ -363,8 +363,8 @@
mergeInterfaces();
mergeFields(prunedItemsBuilder);
mergeMethods(
+ classMergerSharedData,
profileCollectionAdditions,
- syntheticArgumentClass,
syntheticInitializerConverterBuilder,
virtuallyMergedMethodsKeepInfoConsumer);
group.getTarget().clearClassSignature();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPoint.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPoint.java
index 49f51d8..49532c6 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPoint.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorEntryPoint.java
@@ -6,12 +6,14 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.InvokeType;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.IntBox;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
@@ -35,17 +37,20 @@
*/
public class ConstructorEntryPoint extends SyntheticSourceCode {
private final DexField classIdField;
+ private final int extraNulls;
private final Int2ReferenceSortedMap<DexMethod> typeConstructors;
public ConstructorEntryPoint(
Int2ReferenceSortedMap<DexMethod> typeConstructors,
DexMethod newConstructor,
DexField classIdField,
+ int extraNulls,
Position position) {
super(newConstructor.holder, newConstructor, position);
this.typeConstructors = typeConstructors;
this.classIdField = classIdField;
+ this.extraNulls = extraNulls;
}
private boolean hasClassIdField() {
@@ -55,16 +60,37 @@
void addConstructorInvoke(DexMethod typeConstructor) {
add(
builder -> {
- List<Value> arguments = new ArrayList<>(typeConstructor.getArity() + 1);
+ int originalNumberOfNonReceiverArguments =
+ builder.hasArgumentValues()
+ ? (builder.getArgumentValues().size()
+ - BooleanUtils.intValue(typeConstructors.size() > 1)
+ - extraNulls)
+ : 0;
+ int newNumberOfNonReceiverArguments = typeConstructor.getArity();
+ List<Value> arguments = new ArrayList<>(newNumberOfNonReceiverArguments + 1);
arguments.add(builder.getReceiverValue());
-
- // If there are any arguments add them to the list.
- for (int i = 0; i < typeConstructor.getArity(); i++) {
- arguments.add(builder.getArgumentValues().get(i));
+ if (originalNumberOfNonReceiverArguments >= newNumberOfNonReceiverArguments) {
+ for (int i = 0; i < newNumberOfNonReceiverArguments; i++) {
+ arguments.add(builder.getArgumentValues().get(i));
+ }
+ } else {
+ // Exclude the last argument if it is the synthetic class id parameter, since the
+ // original constructor we are calling does not have it.
+ for (int i = 0; i < originalNumberOfNonReceiverArguments; i++) {
+ arguments.add(builder.getArgumentValues().get(i));
+ }
+ int extraRegister = nextRegister(ValueType.INT);
+ ConstNumber constNumber = builder.addIntConst(extraRegister, 0);
+ while (arguments.size() <= newNumberOfNonReceiverArguments) {
+ assert ValueType.fromDexType(
+ typeConstructor.getArgumentTypeForNonStaticMethod(arguments.size()))
+ == ValueType.INT;
+ arguments.add(constNumber.outValue());
+ }
}
-
+ assert arguments.size() == typeConstructor.getNumberOfArgumentsForNonStaticMethod();
builder.addInvoke(
- InvokeType.DIRECT, typeConstructor, typeConstructor.proto, arguments, false);
+ InvokeType.DIRECT, typeConstructor, typeConstructor.getProto(), arguments, false);
});
}
@@ -84,10 +110,8 @@
protected void prepareMultiConstructorInstructions() {
int typeConstructorCount = typeConstructors.size();
- DexMethod exampleTargetConstructor = typeConstructors.values().iterator().next();
// The class id register is always the first synthetic argument.
- int idRegister = getParamRegister(exampleTargetConstructor.getArity());
-
+ int idRegister = getParamRegister(method.getArity() - 1 - extraNulls);
if (hasClassIdField()) {
addRegisterClassIdAssignment(idRegister);
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index 03d62ea..91ca758 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -7,11 +7,12 @@
import static com.android.tools.r8.graph.DexClassAndMethod.asProgramMethodOrNull;
import com.android.tools.r8.classmerging.ClassMergerMode;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
import com.android.tools.r8.classmerging.Policy;
-import com.android.tools.r8.classmerging.SyntheticArgumentClass;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
@@ -130,20 +131,17 @@
// Merge the classes.
List<ClassMerger> classMergers = initializeClassMergers(codeProvider, lensBuilder, groups);
+ ClassMergerSharedData classMergerSharedData = new ClassMergerSharedData(appView);
ProfileCollectionAdditions profileCollectionAdditions =
ProfileCollectionAdditions.create(appView);
- SyntheticArgumentClass syntheticArgumentClass =
- mode.isInitial()
- ? new SyntheticArgumentClass.Builder(appView.withLiveness()).build(groups)
- : null;
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder =
SyntheticInitializerConverter.builder(appView, codeProvider, mode);
List<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfos = new ArrayList<>();
PrunedItems prunedItems =
applyClassMergers(
classMergers,
+ classMergerSharedData,
profileCollectionAdditions,
- syntheticArgumentClass,
syntheticInitializerConverterBuilder,
virtuallyMergedMethodsKeepInfos::add);
@@ -159,13 +157,7 @@
HorizontalClassMergerGraphLens horizontalClassMergerGraphLens =
createLens(
- mergedClasses,
- lensBuilder,
- mode,
- profileCollectionAdditions,
- syntheticArgumentClass,
- executorService,
- timing);
+ classMergerSharedData, mergedClasses, lensBuilder, mode, executorService, timing);
profileCollectionAdditions =
profileCollectionAdditions.rewriteMethodReferences(
horizontalClassMergerGraphLens::getNextMethodToInvoke);
@@ -298,12 +290,19 @@
definition.hasCode()
&& definition.getCode().isIncompleteHorizontalClassMergerCode(),
method -> {
+ // Transform the code object to CfCode. This may return null if the code object does
+ // not have support for generating CfCode. In this case, the call to toCfCode() will
+ // lens rewrite the references of the code object using the lens.
+ //
+ // This should be changed to generate non-null LirCode always.
IncompleteHorizontalClassMergerCode code =
(IncompleteHorizontalClassMergerCode) method.getDefinition().getCode();
- method.setCode(
+ CfCode cfCode =
code.toCfCode(
- appView.withClassHierarchy(), method, horizontalClassMergerGraphLens),
- appView);
+ appView.withClassHierarchy(), method, horizontalClassMergerGraphLens);
+ if (cfCode != null) {
+ method.setCode(cfCode, appView);
+ }
});
},
appView.options().getThreadingModule(),
@@ -387,16 +386,16 @@
/** Merges all class groups using {@link ClassMerger}. */
private PrunedItems applyClassMergers(
Collection<ClassMerger> classMergers,
+ ClassMergerSharedData classMergerSharedData,
ProfileCollectionAdditions profileCollectionAdditions,
- SyntheticArgumentClass syntheticArgumentClass,
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder,
Consumer<VirtuallyMergedMethodsKeepInfo> virtuallyMergedMethodsKeepInfoConsumer) {
PrunedItems.Builder prunedItemsBuilder = PrunedItems.builder().setPrunedApp(appView.app());
for (ClassMerger merger : classMergers) {
merger.mergeGroup(
+ classMergerSharedData,
profileCollectionAdditions,
prunedItemsBuilder,
- syntheticArgumentClass,
syntheticInitializerConverterBuilder,
virtuallyMergedMethodsKeepInfoConsumer);
}
@@ -409,21 +408,15 @@
*/
@SuppressWarnings("ReferenceEquality")
private HorizontalClassMergerGraphLens createLens(
+ ClassMergerSharedData classMergerSharedData,
HorizontallyMergedClasses mergedClasses,
HorizontalClassMergerGraphLens.Builder lensBuilder,
ClassMergerMode mode,
- ProfileCollectionAdditions profileCollectionAdditions,
- SyntheticArgumentClass syntheticArgumentClass,
ExecutorService executorService,
Timing timing)
throws ExecutionException {
return new HorizontalClassMergerTreeFixer(
- appView,
- mergedClasses,
- lensBuilder,
- mode,
- profileCollectionAdditions,
- syntheticArgumentClass)
+ appView, classMergerSharedData, mergedClasses, lensBuilder, mode)
.run(executorService, timing);
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerTreeFixer.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerTreeFixer.java
index 5bc07a2..91f25d0 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerTreeFixer.java
@@ -5,10 +5,9 @@
package com.android.tools.r8.horizontalclassmerging;
import com.android.tools.r8.classmerging.ClassMergerMode;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
import com.android.tools.r8.classmerging.ClassMergerTreeFixer;
-import com.android.tools.r8.classmerging.SyntheticArgumentClass;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
import com.android.tools.r8.utils.Timing;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -28,12 +27,11 @@
public HorizontalClassMergerTreeFixer(
AppView<?> appView,
+ ClassMergerSharedData classMergerSharedData,
HorizontallyMergedClasses mergedClasses,
HorizontalClassMergerGraphLens.Builder lensBuilder,
- ClassMergerMode mode,
- ProfileCollectionAdditions profileCollectionAdditions,
- SyntheticArgumentClass syntheticArgumentClass) {
- super(appView, lensBuilder, mergedClasses, profileCollectionAdditions, syntheticArgumentClass);
+ ClassMergerMode mode) {
+ super(appView, classMergerSharedData, lensBuilder, mergedClasses);
this.mode = mode;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IRCodeProvider.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IRCodeProvider.java
index 6a35c88..95c4020 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IRCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IRCodeProvider.java
@@ -66,7 +66,7 @@
return method
.getDefinition()
.getCode()
- .buildIR(method, appViewForConversion, method.getOrigin(), getConversionOptions.get());
+ .buildIR(method, appViewForConversion, getConversionOptions.get());
}
@Override
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
index 7e37921..7ca989f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteHorizontalClassMergerCode.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.RetracerForCodePrinting;
public abstract class IncompleteHorizontalClassMergerCode extends Code {
@@ -55,7 +54,6 @@
public IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
index 461cbc0..66b8a1e 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/InstanceInitializerMerger.java
@@ -4,12 +4,11 @@
package com.android.tools.r8.horizontalclassmerging;
-import static com.android.tools.r8.dex.Constants.TEMPORARY_INSTANCE_INITIALIZER_PREFIX;
import static com.android.tools.r8.ir.conversion.ExtraUnusedParameter.computeExtraUnusedParameters;
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.classmerging.ClassMergerMode;
-import com.android.tools.r8.classmerging.SyntheticArgumentClass;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
@@ -29,7 +28,6 @@
import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.structural.Ordered;
@@ -160,7 +158,7 @@
for (ProgramMethod instanceInitializer : instanceInitializers) {
typeConstructorClassMap.put(
classIdentifiers.getInt(instanceInitializer.getHolderType()),
- lensBuilder.getRenamedMethodSignature(instanceInitializer.getReference()));
+ instanceInitializer.getReference());
}
return typeConstructorClassMap;
}
@@ -245,27 +243,27 @@
}
private DexMethod moveInstanceInitializer(
- ClassMethodsBuilder classMethodsBuilder, ProgramMethod instanceInitializer) {
- DexMethod method =
- dexItemFactory.createFreshMethodNameWithHolder(
- TEMPORARY_INSTANCE_INITIALIZER_PREFIX,
- instanceInitializer.getHolderType(),
- instanceInitializer.getProto(),
- group.getTarget().getType(),
- classMethodsBuilder::isFresh);
-
- DexEncodedMethod encodedMethod =
+ ClassMergerSharedData classMergerSharedData,
+ ClassMethodsBuilder classMethodsBuilder,
+ ProgramMethod instanceInitializer,
+ DexMethod reservedMethod) {
+ DexMethod newReference =
+ dexItemFactory.createInstanceInitializerWithFreshProto(
+ instanceInitializer.getReference().withHolder(group.getTarget(), dexItemFactory),
+ classMergerSharedData.getExtraUnusedArgumentTypes(),
+ candidate ->
+ classMethodsBuilder.isFresh(candidate)
+ && candidate.isNotIdenticalTo(reservedMethod));
+ if (newReference.isIdenticalTo(instanceInitializer.getReference())) {
+ classMethodsBuilder.addDirectMethod(instanceInitializer.getDefinition());
+ return newReference;
+ }
+ DexEncodedMethod newMethod =
instanceInitializer
.getDefinition()
- .toTypeSubstitutedMethodAsInlining(method, dexItemFactory);
- encodedMethod.getMutableOptimizationInfo().markForceInline();
- encodedMethod.getAccessFlags().unsetConstructor();
- encodedMethod.getAccessFlags().unsetPublic();
- encodedMethod.getAccessFlags().unsetProtected();
- encodedMethod.getAccessFlags().setPrivate();
- classMethodsBuilder.addDirectMethod(encodedMethod);
-
- return method;
+ .toTypeSubstitutedMethodAsInlining(newReference, dexItemFactory);
+ classMethodsBuilder.addDirectMethod(newMethod);
+ return newReference;
}
private MethodAccessFlags getNewAccessFlags() {
@@ -288,7 +286,8 @@
return new ConstructorEntryPointSynthesizedCode(
createClassIdToInstanceInitializerMap(),
newMethodReference,
- group.hasClassIdField() ? group.getClassIdField() : null);
+ group.hasClassIdField() ? group.getClassIdField() : null,
+ extraNulls);
}
private boolean isSingleton() {
@@ -298,9 +297,9 @@
/** Synthesize a new method which selects the constructor based on a parameter type. */
@SuppressWarnings("ReferenceEquality")
void merge(
+ ClassMergerSharedData classMergerSharedData,
ProfileCollectionAdditions profileCollectionAdditions,
ClassMethodsBuilder classMethodsBuilder,
- SyntheticArgumentClass syntheticArgumentClass,
SyntheticInitializerConverter.Builder syntheticInitializerConverterBuilder) {
ProgramMethod representative = ListUtils.first(instanceInitializers);
@@ -313,23 +312,13 @@
DexMethod newMethodReferenceTemplate = getNewMethodReference(representative, needsClassId);
assert mode.isInitial() || classMethodsBuilder.isFresh(newMethodReferenceTemplate);
- Box<Set<DexType>> usedSyntheticArgumentClasses = new Box<>();
DexMethod newMethodReference =
dexItemFactory.createInstanceInitializerWithFreshProto(
newMethodReferenceTemplate,
- mode.isInitial() ? syntheticArgumentClass.getArgumentClasses() : ImmutableList.of(),
- classMethodsBuilder::isFresh,
- usedSyntheticArgumentClasses::set);
-
- // Amend the art profile collection.
- if (usedSyntheticArgumentClasses.isSet()) {
- for (ProgramMethod instanceInitializer : instanceInitializers) {
- profileCollectionAdditions.applyIfContextIsInProfile(
- instanceInitializer.getReference(),
- additionsBuilder ->
- usedSyntheticArgumentClasses.get().forEach(additionsBuilder::addRule));
- }
- }
+ mode.isInitial()
+ ? classMergerSharedData.getExtraUnusedArgumentTypes()
+ : ImmutableList.of(),
+ classMethodsBuilder::isFresh);
// Compute the extra unused null parameters.
List<ExtraUnusedParameter> extraUnusedParameters =
@@ -346,7 +335,11 @@
} else {
for (ProgramMethod instanceInitializer : instanceInitializers) {
DexMethod movedInstanceInitializer =
- moveInstanceInitializer(classMethodsBuilder, instanceInitializer);
+ moveInstanceInitializer(
+ classMergerSharedData,
+ classMethodsBuilder,
+ instanceInitializer,
+ newMethodReference);
lensBuilder.mapMethod(movedInstanceInitializer, movedInstanceInitializer);
lensBuilder.recordNewMethodSignature(
instanceInitializer.getReference(), movedInstanceInitializer);
@@ -361,7 +354,6 @@
// Add a mapping from a synthetic name to the synthetic constructor.
DexMethod syntheticMethodReference =
getSyntheticMethodReference(classMethodsBuilder, newMethodReference);
-
if (useSyntheticMethod()) {
lensBuilder.recordNewMethodSignature(syntheticMethodReference, newMethodReference, true);
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
index a9fa5b6..e4df0c7 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/PolicyScheduler.java
@@ -32,7 +32,6 @@
import com.android.tools.r8.horizontalclassmerging.policies.NoDirectRuntimeTypeChecks;
import com.android.tools.r8.horizontalclassmerging.policies.NoEnums;
import com.android.tools.r8.horizontalclassmerging.policies.NoFailedResolutionTargets;
-import com.android.tools.r8.horizontalclassmerging.policies.NoIllegalInlining;
import com.android.tools.r8.horizontalclassmerging.policies.NoIndirectRuntimeTypeChecks;
import com.android.tools.r8.horizontalclassmerging.policies.NoInnerClasses;
import com.android.tools.r8.horizontalclassmerging.policies.NoInstanceFieldAnnotations;
@@ -125,7 +124,6 @@
AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
builder.add(
new NoDeadEnumLiteMaps(appViewWithLiveness, mode),
- new NoIllegalInlining(appViewWithLiveness, mode),
new NoVerticallyMergedClasses(appViewWithLiveness, mode));
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
index 19efa91..d54026f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ClassInitializerMerger.java
@@ -35,7 +35,6 @@
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.CfVersionUtils;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.ListUtils;
@@ -208,7 +207,6 @@
public IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
assert !classInitializers.isEmpty();
@@ -249,7 +247,6 @@
valueNumberGenerator,
blockNumberGenerator,
metadata,
- origin,
conversionOptions);
ListIterator<BasicBlock> blockIterator = code.listIterator();
@@ -275,7 +272,6 @@
appView.codeLens(),
valueNumberGenerator,
preamblePosition,
- classInitializer.getOrigin(),
RewrittenPrototypeDescription.none());
classInitializer.getDefinition().setObsolete();
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
index 0c0f059..fda1515 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/code/ConstructorEntryPointSynthesizedCode.java
@@ -5,18 +5,20 @@
package com.android.tools.r8.horizontalclassmerging.code;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.ClasspathMethod;
-import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.horizontalclassmerging.ConstructorEntryPoint;
+import com.android.tools.r8.horizontalclassmerging.HorizontalClassMergerGraphLens;
+import com.android.tools.r8.horizontalclassmerging.IncompleteHorizontalClassMergerCode;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
@@ -25,23 +27,26 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.conversion.SourceCode;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.RetracerForCodePrinting;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
-public class ConstructorEntryPointSynthesizedCode extends Code {
+public class ConstructorEntryPointSynthesizedCode extends IncompleteHorizontalClassMergerCode {
private final DexMethod newConstructor;
private final DexField classIdField;
+ private final int extraNulls;
private final Int2ReferenceSortedMap<DexMethod> typeConstructors;
public ConstructorEntryPointSynthesizedCode(
Int2ReferenceSortedMap<DexMethod> typeConstructors,
DexMethod newConstructor,
- DexField classIdField) {
+ DexField classIdField,
+ int extraNulls) {
this.typeConstructors = typeConstructors;
this.newConstructor = newConstructor;
this.classIdField = classIdField;
+ this.extraNulls = extraNulls;
}
private void registerReachableDefinitions(UseRegistry<?> registry) {
@@ -55,11 +60,30 @@
}
@Override
+ public GraphLens getCodeLens(AppView<?> appView) {
+ return appView
+ .graphLens()
+ .asNonIdentityLens()
+ .find(GraphLens::isHorizontalClassMergerGraphLens);
+ }
+
+ @Override
public boolean isHorizontalClassMergerCode() {
return true;
}
@Override
+ public CfCode toCfCode(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ ProgramMethod method,
+ HorizontalClassMergerGraphLens lens) {
+ for (Int2ReferenceMap.Entry<DexMethod> entry : typeConstructors.int2ReferenceEntrySet()) {
+ entry.setValue(lens.getNextMethodSignature(entry.getValue()));
+ }
+ return null;
+ }
+
+ @Override
public final boolean isEmptyVoidMethod() {
return false;
}
@@ -68,7 +92,6 @@
public final IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
SyntheticPosition position =
SyntheticPosition.builder()
@@ -77,8 +100,9 @@
.setIsD8R8Synthesized(true)
.build();
SourceCode sourceCode =
- new ConstructorEntryPoint(typeConstructors, newConstructor, classIdField, position);
- return IRBuilder.create(method, appView, sourceCode, origin).build(method, conversionOptions);
+ new ConstructorEntryPoint(
+ typeConstructors, newConstructor, classIdField, extraNulls, position);
+ return IRBuilder.create(method, appView, sourceCode).build(method, conversionOptions);
}
@Override
@@ -89,28 +113,16 @@
GraphLens codeLens,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
RewrittenPrototypeDescription protoChanges) {
SourceCode sourceCode =
- new ConstructorEntryPoint(typeConstructors, newConstructor, classIdField, callerPosition);
+ new ConstructorEntryPoint(
+ typeConstructors, newConstructor, classIdField, extraNulls, callerPosition);
return IRBuilder.createForInlining(
- method, appView, codeLens, sourceCode, origin, valueNumberGenerator, protoChanges)
+ method, appView, codeLens, sourceCode, valueNumberGenerator, protoChanges)
.build(context, MethodConversionOptions.nonConverting());
}
@Override
- public final Code getCodeAsInlining(
- DexMethod caller,
- boolean isCallerD8R8Synthesized,
- DexMethod callee,
- boolean isCalleeD8R8Synthesized,
- DexItemFactory factory) {
- // This code object is synthesized so "inlining" just "strips" the callee position.
- assert isCalleeD8R8Synthesized;
- return this;
- }
-
- @Override
public final String toString() {
return toString(null, RetracerForCodePrinting.empty());
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoIllegalInlining.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoIllegalInlining.java
deleted file mode 100644
index 5126df8..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoIllegalInlining.java
+++ /dev/null
@@ -1,65 +0,0 @@
-// Copyright (c) 2020, 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.horizontalclassmerging.policies;
-
-import com.android.tools.r8.classmerging.ClassMergerMode;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.google.common.collect.Iterables;
-
-public class NoIllegalInlining extends SingleClassPolicy {
-
- private final AppView<AppInfoWithLiveness> appView;
-
- public NoIllegalInlining(AppView<AppInfoWithLiveness> appView, ClassMergerMode mode) {
- // This policy is only relevant for the first round of horizontal class merging, since the final
- // round of horizontal class merging may not require any inlining.
- assert mode.isInitial();
- this.appView = appView;
- }
-
- @SuppressWarnings("ReferenceEquality")
- private boolean disallowInlining(ProgramMethod method) {
- Code code = method.getDefinition().getCode();
-
- if (!appView.getKeepInfo(method).isInliningAllowed(appView.options())) {
- return true;
- }
-
- // For non-jar/cf code we currently cannot guarantee that markForceInline() will succeed.
- if (code == null) {
- return true;
- }
-
- if (code.isCfCode()) {
- CfCode cfCode = code.asCfCode();
- ConstraintWithTarget constraint =
- cfCode.computeInliningConstraint(appView, appView.graphLens(), method);
- return constraint.isNever();
- } else if (code.isDefaultInstanceInitializerCode()) {
- return false;
- } else {
- return true;
- }
- }
-
- @Override
- public boolean canMerge(DexProgramClass program) {
- return !Iterables.any(
- program.directProgramMethods(),
- method -> method.getDefinition().isInstanceInitializer() && disallowInlining(method));
- }
-
- @Override
- public String getName() {
- return "DontInlinePolicy";
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
index abbb78c..924928b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/ValueMayDependOnEnvironmentAnalysis.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.ir.analysis;
-import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
@@ -13,7 +12,6 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
-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.ir.analysis.environmentdependence.ValueGraph;
@@ -305,8 +303,8 @@
return false;
}
- NewInstance newInstance = value.definition.asNewInstance();
- DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(newInstance.clazz));
+ NewInstance newInstance = value.getDefinition().asNewInstance();
+ DexClass clazz = appView.definitionFor(newInstance.getType(), context);
if (clazz == null) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
index c71f037..e050ed4 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
@@ -205,6 +205,14 @@
return null;
}
+ public boolean isSingleResourceNumberValue() {
+ return false;
+ }
+
+ public SingleResourceNumberValue asSingleResourceNumberValue() {
+ return null;
+ }
+
public boolean isSingleStringValue() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
index 79eca14..567d39a 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValueFactory.java
@@ -26,6 +26,8 @@
new ConcurrentHashMap<>();
private final ConcurrentHashMap<Long, SingleNumberValue> singleNumberValues =
new ConcurrentHashMap<>();
+ private final ConcurrentHashMap<Integer, SingleResourceNumberValue> singleResourceNumberValues =
+ new ConcurrentHashMap<>();
private final ConcurrentHashMap<DexString, SingleStringValue> singleStringValues =
new ConcurrentHashMap<>();
private final ConcurrentHashMap<Integer, KnownLengthArrayState> knownArrayLengthStates =
@@ -122,6 +124,10 @@
return createUncheckedSingleNumberValue(value);
}
+ public SingleResourceNumberValue createSingleResourceNumberValue(int value) {
+ return singleResourceNumberValues.computeIfAbsent(value, SingleResourceNumberValue::new);
+ }
+
public SingleNumberValue createUncheckedSingleNumberValue(long value) {
return singleNumberValues.computeIfAbsent(value, SingleNumberValue::new);
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleResourceNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleResourceNumberValue.java
new file mode 100644
index 0000000..8be7c10
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleResourceNumberValue.java
@@ -0,0 +1,119 @@
+// Copyright (c) 2024, 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.ir.analysis.value;
+
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DebugLocalInfo;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.MaterializingInstructionsInfo;
+import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.ResourceConstNumber;
+import com.android.tools.r8.ir.code.ValueFactory;
+import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+
+public class SingleResourceNumberValue extends SingleConstValue {
+
+ private final int value;
+
+ /** Intentionally package private, use {@link AbstractValueFactory} instead. */
+ SingleResourceNumberValue(int value) {
+ this.value = value;
+ }
+
+ @Override
+ public boolean hasSingleMaterializingInstruction() {
+ return true;
+ }
+
+ @Override
+ public boolean isSingleResourceNumberValue() {
+ return true;
+ }
+
+ @Override
+ public SingleResourceNumberValue asSingleResourceNumberValue() {
+ return this;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return this == o;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public String toString() {
+ return "SingleResourceNumberValue(" + value + ")";
+ }
+
+ @Override
+ public Instruction[] createMaterializingInstructions(
+ AppView<?> appView,
+ ProgramMethod context,
+ ValueFactory valueFactory,
+ MaterializingInstructionsInfo info) {
+ ResourceConstNumber materializingInstruction =
+ createMaterializingInstruction(appView, valueFactory, info);
+ return new Instruction[] {materializingInstruction};
+ }
+
+ public ResourceConstNumber createMaterializingInstruction(
+ AppView<?> appView, ValueFactory valueFactory, MaterializingInstructionsInfo info) {
+ return createMaterializingInstruction(
+ appView, valueFactory, info.getOutType(), info.getLocalInfo(), info.getPosition());
+ }
+
+ public ResourceConstNumber createMaterializingInstruction(
+ AppView<?> appView,
+ ValueFactory valueFactory,
+ TypeElement type,
+ DebugLocalInfo localInfo,
+ Position position) {
+ assert type.isInt();
+ return ResourceConstNumber.builder()
+ .setFreshOutValue(valueFactory, type, localInfo)
+ .setPositionForNonThrowingInstruction(position, appView.options())
+ .setValue(value)
+ .build();
+ }
+
+ @Override
+ boolean internalIsMaterializableInContext(
+ AppView<? extends AppInfoWithClassHierarchy> appView, ProgramMethod context) {
+ return true;
+ }
+
+ @Override
+ public boolean isMaterializableInAllContexts(AppView<AppInfoWithLiveness> appView) {
+ return true;
+ }
+
+ @Override
+ public InstanceFieldInitializationInfo fixupAfterParametersChanged(
+ ArgumentInfoCollection argumentInfoCollection) {
+ return this;
+ }
+
+ @Override
+ public SingleValue rewrittenWithLens(
+ AppView<AppInfoWithLiveness> appView, DexType newType, GraphLens lens, GraphLens codeLens) {
+ return this;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/CatchHandlers.java b/src/main/java/com/android/tools/r8/ir/code/CatchHandlers.java
index 7da900e..357828b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/CatchHandlers.java
+++ b/src/main/java/com/android/tools/r8/ir/code/CatchHandlers.java
@@ -10,6 +10,9 @@
import com.android.tools.r8.utils.ListUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.ints.IntList;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -113,9 +116,29 @@
}
public CatchHandlers<T> rewriteWithLens(GraphLens graphLens, GraphLens codeLens) {
+ IntList targetIndicesToRemove = new IntArrayList();
+ Set<DexType> seenGuards = Sets.newIdentityHashSet();
List<DexType> newGuards =
- ListUtils.mapOrElse(guards, guard -> graphLens.lookupType(guard, codeLens), null);
- return newGuards != null ? new CatchHandlers<>(newGuards, targets) : this;
+ ListUtils.mapOrElse(
+ guards,
+ (index, guard) -> {
+ DexType newGuard = graphLens.lookupType(guard, codeLens);
+ if (seenGuards.add(newGuard)) {
+ return newGuard;
+ }
+ targetIndicesToRemove.add(index);
+ return null;
+ },
+ null);
+ if (newGuards == null) {
+ assert targetIndicesToRemove.isEmpty();
+ return this;
+ }
+ List<T> newTargets =
+ targetIndicesToRemove.isEmpty()
+ ? targets
+ : ListUtils.newArrayListWithoutIndices(targets, targetIndicesToRemove);
+ return new CatchHandlers<>(newGuards, newTargets);
}
public void forEach(BiConsumer<DexType, T> consumer) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/DefaultInstructionVisitor.java b/src/main/java/com/android/tools/r8/ir/code/DefaultInstructionVisitor.java
index a21882a..a3bbdee 100644
--- a/src/main/java/com/android/tools/r8/ir/code/DefaultInstructionVisitor.java
+++ b/src/main/java/com/android/tools/r8/ir/code/DefaultInstructionVisitor.java
@@ -95,6 +95,11 @@
}
@Override
+ public T visit(ResourceConstNumber instruction) {
+ return null;
+ }
+
+ @Override
public T visit(ConstString instruction) {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCode.java b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
index ae74a82..d5e82ff 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCode.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCode.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
+import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
@@ -29,7 +30,6 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.optimize.AffectedValues;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.DequeUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -137,8 +137,6 @@
private final IRMetadata metadata;
private final InternalOptions options;
- public final Origin origin;
-
public IRCode(
InternalOptions options,
ProgramMethod method,
@@ -147,7 +145,6 @@
NumberGenerator valueNumberGenerator,
NumberGenerator basicBlockNumberGenerator,
IRMetadata metadata,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
assert metadata != null;
assert options != null;
@@ -161,7 +158,6 @@
this.valueNumberGenerator = valueNumberGenerator;
this.basicBlockNumberGenerator = basicBlockNumberGenerator;
this.metadata = metadata;
- this.origin = origin;
}
public IRMetadata metadata() {
@@ -622,6 +618,21 @@
return true;
}
+ public boolean verifyInvokeInterface(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ if (appView.testing().allowInvokeErrors) {
+ return true;
+ }
+ for (InvokeMethod invoke : this.<InvokeMethod>instructions(Instruction::isInvokeMethod)) {
+ DexType holderType = invoke.getInvokedMethod().getHolderType();
+ if (holderType.isArrayType()) {
+ continue;
+ }
+ DexClass holder = appView.definitionFor(holderType, context());
+ assert holder == null || invoke.getInterfaceBit() == holder.isInterface();
+ }
+ return true;
+ }
+
public boolean hasNoMergedClasses(AppView<? extends AppInfoWithClassHierarchy> appView) {
MergedClassesCollection mergedClasses = appView.allMergedClasses();
if (mergedClasses == null) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRMetadata.java b/src/main/java/com/android/tools/r8/ir/code/IRMetadata.java
index 2d8cc3e..56f38c3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRMetadata.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRMetadata.java
@@ -103,6 +103,10 @@
return get(Opcodes.CONST_NUMBER);
}
+ public boolean mayHaveResourceConstNumber() {
+ return get(Opcodes.RESOURCE_CONST_NUMBER);
+ }
+
public boolean mayHaveConstString() {
return get(Opcodes.CONST_STRING);
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/IROpcodeUtils.java b/src/main/java/com/android/tools/r8/ir/code/IROpcodeUtils.java
new file mode 100644
index 0000000..b798181
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/IROpcodeUtils.java
@@ -0,0 +1,39 @@
+// Copyright (c) 2024, 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.ir.code;
+
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKEDIRECT;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKEDIRECT_ITF;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKEINTERFACE;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKESTATIC;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKESTATIC_ITF;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKESUPER;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKESUPER_ITF;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKEVIRTUAL;
+
+import com.android.tools.r8.errors.Unreachable;
+
+public class IROpcodeUtils {
+
+ public static int fromLirInvokeOpcode(int opcode) {
+ switch (opcode) {
+ case INVOKEDIRECT:
+ case INVOKEDIRECT_ITF:
+ return Opcodes.INVOKE_DIRECT;
+ case INVOKEINTERFACE:
+ return Opcodes.INVOKE_INTERFACE;
+ case INVOKESTATIC:
+ case INVOKESTATIC_ITF:
+ return Opcodes.INVOKE_STATIC;
+ case INVOKESUPER:
+ case INVOKESUPER_ITF:
+ return Opcodes.INVOKE_SUPER;
+ case INVOKEVIRTUAL:
+ return Opcodes.INVOKE_VIRTUAL;
+ default:
+ throw new Unreachable();
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Instruction.java b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
index d0426ec..08143ae 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Instruction.java
@@ -869,6 +869,14 @@
return null;
}
+ public boolean isResourceConstNumber() {
+ return false;
+ }
+
+ public ResourceConstNumber asResourceConstNumber() {
+ return null;
+ }
+
public boolean isConstInstruction() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionVisitor.java b/src/main/java/com/android/tools/r8/ir/code/InstructionVisitor.java
index 8318365..62bd3de 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstructionVisitor.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionVisitor.java
@@ -38,6 +38,8 @@
T visit(ConstNumber instruction);
+ T visit(ResourceConstNumber instruction);
+
T visit(ConstString instruction);
T visit(DebugLocalRead instruction);
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeType.java b/src/main/java/com/android/tools/r8/ir/code/InvokeType.java
index 8bedc64..28e3846 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeType.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.lightir.LirOpcodes;
import org.objectweb.asm.Opcodes;
public enum InvokeType {
@@ -186,6 +187,23 @@
return dexOpcodeRange;
}
+ public int getLirOpcode(boolean isInterface) {
+ switch (this) {
+ case DIRECT:
+ return isInterface ? LirOpcodes.INVOKEDIRECT_ITF : LirOpcodes.INVOKEDIRECT;
+ case INTERFACE:
+ return LirOpcodes.INVOKEINTERFACE;
+ case STATIC:
+ return isInterface ? LirOpcodes.INVOKESTATIC_ITF : LirOpcodes.INVOKESTATIC;
+ case SUPER:
+ return isInterface ? LirOpcodes.INVOKESUPER_ITF : LirOpcodes.INVOKESUPER;
+ case VIRTUAL:
+ return LirOpcodes.INVOKEVIRTUAL;
+ default:
+ throw new Unreachable();
+ }
+ }
+
public boolean isDirect() {
return this == DIRECT;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
index 1bd40d4..a7c3397 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayEmpty.java
@@ -88,7 +88,11 @@
AbstractValueSupplier abstractValueSupplier,
SideEffectAssumption assumption) {
assert type.isArrayType();
- return isArrayTypeInaccessible(appView, context) || isArraySizeMaybeNegative();
+ return isArrayTypeInaccessible(appView, context)
+ || isArraySizeMaybeNegative()
+ // Cts test relying on dead array allocations of size Integer.MAX_VALUE not getting
+ // removed See b/322478366.
+ || (appView.options().debug && sizeIfConst() == Integer.MAX_VALUE);
}
private boolean isArrayTypeInaccessible(AppView<?> appView, ProgramMethod context) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/Opcodes.java b/src/main/java/com/android/tools/r8/ir/code/Opcodes.java
index 44ad346..58889ac 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Opcodes.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Opcodes.java
@@ -77,4 +77,5 @@
int XOR = 68;
int UNINITIALIZED_THIS_LOCAL_READ = 69;
int RECORD_FIELD_VALUES = 70;
+ int RESOURCE_CONST_NUMBER = 71;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Phi.java b/src/main/java/com/android/tools/r8/ir/code/Phi.java
index 6197751..341ca0b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Phi.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Phi.java
@@ -12,15 +12,14 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.BasicBlock.EdgeType;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.TypeConstraintResolver;
import com.android.tools.r8.ir.optimize.AffectedValues;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.DequeUtils;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Reporter;
@@ -102,11 +101,11 @@
@Override
public void constrainType(
- ValueTypeConstraint constraint, DexMethod method, Origin origin, Reporter reporter) {
+ ValueTypeConstraint constraint, ProgramMethod method, Reporter reporter) {
if (readType == RegisterReadType.DEBUG) {
abortOnInvalidDebugInfo(constraint);
}
- super.constrainType(constraint, method, origin, reporter);
+ super.constrainType(constraint, method, reporter);
}
private void abortOnInvalidDebugInfo(ValueTypeConstraint constraint) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/ResourceConstNumber.java b/src/main/java/com/android/tools/r8/ir/code/ResourceConstNumber.java
new file mode 100644
index 0000000..d18a410
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/code/ResourceConstNumber.java
@@ -0,0 +1,162 @@
+// Copyright (c) 2024, 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.ir.code;
+
+import com.android.tools.r8.cf.LoadStoreHelper;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.conversion.CfBuilder;
+import com.android.tools.r8.ir.conversion.DexBuilder;
+import com.android.tools.r8.lightir.LirBuilder;
+
+/**
+ * Instruction representing the SSA value an R class field value.
+ *
+ * <p>This instruction allows us to correctly trace inlined resource values in the second round of
+ * tree shaking.
+ *
+ * <p>The instruction is simple converted back to a const number before writing.
+ */
+public class ResourceConstNumber extends ConstInstruction {
+
+ private final int value;
+
+ public ResourceConstNumber(Value dest, int value) {
+ super(dest);
+ assert dest.type.isPrimitiveType();
+ this.value = value;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ @Override
+ public int opcode() {
+ return Opcodes.RESOURCE_CONST_NUMBER;
+ }
+
+ @Override
+ public <T> T accept(InstructionVisitor<T> visitor) {
+ return visitor.visit(this);
+ }
+
+ @Override
+ public boolean instructionTypeCanBeCanonicalized() {
+ return true;
+ }
+
+ @Override
+ public void buildDex(DexBuilder builder) {
+ throw new Unreachable("We never write out ResourceConstNumber");
+ }
+
+ @Override
+ public void insertLoadAndStores(InstructionListIterator it, LoadStoreHelper helper) {
+ throw new Unreachable("We never write cf code with resource numbers");
+ }
+
+ public Value dest() {
+ return outValue;
+ }
+
+ @Override
+ public void buildCf(CfBuilder builder) {
+ throw new Unreachable("We never write out a resource const number");
+ }
+
+ @Override
+ public int maxInValueRegister() {
+ throw new Unreachable("We map out of ResourceConstNumber before register allocation");
+ }
+
+ @Override
+ public int maxOutValueRegister() {
+ throw new Unreachable("We map out of ResourceConstNumber before register allocation");
+ }
+
+ @Override
+ public boolean identicalNonValueNonPositionParts(Instruction other) {
+ if (other == this) {
+ return true;
+ }
+ if (!other.isResourceConstNumber()) {
+ return false;
+ }
+ ResourceConstNumber otherNumber = other.asResourceConstNumber();
+ return otherNumber.getValue() == getValue();
+ }
+
+ @Override
+ public boolean isOutConstant() {
+ return true;
+ }
+
+ @Override
+ public boolean isResourceConstNumber() {
+ return true;
+ }
+
+ @Override
+ public TypeElement evaluate(AppView<?> appView) {
+ assert getOutType().isInt();
+ return TypeElement.getInt();
+ }
+
+ @Override
+ public AbstractValue getAbstractValue(
+ AppView<?> appView, ProgramMethod context, AbstractValueSupplier abstractValueSupplier) {
+ if (outValue.hasLocalInfo()) {
+ return AbstractValue.unknown();
+ }
+ return appView.abstractValueFactory().createSingleResourceNumberValue(getValue());
+ }
+
+ @Override
+ public void buildLir(LirBuilder<Value, ?> builder) {
+ builder.addResourceConstNumber(getValue());
+ }
+
+ public static ResourceConstNumber copyOf(IRCode code, ResourceConstNumber original) {
+ Value newValue = code.createValue(TypeElement.getInt(), original.getLocalInfo());
+ return new ResourceConstNumber(newValue, original.getValue());
+ }
+
+ @Override
+ public ResourceConstNumber asResourceConstNumber() {
+ return this;
+ }
+
+ public int getValue() {
+ return value;
+ }
+
+ public static class Builder extends BuilderBase<Builder, ResourceConstNumber> {
+
+ private int value;
+
+ public Builder setValue(int value) {
+ this.value = value;
+ return this;
+ }
+
+ @Override
+ public ResourceConstNumber build() {
+ return amend(new ResourceConstNumber(outValue, value));
+ }
+
+ @Override
+ public Builder self() {
+ return this;
+ }
+
+ @Override
+ protected boolean verifyInstructionTypeCannotThrow() {
+ return true;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java
index f7d98af..0a16889 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Value.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Value.java
@@ -18,7 +18,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DebugLocalInfo;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
@@ -31,12 +30,12 @@
import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.ir.optimize.AffectedValues;
import com.android.tools.r8.ir.regalloc.LiveIntervals;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.LongInterval;
+import com.android.tools.r8.utils.ObjectUtils;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.google.common.base.Predicates;
@@ -53,9 +52,8 @@
public class Value implements Comparable<Value> {
- @SuppressWarnings("ReferenceEquality")
public void constrainType(
- ValueTypeConstraint constraint, DexMethod method, Origin origin, Reporter reporter) {
+ ValueTypeConstraint constraint, ProgramMethod method, Reporter reporter) {
TypeElement constrainedType = constrainedType(constraint);
if (constrainedType == null) {
throw reporter.fatalError(
@@ -66,9 +64,9 @@
+ this
+ " by constraint: "
+ constraint,
- origin,
- new MethodPosition(method.asMethodReference())));
- } else if (constrainedType != type) {
+ method.getOrigin(),
+ new MethodPosition(method.getMethodReference())));
+ } else if (ObjectUtils.notIdentical(constrainedType, type)) {
setType(constrainedType);
}
}
@@ -844,6 +842,10 @@
return isConstant() && getConstInstruction().isConstNumber();
}
+ public boolean isConstResourceNumber() {
+ return isConstant() && getConstInstruction().isResourceConstNumber();
+ }
+
public boolean isConstNumber(long rawValue) {
return isConstant()
&& getConstInstruction().isConstNumber()
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
index de8a584..48241f6 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
@@ -40,7 +40,6 @@
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.CfState.Snapshot;
import com.android.tools.r8.ir.conversion.IRBuilder.BlockInfo;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.InternalOutputMode;
import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
@@ -190,7 +189,6 @@
private final List<CfCode.LocalVariableInfo> localVariables;
private final CfCode code;
private final ProgramMethod method;
- private final Origin origin;
private final AppView<?> appView;
private final Reference2IntMap<CfLabel> labelOffsets = new Reference2IntOpenHashMap<>();
@@ -207,15 +205,13 @@
public CfSourceCode(
CfCode code,
- List<CfCode.LocalVariableInfo> localVariables,
+ List<LocalVariableInfo> localVariables,
ProgramMethod method,
Position callerPosition,
- Origin origin,
AppView<?> appView) {
this.code = code;
this.localVariables = localVariables;
this.method = method;
- this.origin = origin;
this.appView = appView;
int cfPositionCount = 0;
for (int i = 0; i < code.getInstructions().size(); i++) {
@@ -227,7 +223,7 @@
++cfPositionCount;
}
}
- this.state = new CfState(origin);
+ this.state = new CfState(method);
canonicalPositions =
new CanonicalPositions(
callerPosition,
@@ -247,14 +243,6 @@
return method.getDefinition();
}
- public Origin getOrigin() {
- return origin;
- }
-
- public DexType getOriginalHolder() {
- return code.getOriginalHolder();
- }
-
@Override
public int instructionCount() {
return code.getInstructions().size();
@@ -573,7 +561,7 @@
private void recordStateForTarget(int target, Snapshot snapshot) {
Snapshot existing = incomingState.get(target);
- Snapshot merged = CfState.merge(existing, snapshot, origin);
+ Snapshot merged = CfState.merge(existing, snapshot, method);
if (merged != existing) {
incomingState.put(target, merged);
}
@@ -689,8 +677,7 @@
.reporter
.warning(
new CfCodeDiagnostics(
- origin,
- method.getReference(),
+ method,
"Could not find stack map for block at offset "
+ blockOffset
+ ". This is most likely due to invalid"
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfState.java b/src/main/java/com/android/tools/r8/ir/conversion/CfState.java
index 353faac..d7d39f8 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfState.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfState.java
@@ -5,9 +5,9 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.ValueType;
-import com.android.tools.r8.origin.Origin;
public class CfState {
@@ -74,12 +74,12 @@
}
}
- private final Origin origin;
+ private final ProgramMethod method;
private Snapshot current;
private Position position;
- public CfState(Origin origin) {
- this.origin = origin;
+ public CfState(ProgramMethod method) {
+ this.method = method;
}
private static final int MAX_UPDATES = 4;
@@ -110,7 +110,7 @@
if (current == null) {
current = snapshot == null ? new BaseSnapshot() : snapshot;
} else {
- current = merge(current, snapshot, origin);
+ current = merge(current, snapshot, method);
}
}
@@ -118,22 +118,22 @@
return current;
}
- public static Snapshot merge(Snapshot current, Snapshot update, Origin origin) {
+ public static Snapshot merge(Snapshot current, Snapshot update, ProgramMethod method) {
assert update != null;
if (current == null) {
return update;
}
- return merge(current.asBase(), update.asBase(), origin);
+ return merge(current.asBase(), update.asBase(), method);
}
- private static Snapshot merge(BaseSnapshot current, BaseSnapshot update, Origin origin) {
+ private static Snapshot merge(BaseSnapshot current, BaseSnapshot update, ProgramMethod method) {
if (current.stack.length != update.stack.length) {
throw new CompilationError(
"Different stack heights at jump target: "
+ current.stack.length
+ " != "
+ update.stack.length,
- origin);
+ method.getOrigin());
}
// At this point, JarState checks if `current` has special "NULL" or "BYTE/BOOL" types
// that `update` does not have, and if so it computes a refinement.
@@ -149,7 +149,7 @@
+ current.stack[i]
+ " and "
+ update.stack[i],
- origin);
+ method.getOrigin());
}
}
// We could check that locals are compatible, but that doesn't make sense since locals can be
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index a3ca7c5..994ef53 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -121,7 +121,6 @@
import com.android.tools.r8.ir.code.Xor;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.Pair;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
@@ -405,7 +404,6 @@
private ProgramMethod context;
public final AppView<?> appView;
private final GraphLens codeLens;
- private final Origin origin;
private final RewrittenPrototypeDescription prototypeChanges;
private Value receiverValue;
private List<Value> argumentValues;
@@ -437,15 +435,13 @@
// then the IR does not necessarily contain a const-string instruction).
private final IRMetadata metadata = new IRMetadata();
- public static IRBuilder create(
- ProgramMethod method, AppView<?> appView, SourceCode source, Origin origin) {
+ public static IRBuilder create(ProgramMethod method, AppView<?> appView, SourceCode source) {
GraphLens codeLens = method.getDefinition().getCode().getCodeLens(appView);
return new IRBuilder(
method,
appView,
codeLens,
source,
- origin,
lookupPrototypeChanges(appView, method, codeLens),
new NumberGenerator());
}
@@ -455,11 +451,9 @@
AppView<?> appView,
GraphLens codeLens,
SourceCode source,
- Origin origin,
NumberGenerator valueNumberGenerator,
RewrittenPrototypeDescription protoChanges) {
- return new IRBuilder(
- method, appView, codeLens, source, origin, protoChanges, valueNumberGenerator);
+ return new IRBuilder(method, appView, codeLens, source, protoChanges, valueNumberGenerator);
}
public static RewrittenPrototypeDescription lookupPrototypeChanges(
@@ -474,7 +468,6 @@
AppView<?> appView,
GraphLens codeLens,
SourceCode source,
- Origin origin,
RewrittenPrototypeDescription prototypeChanges,
NumberGenerator valueNumberGenerator) {
assert source != null;
@@ -482,7 +475,6 @@
this.method = method;
this.appView = appView;
this.source = source;
- this.origin = origin;
this.codeLens = codeLens;
this.prototypeChanges = prototypeChanges;
this.valueNumberGenerator = valueNumberGenerator;
@@ -517,6 +509,11 @@
return targets;
}
+ public boolean hasArgumentValues() {
+ assert argumentValues == null || !argumentValues.isEmpty();
+ return argumentValues != null;
+ }
+
public List<Value> getArgumentValues() {
return argumentValues;
}
@@ -718,7 +715,6 @@
valueNumberGenerator,
basicBlockNumberGenerator,
metadata,
- origin,
conversionOptions);
// Verify critical edges are split so we have a place to insert phi moves if necessary.
@@ -774,7 +770,7 @@
}
public void constrainType(Value value, ValueTypeConstraint constraint) {
- value.constrainType(constraint, method.getReference(), origin, appView.options().reporter);
+ value.constrainType(constraint, method, appView.reporter());
}
private void addImpreciseInstruction(ImpreciseMemberTypeInstruction instruction) {
@@ -1219,8 +1215,11 @@
add(new ConstNumber(writeRegister(dest, getDouble(), ThrowingInfo.NO_THROW), value));
}
- public void addIntConst(int dest, long value) {
- add(new ConstNumber(writeRegister(dest, getInt(), ThrowingInfo.NO_THROW), value));
+ public ConstNumber addIntConst(int dest, long value) {
+ ConstNumber constNumber =
+ new ConstNumber(writeRegister(dest, getInt(), ThrowingInfo.NO_THROW), value);
+ add(constNumber);
+ return constNumber;
}
public void addFloatConst(int dest, long value) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 676fcc5..72e5dac 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -161,7 +161,7 @@
private final DexItemFactory factory;
private final InternalOptions options;
- LensCodeRewriter(AppView<? extends AppInfoWithClassHierarchy> appView) {
+ public LensCodeRewriter(AppView<? extends AppInfoWithClassHierarchy> appView) {
this.appView = appView;
this.factory = appView.dexItemFactory();
this.options = appView.options();
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
index 19bb6dc..5f5a9c9 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LirConverter.java
@@ -11,8 +11,9 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
import com.android.tools.r8.graph.lens.GraphLens;
-import com.android.tools.r8.graph.lens.NonIdentityGraphLens;
import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.conversion.passes.ConstResourceNumberRemover;
+import com.android.tools.r8.ir.conversion.passes.ConstResourceNumberRewriter;
import com.android.tools.r8.ir.conversion.passes.FilledNewArrayRewriter;
import com.android.tools.r8.ir.optimize.ConstantCanonicalizer;
import com.android.tools.r8.ir.optimize.DeadCodeRemover;
@@ -23,6 +24,7 @@
import com.android.tools.r8.utils.ObjectUtils;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.verticalclassmerging.IncompleteVerticalClassMergerBridgeCode;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -34,6 +36,8 @@
assert appView.testing().canUseLir(appView);
assert appView.testing().isPreLirPhase();
appView.testing().enterLirSupportedPhase();
+ ConstResourceNumberRewriter constResourceNumberRewriter =
+ new ConstResourceNumberRewriter(appView);
// Convert code objects to LIR.
ThreadUtils.processItems(
appView.appInfo().classes(),
@@ -45,10 +49,11 @@
clazz.forEachProgramMethodMatching(
method ->
method.hasCode()
- && !method.isInitializer()
+ && !method.isInstanceInitializer()
&& !appView.isCfByteCodePassThrough(method),
method -> {
IRCode code = method.buildIR(appView, MethodConversionOptions.forLirPhase(appView));
+ constResourceNumberRewriter.run(code, Timing.empty());
LirCode<Integer> lirCode =
IR2LirConverter.translate(
code,
@@ -90,7 +95,7 @@
GraphLens graphLens = appView.graphLens();
assert graphLens.isNonIdentityLens();
- assert appView.codeLens().isAppliedLens();
+ assert appView.codeLens().isAppliedLens() || appView.codeLens().isClearCodeRewritingLens();
MemberRebindingIdentityLens memberRebindingIdentityLens =
graphLens.asNonIdentityLens().find(GraphLens::isMemberRebindingIdentityLens);
@@ -104,9 +109,6 @@
timing.begin("LIR->LIR@" + graphLens.getClass().getTypeName());
rewriteLirWithUnappliedLens(appView, executorService);
timing.end();
-
- // At this point all code has been mapped according to the graph lens.
- updateCodeLens(appView);
}
private static void rewriteLirWithUnappliedLens(
@@ -117,10 +119,7 @@
appView.appInfo().classes(),
clazz ->
clazz.forEachProgramMethodMatching(
- m ->
- m.hasCode()
- && !m.getCode().isSharedCodeObject()
- && !appView.isCfByteCodePassThrough(m),
+ m -> m.hasCode() && m.getCode().isLirCode(),
m -> rewriteLirMethodWithLens(m, appView, rewriterUtils)),
appView.options().getThreadingModule(),
executorService);
@@ -133,14 +132,8 @@
ProgramMethod method,
AppView<? extends AppInfoWithClassHierarchy> appView,
LensCodeRewriterUtils rewriterUtils) {
- Code code = method.getDefinition().getCode();
- if (!code.isLirCode()) {
- assert false;
- return;
- }
- LirCode<Integer> lirCode = code.asLirCode();
- LirCode<Integer> rewrittenLirCode =
- lirCode.rewriteWithSimpleLens(method, appView, rewriterUtils);
+ LirCode<Integer> lirCode = method.getDefinition().getCode().asLirCode();
+ LirCode<Integer> rewrittenLirCode = lirCode.rewriteWithLens(method, appView, rewriterUtils);
if (ObjectUtils.notIdentical(lirCode, rewrittenLirCode)) {
method.setCode(rewrittenLirCode, appView);
}
@@ -171,67 +164,7 @@
// Clear the reference type cache after conversion to reduce memory pressure.
appView.dexItemFactory().clearTypeElementsCache();
// At this point all code has been mapped according to the graph lens.
- updateCodeLens(appView);
- }
-
- private static void updateCodeLens(AppView<? extends AppInfoWithClassHierarchy> appView) {
- final NonIdentityGraphLens lens = appView.graphLens().asNonIdentityLens();
- if (lens == null) {
- assert false;
- return;
- }
-
- // If the current graph lens is the member rebinding identity lens then code lens is simply
- // the previous lens. This is the same structure as the more complicated case below but where
- // there is no need to rewrite any previous pointers.
- if (lens.isMemberRebindingIdentityLens()) {
- appView.setCodeLens(lens.getPrevious());
- return;
- }
-
- // Otherwise search out where the lens pointing to the member rebinding identity lens.
- NonIdentityGraphLens lensAfterMemberRebindingIdentityLens =
- lens.find(p -> p.getPrevious().isMemberRebindingIdentityLens());
- if (lensAfterMemberRebindingIdentityLens == null) {
- // With the current compiler structure we expect to always find the lens.
- assert false;
- appView.setCodeLens(lens);
- return;
- }
-
- GraphLens codeLens = appView.codeLens();
- MemberRebindingIdentityLens memberRebindingIdentityLens =
- lensAfterMemberRebindingIdentityLens.getPrevious().asMemberRebindingIdentityLens();
-
- // We are assuming that the member rebinding identity lens is always installed after the current
- // applied lens/code lens and also that there should not be a rebinding lens from the compilers
- // first phase (this subroutine is only used after IR conversion for now).
- assert memberRebindingIdentityLens
- == lens.findPrevious(
- p -> p == memberRebindingIdentityLens || p == codeLens || p.isMemberRebindingLens());
-
- // Rewrite the graph lens effects from 'lens' and up to the member rebinding identity lens.
- MemberRebindingIdentityLens rewrittenMemberRebindingLens =
- memberRebindingIdentityLens.toRewrittenMemberRebindingIdentityLens(
- appView, lens, memberRebindingIdentityLens, lens);
-
- // The current previous pointers for the graph lenses are:
- // lens -> ... -> lensAfterMemberRebindingIdentityLens -> memberRebindingIdentityLens -> g
- // we rewrite them now to:
- // rewrittenMemberRebindingLens -> lens -> ... -> lensAfterMemberRebindingIdentityLens -> g
-
- // The above will construct the new member rebinding lens such that it points to the new
- // code-lens point already.
- assert rewrittenMemberRebindingLens.getPrevious() == lens;
-
- // Update the previous pointer on the new code lens to jump over the old member rebinding
- // identity lens.
- lensAfterMemberRebindingIdentityLens.setPrevious(memberRebindingIdentityLens.getPrevious());
-
- // The applied lens can now be updated and the rewritten member rebinding lens installed as
- // the current "unapplied lens".
- appView.setCodeLens(lens);
- appView.setGraphLens(rewrittenMemberRebindingLens);
+ appView.clearCodeRewritings(executorService, timing);
}
private static void finalizeLirMethodToOutputFormat(
@@ -245,12 +178,14 @@
}
Timing onThreadTiming = Timing.empty();
LirCode<Integer> lirCode = code.asLirCode();
- LirCode<Integer> rewrittenLirCode =
- lirCode.rewriteWithSimpleLens(method, appView, rewriterUtils);
+ LirCode<Integer> rewrittenLirCode = lirCode.rewriteWithLens(method, appView, rewriterUtils);
if (ObjectUtils.notIdentical(lirCode, rewrittenLirCode)) {
method.setCode(rewrittenLirCode, appView);
}
IRCode irCode = method.buildIR(appView, MethodConversionOptions.forPostLirPhase(appView));
+ assert irCode.verifyInvokeInterface(appView);
+ ConstResourceNumberRemover constResourceNumberRemover = new ConstResourceNumberRemover(appView);
+ constResourceNumberRemover.run(irCode, onThreadTiming);
FilledNewArrayRewriter filledNewArrayRewriter = new FilledNewArrayRewriter(appView);
boolean changed = filledNewArrayRewriter.run(irCode, onThreadTiming).hasChanged().toBoolean();
if (appView.options().isGeneratingDex() && changed) {
@@ -275,6 +210,7 @@
for (DexEncodedMethod method : clazz.methods(DexEncodedMethod::hasCode)) {
assert method.getCode().isLirCode()
|| method.getCode().isSharedCodeObject()
+ || method.getCode() instanceof IncompleteVerticalClassMergerBridgeCode
|| appView.isCfByteCodePassThrough(method)
|| appView.options().skipIR;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
index 8f4c441..c2fb0e6 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
@@ -23,8 +23,6 @@
public interface MethodOptimizationFeedback {
- void markForceInline(DexEncodedMethod method);
-
void markInlinedIntoSingleCallSite(DexEncodedMethod method);
void markMethodCannotBeKept(DexEncodedMethod method);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
index f782127..436969d 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/PrimaryR8IRConverter.java
@@ -118,7 +118,7 @@
// All the code has been processed so the rewriting required by the lenses is done everywhere,
// we clear lens code rewriting so that the lens rewriter can be re-executed in phase 2 if new
// lenses with code rewriting are added.
- appView.clearCodeRewritings(executorService);
+ appView.clearCodeRewritings(executorService, Timing.empty());
// Commit synthetics from the primary optimization pass.
commitPendingSyntheticItems(appView);
@@ -203,7 +203,7 @@
// All the code that should be impacted by the lenses inserted between phase 1 and phase 2
// have now been processed and rewritten, we clear code lens rewriting so that the class
// staticizer and phase 3 does not perform again the rewriting.
- appView.clearCodeRewritings(executorService);
+ appView.clearCodeRewritings(executorService, Timing.empty());
// Commit synthetics before creating a builder (otherwise the builder will not include the
// synthetics.)
@@ -263,17 +263,12 @@
onWaveDoneActions.forEach(com.android.tools.r8.utils.Action::execute);
onWaveDoneActions = null;
}
- if (prunedItemsBuilder.hasFullyInlinedMethods() || prunedItemsBuilder.hasRemovedMethods()) {
- appView.pruneItems(
- prunedItemsBuilder.setPrunedApp(appView.app()).build(), executorService, timing);
- prunedItemsBuilder.clearFullyInlinedMethods();
- prunedItemsBuilder.clearRemovedMethods();
- }
}
private void lastWaveDone(
PostMethodProcessor.Builder postMethodProcessorBuilder, ExecutorService executorService)
throws ExecutionException {
+ pruneItems(executorService);
if (assertionErrorTwoArgsConstructorRewriter != null) {
assertionErrorTwoArgsConstructorRewriter.onLastWaveDone(postMethodProcessorBuilder);
assertionErrorTwoArgsConstructorRewriter = null;
@@ -289,4 +284,13 @@
// Ensure determinism of method-to-reprocess set.
appView.testing().checkDeterminism(postMethodProcessorBuilder::dump);
}
+
+ public void pruneItems(ExecutorService executorService) throws ExecutionException {
+ if (prunedItemsBuilder.hasFullyInlinedMethods() || prunedItemsBuilder.hasRemovedMethods()) {
+ appView.pruneItems(
+ prunedItemsBuilder.setPrunedApp(appView.app()).build(), executorService, timing);
+ prunedItemsBuilder.clearFullyInlinedMethods();
+ prunedItemsBuilder.clearRemovedMethods();
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java b/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java
index 925f84c..edd3db2 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/TypeConstraintResolver.java
@@ -144,16 +144,15 @@
ArrayList<Value> stillImprecise = constrainValues(true, remainingImpreciseValues);
if (!stillImprecise.isEmpty()) {
throw appView
- .options()
- .reporter
+ .reporter()
.fatalError(
new StringDiagnostic(
"Cannot determine precise type for value: "
+ stillImprecise.get(0)
+ ", its imprecise type is: "
+ stillImprecise.get(0).getType(),
- code.origin,
- new MethodPosition(code.method().getReference().asMethodReference())));
+ code.context().getOrigin(),
+ new MethodPosition(code.context().getMethodReference())));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/passes/ConstResourceNumberRemover.java b/src/main/java/com/android/tools/r8/ir/conversion/passes/ConstResourceNumberRemover.java
new file mode 100644
index 0000000..ca379dd
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/passes/ConstResourceNumberRemover.java
@@ -0,0 +1,48 @@
+// Copyright (c) 2024, 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.ir.conversion.passes;
+
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.ir.code.ConstNumber;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.ResourceConstNumber;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.conversion.passes.result.CodeRewriterResult;
+
+public class ConstResourceNumberRemover extends CodeRewriterPass<AppInfo> {
+
+ public ConstResourceNumberRemover(AppView<?> appView) {
+ super(appView);
+ }
+
+ @Override
+ protected String getRewriterId() {
+ return "ConstResourceNumberRemover";
+ }
+
+ @Override
+ protected boolean shouldRewriteCode(IRCode code, MethodProcessor methodProcessor) {
+ return code.metadata().mayHaveResourceConstNumber();
+ }
+
+ @Override
+ protected CodeRewriterResult rewriteCode(IRCode code) {
+ boolean hasChanged = false;
+ InstructionListIterator iterator = code.instructionListIterator();
+ while (iterator.hasNext()) {
+ Instruction current = iterator.next();
+ if (current.isResourceConstNumber()) {
+ ResourceConstNumber resourceConstNumber = current.asResourceConstNumber();
+ iterator.replaceCurrentInstruction(
+ new ConstNumber(resourceConstNumber.dest(), resourceConstNumber.getValue()));
+ hasChanged = true;
+ }
+ }
+ return CodeRewriterResult.hasChanged(hasChanged);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/passes/ConstResourceNumberRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/passes/ConstResourceNumberRewriter.java
new file mode 100644
index 0000000..e6806fc
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/passes/ConstResourceNumberRewriter.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2024, 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.ir.conversion.passes;
+
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.ir.code.ConstNumber;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.ResourceConstNumber;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.conversion.passes.result.CodeRewriterResult;
+import com.android.tools.r8.utils.DescriptorUtils;
+
+public class ConstResourceNumberRewriter extends CodeRewriterPass<AppInfo> {
+ public ConstResourceNumberRewriter(AppView<?> appView) {
+ super(appView);
+ }
+
+ @Override
+ protected String getRewriterId() {
+ return "ConstResourceNumberRewriter";
+ }
+
+ @Override
+ protected boolean shouldRewriteCode(IRCode code, MethodProcessor methodProcessor) {
+ return appView.options().isOptimizedResourceShrinking()
+ && code.context().getDefinition().isClassInitializer()
+ && isRClass(code.context().getHolder());
+ }
+
+ private boolean isRClass(DexProgramClass holder) {
+ return DescriptorUtils.isRClassDescriptor(holder.getType().toDescriptorString());
+ }
+
+ @Override
+ protected CodeRewriterResult rewriteCode(IRCode code) {
+ boolean hasChanged = false;
+ InstructionListIterator iterator = code.instructionListIterator();
+ while (iterator.hasNext()) {
+ Instruction current = iterator.next();
+ if (current.isConstNumber()) {
+ ConstNumber constNumber = current.asConstNumber();
+ // The resource const numbers should always have a single value here
+ Value currentValue = current.outValue();
+ if (currentValue.hasSingleUniqueUser() && !currentValue.hasPhiUsers()) {
+ Instruction singleUser = currentValue.singleUniqueUser();
+ if (singleUser.isStaticPut()
+ || singleUser.isNewArrayFilled()
+ || (singleUser.isArrayPut() && singleUser.asArrayPut().value() == currentValue)) {
+ iterator.replaceCurrentInstruction(
+ new ResourceConstNumber(constNumber.dest(), constNumber.getIntValue()));
+ hasChanged = true;
+ }
+ }
+ }
+ }
+ return CodeRewriterResult.hasChanged(hasChanged);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/passes/DexConstantOptimizer.java b/src/main/java/com/android/tools/r8/ir/conversion/passes/DexConstantOptimizer.java
index 9584e8a..a213f7f 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/passes/DexConstantOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/passes/DexConstantOptimizer.java
@@ -9,6 +9,7 @@
import static com.android.tools.r8.ir.code.Opcodes.CONST_STRING;
import static com.android.tools.r8.ir.code.Opcodes.DEX_ITEM_BASED_CONST_STRING;
import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_GET;
+import static com.android.tools.r8.ir.code.Opcodes.RESOURCE_CONST_NUMBER;
import static com.android.tools.r8.ir.code.Opcodes.STATIC_GET;
import com.android.tools.r8.errors.Unreachable;
@@ -29,6 +30,7 @@
import com.android.tools.r8.ir.code.InstructionOrPhi;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.ResourceConstNumber;
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.MethodProcessor;
@@ -466,6 +468,9 @@
case CONST_NUMBER:
copy = ConstNumber.copyOf(code, instruction.asConstNumber());
break;
+ case RESOURCE_CONST_NUMBER:
+ copy = ResourceConstNumber.copyOf(code, instruction.asResourceConstNumber());
+ break;
case CONST_STRING:
copy = ConstString.copyOf(code, instruction.asConstString());
break;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordFieldValuesRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordFieldValuesRewriter.java
index 40b217e..71e0780 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordFieldValuesRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordFieldValuesRewriter.java
@@ -69,7 +69,6 @@
.buildIR(
programMethod,
appView,
- programMethod.getOrigin(),
MethodConversionOptions.forLirPhase(appView));
boolean done = false;
ListIterator<BasicBlock> blockIterator = irCode.listIterator();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
index 6880ed1..f10854f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
@@ -440,7 +440,7 @@
isWrittenBefore.remove(fieldReference);
}
continue;
- } else if (fieldReference.type.isPrimitiveType()
+ } else if ((fieldReference.type.isPrimitiveType() && !hasPutOfConstResource(put))
|| fieldReference.type == dexItemFactory.stringType) {
finalFieldPuts.put(field, put);
unnecessaryStaticPuts.add(put);
@@ -507,6 +507,10 @@
return validateFinalFieldPuts(finalFieldPuts, isWrittenBefore);
}
+ private boolean hasPutOfConstResource(StaticPut put) {
+ return put.value().isConstResourceNumber();
+ }
+
private Map<DexEncodedField, StaticPut> validateFinalFieldPuts(
Map<DexEncodedField, StaticPut> finalFieldPuts,
Map<DexField, Set<StaticPut>> isWrittenBefore) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java
index 1ef539a..c1f203a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ConstantCanonicalizer.java
@@ -8,6 +8,7 @@
import static com.android.tools.r8.ir.code.Opcodes.CONST_STRING;
import static com.android.tools.r8.ir.code.Opcodes.DEX_ITEM_BASED_CONST_STRING;
import static com.android.tools.r8.ir.code.Opcodes.INSTANCE_GET;
+import static com.android.tools.r8.ir.code.Opcodes.RESOURCE_CONST_NUMBER;
import static com.android.tools.r8.ir.code.Opcodes.STATIC_GET;
import static com.android.tools.r8.utils.MapUtils.ignoreKey;
@@ -39,6 +40,7 @@
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.ResourceConstNumber;
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.passes.BranchSimplifier;
@@ -164,6 +166,8 @@
case CONST_NUMBER:
return Long.hashCode(candidate.asConstNumber().getRawValue())
+ 13 * candidate.outType().hashCode();
+ case RESOURCE_CONST_NUMBER:
+ return Integer.hashCode(candidate.asResourceConstNumber().getValue());
case CONST_STRING:
return candidate.asConstString().getValue().hashCode();
case DEX_ITEM_BASED_CONST_STRING:
@@ -349,6 +353,7 @@
switch (newInstruction.opcode()) {
case CONST_CLASS:
case CONST_NUMBER:
+ case RESOURCE_CONST_NUMBER:
case CONST_STRING:
case DEX_ITEM_BASED_CONST_STRING:
case STATIC_GET:
@@ -388,6 +393,8 @@
return ConstClass.copyOf(code, canonicalizedConstant.asConstClass());
case CONST_NUMBER:
return ConstNumber.copyOf(code, canonicalizedConstant.asConstNumber());
+ case RESOURCE_CONST_NUMBER:
+ return ResourceConstNumber.copyOf(code, canonicalizedConstant.asResourceConstNumber());
case CONST_STRING:
return ConstString.copyOf(code, canonicalizedConstant.asConstString());
case DEX_ITEM_BASED_CONST_STRING:
@@ -434,6 +441,7 @@
return false;
}
break;
+ case RESOURCE_CONST_NUMBER:
case CONST_NUMBER:
break;
case CONST_STRING:
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index 734004b..c6bd2a2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -134,6 +134,7 @@
@Override
public boolean passesInliningConstraints(
+ IRCode code,
SingleResolutionResult<?> resolutionResult,
ProgramMethod singleTarget,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
@@ -158,7 +159,7 @@
return false;
}
- if (canHaveIssuesWithMonitors(singleTarget, method)) {
+ if (canHaveIssuesWithMonitors(code, singleTarget)) {
return false;
}
@@ -198,16 +199,20 @@
return true;
}
- private boolean canHaveIssuesWithMonitors(ProgramMethod singleTarget, ProgramMethod context) {
- if (options.canHaveIssueWithInlinedMonitors() && hasMonitorsOrIsSynchronized(singleTarget)) {
- return context.getOptimizationInfo().forceInline() || hasMonitorsOrIsSynchronized(context);
- }
- return false;
+ private boolean canHaveIssuesWithMonitors(IRCode code, ProgramMethod singleTarget) {
+ return options.canHaveIssueWithInlinedMonitors()
+ && hasMonitorsOrIsSynchronized(code)
+ && hasMonitorsOrIsSynchronized(singleTarget);
}
- public static boolean hasMonitorsOrIsSynchronized(ProgramMethod method) {
- return method.getAccessFlags().isSynchronized()
- || method.getDefinition().getCode().hasMonitorInstructions();
+ public static boolean hasMonitorsOrIsSynchronized(IRCode code) {
+ return code.context().getAccessFlags().isSynchronized()
+ || code.metadata().mayHaveMonitorInstruction();
+ }
+
+ public static boolean hasMonitorsOrIsSynchronized(ProgramMethod singleTarget) {
+ return singleTarget.getAccessFlags().isSynchronized()
+ || singleTarget.getDefinition().getCode().hasMonitorInstructions();
}
public boolean satisfiesRequirementsForSimpleInlining(
@@ -438,9 +443,7 @@
}
if (!passesInliningConstraints(
- resolutionResult,
- singleTarget,
- whyAreYouNotInliningReporter)) {
+ code, resolutionResult, singleTarget, whyAreYouNotInliningReporter)) {
return null;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
index 5dc2341..a3fb7e7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ForcedInliningOracle.java
@@ -44,6 +44,7 @@
@Override
public boolean passesInliningConstraints(
+ IRCode code,
SingleResolutionResult<?> resolutionResult,
ProgramMethod candidate,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index ed9da5c..2a1fc09 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -22,7 +22,6 @@
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.NestMemberClassAttribute;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.ir.analysis.ClassInitializationAnalysis;
import com.android.tools.r8.ir.analysis.proto.ProtoInliningReasonStrategy;
import com.android.tools.r8.ir.analysis.type.Nullability;
@@ -151,8 +150,7 @@
}
ConstraintWithTarget result = ConstraintWithTarget.ALWAYS;
- InliningConstraints inliningConstraints =
- new InliningConstraints(appView, GraphLens.getIdentityLens());
+ InliningConstraints inliningConstraints = new InliningConstraints(appView);
for (Instruction instruction : code.instructions()) {
ConstraintWithTarget state =
instructionAllowedForInlining(instruction, inliningConstraints, context);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
index a3ea046..8f61ce7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.graph.FieldResolutionResult.SingleFieldResolutionResult;
import com.android.tools.r8.graph.MethodResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.lens.GraphLens;
import com.android.tools.r8.ir.code.InvokeType;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
@@ -28,31 +27,14 @@
private AppView<AppInfoWithLiveness> appView;
- // Currently used only by the vertical class merger (in all other cases this is the identity).
- //
- // When merging a type A into its subtype B we need to inline A.<init>() into B.<init>().
- // Therefore, we need to be sure that A.<init>() can in fact be inlined into B.<init>() *before*
- // we merge the two classes. However, at this point, we may reject the method A.<init>() from
- // being inlined into B.<init>() only because it is not declared in the same class as B (which
- // it would be after merging A and B).
- //
- // To circumvent this problem, the vertical class merger creates a graph lens that maps the
- // type A to B, to create a temporary view of what the world would look like after class merging.
- private GraphLens graphLens;
-
- public InliningConstraints(AppView<AppInfoWithLiveness> appView, GraphLens graphLens) {
+ public InliningConstraints(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
- this.graphLens = graphLens; // Note: Intentionally *not* appView.graphLens().
}
public AppView<AppInfoWithLiveness> getAppView() {
return appView;
}
- public GraphLens getGraphLens() {
- return graphLens;
- }
-
public ConstraintWithTarget forAlwaysMaterializingUser() {
return ConstraintWithTarget.ALWAYS;
}
@@ -156,13 +138,11 @@
}
public ConstraintWithTarget forInvokeDirect(DexMethod method, ProgramMethod context) {
- DexMethod lookup =
- graphLens.lookupMethod(method, context.getReference(), InvokeType.DIRECT).getReference();
- if (lookup.holder.isArrayType()) {
+ if (method.holder.isArrayType()) {
return ConstraintWithTarget.ALWAYS;
}
SingleResolutionResult<?> resolutionResult =
- appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(lookup).asSingleResolution();
+ appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(method).asSingleResolution();
if (resolutionResult == null) {
return ConstraintWithTarget.NEVER;
}
@@ -175,9 +155,7 @@
}
public ConstraintWithTarget forInvokeInterface(DexMethod method, ProgramMethod context) {
- DexMethod lookup =
- graphLens.lookupMethod(method, context.getReference(), InvokeType.INTERFACE).getReference();
- return forVirtualInvoke(lookup, context, true);
+ return forVirtualInvoke(method, context, true);
}
public ConstraintWithTarget forInvokeMultiNewArray(DexType type, ProgramMethod context) {
@@ -193,13 +171,11 @@
}
public ConstraintWithTarget forInvokeStatic(DexMethod method, ProgramMethod context) {
- DexMethod lookup =
- graphLens.lookupMethod(method, context.getReference(), InvokeType.STATIC).getReference();
- if (lookup.holder.isArrayType()) {
+ if (method.holder.isArrayType()) {
return ConstraintWithTarget.ALWAYS;
}
SingleResolutionResult<?> resolutionResult =
- appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(lookup).asSingleResolution();
+ appView.appInfo().unsafeResolveMethodDueToDexFormatLegacy(method).asSingleResolution();
if (resolutionResult == null) {
return ConstraintWithTarget.NEVER;
}
@@ -208,9 +184,6 @@
if (target == null) {
return ConstraintWithTarget.NEVER;
}
- if (target != null) {
- return forResolvedMember(resolutionResult.getInitialResolutionHolder(), context, target);
- }
return forResolvedMember(resolutionResult.getInitialResolutionHolder(), context, target);
}
@@ -220,9 +193,7 @@
}
public ConstraintWithTarget forInvokeVirtual(DexMethod method, ProgramMethod context) {
- DexMethod lookup =
- graphLens.lookupMethod(method, context.getReference(), InvokeType.VIRTUAL).getReference();
- return forVirtualInvoke(lookup, context, false);
+ return forVirtualInvoke(method, context, false);
}
public ConstraintWithTarget forJumpInstruction() {
@@ -310,9 +281,8 @@
}
private ConstraintWithTarget forFieldInstruction(DexField field, ProgramMethod context) {
- DexField lookup = graphLens.lookupField(field);
SingleFieldResolutionResult<?> fieldResolutionResult =
- appView.appInfo().resolveField(lookup).asSingleFieldResolutionResult();
+ appView.appInfo().resolveField(field).asSingleFieldResolutionResult();
if (fieldResolutionResult == null) {
return ConstraintWithTarget.NEVER;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
index 69d5ecf..a684ab7 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
@@ -77,6 +77,7 @@
void markInlined(IRCode inlinee);
boolean passesInliningConstraints(
+ IRCode code,
SingleResolutionResult<?> resolutionResult,
ProgramMethod candidate,
WhyAreYouNotInliningReporter whyAreYouNotInliningReporter);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
index ee03422..d9acaba 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadAndStoreElimination.java
@@ -442,6 +442,7 @@
|| instruction.isConstMethodHandle()
|| instruction.isConstMethodType()
|| instruction.isConstNumber()
+ || instruction.isResourceConstNumber()
|| instruction.isConstString()
|| instruction.isDebugInstruction()
|| instruction.isDexItemBasedConstString()
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
index e39ebf6..9e7e988 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
@@ -26,7 +26,6 @@
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.conversion.PostMethodProcessor;
import com.android.tools.r8.ir.desugar.ServiceLoaderSourceCode;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.ListUtils;
@@ -114,7 +113,7 @@
// Check that the first argument is a const class.
Value argument = serviceLoaderLoad.inValues().get(0).getAliasedValue();
if (argument.isPhi() || !argument.definition.isConstClass()) {
- report(code.origin, null, "The service loader type could not be determined");
+ report(code.context(), null, "The service loader type could not be determined");
continue;
}
@@ -122,7 +121,7 @@
if (invokedMethod != serviceLoaderMethods.loadWithClassLoader) {
report(
- code.origin,
+ code.context(),
constClass.getType(),
"Inlining is only support for `java.util.ServiceLoader.load(java.lang.Class,"
+ " java.lang.ClassLoader)`");
@@ -134,7 +133,7 @@
+ " java.lang.ServiceLoader.iterator()`";
Value serviceLoaderLoadOut = serviceLoaderLoad.outValue();
if (serviceLoaderLoadOut.numberOfAllUsers() != 1 || serviceLoaderLoadOut.hasPhiUsers()) {
- report(code.origin, constClass.getType(), invalidUserMessage);
+ report(code.context(), constClass.getType(), invalidUserMessage);
continue;
}
@@ -142,13 +141,14 @@
if (!serviceLoaderLoadOut.singleUniqueUser().isInvokeVirtual()
|| serviceLoaderLoadOut.singleUniqueUser().asInvokeVirtual().getInvokedMethod()
!= serviceLoaderMethods.iterator) {
- report(code.origin, constClass.getType(), invalidUserMessage + ", but found other usages");
+ report(
+ code.context(), constClass.getType(), invalidUserMessage + ", but found other usages");
continue;
}
// Check that the service is not kept.
if (appView.appInfo().isPinnedWithDefinitionLookup(constClass.getValue())) {
- report(code.origin, constClass.getType(), "The service loader type is kept");
+ report(code.context(), constClass.getType(), "The service loader type is kept");
continue;
}
@@ -162,7 +162,7 @@
// Check that we are not service loading anything from a feature into base.
if (appServices.hasServiceImplementationsInFeature(appView, constClass.getValue())) {
report(
- code.origin,
+ code.context(),
constClass.getType(),
"The service loader type has implementations in a feature split");
continue;
@@ -172,7 +172,7 @@
// that we are instantiating or NULL.
if (serviceLoaderLoad.inValues().get(1).isPhi()) {
report(
- code.origin,
+ code.context(),
constClass.getType(),
"The java.lang.ClassLoader argument must be defined locally as null or "
+ constClass.getType()
@@ -195,7 +195,7 @@
== constClass.getValue());
if (!isGetClassLoaderOnConstClassOrNull) {
report(
- code.origin,
+ code.context(),
constClass.getType(),
"The java.lang.ClassLoader argument must be defined locally as null or "
+ constClass.getType()
@@ -210,7 +210,7 @@
DexClass serviceImplementation = appView.definitionFor(serviceImpl);
if (serviceImplementation == null) {
report(
- code.origin,
+ code.context(),
constClass.getType(),
"Unable to find definition for service implementation " + serviceImpl.getTypeName());
seenNull = true;
@@ -247,11 +247,11 @@
postMethodProcessorBuilder.addAll(synthesizedServiceLoadMethods, appView.graphLens());
}
- private void report(Origin origin, DexType serviceLoaderType, String message) {
+ private void report(ProgramMethod method, DexType serviceLoaderType, String message) {
if (reporter != null) {
reporter.info(
new ServiceLoaderRewriterDiagnostic(
- origin,
+ method.getOrigin(),
"Could not inline ServiceLoader.load"
+ (serviceLoaderType == null
? ""
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index b192f8a..a359197 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -153,12 +153,7 @@
while (rootsIterator.hasNext()) {
Instruction root = rootsIterator.next();
InlineCandidateProcessor processor =
- new InlineCandidateProcessor(
- appView,
- inliner,
- methodProcessor,
- method,
- root);
+ new InlineCandidateProcessor(appView, code, inliner, methodProcessor, method, root);
// Assess eligibility of instance and class.
EligibilityStatus status = processor.isInstanceEligible();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 256abbb..46d4883 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -90,6 +90,7 @@
AssumeAndCheckCastAliasedValueConfiguration.getInstance();
private final AppView<AppInfoWithLiveness> appView;
+ private final IRCode code;
private final DexItemFactory dexItemFactory;
private final Inliner inliner;
private final MethodProcessor methodProcessor;
@@ -113,11 +114,13 @@
InlineCandidateProcessor(
AppView<AppInfoWithLiveness> appView,
+ IRCode code,
Inliner inliner,
MethodProcessor methodProcessor,
ProgramMethod method,
Instruction root) {
this.appView = appView;
+ this.code = code;
this.dexItemFactory = appView.dexItemFactory();
this.inliner = inliner;
this.method = method;
@@ -1167,9 +1170,7 @@
// Check if the method is inline-able by standard inliner.
InliningOracle oracle = defaultOracle.computeIfAbsent();
if (!oracle.passesInliningConstraints(
- resolutionResult,
- singleTarget,
- NopWhyAreYouNotInliningReporter.getInstance())) {
+ code, resolutionResult, singleTarget, NopWhyAreYouNotInliningReporter.getInstance())) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
index b17f4b6..5c37f51 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/code/CheckNotZeroCode.java
@@ -22,7 +22,6 @@
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.IteratorUtils;
import com.android.tools.r8.utils.RetracerForCodePrinting;
@@ -48,7 +47,6 @@
public IRCode buildIR(
ProgramMethod checkNotZeroMethod,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
// Build IR from the checkNotNull() method.
Position callerPosition =
@@ -69,7 +67,6 @@
appView.graphLens(),
valueNumberGenerator,
callerPosition,
- checkNotZeroMethod.getOrigin(),
appView
.graphLens()
.lookupPrototypeChangesForMethodDefinition(checkNotNullMethod.getReference()));
@@ -112,7 +109,6 @@
code.valueNumberGenerator,
code.basicBlockNumberGenerator,
code.metadata(),
- checkNotZeroMethod.getOrigin(),
conversionOptions);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index f4de742..8add480 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -162,11 +162,6 @@
// METHOD OPTIMIZATION INFO:
@Override
- public void markForceInline(DexEncodedMethod method) {
- getMethodOptimizationInfoForUpdating(method).markForceInline();
- }
-
- @Override
public synchronized void markInlinedIntoSingleCallSite(DexEncodedMethod method) {
getMethodOptimizationInfoForUpdating(method).markInlinedIntoSingleCallSite();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
index 05a1cdc..bb8f841 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
@@ -55,9 +55,6 @@
// METHOD OPTIMIZATION INFO:
@Override
- public void markForceInline(DexEncodedMethod method) {}
-
- @Override
public void markInlinedIntoSingleCallSite(DexEncodedMethod method) {}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
index 339d9eb..34bb23b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -83,11 +83,6 @@
}
@Override
- public void markForceInline(DexEncodedMethod method) {
- // Ignored.
- }
-
- @Override
public void markInlinedIntoSingleCallSite(DexEncodedMethod method) {
method.getMutableOptimizationInfo().markInlinedIntoSingleCallSite();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningIRProvider.java b/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningIRProvider.java
index c62a014..e63c416 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningIRProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/inliner/InliningIRProvider.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.LensCodeRewriter;
import com.android.tools.r8.ir.conversion.MethodProcessor;
-import com.android.tools.r8.origin.Origin;
import java.util.IdentityHashMap;
import java.util.Map;
@@ -82,14 +81,12 @@
if (cached != null) {
return cached;
}
- Origin origin = method.getOrigin();
IRCode code =
method.buildInliningIR(
context,
appView,
valueNumberGenerator,
Position.getPositionForInlining(invoke, context),
- origin,
methodProcessor);
if (lensCodeRewriter != null && methodProcessor.shouldApplyCodeRewritings(method)) {
lensCodeRewriter.rewrite(code, method, methodProcessor);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ResourcesMemberOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ResourcesMemberOptimizer.java
index 1246516..207d757 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ResourcesMemberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ResourcesMemberOptimizer.java
@@ -8,13 +8,10 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.FieldResolutionResult;
-import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.TopDownClassHierarchyTraversal;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.BasicBlockIterator;
@@ -127,19 +124,16 @@
assert invokedMethod.isIdenticalTo(dexItemFactory.androidResourcesGetStringMethod);
assert invoke.inValues().size() == 2;
Instruction valueDefinition = invoke.getLastArgument().definition;
- if (valueDefinition != null && valueDefinition.isStaticGet()) {
- DexField field = valueDefinition.asStaticGet().getField();
- FieldResolutionResult fieldResolutionResult =
- appView.appInfo().resolveField(field, code.context());
- ProgramField resolvedField = fieldResolutionResult.getProgramField();
- if (resolvedField != null) {
- String singleStringValueForField =
- appView.getResourceAnalysisResult().getSingleStringValueForField(resolvedField);
- if (singleStringValueForField != null) {
- DexString value = dexItemFactory.createString(singleStringValueForField);
- instructionIterator.replaceCurrentInstructionWithConstString(
- appView, code, value, affectedValues);
- }
+ if (valueDefinition.isResourceConstNumber()) {
+ String singleStringValue =
+ appView
+ .getResourceShrinkerState()
+ .getR8ResourceShrinkerModel()
+ .getSingleStringValueOrNull(valueDefinition.asResourceConstNumber().getValue());
+ if (singleStringValue != null) {
+ DexString value = dexItemFactory.createString(singleStringValue);
+ instructionIterator.replaceCurrentInstructionWithConstString(
+ appView, code, value, affectedValues);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
index 9297330..20f7598 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/outliner/OutlinerImpl.java
@@ -71,7 +71,6 @@
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
@@ -1360,7 +1359,7 @@
public OutlinerImpl(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
this.dexItemFactory = appView.dexItemFactory();
- this.inliningConstraints = new InliningConstraints(appView, GraphLens.getIdentityLens());
+ this.inliningConstraints = new InliningConstraints(appView);
}
@Override
@@ -1855,10 +1854,9 @@
public IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
OutlineSourceCode source = new OutlineSourceCode(outline, method.getReference());
- return IRBuilder.create(method, appView, source, origin).build(method, conversionOptions);
+ return IRBuilder.create(method, appView, source).build(method, conversionOptions);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
index a6b6c18..7c5240b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
@@ -140,8 +140,7 @@
method.getHolderType(), abstractParentReturnValue.isTrue()),
appView);
// Rebuild inlining constraints.
- IRCode code =
- parentMethodDefinition.getCode().buildIR(parentMethod, appView, parentMethod.getOrigin());
+ IRCode code = parentMethodDefinition.getCode().buildIR(parentMethod, appView);
converter.markProcessed(code, feedback);
// Fixup method optimization info (the method no longer returns a constant).
feedback.fixupUnusedArguments(parentMethod, unusedArguments -> unusedArguments.clear(0));
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 9307108..2acd209 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -621,9 +621,9 @@
if (intervals == null) {
throw new CompilationError(
"Unexpected attempt to get register for a value without a register in method `"
- + code.method().getReference().toSourceString()
+ + code.context().toSourceString()
+ "`.",
- code.origin);
+ code.context().getOrigin());
}
if (intervals.hasSplits()) {
intervals = intervals.getSplitCovering(instructionNumber);
diff --git a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
index 1bd59ff..d7ee8d3 100644
--- a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
+++ b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
@@ -83,6 +83,7 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.RecordFieldValues;
import com.android.tools.r8.ir.code.Rem;
+import com.android.tools.r8.ir.code.ResourceConstNumber;
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.SafeCheckCast;
import com.android.tools.r8.ir.code.Shl;
@@ -352,7 +353,6 @@
strategy.getValueNumberGenerator(),
basicBlockNumberGenerator,
code.getMetadataForIR(),
- method.getOrigin(),
conversionOptions);
}
@@ -519,6 +519,12 @@
}
@Override
+ public void onConstResourceNumber(int value) {
+ Value dest = getOutValueForNextInstruction(TypeElement.getInt());
+ addInstruction(new ResourceConstNumber(dest, value));
+ }
+
+ @Override
public void onAdd(NumericType type, EV leftValueIndex, EV rightValueIndex) {
Value dest = getOutValueForNextInstruction(valueTypeElement(type));
addInstruction(
diff --git a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
index 5d988d8..c243c7b 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
@@ -579,6 +579,13 @@
}
}
+ public LirBuilder<V, EV> addResourceConstNumber(int value) {
+ advanceInstructionState();
+ writer.writeInstruction(LirOpcodes.RESOURCENUMBER, ByteUtils.intEncodingSize(value));
+ ByteUtils.writeEncodedInt(value, writer::writeOperand);
+ return this;
+ }
+
public LirBuilder<V, EV> addConstString(DexString string) {
return addOneItemInstruction(LirOpcodes.LDC, string);
}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirCode.java b/src/main/java/com/android/tools/r8/lightir/LirCode.java
index 29c7ca6..a571e49 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirCode.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirCode.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.dex.code.CfOrDexInstruction;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ArgumentUse;
import com.android.tools.r8.graph.ClasspathMethod;
@@ -33,11 +34,11 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
import com.android.tools.r8.lightir.LirConstant.LirConstantStructuralAcceptor;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.ComparatorUtils;
import com.android.tools.r8.utils.FastMapUtils;
import com.android.tools.r8.utils.IntBox;
+import com.android.tools.r8.utils.IntObjPredicate;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.RetracerForCodePrinting;
import com.android.tools.r8.utils.structural.CompareToVisitor;
@@ -47,6 +48,7 @@
import com.android.tools.r8.utils.structural.StructuralMapping;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
import java.util.ArrayList;
@@ -183,6 +185,12 @@
this.tryCatchHandlers = new Int2ReferenceOpenHashMap<>(tryCatchHandlers);
}
+ public boolean hasHandlerThatMatches(IntObjPredicate<CatchHandlers<Integer>> predicate) {
+ return Iterables.any(
+ tryCatchHandlers.int2ReferenceEntrySet(),
+ entry -> predicate.test(entry.getIntKey(), entry.getValue()));
+ }
+
public CatchHandlers<Integer> getHandlersForBlock(int blockIndex) {
return tryCatchHandlers.get(blockIndex);
}
@@ -490,6 +498,10 @@
return positionTable;
}
+ public boolean hasTryCatchTable() {
+ return tryCatchTable != null;
+ }
+
public TryCatchTable getTryCatchTable() {
return tryCatchTable;
}
@@ -532,7 +544,6 @@
public IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
RewrittenPrototypeDescription protoChanges =
appView.graphLens().lookupPrototypeChangesForMethodDefinition(method.getReference());
@@ -548,7 +559,6 @@
GraphLens codeLens,
NumberGenerator valueNumberGenerator,
Position callerPosition,
- Origin origin,
RewrittenPrototypeDescription protoChanges) {
assert valueNumberGenerator != null;
assert callerPosition != null;
@@ -802,17 +812,18 @@
metadataMap);
}
- public LirCode<EV> rewriteWithSimpleLens(
- ProgramMethod context, AppView<?> appView, LensCodeRewriterUtils rewriterUtils) {
+ public LirCode<EV> rewriteWithLens(
+ ProgramMethod context,
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ LensCodeRewriterUtils rewriterUtils) {
GraphLens graphLens = appView.graphLens();
assert graphLens.isNonIdentityLens();
if (graphLens.isMemberRebindingIdentityLens()) {
return this;
}
- GraphLens codeLens = context.getDefinition().getCode().getCodeLens(appView);
- SimpleLensLirRewriter<EV> rewriter =
- new SimpleLensLirRewriter<>(this, context, graphLens, codeLens, rewriterUtils);
+ LirLensCodeRewriter<EV> rewriter =
+ new LirLensCodeRewriter<>(appView, this, context, rewriterUtils);
return rewriter.rewrite();
}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java b/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java
new file mode 100644
index 0000000..b4a6cb7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/LirLensCodeRewriter.java
@@ -0,0 +1,481 @@
+// Copyright (c) 2024, 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.lightir;
+
+import static com.android.tools.r8.graph.UseRegistry.MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexMethodHandle;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.bytecodemetadata.BytecodeMetadataProvider;
+import com.android.tools.r8.graph.lens.FieldLookupResult;
+import com.android.tools.r8.graph.lens.GraphLens;
+import com.android.tools.r8.graph.lens.MethodLookupResult;
+import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.IRMetadata;
+import com.android.tools.r8.ir.code.IROpcodeUtils;
+import com.android.tools.r8.ir.code.InvokeType;
+import com.android.tools.r8.ir.conversion.IRToLirFinalizer;
+import com.android.tools.r8.ir.conversion.LensCodeRewriter;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.ir.conversion.MethodConversionOptions;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.optimize.AffectedValues;
+import com.android.tools.r8.ir.optimize.DeadCodeRemover;
+import com.android.tools.r8.lightir.LirBuilder.RecordFieldValuesPayload;
+import com.android.tools.r8.lightir.LirCode.TryCatchTable;
+import com.android.tools.r8.utils.ArrayUtils;
+import com.android.tools.r8.utils.Timing;
+import com.android.tools.r8.verticalclassmerging.VerticalClassMergerGraphLens;
+import it.unimi.dsi.fastutil.objects.Reference2IntMap;
+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+
+public class LirLensCodeRewriter<EV> extends LirParsedInstructionCallback<EV> {
+
+ private final AppView<? extends AppInfoWithClassHierarchy> appView;
+ private final ProgramMethod context;
+ private final DexMethod contextReference;
+ private final GraphLens graphLens;
+ private final GraphLens codeLens;
+ private final LensCodeRewriterUtils helper;
+
+ private int numberOfInvokeOpcodeChanges = 0;
+ private Map<LirConstant, LirConstant> constantPoolMapping = null;
+
+ private boolean hasNonTrivialRewritings = false;
+
+ public LirLensCodeRewriter(
+ AppView<? extends AppInfoWithClassHierarchy> appView,
+ LirCode<EV> code,
+ ProgramMethod context,
+ LensCodeRewriterUtils helper) {
+ super(code);
+ this.appView = appView;
+ this.context = context;
+ this.contextReference = context.getReference();
+ this.graphLens = appView.graphLens();
+ this.codeLens = context.getDefinition().getCode().getCodeLens(appView);
+ this.helper = helper;
+ }
+
+ @Override
+ public int getCurrentValueIndex() {
+ // We do not need to interpret values.
+ return -1;
+ }
+
+ public void onTypeReference(DexType type) {
+ addRewrittenMapping(type, graphLens.lookupType(type, codeLens));
+ }
+
+ public void onFieldReference(DexField field) {
+ FieldLookupResult result = graphLens.lookupFieldResult(field, codeLens);
+ assert !result.hasReadCastType();
+ assert !result.hasWriteCastType();
+ addRewrittenMapping(field, result.getReference());
+ }
+
+ public void onCallSiteReference(DexCallSite callSite) {
+ addRewrittenMapping(callSite, helper.rewriteCallSite(callSite, context));
+ }
+
+ public void onMethodHandleReference(DexMethodHandle methodHandle) {
+ addRewrittenMapping(
+ methodHandle,
+ helper.rewriteDexMethodHandle(methodHandle, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, context));
+ }
+
+ public void onProtoReference(DexProto proto) {
+ addRewrittenMapping(proto, helper.rewriteProto(proto));
+ }
+
+ private void onInvoke(DexMethod method, InvokeType type, boolean isInterface) {
+ MethodLookupResult result = graphLens.lookupMethod(method, contextReference, type, codeLens);
+ if (hasPotentialNonTrivialInvokeRewriting(method, type, result)) {
+ hasNonTrivialRewritings = true;
+ return;
+ }
+ int opcode = type.getLirOpcode(isInterface);
+ DexMethod newMethod = result.getReference();
+ InvokeType newType = result.getType();
+ boolean newIsInterface = lookupIsInterface(method, opcode, result);
+ int newOpcode = newType.getLirOpcode(newIsInterface);
+ assert newMethod.getArity() == method.getArity();
+ if (newOpcode != opcode) {
+ assert type == newType
+ || (type.isVirtual() && newType.isInterface())
+ || (type.isInterface() && newType.isVirtual())
+ || (type.isSuper() && newType.isVirtual())
+ : type + " -> " + newType;
+ numberOfInvokeOpcodeChanges++;
+ } else {
+ // All non-type dependent mappings are just rewritten in the content pool.
+ addRewrittenMapping(method, newMethod);
+ }
+ }
+
+ private boolean hasPotentialNonTrivialInvokeRewriting(
+ DexMethod method, InvokeType type, MethodLookupResult result) {
+ VerticalClassMergerGraphLens verticalClassMergerLens = graphLens.asVerticalClassMergerLens();
+ if (verticalClassMergerLens != null) {
+ if (!result.getPrototypeChanges().isEmpty()) {
+ return true;
+ }
+ for (int argumentIndex = 0;
+ argumentIndex < method.getNumberOfArguments(type.isStatic());
+ argumentIndex++) {
+ DexType argumentType = method.getArgumentType(argumentIndex, type.isStatic());
+ if (verticalClassMergerLens.hasInterfaceBeenMergedIntoClass(argumentType)) {
+ return true;
+ }
+ }
+ }
+ assert result.getPrototypeChanges().isEmpty();
+ return false;
+ }
+
+ private void addRewrittenMapping(LirConstant item, LirConstant rewrittenItem) {
+ if (item == rewrittenItem) {
+ return;
+ }
+ if (constantPoolMapping == null) {
+ constantPoolMapping =
+ new IdentityHashMap<>(
+ // Avoid using initial capacity larger than the number of actual constants.
+ Math.min(getCode().getConstantPool().length, 32));
+ }
+ LirConstant old = constantPoolMapping.put(item, rewrittenItem);
+ if (old != null && old != rewrittenItem) {
+ throw new Unreachable(
+ "Unexpected rewriting of item: "
+ + item
+ + " to two distinct items: "
+ + rewrittenItem
+ + " and "
+ + old);
+ }
+ }
+
+ @Override
+ public void onInstancePut(DexField field, EV object, EV value) {
+ onFieldPut(field);
+ }
+
+ @Override
+ public void onStaticPut(DexField field, EV value) {
+ onFieldPut(field);
+ }
+
+ private void onFieldPut(DexField field) {
+ if (hasPotentialNonTrivialFieldPutRewriting(field)) {
+ hasNonTrivialRewritings = true;
+ }
+ }
+
+ private boolean hasPotentialNonTrivialFieldPutRewriting(DexField field) {
+ VerticalClassMergerGraphLens verticalClassMergerLens = graphLens.asVerticalClassMergerLens();
+ if (verticalClassMergerLens != null
+ && verticalClassMergerLens.hasInterfaceBeenMergedIntoClass(field.getType())) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onInvokeDirect(DexMethod method, List<EV> arguments, boolean isInterface) {
+ onInvoke(method, InvokeType.DIRECT, isInterface);
+ }
+
+ @Override
+ public void onInvokeSuper(DexMethod method, List<EV> arguments, boolean isInterface) {
+ onInvoke(method, InvokeType.SUPER, isInterface);
+ }
+
+ @Override
+ public void onInvokeVirtual(DexMethod method, List<EV> arguments) {
+ onInvoke(method, InvokeType.VIRTUAL, false);
+ }
+
+ @Override
+ public void onInvokeStatic(DexMethod method, List<EV> arguments, boolean isInterface) {
+ onInvoke(method, InvokeType.STATIC, isInterface);
+ }
+
+ @Override
+ public void onInvokeInterface(DexMethod method, List<EV> arguments) {
+ onInvoke(method, InvokeType.INTERFACE, true);
+ }
+
+ private InvokeType getInvokeTypeThatMayChange(int opcode) {
+ if (opcode == LirOpcodes.INVOKEVIRTUAL) {
+ return InvokeType.VIRTUAL;
+ }
+ if (opcode == LirOpcodes.INVOKEINTERFACE) {
+ return InvokeType.INTERFACE;
+ }
+ if (graphLens.isVerticalClassMergerLens()) {
+ if (opcode == LirOpcodes.INVOKESTATIC_ITF) {
+ return InvokeType.STATIC;
+ }
+ if (opcode == LirOpcodes.INVOKESUPER) {
+ return InvokeType.SUPER;
+ }
+ }
+ return null;
+ }
+
+ public LirCode<EV> rewrite() {
+ if (hasNonTrivialMethodChanges()) {
+ return rewriteWithLensCodeRewriter();
+ }
+ assert !hasNonTrivialRewritings;
+ LirCode<EV> rewritten = rewriteConstantPoolAndScanForTypeChanges(getCode());
+ if (hasNonTrivialRewritings) {
+ return rewriteWithLensCodeRewriter();
+ }
+ rewritten = rewriteInstructionsWithInvokeTypeChanges(rewritten);
+ rewritten = rewriteTryCatchTable(rewritten);
+ // In the unusual case where a catch handler has been eliminated as a result of class merging
+ // we remove the unreachable blocks.
+ if (hasPrunedCatchHandlers(rewritten)) {
+ rewritten = removeUnreachableBlocks(rewritten);
+ }
+ return rewritten;
+ }
+
+ private boolean hasNonTrivialMethodChanges() {
+ VerticalClassMergerGraphLens verticalClassMergerLens = graphLens.asVerticalClassMergerLens();
+ if (verticalClassMergerLens != null) {
+ DexMethod previousReference =
+ verticalClassMergerLens.getPreviousMethodSignature(contextReference);
+ if (verticalClassMergerLens.hasInterfaceBeenMergedIntoClass(
+ previousReference.getReturnType())) {
+ return true;
+ }
+ RewrittenPrototypeDescription prototypeChanges =
+ graphLens.lookupPrototypeChangesForMethodDefinition(context.getReference(), codeLens);
+ if (!prototypeChanges.isEmpty()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ private boolean hasPrunedCatchHandlers(LirCode<EV> rewritten) {
+ if (!getCode().hasTryCatchTable()) {
+ return false;
+ }
+ if (!appView.graphLens().isClassMergerLens()) {
+ assert !internalHasPrunedCatchHandlers(rewritten);
+ return false;
+ }
+ return internalHasPrunedCatchHandlers(rewritten);
+ }
+
+ private boolean internalHasPrunedCatchHandlers(LirCode<EV> rewritten) {
+ TryCatchTable tryCatchTable = getCode().getTryCatchTable();
+ TryCatchTable rewrittenTryCatchTable = rewritten.getTryCatchTable();
+ return tryCatchTable.hasHandlerThatMatches(
+ (blockIndex, handlers) ->
+ handlers.size() > rewrittenTryCatchTable.getHandlersForBlock(blockIndex).size());
+ }
+
+ @SuppressWarnings("unchecked")
+ private LirCode<EV> removeUnreachableBlocks(LirCode<EV> rewritten) {
+ IRCode code =
+ rewritten.buildIR(
+ context,
+ appView,
+ MethodConversionOptions.forLirPhase(appView).disableStringSwitchConversion());
+ AffectedValues affectedValues = code.removeUnreachableBlocks();
+ affectedValues.narrowingWithAssumeRemoval(appView, code);
+ DeadCodeRemover deadCodeRemover = new DeadCodeRemover(appView);
+ deadCodeRemover.run(code, Timing.empty());
+ LirCode<Integer> result =
+ new IRToLirFinalizer(appView, deadCodeRemover)
+ .finalizeCode(code, BytecodeMetadataProvider.empty(), Timing.empty());
+ return (LirCode<EV>) result;
+ }
+
+ @SuppressWarnings("unchecked")
+ private LirCode<EV> rewriteWithLensCodeRewriter() {
+ IRCode code =
+ context.buildIR(
+ appView,
+ MethodConversionOptions.forLirPhase(appView)
+ .disableStringSwitchConversion()
+ .setFinalizeAfterLensCodeRewriter());
+ // MethodProcessor argument is only used by unboxing lenses.
+ MethodProcessor methodProcessor = null;
+ new LensCodeRewriter(appView).rewrite(code, context, methodProcessor);
+ DeadCodeRemover deadCodeRemover = new DeadCodeRemover(appView);
+ deadCodeRemover.run(code, Timing.empty());
+ IRToLirFinalizer finalizer = new IRToLirFinalizer(appView, deadCodeRemover);
+ LirCode<?> rewritten =
+ finalizer.finalizeCode(code, BytecodeMetadataProvider.empty(), Timing.empty());
+ return (LirCode<EV>) rewritten;
+ }
+
+ private LirCode<EV> rewriteConstantPoolAndScanForTypeChanges(LirCode<EV> code) {
+ // The code may need to be rewritten by the lens.
+ // First pass scans just the constant pool to see if any types change or if there are any
+ // fields/methods that need to be examined.
+ boolean hasFieldReference = false;
+ boolean hasPotentialRewrittenMethod = false;
+ for (LirConstant constant : code.getConstantPool()) {
+ // RecordFieldValuesPayload is lowered to NewArrayEmpty before lens code rewriting any LIR.
+ assert !(constant instanceof RecordFieldValuesPayload);
+ if (constant instanceof DexType) {
+ onTypeReference((DexType) constant);
+ } else if (constant instanceof DexField) {
+ onFieldReference((DexField) constant);
+ hasFieldReference = true;
+ } else if (constant instanceof DexCallSite) {
+ onCallSiteReference((DexCallSite) constant);
+ } else if (constant instanceof DexMethodHandle) {
+ onMethodHandleReference((DexMethodHandle) constant);
+ } else if (constant instanceof DexProto) {
+ onProtoReference((DexProto) constant);
+ } else if (!hasPotentialRewrittenMethod && constant instanceof DexMethod) {
+ // We might be able to still fast-case this if we can guarantee the method is never
+ // rewritten. Say it is an java.lang.Object reference or if the lens can fast-check it.
+ hasPotentialRewrittenMethod = true;
+ }
+ }
+
+ // If there are potential method rewritings then we need to iterate the instructions as the
+ // rewriting is instruction-sensitive (i.e., may be dependent on the invoke type).
+ boolean hasPotentialNonTrivialFieldPutRewriting =
+ hasFieldReference && graphLens.isVerticalClassMergerLens();
+ if (hasPotentialNonTrivialFieldPutRewriting || hasPotentialRewrittenMethod) {
+ for (LirInstructionView view : code) {
+ view.accept(this);
+ if (hasNonTrivialRewritings) {
+ return null;
+ }
+ }
+ }
+
+ if (constantPoolMapping == null) {
+ return code;
+ }
+
+ return code.newCodeWithRewrittenConstantPool(
+ item -> constantPoolMapping.getOrDefault(item, item));
+ }
+
+ private LirCode<EV> rewriteInstructionsWithInvokeTypeChanges(LirCode<EV> code) {
+ if (numberOfInvokeOpcodeChanges == 0) {
+ return code;
+ }
+ // Build a small map from method refs to index in case the type-dependent methods are already
+ // in the constant pool.
+ Reference2IntMap<DexMethod> methodIndices = new Reference2IntOpenHashMap<>();
+ LirConstant[] rewrittenConstants = code.getConstantPool();
+ for (int i = 0, length = rewrittenConstants.length; i < length; i++) {
+ LirConstant constant = rewrittenConstants[i];
+ if (constant instanceof DexMethod) {
+ methodIndices.put((DexMethod) constant, i);
+ }
+ }
+
+ IRMetadata irMetadata = code.getMetadataForIR();
+ ByteArrayWriter byteWriter = new ByteArrayWriter();
+ LirWriter lirWriter = new LirWriter(byteWriter);
+ List<LirConstant> methodsToAppend = new ArrayList<>(numberOfInvokeOpcodeChanges);
+ for (LirInstructionView view : code) {
+ int opcode = view.getOpcode();
+ // Instructions that do not have an invoke-type change are just mapped via identity.
+ if (LirOpcodes.isOneByteInstruction(opcode)) {
+ lirWriter.writeOneByteInstruction(opcode);
+ continue;
+ }
+ InvokeType type = getInvokeTypeThatMayChange(opcode);
+ if (type == null) {
+ int size = view.getRemainingOperandSizeInBytes();
+ lirWriter.writeInstruction(opcode, size);
+ while (size-- > 0) {
+ lirWriter.writeOperand(view.getNextU1());
+ }
+ continue;
+ }
+ // This is potentially an invoke with a type change, in such cases the method is mapped with
+ // the instruction updated to the new type. The constant pool is amended with the mapped
+ // method if needed.
+ int constantIndex = view.getNextConstantOperand();
+ DexMethod method = (DexMethod) code.getConstantItem(constantIndex);
+ MethodLookupResult result =
+ graphLens.lookupMethod(method, context.getReference(), type, codeLens);
+ boolean newIsInterface = lookupIsInterface(method, opcode, result);
+ InvokeType newType = result.getType();
+ int newOpcode = newType.getLirOpcode(newIsInterface);
+ if (newOpcode != opcode) {
+ --numberOfInvokeOpcodeChanges;
+ if (newType != type) {
+ irMetadata.record(IROpcodeUtils.fromLirInvokeOpcode(newOpcode));
+ }
+ constantIndex =
+ methodIndices.computeIfAbsent(
+ result.getReference(),
+ ref -> {
+ methodsToAppend.add(ref);
+ return rewrittenConstants.length + methodsToAppend.size() - 1;
+ });
+ }
+ int constantIndexSize = ByteUtils.intEncodingSize(constantIndex);
+ int remainingSize = view.getRemainingOperandSizeInBytes();
+ lirWriter.writeInstruction(newOpcode, constantIndexSize + remainingSize);
+ ByteUtils.writeEncodedInt(constantIndex, lirWriter::writeOperand);
+ while (remainingSize-- > 0) {
+ lirWriter.writeOperand(view.getNextU1());
+ }
+ }
+ assert numberOfInvokeOpcodeChanges == 0;
+ // Note that since we assume 'null' in the mapping is identity this may end up with a stale
+ // reference to a no longer used method. That is not an issue as it will be pruned when
+ // building IR again, it is just a small and size overhead.
+ LirCode<EV> newCode =
+ code.copyWithNewConstantsAndInstructions(
+ irMetadata,
+ ArrayUtils.appendElements(code.getConstantPool(), methodsToAppend),
+ byteWriter.toByteArray());
+ return newCode;
+ }
+
+ // TODO(b/157111832): This should be part of the graph lens lookup result.
+ private boolean lookupIsInterface(DexMethod method, int opcode, MethodLookupResult result) {
+ VerticalClassMergerGraphLens verticalClassMergerLens = graphLens.asVerticalClassMergerLens();
+ if (verticalClassMergerLens != null
+ && verticalClassMergerLens.hasInterfaceBeenMergedIntoClass(method.getHolderType())) {
+ DexClass clazz = appView.definitionFor(result.getReference().getHolderType());
+ if (clazz != null) {
+ return clazz.isInterface();
+ }
+ }
+ return LirOpcodeUtils.getInterfaceBitFromInvokeOpcode(opcode);
+ }
+
+ private LirCode<EV> rewriteTryCatchTable(LirCode<EV> code) {
+ TryCatchTable tryCatchTable = code.getTryCatchTable();
+ if (tryCatchTable == null) {
+ return code;
+ }
+ TryCatchTable newTryCatchTable = tryCatchTable.rewriteWithLens(graphLens, codeLens);
+ return code.newCodeWithRewrittenTryCatchTable(newTryCatchTable);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirOpcodeUtils.java b/src/main/java/com/android/tools/r8/lightir/LirOpcodeUtils.java
new file mode 100644
index 0000000..944bfce
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/lightir/LirOpcodeUtils.java
@@ -0,0 +1,32 @@
+// Copyright (c) 2024, 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.lightir;
+
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKEDIRECT;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKEDIRECT_ITF;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKEINTERFACE;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKESTATIC;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKESTATIC_ITF;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKESUPER;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKESUPER_ITF;
+import static com.android.tools.r8.lightir.LirOpcodes.INVOKEVIRTUAL;
+
+public class LirOpcodeUtils {
+
+ public static boolean getInterfaceBitFromInvokeOpcode(int opcode) {
+ switch (opcode) {
+ case INVOKEDIRECT_ITF:
+ case INVOKEINTERFACE:
+ case INVOKESTATIC_ITF:
+ case INVOKESUPER_ITF:
+ return true;
+ default:
+ assert opcode == INVOKEDIRECT
+ || opcode == INVOKESTATIC
+ || opcode == INVOKESUPER
+ || opcode == INVOKEVIRTUAL;
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java b/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
index 393cd05..702dbba 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
@@ -212,6 +212,7 @@
int CHECKCAST_IGNORE_COMPAT = 225;
int CONSTCLASS_IGNORE_COMPAT = 226;
int STRINGSWITCH = 227;
+ int RESOURCENUMBER = 228;
static String toString(int opcode) {
switch (opcode) {
@@ -551,6 +552,8 @@
return "CONSTCLASS_IGNORE_COMPAT";
case STRINGSWITCH:
return "STRINGSWITCH";
+ case RESOURCENUMBER:
+ return "RESOURCENUMBER";
default:
throw new Unreachable("Unexpected LIR opcode: " + opcode);
diff --git a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
index cdd50cc..4fe7d83 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
@@ -82,6 +82,10 @@
onConstNumber(NumericType.INT, value);
}
+ public void onConstResourceNumber(int value) {
+ onInstruction();
+ }
+
public void onConstFloat(int value) {
onConstNumber(NumericType.FLOAT, value);
}
@@ -1278,6 +1282,12 @@
onRecordFieldValues(payload.fields, values);
return;
}
+ case LirOpcodes.RESOURCENUMBER:
+ {
+ int value = view.getNextIntegerOperand();
+ onConstResourceNumber(value);
+ return;
+ }
default:
throw new Unimplemented("No dispatch for opcode " + LirOpcodes.toString(opcode));
}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
index 2e0273d..c27b1ed 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
@@ -153,6 +153,11 @@
}
@Override
+ public void onConstResourceNumber(int value) {
+ appendOutValue().append(value);
+ }
+
+ @Override
public void onConstFloat(int value) {
appendOutValue().append(Float.intBitsToFloat(value));
}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirSizeEstimation.java b/src/main/java/com/android/tools/r8/lightir/LirSizeEstimation.java
index 7b78efa..3c0961e 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirSizeEstimation.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirSizeEstimation.java
@@ -352,6 +352,9 @@
case CONSTCLASS_IGNORE_COMPAT:
return DexConstClass.SIZE;
+ case RESOURCENUMBER:
+ return DexConst4.SIZE;
+
default:
throw new Unreachable("Unexpected LIR opcode: " + opcode);
}
diff --git a/src/main/java/com/android/tools/r8/lightir/LirUseRegistryCallback.java b/src/main/java/com/android/tools/r8/lightir/LirUseRegistryCallback.java
index 83a34f1..d97b0a9 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirUseRegistryCallback.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirUseRegistryCallback.java
@@ -227,6 +227,11 @@
}
@Override
+ public void onConstResourceNumber(int value) {
+ registry.registerConstResourceNumber(value);
+ }
+
+ @Override
public void onRecordFieldValues(DexField[] fields, List<EV> values) {
registry.registerRecordFieldValues(fields);
}
diff --git a/src/main/java/com/android/tools/r8/lightir/SimpleLensLirRewriter.java b/src/main/java/com/android/tools/r8/lightir/SimpleLensLirRewriter.java
deleted file mode 100644
index 1a4d065..0000000
--- a/src/main/java/com/android/tools/r8/lightir/SimpleLensLirRewriter.java
+++ /dev/null
@@ -1,293 +0,0 @@
-// 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.lightir;
-
-import static com.android.tools.r8.graph.UseRegistry.MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
-
-import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.DexCallSite;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexMethodHandle;
-import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.graph.lens.GraphLens;
-import com.android.tools.r8.graph.lens.MethodLookupResult;
-import com.android.tools.r8.ir.code.IRMetadata;
-import com.android.tools.r8.ir.code.InvokeType;
-import com.android.tools.r8.ir.code.Opcodes;
-import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.lightir.LirBuilder.RecordFieldValuesPayload;
-import com.android.tools.r8.lightir.LirCode.TryCatchTable;
-import com.android.tools.r8.utils.ArrayUtils;
-import it.unimi.dsi.fastutil.objects.Reference2IntMap;
-import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
-import java.util.ArrayList;
-import java.util.IdentityHashMap;
-import java.util.List;
-import java.util.Map;
-
-public class SimpleLensLirRewriter<EV> extends LirParsedInstructionCallback<EV> {
-
- private final ProgramMethod context;
- private final DexMethod contextReference;
- private final GraphLens graphLens;
- private final GraphLens codeLens;
- private final LensCodeRewriterUtils helper;
-
- private int numberOfInvokeTypeChanges = 0;
- private Map<LirConstant, LirConstant> constantPoolMapping = null;
-
- public SimpleLensLirRewriter(
- LirCode<EV> code,
- ProgramMethod context,
- GraphLens graphLens,
- GraphLens codeLens,
- LensCodeRewriterUtils helper) {
- super(code);
- this.context = context;
- this.contextReference = context.getReference();
- this.graphLens = graphLens;
- this.codeLens = codeLens;
- this.helper = helper;
- }
-
- @Override
- public int getCurrentValueIndex() {
- // We do not need to interpret values.
- return -1;
- }
-
- public void onTypeReference(DexType type) {
- addRewrittenMapping(type, graphLens.lookupType(type, codeLens));
- }
-
- public void onFieldReference(DexField field) {
- addRewrittenMapping(field, graphLens.lookupField(field, codeLens));
- }
-
- public void onCallSiteReference(DexCallSite callSite) {
- addRewrittenMapping(callSite, helper.rewriteCallSite(callSite, context));
- }
-
- public void onMethodHandleReference(DexMethodHandle methodHandle) {
- addRewrittenMapping(
- methodHandle,
- helper.rewriteDexMethodHandle(methodHandle, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, context));
- }
-
- public void onProtoReference(DexProto proto) {
- addRewrittenMapping(proto, helper.rewriteProto(proto));
- }
-
- private void onInvoke(DexMethod method, InvokeType type) {
- MethodLookupResult result = graphLens.lookupMethod(method, contextReference, type, codeLens);
- if (result.getType() != type) {
- assert (type == InvokeType.VIRTUAL && result.getType() == InvokeType.INTERFACE)
- || (type == InvokeType.INTERFACE && result.getType() == InvokeType.VIRTUAL);
- numberOfInvokeTypeChanges++;
- } else {
- // All non-type dependent mappings are just rewritten in the content pool.
- addRewrittenMapping(method, result.getReference());
- }
- }
-
- private void addRewrittenMapping(LirConstant item, LirConstant rewrittenItem) {
- if (item == rewrittenItem) {
- return;
- }
- if (constantPoolMapping == null) {
- constantPoolMapping =
- new IdentityHashMap<>(
- // Avoid using initial capacity larger than the number of actual constants.
- Math.min(getCode().getConstantPool().length, 32));
- }
- LirConstant old = constantPoolMapping.put(item, rewrittenItem);
- if (old != null && old != rewrittenItem) {
- throw new Unreachable(
- "Unexpected rewriting of item: "
- + item
- + " to two distinct items: "
- + rewrittenItem
- + " and "
- + old);
- }
- }
-
- @Override
- public void onInvokeDirect(DexMethod method, List<EV> arguments, boolean isInterface) {
- onInvoke(method, InvokeType.DIRECT);
- }
-
- @Override
- public void onInvokeSuper(DexMethod method, List<EV> arguments, boolean isInterface) {
- onInvoke(method, InvokeType.SUPER);
- }
-
- @Override
- public void onInvokeVirtual(DexMethod method, List<EV> arguments) {
- onInvoke(method, InvokeType.VIRTUAL);
- }
-
- @Override
- public void onInvokeStatic(DexMethod method, List<EV> arguments, boolean isInterface) {
- onInvoke(method, InvokeType.STATIC);
- }
-
- @Override
- public void onInvokeInterface(DexMethod method, List<EV> arguments) {
- onInvoke(method, InvokeType.INTERFACE);
- }
-
- private InvokeType getInvokeTypeThatMayChange(int opcode) {
- if (opcode == LirOpcodes.INVOKEVIRTUAL) {
- return InvokeType.VIRTUAL;
- }
- if (opcode == LirOpcodes.INVOKEINTERFACE) {
- return InvokeType.INTERFACE;
- }
- return null;
- }
-
- public LirCode<EV> rewrite() {
- LirCode<EV> rewritten = rewriteConstantPoolAndScanForTypeChanges(getCode());
- rewritten = rewriteInstructionsWithInvokeTypeChanges(rewritten);
- return rewriteTryCatchTable(rewritten);
- }
-
- private LirCode<EV> rewriteConstantPoolAndScanForTypeChanges(LirCode<EV> code) {
- // The code may need to be rewritten by the lens.
- // First pass scans just the constant pool to see if any types change or if there are any
- // fields/methods that need to be examined.
- boolean hasPotentialRewrittenMethod = false;
- for (LirConstant constant : code.getConstantPool()) {
- // RecordFieldValuesPayload is lowered to NewArrayEmpty before lens code rewriting any LIR.
- assert !(constant instanceof RecordFieldValuesPayload);
- if (constant instanceof DexType) {
- onTypeReference((DexType) constant);
- } else if (constant instanceof DexField) {
- onFieldReference((DexField) constant);
- } else if (constant instanceof DexCallSite) {
- onCallSiteReference((DexCallSite) constant);
- } else if (constant instanceof DexMethodHandle) {
- onMethodHandleReference((DexMethodHandle) constant);
- } else if (constant instanceof DexProto) {
- onProtoReference((DexProto) constant);
- } else if (!hasPotentialRewrittenMethod && constant instanceof DexMethod) {
- // We might be able to still fast-case this if we can guarantee the method is never
- // rewritten. Say it is an java.lang.Object reference or if the lens can fast-check it.
- hasPotentialRewrittenMethod = true;
- }
- }
-
- // If there are potential method rewritings then we need to iterate the instructions as the
- // rewriting is instruction-sensitive (i.e., may be dependent on the invoke type).
- if (hasPotentialRewrittenMethod) {
- for (LirInstructionView view : code) {
- view.accept(this);
- }
- }
-
- if (constantPoolMapping == null) {
- return code;
- }
-
- return code.newCodeWithRewrittenConstantPool(
- item -> constantPoolMapping.getOrDefault(item, item));
- }
-
- private LirCode<EV> rewriteInstructionsWithInvokeTypeChanges(LirCode<EV> code) {
- if (numberOfInvokeTypeChanges == 0) {
- return code;
- }
- // Build a small map from method refs to index in case the type-dependent methods are already
- // in the constant pool.
- Reference2IntMap<DexMethod> methodIndices = new Reference2IntOpenHashMap<>();
- LirConstant[] rewrittenConstants = code.getConstantPool();
- for (int i = 0, length = rewrittenConstants.length; i < length; i++) {
- LirConstant constant = rewrittenConstants[i];
- if (constant instanceof DexMethod) {
- methodIndices.put((DexMethod) constant, i);
- }
- }
-
- IRMetadata irMetadata = code.getMetadataForIR();
- ByteArrayWriter byteWriter = new ByteArrayWriter();
- LirWriter lirWriter = new LirWriter(byteWriter);
- List<LirConstant> methodsToAppend = new ArrayList<>(numberOfInvokeTypeChanges);
- for (LirInstructionView view : code) {
- int opcode = view.getOpcode();
- // Instructions that do not have an invoke-type change are just mapped via identity.
- if (LirOpcodes.isOneByteInstruction(opcode)) {
- lirWriter.writeOneByteInstruction(opcode);
- continue;
- }
- InvokeType type = getInvokeTypeThatMayChange(opcode);
- if (type == null) {
- int size = view.getRemainingOperandSizeInBytes();
- lirWriter.writeInstruction(opcode, size);
- while (size-- > 0) {
- lirWriter.writeOperand(view.getNextU1());
- }
- continue;
- }
- // This is potentially an invoke with a type change, in such cases the method is mapped with
- // the instruction updated to the new type. The constant pool is amended with the mapped
- // method if needed.
- int constantIndex = view.getNextConstantOperand();
- DexMethod method = (DexMethod) code.getConstantItem(constantIndex);
- MethodLookupResult result =
- graphLens.lookupMethod(method, context.getReference(), type, codeLens);
- if (result.getType() != type) {
- --numberOfInvokeTypeChanges;
- if (result.getType().isVirtual()) {
- opcode = LirOpcodes.INVOKEVIRTUAL;
- irMetadata.record(Opcodes.INVOKE_VIRTUAL);
- } else if (result.getType().isInterface()) {
- opcode = LirOpcodes.INVOKEINTERFACE;
- irMetadata.record(Opcodes.INVOKE_INTERFACE);
- } else {
- throw new Unreachable(
- "Unexpected change of invoke that may need an interface bit set: "
- + result.getType());
- }
- constantIndex =
- methodIndices.computeIfAbsent(
- result.getReference(),
- ref -> {
- methodsToAppend.add(ref);
- return rewrittenConstants.length + methodsToAppend.size() - 1;
- });
- }
- int constantIndexSize = ByteUtils.intEncodingSize(constantIndex);
- int remainingSize = view.getRemainingOperandSizeInBytes();
- lirWriter.writeInstruction(opcode, constantIndexSize + remainingSize);
- ByteUtils.writeEncodedInt(constantIndex, lirWriter::writeOperand);
- while (remainingSize-- > 0) {
- lirWriter.writeOperand(view.getNextU1());
- }
- }
- assert numberOfInvokeTypeChanges == 0;
- // Note that since we assume 'null' in the mapping is identity this may end up with a stale
- // reference to a no longer used method. That is not an issue as it will be pruned when
- // building IR again, it is just a small and size overhead.
- LirCode<EV> newCode =
- code.copyWithNewConstantsAndInstructions(
- irMetadata,
- ArrayUtils.appendElements(code.getConstantPool(), methodsToAppend),
- byteWriter.toByteArray());
- return newCode;
- }
-
- private LirCode<EV> rewriteTryCatchTable(LirCode<EV> code) {
- TryCatchTable tryCatchTable = code.getTryCatchTable();
- if (tryCatchTable == null) {
- return code;
- }
- TryCatchTable newTryCatchTable = tryCatchTable.rewriteWithLens(graphLens, codeLens);
- return code.newCodeWithRewrittenTryCatchTable(newTryCatchTable);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
index 0b947a3..4a19396 100644
--- a/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
+++ b/src/main/java/com/android/tools/r8/optimize/argumentpropagation/ArgumentPropagatorOptimizationInfoPopulator.java
@@ -88,6 +88,7 @@
converter.onMethodPruned(prunedMethod);
postMethodProcessorBuilder.remove(prunedMethod, appView.graphLens());
}
+ converter.pruneItems(executorService);
converter.waveDone(ProgramMethodSet.empty(), executorService);
}
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
index 5272500..d6bc517 100644
--- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
+++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.InnerClassAttribute;
@@ -22,7 +21,6 @@
import com.android.tools.r8.graph.ProgramPackageCollection;
import com.android.tools.r8.graph.SortedProgramPackageCollection;
import com.android.tools.r8.graph.fixup.TreeFixerBase;
-import com.android.tools.r8.graph.lens.NestedGraphLens;
import com.android.tools.r8.naming.Minifier.MinificationPackageNamingStrategy;
import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
import com.android.tools.r8.repackaging.RepackagingLens.Builder;
@@ -113,18 +111,7 @@
assert false;
}
}.fixupClasses(appView.appInfo().classesWithDeterministicOrder());
- NestedGraphLens emptyRepackagingLens =
- new NestedGraphLens(appView) {
- @Override
- protected boolean isLegitimateToHaveEmptyMappings() {
- return true;
- }
-
- @Override
- public <T extends DexReference> boolean isSimpleRenaming(T from, T to) {
- return getPrevious().isSimpleRenaming(from, to);
- }
- };
+ RepackagingLens emptyRepackagingLens = new RepackagingLens.Builder().buildEmpty(appView);
DirectMappedDexApplication newApplication =
appView
.appInfo()
@@ -479,58 +466,4 @@
|| appView.appInfo().getMissingClasses().contains(type);
}
}
-
- /** Testing only. */
- public static class SuffixRenamingRepackagingConfiguration implements RepackagingConfiguration {
-
- private final String classNameSuffix;
- private final DexItemFactory dexItemFactory;
-
- public SuffixRenamingRepackagingConfiguration(
- String classNameSuffix, DexItemFactory dexItemFactory) {
- this.classNameSuffix = classNameSuffix;
- this.dexItemFactory = dexItemFactory;
- }
-
- @Override
- public String getNewPackageDescriptor(ProgramPackage pkg, Set<String> seenPackageDescriptors) {
- // Don't change the package of classes.
- return pkg.getPackageDescriptor();
- }
-
- @Override
- public boolean isPackageInTargetLocation(ProgramPackage pkg) {
- return true;
- }
-
- @Override
- public DexType getRepackagedType(
- DexProgramClass clazz,
- DexProgramClass outerClass,
- String newPackageDescriptor,
- BiMap<DexType, DexType> mappings) {
- DexType repackagedDexType = clazz.getType();
- // Rename the class consistently with its outer class.
- if (outerClass != null) {
- String simpleName = clazz.getType().getSimpleName();
- String outerClassSimpleName = outerClass.getType().getSimpleName();
- if (simpleName.startsWith(outerClassSimpleName + INNER_CLASS_SEPARATOR)) {
- String newSimpleName =
- mappings.get(outerClass.getType()).getSimpleName()
- + simpleName.substring(outerClassSimpleName.length());
- repackagedDexType = repackagedDexType.withSimpleName(newSimpleName, dexItemFactory);
- }
- }
- // Append the class name suffix to all classes.
- repackagedDexType = repackagedDexType.addSuffix(classNameSuffix, dexItemFactory);
- // Ensure that the generated name is unique.
- DexType finalRepackagedDexType = repackagedDexType;
- for (int i = 1; mappings.inverse().containsKey(finalRepackagedDexType); i++) {
- finalRepackagedDexType =
- repackagedDexType.addSuffix(
- Character.toString(INNER_CLASS_SEPARATOR) + i, dexItemFactory);
- }
- return finalRepackagedDexType;
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
index 0b40c72..acc7ed6 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
+import java.util.Collections;
import java.util.Map;
public class RepackagingLens extends NestedGraphLens {
@@ -36,7 +37,8 @@
@Override
public String lookupPackageName(String pkg) {
- return packageRenamings.getOrDefault(getPrevious().lookupPackageName(pkg), pkg);
+ String previousPkg = getPrevious().lookupPackageName(pkg);
+ return packageRenamings.getOrDefault(previousPkg, previousPkg);
}
@Override
@@ -101,5 +103,16 @@
return new RepackagingLens(
appView, newFieldSignatures, newMethodSignatures, newTypes, packageRenamings);
}
+
+ public RepackagingLens buildEmpty(AppView<AppInfoWithLiveness> appView) {
+ return new RepackagingLens(
+ appView, EMPTY_FIELD_MAP, EMPTY_METHOD_MAP, EMPTY_TYPE_MAP, Collections.emptyMap()) {
+
+ @Override
+ protected boolean isLegitimateToHaveEmptyMappings() {
+ return true;
+ }
+ };
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
index 7e988c4..736f285 100644
--- a/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/shaking/DefaultEnqueuerUseRegistry.java
@@ -57,6 +57,12 @@
}
@Override
+ public void registerConstResourceNumber(int value) {
+ super.registerConstResourceNumber(value);
+ enqueuer.traceResourceValue(value);
+ }
+
+ @Override
public void registerInvokeVirtual(DexMethod invokedMethod) {
super.registerInvokeVirtual(invokedMethod);
enqueuer.traceInvokeVirtual(invokedMethod, getContext());
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 5279f1d..34cb2ec 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -17,7 +17,11 @@
import static com.android.tools.r8.utils.MapUtils.ignoreKey;
import static java.util.Collections.emptySet;
+import com.android.build.shrinker.r8integration.R8ResourceShrinkerState;
+import com.android.tools.r8.AndroidResourceInput;
+import com.android.tools.r8.AndroidResourceInput.Kind;
import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.ResourceException;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
@@ -479,6 +483,8 @@
private final ProfileCollectionAdditions profileCollectionAdditions;
+ private final R8ResourceShrinkerState r8ResourceShrinkerState;
+
Enqueuer(
AppView<? extends AppInfoWithClassHierarchy> appView,
ProfileCollectionAdditions profileCollectionAdditions,
@@ -537,6 +543,27 @@
objectAllocationInfoCollection =
ObjectAllocationInfoCollectionImpl.builder(mode.isInitialTreeShaking(), graphReporter);
+ r8ResourceShrinkerState = setupResourceShrinkerState(appView);
+ }
+
+ private R8ResourceShrinkerState setupResourceShrinkerState(
+ AppView<? extends AppInfoWithClassHierarchy> appView) {
+ R8ResourceShrinkerState r8ResourceShrinkerState = new R8ResourceShrinkerState();
+ if (options.resourceShrinkerConfiguration.isOptimizedShrinking()
+ && options.androidResourceProvider != null) {
+ try {
+ for (AndroidResourceInput androidResource :
+ options.androidResourceProvider.getAndroidResources()) {
+ if (androidResource.getKind() == Kind.RESOURCE_TABLE) {
+ r8ResourceShrinkerState.setResourceTableInput(androidResource.getByteStream());
+ break;
+ }
+ }
+ } catch (ResourceException e) {
+ throw appView.reporter().fatalError("Failed initializing resource table");
+ }
+ }
+ return r8ResourceShrinkerState;
}
private AppInfoWithClassHierarchy appInfo() {
@@ -1107,6 +1134,10 @@
}
}
+ public void traceResourceValue(int value) {
+ r8ResourceShrinkerState.trace(value);
+ }
+
public void traceReflectiveFieldWrite(ProgramField field, ProgramMethod context) {
deferredTracing.notifyReflectiveFieldAccess(field, context);
if (registerReflectiveFieldWrite(field, context)) {
@@ -3740,6 +3771,7 @@
EnqueuerResult result = createEnqueuerResult(appInfo, timing);
profileCollectionAdditions.commit(appView);
timing.end();
+ appView.setResourceShrinkerState(r8ResourceShrinkerState);
return result;
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index a1795a7..a9f9957 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -49,12 +49,6 @@
public final SyntheticKind WRAPPER = generator.forFixedClass("$Wrapper");
public final SyntheticKind VIVIFIED_WRAPPER = generator.forFixedClass("$VivifiedWrapper");
public final SyntheticKind INIT_TYPE_ARGUMENT = generator.forFixedClass("-IA");
- public final SyntheticKind HORIZONTAL_INIT_TYPE_ARGUMENT_1 =
- generator.forFixedClass(SYNTHETIC_CLASS_SEPARATOR + "IA$1");
- public final SyntheticKind HORIZONTAL_INIT_TYPE_ARGUMENT_2 =
- generator.forFixedClass(SYNTHETIC_CLASS_SEPARATOR + "IA$2");
- public final SyntheticKind HORIZONTAL_INIT_TYPE_ARGUMENT_3 =
- generator.forFixedClass(SYNTHETIC_CLASS_SEPARATOR + "IA$3");
public final SyntheticKind ENUM_CONVERSION = generator.forFixedClass("$EnumConversion");
// Locally generated synthetic classes.
diff --git a/src/main/java/com/android/tools/r8/utils/DequeUtils.java b/src/main/java/com/android/tools/r8/utils/DequeUtils.java
index 6745d6b..986a6a2 100644
--- a/src/main/java/com/android/tools/r8/utils/DequeUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/DequeUtils.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.utils;
import java.util.ArrayDeque;
+import java.util.Collections;
import java.util.Deque;
public class DequeUtils {
@@ -14,4 +15,10 @@
deque.add(element);
return deque;
}
+
+ public static <T> Deque<T> newArrayDeque(T... elements) {
+ Deque<T> deque = new ArrayDeque<>();
+ Collections.addAll(deque, elements);
+ return deque;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
index df0ac25..7d8e995 100644
--- a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
@@ -17,6 +17,7 @@
import com.google.common.collect.ImmutableMap;
import java.io.File;
import java.nio.file.Path;
+import java.util.List;
import java.util.Map;
import java.util.function.Function;
@@ -805,6 +806,22 @@
return new ModuleAndDescriptor(module, 'L' + descriptor + ';');
}
+ public static boolean isRClassDescriptor(String descriptor) {
+ String simpleClassName = DescriptorUtils.getSimpleClassNameFromDescriptor(descriptor);
+ List<String> split = StringUtils.split(simpleClassName, '$');
+
+ if (split.size() < 2) {
+ return false;
+ }
+ String type = split.get(split.size() - 1);
+ String rClass = split.get(split.size() - 2);
+ // We match on R if:
+ // - The name of the Class is R$type - we allow R to be an inner class.
+ // - The inner type should be with lower case
+ boolean isRClass = Character.isLowerCase(type.charAt(0)) && rClass.equals("R");
+ return isRClass;
+ }
+
public static String getPathFromDescriptor(String descriptor) {
// We are quite loose on names here to support testing illegal names, too.
assert descriptor.startsWith("L");
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 838558f..29f4710 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -229,6 +229,10 @@
return proguardConfiguration != null;
}
+ public boolean isOptimizedResourceShrinking() {
+ return androidResourceProvider != null && resourceShrinkerConfiguration.isOptimizedShrinking();
+ }
+
public ProguardConfiguration getProguardConfiguration() {
return proguardConfiguration;
}
@@ -1399,14 +1403,14 @@
}
}
- public void warningInvalidDebugInfo(
- ProgramMethod method, Origin origin, InvalidDebugInfoException e) {
+ public void warningInvalidDebugInfo(ProgramMethod method, InvalidDebugInfoException e) {
if (invalidDebugInfoFatal) {
throw new CompilationError("Fatal warning: Invalid debug info", e);
}
synchronized (warningInvalidDebugInfo) {
- warningInvalidDebugInfo.computeIfAbsent(
- origin, k -> new ArrayList<>()).add(new Pair<>(method, e.getMessage()));
+ warningInvalidDebugInfo
+ .computeIfAbsent(method.getOrigin(), k -> new ArrayList<>())
+ .add(new Pair<>(method, e.getMessage()));
}
}
@@ -1877,7 +1881,7 @@
}
}
if (mode.isInitial()) {
- return enableInitial && inlinerOptions.enableInlining;
+ return enableInitial;
}
assert mode.isFinal();
return true;
diff --git a/src/main/java/com/android/tools/r8/utils/ListUtils.java b/src/main/java/com/android/tools/r8/utils/ListUtils.java
index 1210325..22d19f7 100644
--- a/src/main/java/com/android/tools/r8/utils/ListUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ListUtils.java
@@ -7,6 +7,8 @@
import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
+import it.unimi.dsi.fastutil.ints.IntList;
+import it.unimi.dsi.fastutil.ints.IntListIterator;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -208,6 +210,35 @@
return list;
}
+ public static <T> List<T> newArrayListWithoutIndices(List<T> list, IntList indicesToRemove) {
+ // Verify each index to remove is unique and in bounds.
+ assert indicesToRemove.stream().distinct().count() == indicesToRemove.size();
+ assert indicesToRemove.stream().allMatch(indexToRemove -> indexToRemove < list.size());
+ if (indicesToRemove.size() == list.size()) {
+ return new ArrayList<>();
+ }
+ List<T> result = new ArrayList<>(list.size() - indicesToRemove.size());
+ IntListIterator indicesToRemoveIterator = indicesToRemove.iterator();
+ int nextIndexToRemove = indicesToRemoveIterator.nextInt();
+ for (int i = 0; i < list.size(); i++) {
+ assert i <= nextIndexToRemove;
+ if (i == nextIndexToRemove) {
+ if (indicesToRemoveIterator.hasNext()) {
+ nextIndexToRemove = indicesToRemoveIterator.nextInt();
+ assert nextIndexToRemove > i;
+ } else {
+ for (int j = i + 1; j < list.size(); j++) {
+ result.add(list.get(j));
+ }
+ break;
+ }
+ } else {
+ result.add(list.get(i));
+ }
+ }
+ return result;
+ }
+
public static <T> ArrayList<T> newInitializedArrayList(int size, T element) {
ArrayList<T> list = new ArrayList<>(size);
for (int i = 0; i < size; i++) {
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMerger.java
index 6f89166..2fdda52 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/ClassMerger.java
@@ -9,6 +9,7 @@
import static java.util.function.Predicate.not;
import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
import com.android.tools.r8.graph.AccessControl;
import com.android.tools.r8.graph.AccessFlags;
import com.android.tools.r8.graph.AppView;
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/ConnectedComponentVerticalClassMerger.java b/src/main/java/com/android/tools/r8/verticalclassmerging/ConnectedComponentVerticalClassMerger.java
index 72547ec..56e619f 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/ConnectedComponentVerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/ConnectedComponentVerticalClassMerger.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.verticalclassmerging;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ListUtils;
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/IncompleteVerticalClassMergerBridgeCode.java b/src/main/java/com/android/tools/r8/verticalclassmerging/IncompleteVerticalClassMergerBridgeCode.java
index f13c3c6..ffe892f 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/IncompleteVerticalClassMergerBridgeCode.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/IncompleteVerticalClassMergerBridgeCode.java
@@ -28,7 +28,6 @@
import com.android.tools.r8.lightir.LirCode;
import com.android.tools.r8.lightir.LirEncodingStrategy;
import com.android.tools.r8.lightir.LirStrategy;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.RetracerForCodePrinting;
import java.util.ArrayList;
@@ -148,7 +147,6 @@
public IRCode buildIR(
ProgramMethod method,
AppView<?> appView,
- Origin origin,
MutableMethodConversionOptions conversionOptions) {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
index 26ff3b6..8ef8743 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMerger.java
@@ -6,7 +6,8 @@
import static com.android.tools.r8.graph.DexClassAndMethod.asProgramMethodOrNull;
import com.android.tools.r8.classmerging.ClassMergerMode;
-import com.android.tools.r8.classmerging.SyntheticArgumentClass;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
+import com.android.tools.r8.classmerging.Policy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
@@ -17,18 +18,13 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.graph.lens.GraphLens;
-import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.ir.conversion.MethodConversionOptions;
-import com.android.tools.r8.ir.conversion.MethodProcessorEventConsumer;
-import com.android.tools.r8.ir.conversion.OneTimeMethodProcessor;
-import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
+import com.android.tools.r8.ir.conversion.LirConverter;
import com.android.tools.r8.optimize.argumentpropagation.utils.ProgramClassesBidirectedGraph;
import com.android.tools.r8.profile.art.ArtProfileCompletenessChecker;
import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.KeepInfoCollection;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.Timing.TimingMerger;
@@ -36,7 +32,6 @@
import com.google.common.collect.Streams;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ExecutionException;
@@ -76,7 +71,7 @@
public void runIfNecessary(ExecutorService executorService, Timing timing)
throws ExecutionException {
- timing.begin("VerticalClassMerger");
+ timing.begin("VerticalClassMerger (" + mode.toString() + ")");
if (shouldRun()) {
run(executorService, timing);
} else {
@@ -93,7 +88,6 @@
}
private void run(ExecutorService executorService, Timing timing) throws ExecutionException {
- appView.appInfo().getMethodAccessInfoCollection().verifyNoNonResolving(appView);
timing.begin("Setup");
ImmediateProgramSubtypingInfo immediateSubtypingInfo =
ImmediateProgramSubtypingInfo.create(appView);
@@ -108,45 +102,49 @@
timing.end();
// Apply class merging concurrently in disjoint class hierarchies.
+ ClassMergerSharedData classMergerSharedData = new ClassMergerSharedData(appView);
VerticalClassMergerResult verticalClassMergerResult =
mergeClassesInConnectedComponents(
- connectedComponents, immediateSubtypingInfo, executorService, timing);
+ classMergerSharedData,
+ connectedComponents,
+ immediateSubtypingInfo,
+ executorService,
+ timing);
appView.setVerticallyMergedClasses(
verticalClassMergerResult.getVerticallyMergedClasses(), mode);
if (verticalClassMergerResult.isEmpty()) {
return;
}
- ProfileCollectionAdditions profileCollectionAdditions =
- ProfileCollectionAdditions.create(appView);
VerticalClassMergerGraphLens lens =
- runFixup(profileCollectionAdditions, verticalClassMergerResult, executorService, timing);
+ runFixup(classMergerSharedData, verticalClassMergerResult, executorService, timing);
assert verifyGraphLens(lens, verticalClassMergerResult);
// Update keep info and art profiles.
- updateKeepInfoForMergedClasses(verticalClassMergerResult);
- updateArtProfiles(profileCollectionAdditions, lens, verticalClassMergerResult);
+ updateKeepInfoForMergedClasses(verticalClassMergerResult, timing);
+ updateArtProfiles(lens, verticalClassMergerResult, timing);
// Remove merged classes and rewrite AppView with the new lens.
appView.rewriteWithLens(lens, executorService, timing);
// The code must be rewritten before we remove the merged classes from the app. Otherwise we
// can't build IR.
- rewriteCodeWithLens(executorService);
+ rewriteCodeWithLens(executorService, timing);
// Remove force inlined constructors.
- removeFullyInlinedInstanceInitializers(executorService);
- removeMergedClasses(verticalClassMergerResult.getVerticallyMergedClasses());
+ removeFullyInlinedInstanceInitializers(executorService, timing);
+ removeMergedClasses(verticalClassMergerResult.getVerticallyMergedClasses(), timing);
// Convert the (incomplete) synthesized bridges to CF or LIR.
- finalizeSynthesizedBridges(verticalClassMergerResult.getSynthesizedBridges(), lens);
+ finalizeSynthesizedBridges(verticalClassMergerResult.getSynthesizedBridges(), lens, timing);
// Finally update the code lens to signal that the code is fully up to date.
- markRewrittenWithLens(executorService);
+ markRewrittenWithLens(executorService, timing);
appView.notifyOptimizationFinishedForTesting();
}
private VerticalClassMergerResult mergeClassesInConnectedComponents(
+ ClassMergerSharedData classMergerSharedData,
List<Set<DexProgramClass>> connectedComponents,
ImmediateProgramSubtypingInfo immediateSubtypingInfo,
ExecutorService executorService,
@@ -155,7 +153,8 @@
Collection<ConnectedComponentVerticalClassMerger> connectedComponentMergers =
getConnectedComponentMergers(
connectedComponents, immediateSubtypingInfo, executorService, timing);
- return applyConnectedComponentMergers(connectedComponentMergers, executorService, timing);
+ return applyConnectedComponentMergers(
+ classMergerSharedData, connectedComponentMergers, executorService, timing);
}
private Collection<ConnectedComponentVerticalClassMerger> getConnectedComponentMergers(
@@ -164,17 +163,19 @@
ExecutorService executorService,
Timing timing)
throws ExecutionException {
+ timing.begin("Compute classes to merge");
TimingMerger merger = timing.beginMerger("Compute classes to merge", executorService);
List<ConnectedComponentVerticalClassMerger> connectedComponentMergers =
new ArrayList<>(connectedComponents.size());
+ Collection<Policy> policies = VerticalClassMergerPolicyScheduler.getPolicies(appView, mode);
Collection<Timing> timings =
ThreadUtils.processItemsWithResults(
connectedComponents,
connectedComponent -> {
Timing threadTiming = Timing.create("Compute classes to merge in component", options);
ConnectedComponentVerticalClassMerger connectedComponentMerger =
- new VerticalClassMergerPolicyExecutor(appView, immediateSubtypingInfo, mode)
- .run(connectedComponent, executorService, threadTiming);
+ new VerticalClassMergerPolicyExecutor(appView, immediateSubtypingInfo)
+ .run(connectedComponent, policies, executorService, threadTiming);
if (!connectedComponentMerger.isEmpty()) {
synchronized (connectedComponentMergers) {
connectedComponentMergers.add(connectedComponentMerger);
@@ -187,16 +188,18 @@
executorService);
merger.add(timings);
merger.end();
+ timing.end();
return connectedComponentMergers;
}
private VerticalClassMergerResult applyConnectedComponentMergers(
+ ClassMergerSharedData classMergerSharedData,
Collection<ConnectedComponentVerticalClassMerger> connectedComponentMergers,
ExecutorService executorService,
Timing timing)
throws ExecutionException {
+ timing.begin("Merge classes");
TimingMerger merger = timing.beginMerger("Merge classes", executorService);
- ClassMergerSharedData sharedData = new ClassMergerSharedData(appView);
VerticalClassMergerResult.Builder verticalClassMergerResult =
VerticalClassMergerResult.builder(appView);
Collection<Timing> timings =
@@ -205,7 +208,7 @@
connectedComponentMerger -> {
Timing threadTiming = Timing.create("Merge classes in component", options);
VerticalClassMergerResult.Builder verticalClassMergerComponentResult =
- connectedComponentMerger.run(sharedData);
+ connectedComponentMerger.run(classMergerSharedData);
verticalClassMergerResult.merge(verticalClassMergerComponentResult);
threadTiming.end();
return threadTiming;
@@ -214,82 +217,40 @@
executorService);
merger.add(timings);
merger.end();
+ timing.end();
return verticalClassMergerResult.build();
}
private VerticalClassMergerGraphLens runFixup(
- ProfileCollectionAdditions profileCollectionAdditions,
+ ClassMergerSharedData classMergerSharedData,
VerticalClassMergerResult verticalClassMergerResult,
ExecutorService executorService,
Timing timing)
throws ExecutionException {
- DexProgramClass deterministicContext =
- appView
- .definitionFor(
- ListUtils.first(
- ListUtils.sort(
- verticalClassMergerResult.getVerticallyMergedClasses().getTargets(),
- Comparator.naturalOrder())))
- .asProgramClass();
- SyntheticArgumentClass syntheticArgumentClass =
- new SyntheticArgumentClass.Builder(appView).build(deterministicContext);
- VerticalClassMergerGraphLens lens =
- new VerticalClassMergerTreeFixer(
- appView,
- profileCollectionAdditions,
- syntheticArgumentClass,
- verticalClassMergerResult)
- .run(executorService, timing);
- return lens;
+ return new VerticalClassMergerTreeFixer(
+ appView, classMergerSharedData, verticalClassMergerResult)
+ .run(executorService, timing);
}
- // TODO(b/320432664): For code objects where the rewriting is an alpha renaming we can rewrite the
- // LIR directly without building IR.
- private void rewriteCodeWithLens(ExecutorService executorService) throws ExecutionException {
+ private void rewriteCodeWithLens(ExecutorService executorService, Timing timing)
+ throws ExecutionException {
if (mode.isInitial()) {
return;
}
-
- MethodProcessorEventConsumer eventConsumer = MethodProcessorEventConsumer.empty();
- OneTimeMethodProcessor.Builder methodProcessorBuilder =
- OneTimeMethodProcessor.builder(eventConsumer, appView);
- for (DexProgramClass clazz : appView.appInfo().classes()) {
- clazz.forEachProgramMethodMatching(
- method ->
- method.hasCode()
- && !(method.getCode() instanceof IncompleteVerticalClassMergerBridgeCode),
- methodProcessorBuilder::add);
- }
-
- IRConverter converter = new IRConverter(appView);
- converter.clearEnumUnboxer();
- converter.clearServiceLoaderRewriter();
- OneTimeMethodProcessor methodProcessor = methodProcessorBuilder.build();
- methodProcessor.forEachWaveWithExtension(
- (method, methodProcessingContext) ->
- converter.processDesugaredMethod(
- method,
- OptimizationFeedbackIgnore.getInstance(),
- methodProcessor,
- methodProcessingContext,
- MethodConversionOptions.forLirPhase(appView)
- .disableStringSwitchConversion()
- .setFinalizeAfterLensCodeRewriter()),
- options.getThreadingModule(),
- executorService);
-
- // Clear type elements created during IR processing.
- dexItemFactory.clearTypeElementsCache();
+ LirConverter.rewriteLirWithLens(appView, timing, executorService);
}
private void updateArtProfiles(
- ProfileCollectionAdditions profileCollectionAdditions,
VerticalClassMergerGraphLens verticalClassMergerLens,
- VerticalClassMergerResult verticalClassMergerResult) {
+ VerticalClassMergerResult verticalClassMergerResult,
+ Timing timing) {
// Include bridges in art profiles.
+ ProfileCollectionAdditions profileCollectionAdditions =
+ ProfileCollectionAdditions.create(appView);
if (profileCollectionAdditions.isNop()) {
return;
}
+ timing.begin("Update ART profiles");
List<IncompleteVerticalClassMergerBridgeCode> synthesizedBridges =
verticalClassMergerResult.getSynthesizedBridges();
for (IncompleteVerticalClassMergerBridgeCode synthesizedBridge : synthesizedBridges) {
@@ -298,9 +259,12 @@
additionsBuilder -> additionsBuilder.addRule(synthesizedBridge.getMethod()));
}
profileCollectionAdditions.commit(appView);
+ timing.end();
}
- private void updateKeepInfoForMergedClasses(VerticalClassMergerResult verticalClassMergerResult) {
+ private void updateKeepInfoForMergedClasses(
+ VerticalClassMergerResult verticalClassMergerResult, Timing timing) {
+ timing.begin("Update keep info");
KeepInfoCollection keepInfo = appView.getKeepInfo();
keepInfo.mutate(
mutator -> {
@@ -311,13 +275,15 @@
.setRemovedClasses(verticallyMergedClasses.getSources())
.build());
});
+ timing.end();
}
- private void removeFullyInlinedInstanceInitializers(ExecutorService executorService)
- throws ExecutionException {
+ private void removeFullyInlinedInstanceInitializers(
+ ExecutorService executorService, Timing timing) throws ExecutionException {
if (mode.isInitial()) {
return;
}
+ timing.begin("Remove fully inlined instance initializers");
PrunedItems.Builder prunedItemsBuilder =
PrunedItems.concurrentBuilder().setPrunedApp(appView.app());
ThreadUtils.<DexProgramClass, Exception>processItems(
@@ -341,13 +307,15 @@
PrunedItems prunedItems = prunedItemsBuilder.build();
appView.pruneItems(prunedItems, executorService, Timing.empty());
appView.appInfo().getMethodAccessInfoCollection().withoutPrunedItems(prunedItems);
+ timing.end();
}
- private void removeMergedClasses(VerticallyMergedClasses verticallyMergedClasses) {
+ private void removeMergedClasses(VerticallyMergedClasses verticallyMergedClasses, Timing timing) {
if (mode.isInitial()) {
return;
}
+ timing.begin("Remove merged classes");
DirectMappedDexApplication newApplication =
appView
.app()
@@ -356,10 +324,14 @@
.removeProgramClasses(clazz -> verticallyMergedClasses.isMergeSource(clazz.getType()))
.build();
appView.setAppInfo(appView.appInfo().rebuildWithLiveness(newApplication));
+ timing.end();
}
private void finalizeSynthesizedBridges(
- List<IncompleteVerticalClassMergerBridgeCode> bridges, VerticalClassMergerGraphLens lens) {
+ List<IncompleteVerticalClassMergerBridgeCode> bridges,
+ VerticalClassMergerGraphLens lens,
+ Timing timing) {
+ timing.begin("Finalize synthesized bridges");
KeepInfoCollection keepInfo = appView.getKeepInfo();
for (IncompleteVerticalClassMergerBridgeCode code : bridges) {
ProgramMethod bridge = asProgramMethodOrNull(appView.definitionFor(code.getMethod()));
@@ -380,13 +352,17 @@
mutator ->
mutator.joinMethod(bridge, info -> info.merge(appView.getKeepInfo(target).joiner())));
}
+ timing.end();
}
- private void markRewrittenWithLens(ExecutorService executorService) throws ExecutionException {
+ private void markRewrittenWithLens(ExecutorService executorService, Timing timing)
+ throws ExecutionException {
if (mode.isInitial()) {
return;
}
- appView.clearCodeRewritings(executorService);
+ timing.begin("Mark rewritten with lens");
+ appView.clearCodeRewritings(executorService, timing);
+ timing.end();
}
private boolean verifyGraphLens(
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java
index 7fa9f56..fcbf5eb 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerGraphLens.java
@@ -100,6 +100,10 @@
this.staticizedMethods = staticizedMethods;
}
+ public boolean hasInterfaceBeenMergedIntoClass(DexType type) {
+ return mergedClasses.hasInterfaceBeenMergedIntoClass(type);
+ }
+
private boolean isMerged(DexMethod method) {
return mergedMethods.contains(method);
}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerOptions.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerOptions.java
index 31d25ab..dbe28ca 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerOptions.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerOptions.java
@@ -11,6 +11,7 @@
private final InternalOptions options;
private boolean enabled = true;
+ private boolean enableInitial = true;
public VerticalClassMergerOptions(InternalOptions options) {
this.options = options;
@@ -20,9 +21,18 @@
setEnabled(false);
}
+ public void disableInitial() {
+ enableInitial = false;
+ }
+
public boolean isEnabled(ClassMergerMode mode) {
- assert mode != null;
- return enabled && options.isOptimizing() && options.isShrinking();
+ if (!enabled || !options.isOptimizing() || !options.isShrinking()) {
+ return false;
+ }
+ if (mode.isInitial() && !enableInitial) {
+ return false;
+ }
+ return true;
}
public void setEnabled(boolean enabled) {
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerPolicyExecutor.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerPolicyExecutor.java
index 264441e..1b5f45a 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerPolicyExecutor.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerPolicyExecutor.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.verticalclassmerging;
-import com.android.tools.r8.classmerging.ClassMergerMode;
import com.android.tools.r8.classmerging.Policy;
import com.android.tools.r8.classmerging.PolicyExecutor;
import com.android.tools.r8.graph.AppView;
@@ -12,33 +11,10 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.Timing;
-import com.android.tools.r8.verticalclassmerging.policies.NoAbstractMethodsOnAbstractClassesPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoAnnotationClassesPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoClassInitializationChangesPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoDirectlyInstantiatedClassesPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoEnclosingMethodAttributesPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoFieldResolutionChangesPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoIllegalAccessesPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoInnerClassAttributesPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoInterfacesWithInvokeSpecialToDefaultMethodIntoClassPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoInterfacesWithUnknownSubtypesPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoInvokeSuperNoSuchMethodErrorsPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoKeptClassesPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoLockMergingPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoMethodResolutionChangesPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoNestedMergingPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoNonSerializableClassIntoSerializableClassPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.NoServiceInterfacesPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.SafeConstructorInliningPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.SameApiReferenceLevelPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.SameFeatureSplitPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.SameMainDexGroupPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.SameNestPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.SameStartupPartitionPolicy;
-import com.android.tools.r8.verticalclassmerging.policies.SuccessfulVirtualMethodResolutionInTargetPolicy;
import com.android.tools.r8.verticalclassmerging.policies.VerticalClassMergerPolicyWithPreprocessing;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
@@ -50,48 +26,21 @@
private final AppView<AppInfoWithLiveness> appView;
private final ImmediateProgramSubtypingInfo immediateSubtypingInfo;
- private final ClassMergerMode mode;
VerticalClassMergerPolicyExecutor(
- AppView<AppInfoWithLiveness> appView,
- ImmediateProgramSubtypingInfo immediateSubtypingInfo,
- ClassMergerMode mode) {
+ AppView<AppInfoWithLiveness> appView, ImmediateProgramSubtypingInfo immediateSubtypingInfo) {
this.appView = appView;
this.immediateSubtypingInfo = immediateSubtypingInfo;
- this.mode = mode;
}
ConnectedComponentVerticalClassMerger run(
- Set<DexProgramClass> connectedComponent, ExecutorService executorService, Timing timing)
+ Set<DexProgramClass> connectedComponent,
+ Collection<Policy> policies,
+ ExecutorService executorService,
+ Timing timing)
throws ExecutionException {
Collection<VerticalMergeGroup> groups =
createInitialMergeGroupsWithDeterministicOrder(connectedComponent);
- Collection<Policy> policies =
- List.of(
- new NoDirectlyInstantiatedClassesPolicy(appView),
- new NoInterfacesWithUnknownSubtypesPolicy(appView),
- new NoKeptClassesPolicy(appView),
- new SameFeatureSplitPolicy(appView),
- new SameStartupPartitionPolicy(appView),
- new NoServiceInterfacesPolicy(appView),
- new NoAnnotationClassesPolicy(),
- new NoNonSerializableClassIntoSerializableClassPolicy(appView),
- new SafeConstructorInliningPolicy(appView),
- new NoEnclosingMethodAttributesPolicy(),
- new NoInnerClassAttributesPolicy(),
- new SameNestPolicy(),
- new SameMainDexGroupPolicy(appView),
- new NoLockMergingPolicy(appView),
- new SameApiReferenceLevelPolicy(appView),
- new NoFieldResolutionChangesPolicy(appView),
- new NoMethodResolutionChangesPolicy(appView),
- new NoIllegalAccessesPolicy(appView),
- new NoClassInitializationChangesPolicy(appView),
- new NoInterfacesWithInvokeSpecialToDefaultMethodIntoClassPolicy(appView, mode),
- new NoInvokeSuperNoSuchMethodErrorsPolicy(appView),
- new SuccessfulVirtualMethodResolutionInTargetPolicy(appView),
- new NoAbstractMethodsOnAbstractClassesPolicy(appView),
- new NoNestedMergingPolicy());
groups = run(groups, policies, executorService, timing);
return new ConnectedComponentVerticalClassMerger(appView, groups);
}
@@ -121,7 +70,15 @@
VerticalClassMergerPolicyWithPreprocessing<T> policy,
LinkedList<VerticalMergeGroup> linkedGroups) {
T data = policy.preprocess(linkedGroups);
- linkedGroups.removeIf(group -> !policy.canMerge(group, data));
+ linkedGroups.removeIf(
+ group -> {
+ if (policy.canMerge(group, data)) {
+ return false;
+ }
+ assert policy.recordRemovedClassesForDebugging(
+ group.getSource().isInterface(), group.size(), Collections.emptyList());
+ return true;
+ });
return linkedGroups;
}
}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerPolicyScheduler.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerPolicyScheduler.java
new file mode 100644
index 0000000..6d58316
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerPolicyScheduler.java
@@ -0,0 +1,64 @@
+// Copyright (c) 2024, 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.verticalclassmerging;
+
+import com.android.tools.r8.classmerging.ClassMergerMode;
+import com.android.tools.r8.classmerging.Policy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.verticalclassmerging.policies.NoAbstractMethodsOnAbstractClassesPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoAnnotationClassesPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoClassInitializationChangesPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoDirectlyInstantiatedClassesPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoEnclosingMethodAttributesPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoFieldResolutionChangesPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoIllegalAccessesPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoInnerClassAttributesPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoInterfacesWithInvokeSpecialToDefaultMethodIntoClassPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoInterfacesWithUnknownSubtypesPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoInvokeSuperNoSuchMethodErrorsPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoKeptClassesPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoLockMergingPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoMethodResolutionChangesPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoNestedMergingPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoNonSerializableClassIntoSerializableClassPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.NoServiceInterfacesPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.SameApiReferenceLevelPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.SameFeatureSplitPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.SameMainDexGroupPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.SameNestPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.SameStartupPartitionPolicy;
+import com.android.tools.r8.verticalclassmerging.policies.SuccessfulVirtualMethodResolutionInTargetPolicy;
+import java.util.List;
+
+public class VerticalClassMergerPolicyScheduler {
+
+ public static List<Policy> getPolicies(
+ AppView<AppInfoWithLiveness> appView, ClassMergerMode mode) {
+ return List.of(
+ new NoDirectlyInstantiatedClassesPolicy(appView),
+ new NoInterfacesWithUnknownSubtypesPolicy(appView),
+ new NoKeptClassesPolicy(appView),
+ new SameFeatureSplitPolicy(appView),
+ new SameStartupPartitionPolicy(appView),
+ new NoServiceInterfacesPolicy(appView),
+ new NoAnnotationClassesPolicy(),
+ new NoNonSerializableClassIntoSerializableClassPolicy(appView),
+ new NoEnclosingMethodAttributesPolicy(),
+ new NoInnerClassAttributesPolicy(),
+ new SameNestPolicy(),
+ new SameMainDexGroupPolicy(appView),
+ new NoLockMergingPolicy(appView),
+ new SameApiReferenceLevelPolicy(appView),
+ new NoFieldResolutionChangesPolicy(appView),
+ new NoMethodResolutionChangesPolicy(appView),
+ new NoIllegalAccessesPolicy(appView),
+ new NoClassInitializationChangesPolicy(appView),
+ new NoInterfacesWithInvokeSpecialToDefaultMethodIntoClassPolicy(appView, mode),
+ new NoInvokeSuperNoSuchMethodErrorsPolicy(appView),
+ new SuccessfulVirtualMethodResolutionInTargetPolicy(appView),
+ new NoAbstractMethodsOnAbstractClassesPolicy(appView),
+ new NoNestedMergingPolicy());
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java
index c6c1f4d..dc6763b 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/VerticalClassMergerTreeFixer.java
@@ -3,10 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.verticalclassmerging;
+import com.android.tools.r8.classmerging.ClassMergerSharedData;
import com.android.tools.r8.classmerging.ClassMergerTreeFixer;
-import com.android.tools.r8.classmerging.SyntheticArgumentClass;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.Timing;
import java.util.List;
@@ -23,15 +22,13 @@
VerticalClassMergerTreeFixer(
AppView<AppInfoWithLiveness> appView,
- ProfileCollectionAdditions profileCollectionAdditions,
- SyntheticArgumentClass syntheticArgumentClass,
+ ClassMergerSharedData classMergerSharedData,
VerticalClassMergerResult verticalClassMergerResult) {
super(
appView,
+ classMergerSharedData,
VerticalClassMergerGraphLens.Builder.createBuilderForFixup(verticalClassMergerResult),
- verticalClassMergerResult.getVerticallyMergedClasses(),
- profileCollectionAdditions,
- syntheticArgumentClass);
+ verticalClassMergerResult.getVerticallyMergedClasses());
this.synthesizedBridges = verticalClassMergerResult.getSynthesizedBridges();
}
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/policies/NoKeptClassesPolicy.java b/src/main/java/com/android/tools/r8/verticalclassmerging/policies/NoKeptClassesPolicy.java
index c9b0cb5..f9a91a3 100644
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/policies/NoKeptClassesPolicy.java
+++ b/src/main/java/com/android/tools/r8/verticalclassmerging/policies/NoKeptClassesPolicy.java
@@ -20,23 +20,23 @@
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.List;
import java.util.Set;
-public class NoKeptClassesPolicy
- extends VerticalClassMergerPolicyWithPreprocessing<Set<DexProgramClass>> {
+public class NoKeptClassesPolicy extends VerticalClassMergerPolicy {
private final AppView<AppInfoWithLiveness> appView;
private final InternalOptions options;
+ private final Set<DexProgramClass> keptClasses;
public NoKeptClassesPolicy(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
this.options = appView.options();
+ this.keptClasses = getPinnedClasses();
}
@Override
- public boolean canMerge(VerticalMergeGroup group, Set<DexProgramClass> keptClasses) {
+ public boolean canMerge(VerticalMergeGroup group) {
DexProgramClass sourceClass = group.getSource();
return appView.getKeepInfo(sourceClass).isVerticalClassMergingAllowed(options)
&& !keptClasses.contains(sourceClass);
@@ -47,11 +47,6 @@
return "NoKeptClassesPolicy";
}
- @Override
- public Set<DexProgramClass> preprocess(Collection<VerticalMergeGroup> groups) {
- return getPinnedClasses();
- }
-
// Returns a set of types that must not be merged into other types.
private Set<DexProgramClass> getPinnedClasses() {
Set<DexProgramClass> pinnedClasses = Sets.newIdentityHashSet();
diff --git a/src/main/java/com/android/tools/r8/verticalclassmerging/policies/SafeConstructorInliningPolicy.java b/src/main/java/com/android/tools/r8/verticalclassmerging/policies/SafeConstructorInliningPolicy.java
deleted file mode 100644
index 15bcf11..0000000
--- a/src/main/java/com/android/tools/r8/verticalclassmerging/policies/SafeConstructorInliningPolicy.java
+++ /dev/null
@@ -1,72 +0,0 @@
-// 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.verticalclassmerging.policies;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.shaking.MainDexInfo;
-import com.android.tools.r8.utils.TraversalContinuation;
-import com.android.tools.r8.verticalclassmerging.VerticalMergeGroup;
-import com.google.common.collect.Iterables;
-
-public class SafeConstructorInliningPolicy extends VerticalClassMergerPolicy {
-
- private final AppView<AppInfoWithLiveness> appView;
- private final MainDexInfo mainDexInfo;
-
- public SafeConstructorInliningPolicy(AppView<AppInfoWithLiveness> appView) {
- this.appView = appView;
- this.mainDexInfo = appView.appInfo().getMainDexInfo();
- }
-
- @Override
- public boolean canMerge(VerticalMergeGroup group) {
- DexProgramClass sourceClass = group.getSource();
- DexProgramClass targetClass = group.getTarget();
- // If there is a constructor in the target, make sure that all source constructors can be
- // inlined.
- if (Iterables.isEmpty(targetClass.programInstanceInitializers())) {
- return true;
- }
- TraversalContinuation<?, ?> result =
- sourceClass.traverseProgramInstanceInitializers(
- method -> TraversalContinuation.breakIf(disallowInlining(method, targetClass)));
- return result.shouldContinue();
- }
-
- private boolean disallowInlining(ProgramMethod method, DexProgramClass context) {
- if (!appView.options().inlinerOptions().enableInlining) {
- return true;
- }
- Code code = method.getDefinition().getCode();
- if (code.isCfCode()) {
- CfCode cfCode = code.asCfCode();
- ConstraintWithTarget constraint =
- cfCode.computeInliningConstraint(appView, appView.graphLens(), method);
- if (constraint.isNever()) {
- return true;
- }
- // Constructors can have references beyond the root main dex classes. This can increase the
- // size of the main dex dependent classes and we should bail out.
- if (mainDexInfo.disallowInliningIntoContext(appView, context, method)) {
- return true;
- }
- return false;
- }
- if (code.isDefaultInstanceInitializerCode()) {
- return false;
- }
- return true;
- }
-
- @Override
- public String getName() {
- return "SafeConstructorInliningPolicy";
- }
-}
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/ResourceShrinkerImpl.kt b/src/resourceshrinker/java/com/android/build/shrinker/ResourceShrinkerImpl.kt
index d8f6fa2..d404e2e6 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/ResourceShrinkerImpl.kt
+++ b/src/resourceshrinker/java/com/android/build/shrinker/ResourceShrinkerImpl.kt
@@ -171,7 +171,9 @@
private fun removeResourceUnusedTableEntries(zis: InputStream,
zos: JarOutputStream,
srcEntry: ZipEntry) {
- val resourceIdsToRemove = unused.map { resource -> resource.value }
+ val resourceIdsToRemove = unused
+ .filterNot { it.type == ResourceType.ID }
+ .map { resource -> resource.value }
val shrunkenResourceTable = Resources.ResourceTable.parseFrom(zis)
.nullOutEntriesWithIds(resourceIdsToRemove)
val bytes = shrunkenResourceTable.toByteArray()
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/LegacyResourceShrinker.java b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/LegacyResourceShrinker.java
index ab97ce2..f37d381 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/LegacyResourceShrinker.java
+++ b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/LegacyResourceShrinker.java
@@ -24,6 +24,7 @@
import com.android.ide.common.resources.ResourcesUtil;
import com.android.ide.common.resources.usage.ResourceStore;
import com.android.ide.common.resources.usage.ResourceUsageModel.Resource;
+import com.android.resources.ResourceType;
import com.android.tools.r8.FeatureSplit;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
@@ -210,10 +211,14 @@
R8ResourceShrinkerModel model,
boolean exactMatchingOfStyleablesAndAttr) {
if (!exactMatchingOfStyleablesAndAttr) {
- return unusedResources.stream().map(resource -> resource.value).collect(Collectors.toList());
+ return unusedResources.stream()
+ .filter(s -> s.type != ResourceType.ID)
+ .map(resource -> resource.value)
+ .collect(Collectors.toList());
}
return model.getResourceStore().getResources().stream()
.filter(r -> !r.isReachable())
+ .filter(r -> r.type != ResourceType.ID)
.map(r -> r.value)
.collect(Collectors.toList());
}
diff --git a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
index 088547e..5e0a8ae 100644
--- a/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
+++ b/src/resourceshrinker/java/com/android/build/shrinker/r8integration/R8ResourceShrinkerState.java
@@ -51,8 +51,8 @@
super(debugReporter, supportMultipackages);
}
- public Map<Integer, String> getStringResourcesWithSingleValue() {
- return stringResourcesWithSingleValue;
+ public String getSingleStringValueOrNull(int id) {
+ return stringResourcesWithSingleValue.get(id);
}
// Similar to instantiation in ProtoResourceTableGatherer, but using an inputstream.
diff --git a/src/test/java/com/android/tools/r8/ProguardVersion.java b/src/test/java/com/android/tools/r8/ProguardVersion.java
index b3ff1a6..28f0cf6 100644
--- a/src/test/java/com/android/tools/r8/ProguardVersion.java
+++ b/src/test/java/com/android/tools/r8/ProguardVersion.java
@@ -13,7 +13,8 @@
V5_2_1("5.2.1"),
V6_0_1("6.0.1"),
V7_0_0("7.0.0"),
- V7_3_2("7.3.2");
+ V7_3_2("7.3.2"),
+ V7_4_1("7.4.1");
private final String version;
@@ -22,7 +23,7 @@
}
public static ProguardVersion getLatest() {
- return V7_3_2;
+ return V7_4_1;
}
public Path getProguardScript() {
@@ -39,7 +40,7 @@
private Path getScriptDirectory() {
Path scriptDirectory = Paths.get(ToolHelper.THIRD_PARTY_DIR).resolve("proguard");
- if (this == V7_0_0 || this == V7_3_2) {
+ if (version.startsWith("7.")) {
scriptDirectory = scriptDirectory.resolve("proguard-" + version).resolve("bin");
} else {
scriptDirectory = scriptDirectory.resolve("proguard" + version).resolve("bin");
diff --git a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
index 384043c..228536e 100644
--- a/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunSmaliTestsTest.java
@@ -36,7 +36,7 @@
@Parameters(name = "{0}: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withDexRuntimes().withAllApiLevels().build(), tests.keySet());
+ getTestParameters().withDexRuntimesAndAllApiLevels().build(), tests.keySet());
}
private static final String SMALI_DIR = ToolHelper.SMALI_BUILD_DIR;
@@ -106,6 +106,8 @@
tests = testsBuilder.build();
}
+ private static Set<String> invokeErrors = ImmutableSet.of("bad-codegen", "illegal-invokes");
+
private static Map<String, Set<String>> missingClasses =
ImmutableMap.of(
"try-catch", ImmutableSet.of("test.X"),
@@ -244,6 +246,10 @@
.addProgramDexFileData(Files.readAllBytes(originalDexFile))
.applyIf(testJarExists, p -> p.addProgramFiles(testJar))
.addDontWarn(missingClasses.getOrDefault(directoryName, Collections.emptySet()))
+ .addOptionsModification(
+ options ->
+ options.getTestingOptions().allowInvokeErrors =
+ invokeErrors.contains(directoryName))
.setMinApi(parameters)
.compile()
.run(parameters.getRuntime(), "Test")
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index f803d78..c9b9401 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -946,4 +946,12 @@
return addProgramClassFileData(testResource.getRClass().getClassFileData());
}
+ public T setAndroidResourcesFromPath(Path input, Path output) {
+ resourceShrinkerOutput = output;
+ getBuilder()
+ .setAndroidResourceProvider(
+ new ArchiveProtoAndroidResourceProvider(input, new PathOrigin(input)));
+ getBuilder().setAndroidResourceConsumer(new ArchiveProtoAndroidResourceConsumer(output, input));
+ return self();
+ }
}
diff --git a/src/test/java/com/android/tools/r8/TestParameters.java b/src/test/java/com/android/tools/r8/TestParameters.java
index 1792e97..fc90c26 100644
--- a/src/test/java/com/android/tools/r8/TestParameters.java
+++ b/src/test/java/com/android/tools/r8/TestParameters.java
@@ -280,7 +280,7 @@
"No need to use is/assumeR8TestParameters() when not using api levels for CF",
isCfRuntime() && apiLevel == null);
assertTrue(apiLevel != null || representativeApiLevelForRuntime);
- return isDexRuntime() || representativeApiLevelForRuntime;
+ return (isDexRuntime() || representativeApiLevelForRuntime) && !isNoneRuntime();
}
public TestParameters assumeRuntimeTestParameters() {
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 9b4e4fd..2c07a9a 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -4,6 +4,8 @@
package com.android.tools.r8;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.dexsplitter.SplitterTestBase.RunInterface;
import com.android.tools.r8.references.ClassReference;
@@ -480,6 +482,10 @@
public abstract T addApplyMapping(String proguardMap);
+ public T addApplyMapping(Path proguardMap) throws IOException {
+ return addApplyMapping(FileUtils.readTextFile(proguardMap, UTF_8));
+ }
+
public final T addAlwaysClassInlineAnnotation() {
return addTestingAnnotation(AlwaysClassInline.class);
}
diff --git a/src/test/java/com/android/tools/r8/androidresources/AlwaysKeepIDsInLegacyMode.java b/src/test/java/com/android/tools/r8/androidresources/AlwaysKeepIDsInLegacyMode.java
new file mode 100644
index 0000000..605a771
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/androidresources/AlwaysKeepIDsInLegacyMode.java
@@ -0,0 +1,79 @@
+// Copyright (c) 2024, 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.androidresources;
+
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResource;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResourceBuilder;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.util.List;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+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 AlwaysKeepIDsInLegacyMode extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameter(1)
+ public boolean optimized;
+
+ @Parameters(name = "{0}, optimized: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDefaultDexRuntime().withAllApiLevels().build(),
+ BooleanUtils.values());
+ }
+
+ public static AndroidTestResource getTestResources(TemporaryFolder temp) throws Exception {
+ return new AndroidTestResourceBuilder()
+ .withSimpleManifestAndAppNameString()
+ .addRClassInitializeWithDefaultValues(R.string.class, R.id.class)
+ .build(temp);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .setMinApi(parameters)
+ .addProgramClasses(FooBar.class)
+ .addAndroidResources(getTestResources(temp))
+ .addKeepMainRule(FooBar.class)
+ .applyIf(optimized, R8TestBuilder::enableOptimizedShrinking)
+ .compile()
+ .inspectShrunkenResources(
+ resourceTableInspector -> {
+ resourceTableInspector.assertContainsResourceWithName("string", "foo");
+ // The id resource should not be removed in any mode, even though there are no
+ // references to it.
+ resourceTableInspector.assertContainsResourceWithName("id", "the_id");
+ })
+ .run(parameters.getRuntime(), FooBar.class)
+ .assertSuccess();
+ }
+
+ public static class FooBar {
+
+ public static void main(String[] args) {
+ System.out.println(R.string.foo);
+ }
+ }
+
+ public static class R {
+ public static class string {
+ public static int foo;
+ }
+
+ public static class id {
+ public static int the_id;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java b/src/test/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
index e0a3a59..5040ed3 100644
--- a/src/test/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
+++ b/src/test/java/com/android/tools/r8/androidresources/AndroidResourceTestingUtils.java
@@ -52,7 +52,8 @@
STRING,
DRAWABLE,
STYLEABLE,
- XML;
+ XML,
+ ID;
public static RClassType fromClass(Class clazz) {
String type = rClassWithoutNamespaceAndOuter(clazz).substring(2);
@@ -119,6 +120,13 @@
+ " path=\"let/it/be\" />\n"
+ "</paths>";
+ public static String XML_FILE_WITH_ID =
+ "<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ + " xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n"
+ + " xmlns:tools=\"http://schemas.android.com/tools\">\n"
+ + " <item android:id=\"@+id/%s\"/>\n"
+ + "</menu>";
+
public static class AndroidTestRClass {
// The original aapt2 generated R.java class
private final Path javaFilePath;
@@ -256,6 +264,7 @@
public static class AndroidTestResourceBuilder {
private String manifest;
private final Map<String, String> stringValues = new TreeMap<>();
+ private final Set<String> idValues = new TreeSet<>();
private final Set<String> stringValuesWithExtraLanguage = new TreeSet<>();
private final Map<String, String> overlayableValues = new TreeMap<>();
private final Map<String, Integer> styleables = new TreeMap<>();
@@ -285,6 +294,9 @@
// Add 4 different values, i.e., the array will be 4 integers.
addStyleable(name, 4);
}
+ if (rClassType == RClassType.ID) {
+ addIdValue(name);
+ }
}
}
return this;
@@ -317,6 +329,11 @@
return this;
}
+ AndroidTestResourceBuilder addIdValue(String name) {
+ xmlFiles.put(name + ".xml", String.format(XML_FILE_WITH_ID, name));
+ return this;
+ }
+
AndroidTestResourceBuilder addExtraLanguageString(String name) {
stringValuesWithExtraLanguage.add(name);
return this;
diff --git a/src/test/java/com/android/tools/r8/androidresources/ResourceIDCannonicalizationTest.java b/src/test/java/com/android/tools/r8/androidresources/ResourceIDCannonicalizationTest.java
new file mode 100644
index 0000000..60ce942
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/androidresources/ResourceIDCannonicalizationTest.java
@@ -0,0 +1,87 @@
+// Copyright (c) 2024, 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.androidresources;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResource;
+import com.android.tools.r8.androidresources.AndroidResourceTestingUtils.AndroidTestResourceBuilder;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+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 ResourceIDCannonicalizationTest extends TestBase {
+ public static final int EXPECTED_RESOURCE_NUMBER = 0x7f010001;
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection parameters() {
+ return getTestParameters().withDefaultDexRuntime().withAllApiLevels().build();
+ }
+
+ public static AndroidTestResource getTestResources(TemporaryFolder temp) throws Exception {
+ return new AndroidTestResourceBuilder()
+ .withSimpleManifestAndAppNameString()
+ .addRClassInitializeWithDefaultValues(R.string.class)
+ .build(temp);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .setMinApi(parameters)
+ .addProgramClasses(FooBar.class)
+ .addAndroidResources(getTestResources(temp))
+ .addKeepMainRule(FooBar.class)
+ .enableOptimizedShrinking()
+ .compile()
+ .inspect(
+ codeInspector -> {
+ // We should canonicalize the resource numbers separately from the normal const
+ // numbers.
+ // This implies that the output have two distinct const numbers with the same value.
+ long constNumbers =
+ codeInspector
+ .clazz(FooBar.class)
+ .mainMethod()
+ .streamInstructions()
+ .filter(i -> i.isConstNumber(EXPECTED_RESOURCE_NUMBER))
+ .count();
+ assertEquals(2, constNumbers);
+ })
+ .inspectShrunkenResources(
+ resourceTableInspector -> {
+ resourceTableInspector.assertContainsResourceWithName("string", "foo");
+ });
+ }
+
+ public static class FooBar {
+
+ public static void main(String[] args) {
+ if (System.currentTimeMillis() == 0) {
+ System.out.println(EXPECTED_RESOURCE_NUMBER);
+ System.out.println(R.string.foo);
+ System.out.println(EXPECTED_RESOURCE_NUMBER);
+ System.out.println(R.string.foo);
+ System.out.println(EXPECTED_RESOURCE_NUMBER);
+ System.out.println(EXPECTED_RESOURCE_NUMBER);
+ }
+ }
+ }
+
+ public static class R {
+ public static class string {
+ public static int foo;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/androidresources/optimizedshrinking/TestOptimizedShrinking.java b/src/test/java/com/android/tools/r8/androidresources/optimizedshrinking/TestOptimizedShrinking.java
index 662d00f..74c7102 100644
--- a/src/test/java/com/android/tools/r8/androidresources/optimizedshrinking/TestOptimizedShrinking.java
+++ b/src/test/java/com/android/tools/r8/androidresources/optimizedshrinking/TestOptimizedShrinking.java
@@ -71,7 +71,7 @@
resourceTableInspector.assertContainsResourceWithName("drawable", "foobar");
// In debug mode legacy shrinker will not attribute our $R inner class as an R class
// (this is only used for testing, _real_ R classes are not inner classes.
- if (!debug || optimized) {
+ if (!debug) {
resourceTableInspector.assertDoesNotContainResourceWithName(
"string", "unused_string");
resourceTableInspector.assertDoesNotContainResourceWithName(
@@ -107,7 +107,7 @@
// In optimized mode we track these correctly, so we should not unconditionally keep
// all attributes.
- if (optimized) {
+ if (optimized && !debug) {
resourceTableInspector.assertDoesNotContainResourceWithName(
"attr", "attr_unused_styleable" + i);
} else {
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java
index f2db164..3e84ae4 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentIf;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverClassInline;
@@ -33,7 +34,7 @@
.inspect(
codeInspector -> {
assertThat(codeInspector.clazz(A.class), isAbsent());
- assertThat(codeInspector.clazz(B.class), isAbsent());
+ assertThat(codeInspector.clazz(B.class), isPresentIf(parameters.isCfRuntime()));
assertThat(codeInspector.clazz(C.class), isPresent());
assertThat(codeInspector.clazz(D.class), isAbsent());
});
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java
index 7dee4de..e6e1d11 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java
@@ -45,7 +45,8 @@
assertThat(firstInitSubject, isPresent());
assertThat(firstInitSubject, writesInstanceField(classIdFieldSubject.getDexField()));
- MethodSubject otherInitSubject = aClassSubject.init("int", "int");
+ MethodSubject otherInitSubject =
+ aClassSubject.init("int", parameters.isCfRuntime() ? "java.lang.Object" : "int");
assertThat(otherInitSubject, isPresent());
assertThat(otherInitSubject, writesInstanceField(classIdFieldSubject.getDexField()));
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java
index 2be25d3..ecb49d6 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java
@@ -45,7 +45,8 @@
assertThat(firstInitSubject, isPresent());
assertThat(firstInitSubject, writesInstanceField(classIdFieldSubject.getDexField()));
- MethodSubject otherInitSubject = aClassSubject.init("int", "int");
+ MethodSubject otherInitSubject =
+ aClassSubject.init("int", parameters.isCfRuntime() ? "java.lang.Object" : "int");
assertThat(otherInitSubject, isPresent());
assertThat(otherInitSubject, writesInstanceField(classIdFieldSubject.getDexField()));
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentAndAssignmentOrderMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentAndAssignmentOrderMergingTest.java
index f319d54..c8b807f 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentAndAssignmentOrderMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentAndAssignmentOrderMergingTest.java
@@ -53,9 +53,10 @@
ClassSubject aClassSubject = inspector.clazz(A.class);
assertThat(aClassSubject, isPresent());
// TODO(b/189296638): Enable constructor merging by changing the constructor
- // arguments.
+ // arguments.
assertEquals(
- 2, aClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
+ parameters.isCfRuntime() ? 4 : 2,
+ aClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
})
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("CD", "CD");
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentOrderMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentOrderMergingTest.java
index ba0b57d..19ed979 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentOrderMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndDifferentArgumentOrderMergingTest.java
@@ -54,9 +54,10 @@
assertThat(aClassSubject, isPresent());
// TODO(b/189296638): Enable constructor merging by changing the constructor
- // arguments.
+ // arguments.
assertEquals(
- 2, aClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
+ parameters.isCfRuntime() ? 4 : 2,
+ aClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
})
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("C0", "D1");
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndExtraNullsMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndExtraNullsMergingTest.java
index 5e15d11..fa03ace 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndExtraNullsMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/EquivalentConstructorsWithClassIdAndExtraNullsMergingTest.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.classmerging.horizontal;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentIf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
@@ -53,12 +54,13 @@
ClassSubject aClassSubject = inspector.clazz(A.class);
assertThat(aClassSubject, isPresent());
assertEquals(
- 2, aClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
+ parameters.isCfRuntime() ? 3 : 2,
+ aClassSubject.allMethods(FoundMethodSubject::isInstanceInitializer).size());
+ assertThat(aClassSubject.init("java.lang.Object", "int"), isPresent());
+ assertThat(aClassSubject.init("java.lang.Object", "int", "int"), isPresent());
assertThat(
- aClassSubject.method("void", "<init>", "java.lang.Object", "int"), isPresent());
- assertThat(
- aClassSubject.method("void", "<init>", "java.lang.Object", "int", "int"),
- isPresent());
+ aClassSubject.init("java.lang.Object", "int", "java.lang.Object"),
+ isPresentIf(parameters.isCfRuntime()));
})
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("C", "0", "C", "D");
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java
index 0d09fd4..0d912b3 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java
@@ -26,9 +26,9 @@
.addProgramClasses(C.class)
.addProgramClasses(D.class)
.addKeepMainRule(Main.class)
- .allowAccessModification(false)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
+ .enableNoAccessModificationAnnotationsForMembers()
.setMinApi(parameters)
.compile()
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java
index f3335fa..fe4a7d8 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java
@@ -4,9 +4,9 @@
package com.android.tools.r8.classmerging.horizontal;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.core.IsNot.not;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
@@ -23,6 +23,9 @@
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
+ .addHorizontallyMergedClassesInspector(
+ inspector ->
+ inspector.assertIsCompleteMergeGroup(A.class, B.class).assertNoOtherClassesMerged())
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters)
@@ -30,9 +33,9 @@
.assertSuccessWithOutputLines("5", "foo hello", "B", "bar world", "5", "B")
.inspect(
codeInspector -> {
- assertThat(codeInspector.clazz(Parent.class), isPresent());
+ assertThat(codeInspector.clazz(Parent.class), isAbsent());
assertThat(codeInspector.clazz(A.class), isPresent());
- assertThat(codeInspector.clazz(B.class), not(isPresent()));
+ assertThat(codeInspector.clazz(B.class), isAbsent());
});
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/C.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/C.java
index f2220c0..003bc93 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/C.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/C.java
@@ -6,11 +6,14 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoAccessModification;
@NeverClassInline
public class C {
- String field;
+ @NoAccessModification String field;
+
+ @NoAccessModification
protected C(String field) {
this.field = field;
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/ExceptionTablesTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/ExceptionTablesTest.java
index 1ba7dcf..4025566 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/ExceptionTablesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/ExceptionTablesTest.java
@@ -4,18 +4,19 @@
package com.android.tools.r8.classmerging.vertical;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.android.tools.r8.utils.codeinspector.TypeSubject;
import com.android.tools.r8.utils.codeinspector.VerticallyMergedClassesInspector;
+import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.Test;
@@ -28,13 +29,17 @@
@RunWith(Parameterized.class)
public class ExceptionTablesTest extends VerticalClassMergerTestBase {
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return TestBase.getTestParameters().withAllRuntimesAndApiLevels().build();
+ private final boolean disableInitial;
+
+ @Parameters(name = "{1}, disable initial: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(), TestBase.getTestParameters().withAllRuntimesAndApiLevels().build());
}
- public ExceptionTablesTest(TestParameters parameters) {
+ public ExceptionTablesTest(boolean disableInitial, TestParameters parameters) {
super(parameters);
+ this.disableInitial = disableInitial;
}
@Test
@@ -42,7 +47,14 @@
testForR8(parameters.getBackend())
.addInnerClasses(ExceptionTablesTest.class)
.addKeepMainRule(TestClass.class)
- .addVerticallyMergedClassesInspector(this::inspectVerticallyMergedClasses)
+ .applyIf(
+ disableInitial,
+ testBuilder ->
+ testBuilder.addOptionsModification(
+ options -> options.getVerticalClassMergerOptions().disableInitial()),
+ testBuilder ->
+ testBuilder.addVerticallyMergedClassesInspector(
+ this::inspectVerticallyMergedClasses))
.setMinApi(parameters)
.compile()
.inspect(this::inspect)
@@ -58,8 +70,8 @@
assertThat(inspector.clazz(TestClass.class), isPresent());
assertThat(inspector.clazz(ExceptionB.class), isPresent());
assertThat(inspector.clazz(Exception2.class), isPresent());
- assertThat(inspector.clazz(ExceptionA.class), not(isPresent()));
- assertThat(inspector.clazz(Exception1.class), not(isPresent()));
+ assertThat(inspector.clazz(ExceptionA.class), isAbsent());
+ assertThat(inspector.clazz(Exception1.class), isAbsent());
// Check that only two exception guard types remain.
MethodSubject mainMethodSubject = inspector.clazz(TestClass.class).mainMethod();
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/InvokeStaticToInterfaceVerticalClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/InvokeStaticToInterfaceVerticalClassMergerTest.java
new file mode 100644
index 0000000..ba6a83c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/InvokeStaticToInterfaceVerticalClassMergerTest.java
@@ -0,0 +1,96 @@
+// Copyright (c) 2024, 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.classmerging.vertical;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentIf;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+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 InvokeStaticToInterfaceVerticalClassMergerTest extends TestBase {
+
+ @Parameter(0)
+ public boolean disableInitialRoundOfVerticalClassMerging;
+
+ @Parameter(1)
+ public TestParameters parameters;
+
+ @Parameters(name = "{1}, disable initial: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .applyIf(
+ disableInitialRoundOfVerticalClassMerging,
+ b ->
+ b.addOptionsModification(
+ options -> options.getVerticalClassMergerOptions().disableInitial()))
+ .enableInliningAnnotations()
+ .setMinApi(parameters)
+ .compile()
+ .inspect(
+ inspector -> {
+ // Check interface is removed due to class merging and the static interface method is
+ // present on the subclass except when moved as a result of static interface method
+ // desugaring.
+ ClassSubject iClassSubject = inspector.clazz(I.class);
+ assertThat(iClassSubject, isAbsent());
+
+ ClassSubject aClassSubject = inspector.clazz(A.class);
+ assertThat(aClassSubject, isPresent());
+
+ MethodSubject fooMethodSubject = aClassSubject.uniqueMethodWithOriginalName("hello");
+ assertThat(
+ fooMethodSubject,
+ isPresentIf(parameters.canUseDefaultAndStaticInterfaceMethods()));
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello, world!");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ // After vertical class merging, invoke should have the is-interface bit set to false.
+ I.hello();
+ System.out.println(new A());
+ }
+ }
+
+ interface I {
+
+ @NeverInline
+ static void hello() {
+ System.out.print("Hello");
+ }
+ }
+
+ static class A implements I {
+
+ @Override
+ public String toString() {
+ return ", world!";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerInitTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerInitTest.java
index 466e9fd..f1b4b6a 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerInitTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerInitTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.classmerging.vertical;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -13,13 +14,12 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.InternalOptions.InlinerOptions;
-import com.android.tools.r8.utils.codeinspector.VerticallyMergedClassesInspector;
import java.io.IOException;
import java.util.concurrent.ExecutionException;
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)
@@ -28,38 +28,29 @@
// force-inlining, so the renamed constructor broke the init chain.
public class VerticalClassMergerInitTest extends TestBase {
- private final TestParameters parameters;
+ @Parameter(0)
+ public TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters().withDexRuntimes().build();
- }
-
- public VerticalClassMergerInitTest(TestParameters parameters) {
- this.parameters = parameters;
+ return getTestParameters().withDexRuntimes().withApiLevel(AndroidApiLevel.K_WATCH).build();
}
@Test
public void testMergingClassWithConstructorNotInMainDex()
throws IOException, CompilationFailedException, ExecutionException {
- testForR8(parameters.getBackend())
+ testForR8Compat(parameters.getBackend())
.addInnerClasses(VerticalClassMergerInitTest.class)
.addKeepMainRule(Main.class)
.addMainDexRules("-keep class " + Main.class.getTypeName())
- .enableNeverClassInliningAnnotations()
- .setMinApi(AndroidApiLevel.K_WATCH)
- .addOptionsModification(
- options -> {
- options.forceProguardCompatibility = true;
- })
- // The initializer is small in this example so only allow FORCE inlining.
- .addOptionsModification(InlinerOptions::setOnlyForceInlining)
.addVerticallyMergedClassesInspector(
- VerticallyMergedClassesInspector::assertNoClassesMerged)
+ inspector -> inspector.assertMergedIntoSubtype(Base.class))
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters)
.compile()
.inspect(
inspector -> {
- assertThat(inspector.clazz(Base.class), isPresent());
+ assertThat(inspector.clazz(Base.class), isAbsent());
assertThat(inspector.clazz(Child.class), isPresent());
})
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java
index 4a1e82c..121a0f3 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDexShrinkingFieldsTest.java
@@ -89,7 +89,11 @@
.setMinApi(parameters)
.addOptionsModification(options -> options.emitNestAnnotationsInDex = true)
.compile()
- .inspect(inspector -> assertEquals(1, inspector.allClasses().size()))
+ // TODO(b/136250031, b/136458109): Allow inlining of constructors into constructors when
+ // compiling to CF.
+ .inspect(
+ inspector ->
+ assertEquals(parameters.isCfRuntime() ? 2 : 1, inspector.allClasses().size()))
.run(parameters.getRuntime(), "Host")
.assertSuccessWithOutput(EXPECTED_OUTPUT);
}
diff --git a/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/InvokeStaticInterfaceNestedTest.java b/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/InvokeStaticInterfaceNestedTest.java
index a15add8..f683135 100644
--- a/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/InvokeStaticInterfaceNestedTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/staticinterfacemethod/InvokeStaticInterfaceNestedTest.java
@@ -5,39 +5,43 @@
package com.android.tools.r8.desugar.staticinterfacemethod;
import static com.android.tools.r8.desugar.staticinterfacemethod.InvokeStaticInterfaceNestedTest.Library.foo;
-import static org.junit.Assert.assertThrows;
+import static com.android.tools.r8.utils.codeinspector.AssertUtils.assertFailsCompilationIf;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.DesugarTestConfiguration;
-import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRunResult;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.BooleanUtils;
+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 InvokeStaticInterfaceNestedTest extends TestBase {
- private final TestParameters parameters;
- private final String UNEXPECTED_SUCCESS = "Hello World!";
+ private static final String UNEXPECTED_SUCCESS = "Hello World!";
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
+ @Parameter(0)
+ public boolean allowInvokeErrors;
+
+ @Parameter(1)
+ public TestParameters parameters;
+
+ @Parameters(name = "{1}, allow invalid invokes: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(),
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
}
- public InvokeStaticInterfaceNestedTest(TestParameters parameters) {
- this.parameters = parameters;
- }
-
- private void checkDexResult(TestRunResult<?> runResult, boolean isDesugared) {
+ private void inspectRunResult(TestRunResult<?> runResult, boolean isDesugared) {
boolean didDesugarInterfaceMethods =
isDesugared && !parameters.canUseDefaultAndStaticInterfaceMethodsWhenDesugaring();
if (parameters.isCfRuntime()) {
@@ -67,6 +71,7 @@
@Test
public void testDesugar() throws Exception {
+ assumeFalse(allowInvokeErrors);
testForDesugaring(parameters)
.addProgramClassFileData(
rewriteToUseNonInterfaceMethodReference(Main.class, "main"),
@@ -76,27 +81,27 @@
result ->
result.applyIf(
DesugarTestConfiguration::isDesugared,
- r -> checkDexResult(r, true),
- r -> checkDexResult(r, false)));
+ r -> inspectRunResult(r, true),
+ r -> inspectRunResult(r, false)));
}
@Test
public void testR8() throws Exception {
parameters.assumeR8TestParameters();
- R8FullTestBuilder testBuilder =
- testForR8(parameters.getBackend())
- .addProgramClassFileData(
- rewriteToUseNonInterfaceMethodReference(Main.class, "main"),
- rewriteToUseNonInterfaceMethodReference(Library.class, "foo"))
- .addKeepAllClassesRule()
- .setMinApi(parameters)
- .addKeepMainRule(Main.class);
- if (parameters.isDexRuntime()) {
- checkDexResult(testBuilder.run(parameters.getRuntime(), Main.class), true);
- } else {
- // TODO(b/166213037): Should not throw an error.
- assertThrows(CompilationFailedException.class, testBuilder::compile);
- }
+ assertFailsCompilationIf(
+ !allowInvokeErrors,
+ () ->
+ testForR8(parameters.getBackend())
+ .addProgramClassFileData(
+ rewriteToUseNonInterfaceMethodReference(Main.class, "main"),
+ rewriteToUseNonInterfaceMethodReference(Library.class, "foo"))
+ .addKeepAllClassesRule()
+ .addOptionsModification(
+ options -> options.getTestingOptions().allowInvokeErrors = allowInvokeErrors)
+ .setMinApi(parameters)
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .apply(runResult -> inspectRunResult(runResult, parameters.isDexRuntime())));
}
private byte[] rewriteToUseNonInterfaceMethodReference(Class<?> clazz, String methodName)
diff --git a/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialInterfaceWithBridge3Test.java b/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialInterfaceWithBridge3Test.java
index e070f46..0e3f590 100644
--- a/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialInterfaceWithBridge3Test.java
+++ b/src/test/java/com/android/tools/r8/graph/invokespecial/InvokeSpecialInterfaceWithBridge3Test.java
@@ -13,13 +13,13 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRunResult;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.StringUtils;
import java.io.IOException;
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)
@@ -27,25 +27,21 @@
private static final String EXPECTED = StringUtils.lines("Hello World!");
- private final TestParameters parameters;
+ @Parameter(0)
+ public TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimesAndApiLevels().build();
}
- public InvokeSpecialInterfaceWithBridge3Test(TestParameters parameters) {
- this.parameters = parameters;
- }
-
@Test
public void testRuntime() throws Exception {
- TestRunResult<?> result =
- testForRuntime(parameters.getRuntime(), parameters.getApiLevel())
- .addProgramClasses(I.class, A.class, Main.class)
- .addProgramClassFileData(getClassWithTransformedInvoked())
- .run(parameters.getRuntime(), Main.class)
- .apply(this::inspectRunResult);
+ testForRuntime(parameters)
+ .addProgramClasses(I.class, A.class, Main.class)
+ .addProgramClassFileData(getClassWithTransformedInvoked())
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::inspectRunResult);
}
private void inspectRunResult(SingleTestRunResult<?> runResult) {
@@ -77,6 +73,7 @@
.addProgramClasses(I.class, A.class, Main.class)
.addProgramClassFileData(getClassWithTransformedInvoked())
.addKeepMainRule(Main.class)
+ .addOptionsModification(options -> options.getTestingOptions().allowInvokeErrors = true)
.setMinApi(parameters)
.run(parameters.getRuntime(), Main.class)
.applyIf(
diff --git a/src/test/java/com/android/tools/r8/gson/GsonDefaultConstructorTest.java b/src/test/java/com/android/tools/r8/gson/GsonDefaultConstructorTest.java
index 9d0b65d..fd6deea 100644
--- a/src/test/java/com/android/tools/r8/gson/GsonDefaultConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/gson/GsonDefaultConstructorTest.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.ProguardVersion;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper.DexVm.Version;
-import com.android.tools.r8.gson.GsonNoDefaultConstructorTest.Data;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/sideeffect/NewObjectCanBePostponedTest.java b/src/test/java/com/android/tools/r8/ir/analysis/sideeffect/NewObjectCanBePostponedTest.java
new file mode 100644
index 0000000..12249de
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/analysis/sideeffect/NewObjectCanBePostponedTest.java
@@ -0,0 +1,59 @@
+// Copyright (c) 2024, 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.ir.analysis.sideeffect;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+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 NewObjectCanBePostponedTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters)
+ .compile()
+ .inspect(
+ inspector -> {
+ MethodSubject mainMethodSubject = inspector.clazz(Main.class).mainMethod();
+ assertThat(mainMethodSubject, isPresent());
+ assertTrue(mainMethodSubject.getMethod().getCode().isEmptyVoidMethod());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithEmptyOutput();
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ Object o = A.f;
+ }
+ }
+
+ static class A {
+
+ static final Object f = new Object();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
index 93ad7a7..eff9d7a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/ConstantRemovalTest.java
@@ -27,7 +27,6 @@
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.regalloc.LinearScanRegisterAllocator;
import com.android.tools.r8.ir.regalloc.LiveIntervals;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.synthesis.SyntheticItems.GlobalSyntheticsStrategy;
import com.android.tools.r8.utils.InternalOptions;
import java.util.LinkedList;
@@ -166,7 +165,6 @@
new NumberGenerator(),
basicBlockNumberGenerator,
IRMetadata.unknown(),
- Origin.unknown(),
MethodConversionOptions.nonConverting());
PeepholeOptimizer.optimize(appView, code, new MockLinearScanRegisterAllocator(appView, code));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
index 18c5121..997f0e0 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/TrivialGotoEliminationTest.java
@@ -30,7 +30,6 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.MethodConversionOptions;
import com.android.tools.r8.ir.conversion.passes.TrivialGotosCollapser;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
@@ -107,7 +106,6 @@
new NumberGenerator(),
basicBlockNumberGenerator,
IRMetadata.unknown(),
- Origin.unknown(),
MethodConversionOptions.forD8(appView));
new TrivialGotosCollapser(appView).run(code, Timing.empty());
assertTrue(code.entryBlock().isTrivialGoto());
@@ -196,7 +194,6 @@
new NumberGenerator(),
basicBlockNumberGenerator,
IRMetadata.unknown(),
- Origin.unknown(),
MethodConversionOptions.forD8(appView));
new TrivialGotosCollapser(appView).run(code, Timing.empty());
assertTrue(block0.getInstructions().get(1).isIf());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/sync/InlineWithMonitorInConstructorInline.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/sync/InlineWithMonitorInConstructorInline.java
index de3375c..a2b9b48 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/sync/InlineWithMonitorInConstructorInline.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/sync/InlineWithMonitorInConstructorInline.java
@@ -4,9 +4,13 @@
package com.android.tools.r8.ir.optimize.inliner.sync;
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.containsConstString;
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentIf;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -14,50 +18,91 @@
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
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 InlineWithMonitorInConstructorInline extends TestBase {
- private final TestParameters parameters;
+ @Parameter(0)
+ public TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimesAndApiLevels().build();
}
- public InlineWithMonitorInConstructorInline(TestParameters parameters) {
- this.parameters = parameters;
- }
-
@Test
public void test() throws Exception {
testForR8(parameters.getBackend())
.addInnerClasses(InlineWithMonitorInConstructorInline.class)
.addKeepMainRule(TestClass.class)
+ .addHorizontallyMergedClassesInspector(
+ inspector ->
+ inspector
+ .assertIsCompleteMergeGroup(Foo.class, Bar.class)
+ .assertNoOtherClassesMerged())
.setMinApi(parameters)
.run(parameters.getRuntime(), TestClass.class)
.inspect(this::inspect)
.assertSuccessWithOutputLines("foo", "monitor", "bar", "monitor2");
}
+ // Check we at most inline one method with monitor instructions into synthetic constructors
+ // created by class merging. See also b/238399429.
private void inspect(CodeInspector inspector) {
ClassSubject classSubject = inspector.clazz(TestClass.class);
assertThat(classSubject, isPresent());
+
+ ClassSubject fooClassSubject = inspector.clazz(Bar.class);
+ assertThat(fooClassSubject, isPresent());
+
+ // When compiling to CF we do not allow inlining methods into constructors.
+ // TODO(b/136458109): Util class should be absent when compiling to CF.
ClassSubject utilClassSubject = inspector.clazz(Util.class);
- if (parameters.isCfRuntime()
- || parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.M)) {
- // We disallow merging methods with monitors into constructors which will be class merged
- // on pre M devices, see b/238399429
- assertThat(utilClassSubject, isPresent());
- } else {
- assertThat(utilClassSubject, not(isPresent()));
+ assertThat(utilClassSubject, isPresentIf(parameters.isCfRuntime()));
+
+ // The Util class is fully inlined when compiling to DEX. Verify that the two monitor
+ // instructions are not inlined into the same method.
+ if (parameters.isDexRuntime()) {
+ if (parameters.getApiLevel().isLessThanOrEqualTo(AndroidApiLevel.M)) {
+ // Find the synthetic constructor with an added `int classId` parameter. Verify that only
+ // Foo.<init> has been inlined this constructor.
+ MethodSubject syntheticInit = fooClassSubject.init("int");
+ assertThat(syntheticInit, isPresent());
+ assertThat(syntheticInit, containsConstString("foo"));
+ assertThat(syntheticInit, not(containsConstString("bar")));
+ assertEquals(1, numberOfMonitorEnterInstructions(syntheticInit));
+
+ // Find the non-synthetic constructor corresponding to Bar.<init>.
+ MethodSubject barInit = fooClassSubject.init();
+ assertThat(barInit, isPresent());
+ assertThat(barInit, containsConstString("bar"));
+ assertThat(barInit, not(containsConstString("foo")));
+ assertEquals(1, numberOfMonitorEnterInstructions(barInit));
+
+ // Finally verify that the synthetic constructor calls the non-synthetic constructor, due to
+ // inlining being prohibited.
+ assertThat(syntheticInit, invokesMethod(barInit));
+ } else {
+ MethodSubject syntheticInit = fooClassSubject.uniqueInstanceInitializer();
+ assertThat(syntheticInit, isPresent());
+ assertThat(syntheticInit, containsConstString("bar"));
+ assertThat(syntheticInit, containsConstString("foo"));
+ assertEquals(2, numberOfMonitorEnterInstructions(syntheticInit));
+ }
}
}
+ private static long numberOfMonitorEnterInstructions(MethodSubject methodSubject) {
+ return methodSubject.streamInstructions().filter(InstructionSubject::isMonitorEnter).count();
+ }
+
static class Foo {
public Foo() {
System.out.println("foo");
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepAnnoTestUtils.java b/src/test/java/com/android/tools/r8/keepanno/KeepAnnoTestUtils.java
index 7335975..176c263 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepAnnoTestUtils.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepAnnoTestUtils.java
@@ -24,11 +24,11 @@
public class KeepAnnoTestUtils {
- // TODO(b/321674067): Update this to PG 7.4.
- public static ProguardVersion PG_VERSION = ProguardVersion.V7_3_2;
+ public static ProguardVersion PG_VERSION = ProguardVersion.V7_4_1;
- // TODO(b/321674067): Downgrade this to oldest supported AGP, such as R8 8.0.35.
- public static Path R8_LIB = Paths.get(ToolHelper.THIRD_PARTY_DIR, "r8", "r8lib_8.2.20-dev.jar");
+ // Track support for R8 version 8.0.46 which is included in AGP 8.0.2
+ public static Path R8_LIB =
+ Paths.get(ToolHelper.THIRD_PARTY_DIR, "r8-releases", "8.0.46", "r8lib.jar");
public static Path getKeepAnnoLib(TemporaryFolder temp) throws IOException {
Path archive = temp.newFolder().toPath().resolve("keepanno.jar");
diff --git a/src/test/java/com/android/tools/r8/keepanno/KeepSameMethodTest.java b/src/test/java/com/android/tools/r8/keepanno/KeepSameMethodTest.java
index aebeeb2..b0c50d2 100644
--- a/src/test/java/com/android/tools/r8/keepanno/KeepSameMethodTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/KeepSameMethodTest.java
@@ -27,9 +27,6 @@
static final String EXPECTED = StringUtils.lines("foo");
- // TODO(b/265893433): The use of backreferences does not work in PG.
- static final String UNEXPECTED_PG = StringUtils.lines("main");
-
@Parameter public KeepAnnoParameters parameters;
@Parameterized.Parameters(name = "{0}")
@@ -47,7 +44,7 @@
// The "all members" target will create an unused "all fields" rule.
.allowUnusedProguardConfigurationRules()
.run(TestClass.class)
- .assertSuccessWithOutput(parameters.isPG() ? UNEXPECTED_PG : EXPECTED)
+ .assertSuccessWithOutput(EXPECTED)
.applyIf(parameters.isR8(), r -> r.inspect(this::checkOutput));
}
diff --git a/src/test/java/com/android/tools/r8/keepanno/MembersAnnotatedByPatternsTest.java b/src/test/java/com/android/tools/r8/keepanno/MembersAnnotatedByPatternsTest.java
index 0f2aadf..52850da 100644
--- a/src/test/java/com/android/tools/r8/keepanno/MembersAnnotatedByPatternsTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/MembersAnnotatedByPatternsTest.java
@@ -8,9 +8,6 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.keepanno.annotations.AnnotationPattern;
import com.android.tools.r8.keepanno.annotations.ClassNamePattern;
import com.android.tools.r8.keepanno.annotations.KeepItemKind;
@@ -29,44 +26,32 @@
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;
-import org.checkerframework.checker.units.qual.A;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
@RunWith(Parameterized.class)
-public class MembersAnnotatedByPatternsTest extends TestBase {
+public class MembersAnnotatedByPatternsTest extends KeepAnnoTestBase {
static final String EXPECTED = StringUtils.lines("b", "bar", "a", "foo");
- private final TestParameters parameters;
+ @Parameter public KeepAnnoParameters parameters;
@Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
- }
-
- public MembersAnnotatedByPatternsTest(TestParameters parameters) {
- this.parameters = parameters;
+ public static List<KeepAnnoParameters> data() {
+ return createParameters(
+ getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build());
}
@Test
- public void testReference() throws Exception {
- testForRuntime(parameters)
+ public void test() throws Exception {
+ testForKeepAnno(parameters)
.addProgramClasses(getInputClasses())
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED);
- }
-
- @Test
- public void testR8() throws Exception {
- testForR8(parameters.getBackend())
- .enableExperimentalKeepAnnotations()
- .addProgramClasses(getInputClasses())
- .setMinApi(parameters)
- .run(parameters.getRuntime(), TestClass.class)
+ .setExcludedOuterClass(getClass())
+ .run(TestClass.class)
.assertSuccessWithOutput(EXPECTED)
- .inspect(this::checkOutput);
+ .applyIf(parameters.isShrinker(), r -> r.inspect(this::checkOutput));
}
public List<Class<?>> getInputClasses() {
diff --git a/src/test/java/com/android/tools/r8/keepanno/MethodNameStringPatternsTest.java b/src/test/java/com/android/tools/r8/keepanno/MethodNameStringPatternsTest.java
index 2444ccf..9306ca4 100644
--- a/src/test/java/com/android/tools/r8/keepanno/MethodNameStringPatternsTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/MethodNameStringPatternsTest.java
@@ -8,9 +8,6 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.keepanno.annotations.KeepItemKind;
import com.android.tools.r8.keepanno.annotations.KeepTarget;
import com.android.tools.r8.keepanno.annotations.StringPattern;
@@ -25,40 +22,29 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
@RunWith(Parameterized.class)
-public class MethodNameStringPatternsTest extends TestBase {
+public class MethodNameStringPatternsTest extends KeepAnnoTestBase {
static final String EXPECTED = StringUtils.lines("1");
- private final TestParameters parameters;
+ @Parameter public KeepAnnoParameters parameters;
@Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
- }
-
- public MethodNameStringPatternsTest(TestParameters parameters) {
- this.parameters = parameters;
+ public static List<KeepAnnoParameters> data() {
+ return createParameters(
+ getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build());
}
@Test
- public void testReference() throws Exception {
- testForRuntime(parameters)
+ public void test() throws Exception {
+ testForKeepAnno(parameters)
.addProgramClasses(getInputClasses())
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED);
- }
-
- @Test
- public void testR8() throws Exception {
- testForR8(parameters.getBackend())
- .enableExperimentalKeepAnnotations()
- .addProgramClasses(getInputClasses())
- .setMinApi(parameters)
- .run(parameters.getRuntime(), TestClass.class)
+ .setExcludedOuterClass(getClass())
+ .run(TestClass.class)
.assertSuccessWithOutput(EXPECTED)
- .inspect(this::checkOutput);
+ .applyIf(parameters.isShrinker(), r -> r.inspect(this::checkOutput));
}
public List<Class<?>> getInputClasses() {
diff --git a/src/test/java/com/android/tools/r8/keepanno/MethodPatternsTest.java b/src/test/java/com/android/tools/r8/keepanno/MethodPatternsTest.java
index 86f2f9c..7654721 100644
--- a/src/test/java/com/android/tools/r8/keepanno/MethodPatternsTest.java
+++ b/src/test/java/com/android/tools/r8/keepanno/MethodPatternsTest.java
@@ -8,9 +8,6 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.keepanno.annotations.KeepItemKind;
import com.android.tools.r8.keepanno.annotations.KeepTarget;
import com.android.tools.r8.keepanno.annotations.TypePattern;
@@ -25,41 +22,30 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
@RunWith(Parameterized.class)
-public class MethodPatternsTest extends TestBase {
+public class MethodPatternsTest extends KeepAnnoTestBase {
static final String EXPECTED =
StringUtils.lines("Hello 42", "Hello 12", "int", "long", "class java.lang.Integer");
- private final TestParameters parameters;
+ @Parameter public KeepAnnoParameters parameters;
@Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build();
- }
-
- public MethodPatternsTest(TestParameters parameters) {
- this.parameters = parameters;
+ public static List<KeepAnnoParameters> data() {
+ return createParameters(
+ getTestParameters().withDefaultRuntimes().withApiLevel(AndroidApiLevel.B).build());
}
@Test
- public void testReference() throws Exception {
- testForRuntime(parameters)
+ public void test() throws Exception {
+ testForKeepAnno(parameters)
.addProgramClasses(getInputClasses())
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED);
- }
-
- @Test
- public void testR8() throws Exception {
- testForR8(parameters.getBackend())
- .enableExperimentalKeepAnnotations()
- .addProgramClasses(getInputClasses())
- .setMinApi(parameters)
- .run(parameters.getRuntime(), TestClass.class)
+ .setExcludedOuterClass(getClass())
+ .run(TestClass.class)
.assertSuccessWithOutput(EXPECTED)
- .inspect(this::checkOutput);
+ .applyIf(parameters.isShrinker(), r -> r.inspect(this::checkOutput));
}
public List<Class<?>> getInputClasses() {
diff --git a/src/test/java/com/android/tools/r8/keepanno/compatissues/BackReferenceIssuesTest.java b/src/test/java/com/android/tools/r8/keepanno/compatissues/BackReferenceIssuesTest.java
new file mode 100644
index 0000000..63692c5
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/keepanno/compatissues/BackReferenceIssuesTest.java
@@ -0,0 +1,249 @@
+// Copyright (c) 2024, 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.keepanno.compatissues;
+
+import static com.android.tools.r8.utils.codeinspector.AssertUtils.assertThrowsIf;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.ProguardVersion;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+
+@RunWith(Parameterized.class)
+public class BackReferenceIssuesTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("42");
+
+ public enum Shrinker {
+ PG,
+ R8;
+
+ public boolean isPG() {
+ return this == PG;
+ }
+ }
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameter(1)
+ public Shrinker shrinker;
+
+ @Parameterized.Parameters(name = "{0}, {1}")
+ public static List<Object[]> data() {
+ return buildParameters(getTestParameters().withDefaultCfRuntime().build(), Shrinker.values());
+ }
+
+ private TestRunResult<?> runTest(String... keepRules) throws Exception {
+ TestShrinkerBuilder<?, ?, ?, ?, ?> builder;
+ if (shrinker.isPG()) {
+ assumeTrue(parameters.isCfRuntime());
+ builder = testForProguard(ProguardVersion.getLatest()).addDontWarn(getClass());
+ } else {
+ builder = testForR8(parameters.getBackend());
+ }
+ return builder
+ .addProgramClasses(A.class, TestClass.class)
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules(keepRules)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void testMissingReturnTypeBackref() throws Exception {
+ runTest(
+ "-if class **$A {",
+ " *** *(int);",
+ "}",
+ "-keepclassmembers class <1>$A {",
+ // This should have been `<2> <3>(int);` but wildcard on the return type is gone.
+ // TODO(b/322114141): Update this rule if fixed in future version of PG.
+ " *** <2>(int);",
+ "}")
+ .inspect(
+ inspector ->
+ assertThat(
+ inspector.clazz(A.class).uniqueMethodWithOriginalName("foo"),
+ // The rule is not valid and does not keep the method in R8.
+ shrinker.isPG() ? isPresentAndNotRenamed() : isPresentAndRenamed()));
+ }
+
+ @Test
+ public void testMissingMethodParameterBackref() throws Exception {
+ runTest(
+ "-if class **$A {",
+ " void foo(***);",
+ "}",
+ "-keepclassmembers class <1>$A {",
+ " void foo(<2>);",
+ "}")
+ .inspect(
+ inspector ->
+ assertThat(
+ inspector.clazz(A.class).uniqueMethodWithOriginalName("foo"),
+ // The above rule should have retained foo.
+ // TODO(b/322114141): Update the status if fixed in future version of PG.
+ shrinker.isPG() ? isAbsent() : isPresentAndNotRenamed()));
+ }
+
+ @Test
+ public void testMissingMethodAnyParametersBackref() throws Exception {
+ // TODO(b/265892343): R8 will throw when parsing a backref to `...`
+ assertThrowsIf(
+ !shrinker.isPG(),
+ CompilationFailedException.class,
+ () ->
+ runTest(
+ "-if class **$A {",
+ " void foo(...);",
+ "}",
+ "-keepclassmembers class <1>$A {",
+ " void foo(<2>);",
+ "}")
+ .inspect(
+ inspector ->
+ assertThat(
+ inspector.clazz(A.class).uniqueMethodWithOriginalName("foo"),
+ // The above rule should have retained foo.
+ // TODO(b/322114141): Update the status if fixed in future version of
+ // PG.
+ isAbsent())));
+ }
+
+ @Test
+ public void testMissingFieldTypeBackref() throws Exception {
+ runTest(
+ "-if class **$A {",
+ " *** x;",
+ "}",
+ // Just a comment to avoid a one-line formatting.
+ "-keepclassmembers class <1>$A {",
+ " <2> y;",
+ "}")
+ .inspect(
+ inspector ->
+ assertThat(
+ inspector.clazz(A.class).uniqueFieldWithOriginalName("y"),
+ // TODO(b/322114141): Update this status if fixed in future version of PG.
+ // TODO(b/322910135): R8 should not throw away a kept static final field.
+ isAbsent()));
+ }
+
+ @Test
+ public void testMissingFieldTypeBackrefPrefixPg() throws Exception {
+ runTest(
+ "-if class **$A {",
+ " !static *** *;",
+ "}",
+ "-keepclassmembers class <1>$A {",
+ // This should have been `<2> <3>y;` but the field type is skipped.
+ // TODO(b/322114141): Update this rule if fixed in future version of PG.
+ " *** <2>y;",
+ "}")
+ .inspect(
+ inspector ->
+ assertThat(
+ inspector.clazz(A.class).uniqueFieldWithOriginalName("xy"),
+ // The rule does not match with R8.
+ shrinker.isPG() ? isPresentAndNotRenamed() : isAbsent()));
+ }
+
+ @Test
+ public void testTypeRefInMember() throws Exception {
+ runTest(
+ "-if class **$A {",
+ " " + typeName(A.class) + " *(" + typeName(A.class) + ");",
+ "}",
+ "-keepclassmembers class <1>$A {",
+ // This test shows that we can reference the class type wildcard in the member rule.
+ // 1: outer(A)
+ // 2: bar
+ " <1>$A <2>(<1>$A);",
+ "}")
+ .inspect(
+ inspector ->
+ assertThat(
+ inspector.clazz(A.class).uniqueMethodWithOriginalName("bar"), isPresent()));
+ }
+
+ @Test
+ public void testTypeAndReturnTypeInMember() throws Exception {
+ runTest(
+ "-if class **$A {",
+ " *** *(" + typeName(A.class) + ");",
+ "}",
+ "-keepclassmembers class <1>$A {",
+ // This test shows that adding the return type wildcard does not add to the wildcard
+ // refs.
+ // 1: outer(A)
+ // 2: bar -- expected A
+ // 3: undefined -- expected bar
+ // TODO(b/322114141): Update this rule if fixed in future version of PG.
+ " <1>$A <2>(<1>$A);",
+ "}")
+ .inspect(
+ inspector ->
+ assertThat(
+ inspector.clazz(A.class).uniqueMethodWithOriginalName("bar"),
+ // The rule does not match with R8.
+ shrinker.isPG() ? isPresentAndNotRenamed() : isAbsent()));
+ }
+
+ @Test
+ public void testTypeAndReturnTypeInMemberAbsent() throws Exception {
+ runTest(
+ "-if class **$A {",
+ " *** *(" + typeName(A.class) + ");",
+ "}",
+ "-keepclassmembers class <1>$A {",
+ " <2> <3>(<2>);",
+ "}")
+ .inspect(
+ inspector ->
+ // The above pattern should have worked if <2> had been the return type.
+ // TODO(b/322114141): Update this status if fixed in future version of PG.
+ assertThat(
+ inspector.clazz(A.class).uniqueMethodWithOriginalName("bar"),
+ shrinker.isPG() ? isAbsent() : isPresentAndNotRenamed()));
+ }
+
+ public static class A {
+
+ // Use two fields to test removal as PG won't optimize out the non-static by default.
+ private final int x = 42;
+ private static final int y = 42;
+ private static final int xy = 42;
+
+ public void foo(int arg) {
+ System.out.println(arg + x);
+ }
+
+ public A bar(A arg) {
+ return arg;
+ }
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ new A().bar(new A()).foo(args.length);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepClassAndDefaultConstructorSource.java b/src/test/java/com/android/tools/r8/keepanno/testsource/KeepClassAndDefaultConstructorSource.java
deleted file mode 100644
index b9fb2b6..0000000
--- a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepClassAndDefaultConstructorSource.java
+++ /dev/null
@@ -1,34 +0,0 @@
-// 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.keepanno.testsource;
-
-import com.android.tools.r8.keepanno.annotations.KeepEdge;
-import com.android.tools.r8.keepanno.annotations.KeepTarget;
-
-@KeepEdge(
- consequences = {
- // Keep the class to allow lookup of it.
- @KeepTarget(classConstant = KeepClassAndDefaultConstructorSource.A.class),
- // Keep the default constructor.
- @KeepTarget(
- classConstant = KeepClassAndDefaultConstructorSource.A.class,
- methodName = "<init>")
- })
-public class KeepClassAndDefaultConstructorSource {
-
- public static class A {
- public A() {
- System.out.println("A is alive!");
- }
- }
-
- public static void main(String[] args) throws Exception {
- Class<?> aClass =
- Class.forName(
- KeepClassAndDefaultConstructorSource.class.getPackage().getName()
- + (args.length > 0 ? ".." : ".")
- + "KeepClassAndDefaultConstructorSource$A");
- aClass.getDeclaredConstructor().newInstance();
- }
-}
diff --git a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepDependentFieldSource.java b/src/test/java/com/android/tools/r8/keepanno/testsource/KeepDependentFieldSource.java
deleted file mode 100644
index 4a0df32..0000000
--- a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepDependentFieldSource.java
+++ /dev/null
@@ -1,41 +0,0 @@
-// 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.keepanno.testsource;
-
-import com.android.tools.r8.keepanno.annotations.KeepCondition;
-import com.android.tools.r8.keepanno.annotations.KeepEdge;
-import com.android.tools.r8.keepanno.annotations.KeepTarget;
-import java.lang.reflect.Field;
-
-public class KeepDependentFieldSource {
-
- public static class A {
-
- public int f;
-
- public A(int x) {
- f = x;
- }
- }
-
- // The keep edge is context independent, but natural to place close to the reflection usage.
- @KeepEdge(
- preconditions = {
- // The edge is only needed if the main method that uses reflection is actually present.
- @KeepCondition(classConstant = KeepDependentFieldSource.class, methodName = "main")
- },
- consequences = {
- // Keep the reflectively accessed field.
- @KeepTarget(classConstant = KeepDependentFieldSource.A.class, fieldName = "f")
- })
- public static void main(String[] args) throws Exception {
- int x = 42 + args.length;
- Object o = System.nanoTime() > 0 ? new A(x) : null;
- Field f = o.getClass().getDeclaredField("f");
- int y = f.getInt(o);
- if (x == y) {
- System.out.println("The values match!");
- }
- }
-}
diff --git a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepFieldSource.java b/src/test/java/com/android/tools/r8/keepanno/testsource/KeepFieldSource.java
deleted file mode 100644
index 6f577e4..0000000
--- a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepFieldSource.java
+++ /dev/null
@@ -1,35 +0,0 @@
-// 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.keepanno.testsource;
-
-import com.android.tools.r8.keepanno.annotations.KeepEdge;
-import com.android.tools.r8.keepanno.annotations.KeepTarget;
-import java.lang.reflect.Field;
-
-@KeepEdge(
- consequences = {
- // Keep the reflectively accessed field.
- @KeepTarget(classConstant = KeepFieldSource.A.class, fieldName = "f")
- })
-public class KeepFieldSource {
-
- public static class A {
-
- public int f;
-
- public A(int x) {
- f = x;
- }
- }
-
- public static void main(String[] args) throws Exception {
- int x = 42 + args.length;
- Object o = System.nanoTime() > 0 ? new A(x) : null;
- Field f = o.getClass().getDeclaredField("f");
- int y = f.getInt(o);
- if (x == y) {
- System.out.println("The values match!");
- }
- }
-}
diff --git a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepSourceEdges.java b/src/test/java/com/android/tools/r8/keepanno/testsource/KeepSourceEdges.java
deleted file mode 100644
index 0b2265a..0000000
--- a/src/test/java/com/android/tools/r8/keepanno/testsource/KeepSourceEdges.java
+++ /dev/null
@@ -1,174 +0,0 @@
-// 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.keepanno.testsource;
-
-import com.android.tools.r8.keepanno.ast.KeepClassItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepClassItemReference;
-import com.android.tools.r8.keepanno.ast.KeepCondition;
-import com.android.tools.r8.keepanno.ast.KeepConsequences;
-import com.android.tools.r8.keepanno.ast.KeepConsequences.Builder;
-import com.android.tools.r8.keepanno.ast.KeepEdge;
-import com.android.tools.r8.keepanno.ast.KeepFieldNamePattern;
-import com.android.tools.r8.keepanno.ast.KeepFieldPattern;
-import com.android.tools.r8.keepanno.ast.KeepItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepMemberItemPattern;
-import com.android.tools.r8.keepanno.ast.KeepMethodNamePattern;
-import com.android.tools.r8.keepanno.ast.KeepMethodPattern;
-import com.android.tools.r8.keepanno.ast.KeepPreconditions;
-import com.android.tools.r8.keepanno.ast.KeepQualifiedClassNamePattern;
-import com.android.tools.r8.keepanno.ast.KeepTarget;
-import com.android.tools.r8.utils.StringUtils;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Utility to get the AST edges for the various annotation test sources.
- *
- * <p>This makes it easier to share the test sources among tests (e.g., processor and asm tests).
- */
-public class KeepSourceEdges {
-
- private static class SourceData {
- final Class<?> clazz;
- final String expected;
- final List<KeepEdge> edges;
-
- public SourceData(Class<?> clazz, String expected, List<KeepEdge> edges) {
- this.clazz = clazz;
- this.expected = expected;
- this.edges = edges;
- }
- }
-
- private static final List<SourceData> SOURCES = new ArrayList<>();
-
- static {
- SOURCES.add(
- new SourceData(
- KeepClassAndDefaultConstructorSource.class,
- getKeepClassAndDefaultConstructorSourceExpected(),
- getKeepClassAndDefaultConstructorSourceEdges()));
- SOURCES.add(
- new SourceData(
- KeepFieldSource.class, getKeepFieldSourceExpected(), getKeepFieldSourceEdges()));
- SOURCES.add(
- new SourceData(
- KeepDependentFieldSource.class,
- getKeepDependentFieldSourceExpected(),
- getKeepDependentFieldSourceEdges()));
- }
-
- public static List<KeepEdge> getExpectedEdges(Class<?> clazz) {
- for (SourceData source : SOURCES) {
- if (source.clazz == clazz) {
- return source.edges;
- }
- }
- throw new RuntimeException();
- }
-
- public static String getExpected(Class<?> clazz) {
- for (SourceData source : SOURCES) {
- if (source.clazz == clazz) {
- return source.expected;
- }
- }
- throw new RuntimeException();
- }
-
- public static String getKeepClassAndDefaultConstructorSourceExpected() {
- return StringUtils.lines("A is alive!");
- }
-
- public static List<KeepEdge> getKeepClassAndDefaultConstructorSourceEdges() {
- Class<?> clazz = KeepClassAndDefaultConstructorSource.A.class;
- return Collections.singletonList(
- mkEdge(mkConsequences(mkTarget(mkClass(clazz)), mkTarget(mkMethod(clazz, "<init>")))));
- }
-
- public static String getKeepFieldSourceExpected() {
- return StringUtils.lines("The values match!");
- }
-
- public static List<KeepEdge> getKeepFieldSourceEdges() {
- return Collections.singletonList(
- mkEdge(mkConsequences(mkTarget(mkField(KeepFieldSource.A.class, "f")))));
- }
-
- public static String getKeepDependentFieldSourceExpected() {
- return getKeepFieldSourceExpected();
- }
-
- public static List<KeepEdge> getKeepDependentFieldSourceEdges() {
- return Collections.singletonList(
- mkDepEdge(
- mkPreconditions(mkCondition(mkMethod(KeepDependentFieldSource.class, "main"))),
- mkConsequences(mkTarget(mkField(KeepDependentFieldSource.A.class, "f")))));
- }
-
- // Ast helpers.
-
- static KeepClassItemPattern mkClass(Class<?> clazz) {
- KeepQualifiedClassNamePattern name = KeepQualifiedClassNamePattern.exact(clazz.getTypeName());
- return KeepClassItemPattern.builder().setClassNamePattern(name).build();
- }
-
- static KeepMemberItemPattern mkMethod(Class<?> clazz, String methodName) {
- KeepQualifiedClassNamePattern name = KeepQualifiedClassNamePattern.exact(clazz.getTypeName());
- KeepClassItemReference classReference =
- KeepClassItemPattern.builder().setClassNamePattern(name).build().toClassItemReference();
- KeepMethodPattern methodPattern =
- KeepMethodPattern.builder().setNamePattern(KeepMethodNamePattern.exact(methodName)).build();
- KeepMemberItemPattern methodItem =
- KeepMemberItemPattern.builder()
- .setClassReference(classReference)
- .setMemberPattern(methodPattern)
- .build();
- return methodItem;
- }
-
- static KeepItemPattern mkField(Class<?> clazz, String fieldName) {
- KeepQualifiedClassNamePattern name = KeepQualifiedClassNamePattern.exact(clazz.getTypeName());
- KeepClassItemReference classReference =
- KeepClassItemPattern.builder().setClassNamePattern(name).build().toClassItemReference();
- KeepFieldPattern fieldPattern =
- KeepFieldPattern.builder().setNamePattern(KeepFieldNamePattern.exact(fieldName)).build();
- KeepMemberItemPattern fieldItem =
- KeepMemberItemPattern.builder()
- .setClassReference(classReference)
- .setMemberPattern(fieldPattern)
- .build();
- return fieldItem;
- }
-
- static KeepTarget mkTarget(KeepItemPattern item) {
- return KeepTarget.builder().setItemPattern(item).build();
- }
-
- static KeepCondition mkCondition(KeepItemPattern item) {
- return KeepCondition.builder().setItemPattern(item).build();
- }
-
- static KeepConsequences mkConsequences(KeepTarget... targets) {
- Builder builder = KeepConsequences.builder();
- Arrays.asList(targets).forEach(builder::addTarget);
- return builder.build();
- }
-
- static KeepPreconditions mkPreconditions(KeepCondition... conditions) {
- KeepPreconditions.Builder builder = KeepPreconditions.builder();
- Arrays.asList(conditions).forEach(builder::addCondition);
- return builder.build();
- }
-
- static KeepEdge mkEdge(KeepConsequences consequences) {
- return KeepEdge.builder().setConsequences(consequences).build();
- }
-
- static KeepEdge mkDepEdge(KeepPreconditions preconditions, KeepConsequences consequences) {
- return KeepEdge.builder().setPreconditions(preconditions).setConsequences(consequences).build();
- }
-}
diff --git a/src/test/java/com/android/tools/r8/keepanno/utils/KeepAnnoMarkdownGenerator.java b/src/test/java/com/android/tools/r8/keepanno/utils/KeepAnnoMarkdownGenerator.java
index c2dec45..b543b8d 100644
--- a/src/test/java/com/android/tools/r8/keepanno/utils/KeepAnnoMarkdownGenerator.java
+++ b/src/test/java/com/android/tools/r8/keepanno/utils/KeepAnnoMarkdownGenerator.java
@@ -36,7 +36,6 @@
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
-import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
@@ -49,9 +48,9 @@
public class KeepAnnoMarkdownGenerator {
- public static void generateMarkdownDoc(Generator generator) {
+ public static void generateMarkdownDoc(Generator generator, Path projectRoot) {
try {
- new KeepAnnoMarkdownGenerator(generator).internalGenerateMarkdownDoc();
+ new KeepAnnoMarkdownGenerator(generator).internalGenerateMarkdownDoc(projectRoot);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -202,10 +201,11 @@
generator.println(line);
}
- private void internalGenerateMarkdownDoc() throws IOException {
- Path template = Paths.get("doc/keepanno-guide.template.md");
+ private void internalGenerateMarkdownDoc(Path projectRoot) throws IOException {
+ String relativeUnixPath = "doc/keepanno-guide.template.md";
+ Path template = projectRoot.resolve(relativeUnixPath);
println("[comment]: <> (DO NOT EDIT - GENERATED FILE)");
- println("[comment]: <> (Changes should be made in " + template + ")");
+ println("[comment]: <> (Changes should be made in " + relativeUnixPath + ")");
println();
List<String> readAllLines = FileUtils.readAllLines(template);
TableEntry root = new TableEntry(0, "root", "root", null);
diff --git a/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemAnnotationGenerator.java b/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemAnnotationGenerator.java
index 475813b..f1d26bb 100644
--- a/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemAnnotationGenerator.java
+++ b/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemAnnotationGenerator.java
@@ -4,30 +4,13 @@
package com.android.tools.r8.keepanno.utils;
-import com.android.tools.r8.TestBase;
+import static com.android.tools.r8.references.Reference.classFromClass;
+import static com.android.tools.r8.references.Reference.classFromTypeName;
+
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.cfmethodgeneration.CodeGenerationBase;
-import com.android.tools.r8.keepanno.annotations.AnnotationPattern;
-import com.android.tools.r8.keepanno.annotations.CheckOptimizedOut;
-import com.android.tools.r8.keepanno.annotations.CheckRemoved;
-import com.android.tools.r8.keepanno.annotations.ClassNamePattern;
-import com.android.tools.r8.keepanno.annotations.FieldAccessFlags;
-import com.android.tools.r8.keepanno.annotations.KeepBinding;
-import com.android.tools.r8.keepanno.annotations.KeepCondition;
-import com.android.tools.r8.keepanno.annotations.KeepConstraint;
-import com.android.tools.r8.keepanno.annotations.KeepEdge;
-import com.android.tools.r8.keepanno.annotations.KeepForApi;
import com.android.tools.r8.keepanno.annotations.KeepItemKind;
-import com.android.tools.r8.keepanno.annotations.KeepOption;
-import com.android.tools.r8.keepanno.annotations.KeepTarget;
-import com.android.tools.r8.keepanno.annotations.MemberAccessFlags;
-import com.android.tools.r8.keepanno.annotations.MethodAccessFlags;
-import com.android.tools.r8.keepanno.annotations.StringPattern;
-import com.android.tools.r8.keepanno.annotations.TypePattern;
-import com.android.tools.r8.keepanno.annotations.UsedByNative;
-import com.android.tools.r8.keepanno.annotations.UsedByReflection;
-import com.android.tools.r8.keepanno.annotations.UsesReflection;
-import com.android.tools.r8.keepanno.ast.AnnotationConstants;
+import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.StringUtils.BraceType;
import com.google.common.base.Strings;
@@ -39,6 +22,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -46,28 +30,194 @@
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.function.BiConsumer;
import java.util.function.Consumer;
public class KeepItemAnnotationGenerator {
public static void main(String[] args) throws IOException {
Generator.class.getClassLoader().setDefaultAssertionStatus(true);
- Generator.run();
+ Generator.run(
+ (file, content) -> {
+ try {
+ Files.write(file, content.getBytes(StandardCharsets.UTF_8));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
}
+ private static class EnumReference {
+ public final ClassReference enumClass;
+ public final String enumValue;
+
+ public EnumReference(ClassReference enumClass, String enumValue) {
+ this.enumClass = enumClass;
+ this.enumValue = enumValue;
+ }
+
+ public String name() {
+ return enumValue;
+ }
+ }
+
+ private static final ClassReference JAVA_STRING = classFromClass(String.class);
+ private static final ClassReference JAVA_RETENTION_POLICY = classFromClass(RetentionPolicy.class);
+
+ private static final String PKG = "com.android.tools.r8.keepanno.";
+ private static final String AST_PKG = PKG + "ast.";
+ private static final String ANNO_PKG = PKG + "annotations.";
+
+ private static final ClassReference ANNOTATION_CONSTANTS = astClass("AnnotationConstants");
+
+ private static final ClassReference STRING_PATTERN = annoClass("StringPattern");
+ private static final ClassReference TYPE_PATTERN = annoClass("TypePattern");
+ private static final ClassReference CLASS_NAME_PATTERN = annoClass("ClassNamePattern");
+ private static final ClassReference ANNOTATION_PATTERN = annoClass("AnnotationPattern");
+ private static final ClassReference USES_REFLECTION = annoClass("UsesReflection");
+ private static final ClassReference USED_BY_REFLECTION = annoClass("UsedByReflection");
+ private static final ClassReference USED_BY_NATIVE = annoClass("UsedByNative");
+ private static final ClassReference CHECK_REMOVED = annoClass("CheckRemoved");
+ private static final ClassReference CHECK_OPTIMIZED_OUT = annoClass("CheckOptimizedOut");
+ private static final ClassReference KEEP_EDGE = annoClass("KeepEdge");
+ private static final ClassReference KEEP_BINDING = annoClass("KeepBinding");
+ private static final ClassReference KEEP_TARGET = annoClass("KeepTarget");
+ private static final ClassReference KEEP_CONDITION = annoClass("KeepCondition");
+ private static final ClassReference KEEP_FOR_API = annoClass("KeepForApi");
+
+ private static final ClassReference KEEP_ITEM_KIND = annoClass("KeepItemKind");
+ private static final EnumReference KIND_ONLY_CLASS = enumRef(KEEP_ITEM_KIND, "ONLY_CLASS");
+ private static final EnumReference KIND_ONLY_MEMBERS = enumRef(KEEP_ITEM_KIND, "ONLY_MEMBERS");
+ private static final EnumReference KIND_ONLY_METHODS = enumRef(KEEP_ITEM_KIND, "ONLY_METHODS");
+ private static final EnumReference KIND_ONLY_FIELDS = enumRef(KEEP_ITEM_KIND, "ONLY_FIELDS");
+ private static final EnumReference KIND_CLASS_AND_MEMBERS =
+ enumRef(KEEP_ITEM_KIND, "CLASS_AND_MEMBERS");
+ private static final EnumReference KIND_CLASS_AND_METHODS =
+ enumRef(KEEP_ITEM_KIND, "CLASS_AND_METHODS");
+ private static final EnumReference KIND_CLASS_AND_FIELDS =
+ enumRef(KEEP_ITEM_KIND, "CLASS_AND_FIELDS");
+ private static final List<EnumReference> KEEP_ITEM_KIND_VALUES =
+ ImmutableList.of(
+ KIND_ONLY_CLASS,
+ KIND_ONLY_MEMBERS,
+ KIND_ONLY_METHODS,
+ KIND_ONLY_FIELDS,
+ KIND_CLASS_AND_MEMBERS,
+ KIND_CLASS_AND_METHODS,
+ KIND_CLASS_AND_FIELDS);
+
+ private static final ClassReference KEEP_CONSTRAINT = annoClass("KeepConstraint");
+ private static final EnumReference CONSTRAINT_LOOKUP = enumRef(KEEP_CONSTRAINT, "LOOKUP");
+ private static final EnumReference CONSTRAINT_NAME = enumRef(KEEP_CONSTRAINT, "NAME");
+ private static final EnumReference CONSTRAINT_VISIBILITY_RELAX =
+ enumRef(KEEP_CONSTRAINT, "VISIBILITY_RELAX");
+ private static final EnumReference CONSTRAINT_VISIBILITY_RESTRICT =
+ enumRef(KEEP_CONSTRAINT, "VISIBILITY_RESTRICT");
+ private static final EnumReference CONSTRAINT_VISIBILITY_INVARIANT =
+ enumRef(KEEP_CONSTRAINT, "VISIBILITY_INVARIANT");
+ private static final EnumReference CONSTRAINT_CLASS_INSTANTIATE =
+ enumRef(KEEP_CONSTRAINT, "CLASS_INSTANTIATE");
+ private static final EnumReference CONSTRAINT_METHOD_INVOKE =
+ enumRef(KEEP_CONSTRAINT, "METHOD_INVOKE");
+ private static final EnumReference CONSTRAINT_FIELD_GET = enumRef(KEEP_CONSTRAINT, "FIELD_GET");
+ private static final EnumReference CONSTRAINT_FIELD_SET = enumRef(KEEP_CONSTRAINT, "FIELD_SET");
+ private static final EnumReference CONSTRAINT_METHOD_REPLACE =
+ enumRef(KEEP_CONSTRAINT, "METHOD_REPLACE");
+ private static final EnumReference CONSTRAINT_FIELD_REPLACE =
+ enumRef(KEEP_CONSTRAINT, "FIELD_REPLACE");
+ private static final EnumReference CONSTRAINT_NEVER_INLINE =
+ enumRef(KEEP_CONSTRAINT, "NEVER_INLINE");
+ private static final EnumReference CONSTRAINT_CLASS_OPEN_HIERARCHY =
+ enumRef(KEEP_CONSTRAINT, "CLASS_OPEN_HIERARCHY");
+ private static final List<EnumReference> KEEP_CONSTRAINT_VALUES =
+ ImmutableList.of(
+ CONSTRAINT_LOOKUP,
+ CONSTRAINT_NAME,
+ CONSTRAINT_VISIBILITY_RELAX,
+ CONSTRAINT_VISIBILITY_RESTRICT,
+ CONSTRAINT_VISIBILITY_INVARIANT,
+ CONSTRAINT_CLASS_INSTANTIATE,
+ CONSTRAINT_METHOD_INVOKE,
+ CONSTRAINT_FIELD_GET,
+ CONSTRAINT_FIELD_SET,
+ CONSTRAINT_METHOD_REPLACE,
+ CONSTRAINT_FIELD_REPLACE,
+ CONSTRAINT_NEVER_INLINE,
+ CONSTRAINT_CLASS_OPEN_HIERARCHY);
+
+ private static final ClassReference MEMBER_ACCESS_FLAGS = annoClass("MemberAccessFlags");
+ private static final EnumReference MEMBER_ACCESS_PUBLIC = enumRef(MEMBER_ACCESS_FLAGS, "PUBLIC");
+ private static final EnumReference MEMBER_ACCESS_PROTECTED =
+ enumRef(MEMBER_ACCESS_FLAGS, "PROTECTED");
+ private static final EnumReference MEMBER_ACCESS_PACKAGE_PRIVATE =
+ enumRef(MEMBER_ACCESS_FLAGS, "PACKAGE_PRIVATE");
+ private static final EnumReference MEMBER_ACCESS_PRIVATE =
+ enumRef(MEMBER_ACCESS_FLAGS, "PRIVATE");
+ private static final EnumReference MEMBER_ACCESS_STATIC = enumRef(MEMBER_ACCESS_FLAGS, "STATIC");
+ private static final EnumReference MEMBER_ACCESS_FINAL = enumRef(MEMBER_ACCESS_FLAGS, "FINAL");
+ private static final EnumReference MEMBER_ACCESS_SYNTHETIC =
+ enumRef(MEMBER_ACCESS_FLAGS, "SYNTHETIC");
+ private static final List<EnumReference> MEMBER_ACCESS_VALUES =
+ ImmutableList.of(
+ MEMBER_ACCESS_PUBLIC,
+ MEMBER_ACCESS_PROTECTED,
+ MEMBER_ACCESS_PACKAGE_PRIVATE,
+ MEMBER_ACCESS_PRIVATE,
+ MEMBER_ACCESS_STATIC,
+ MEMBER_ACCESS_FINAL,
+ MEMBER_ACCESS_SYNTHETIC);
+
+ private static final ClassReference METHOD_ACCESS_FLAGS = annoClass("MethodAccessFlags");
+ private static final EnumReference METHOD_ACCESS_SYNCHRONIZED =
+ enumRef(METHOD_ACCESS_FLAGS, "SYNCHRONIZED");
+ private static final EnumReference METHOD_ACCESS_BRIDGE = enumRef(METHOD_ACCESS_FLAGS, "BRIDGE");
+ private static final EnumReference METHOD_ACCESS_NATIVE = enumRef(METHOD_ACCESS_FLAGS, "NATIVE");
+ private static final EnumReference METHOD_ACCESS_ABSTRACT =
+ enumRef(METHOD_ACCESS_FLAGS, "ABSTRACT");
+ private static final EnumReference METHOD_ACCESS_STRICT_FP =
+ enumRef(METHOD_ACCESS_FLAGS, "STRICT_FP");
+ private static final List<EnumReference> METHOD_ACCESS_VALUES =
+ ImmutableList.of(
+ METHOD_ACCESS_SYNCHRONIZED,
+ METHOD_ACCESS_BRIDGE,
+ METHOD_ACCESS_NATIVE,
+ METHOD_ACCESS_ABSTRACT,
+ METHOD_ACCESS_STRICT_FP);
+
+ private static final ClassReference FIELD_ACCESS_FLAGS = annoClass("FieldAccessFlags");
+ private static final EnumReference FIELD_ACCESS_VOLATILE =
+ enumRef(FIELD_ACCESS_FLAGS, "VOLATILE");
+ private static final EnumReference FIELD_ACCESS_TRANSIENT =
+ enumRef(FIELD_ACCESS_FLAGS, "TRANSIENT");
+ private static final List<EnumReference> FIELD_ACCESS_VALUES =
+ ImmutableList.of(FIELD_ACCESS_VOLATILE, FIELD_ACCESS_TRANSIENT);
+
private static final String DEFAULT_INVALID_STRING_PATTERN =
- "@" + simpleName(StringPattern.class) + "(exact = \"\")";
+ "@" + simpleName(STRING_PATTERN) + "(exact = \"\")";
private static final String DEFAULT_INVALID_TYPE_PATTERN =
- "@" + simpleName(TypePattern.class) + "(name = \"\")";
+ "@" + simpleName(TYPE_PATTERN) + "(name = \"\")";
private static final String DEFAULT_INVALID_CLASS_NAME_PATTERN =
- "@" + simpleName(ClassNamePattern.class) + "(simpleName = \"\")";
+ "@" + simpleName(CLASS_NAME_PATTERN) + "(simpleName = \"\")";
+
+ private static ClassReference astClass(String simpleName) {
+ return classFromTypeName(AST_PKG + simpleName);
+ }
+
+ private static ClassReference annoClass(String simpleName) {
+ return classFromTypeName(ANNO_PKG + simpleName);
+ }
+
+ private static EnumReference enumRef(ClassReference enumClass, String valueName) {
+ return new EnumReference(enumClass, valueName);
+ }
public static String quote(String str) {
return "\"" + str + "\"";
}
- private static String simpleName(Class<?> clazz) {
- return clazz.getSimpleName();
+ private static String simpleName(ClassReference clazz) {
+ String binaryName = clazz.getBinaryName();
+ return binaryName.substring(binaryName.lastIndexOf('/') + 1);
}
private static class GroupMember extends DocPrinterBase<GroupMember> {
@@ -111,39 +261,39 @@
generator.println("public static final String " + name + " = " + quote(name) + ";");
}
- public GroupMember requiredValue(Class<?> type) {
+ public GroupMember requiredValue(ClassReference type) {
assert valueDefault == null;
return setType(simpleName(type));
}
- public GroupMember requiredArrayValue(Class<?> type) {
+ public GroupMember requiredArrayValue(ClassReference type) {
assert valueDefault == null;
return setType(simpleName(type) + "[]");
}
public GroupMember requiredStringValue() {
- return requiredValue(String.class);
+ return requiredValue(JAVA_STRING);
}
- public GroupMember defaultValue(Class<?> type, String value) {
+ public GroupMember defaultValue(ClassReference type, String value) {
setType(simpleName(type));
return setValue(value);
}
- public GroupMember defaultArrayValue(Class<?> type, String value) {
+ public GroupMember defaultArrayValue(ClassReference type, String value) {
setType(simpleName(type) + "[]");
return setValue("{" + value + "}");
}
public GroupMember defaultEmptyString() {
- return defaultValue(String.class, quote(""));
+ return defaultValue(JAVA_STRING, quote(""));
}
public GroupMember defaultObjectClass() {
return setType("Class<?>").setValue("Object.class");
}
- public GroupMember defaultArrayEmpty(Class<?> type) {
+ public GroupMember defaultArrayEmpty(ClassReference type) {
return defaultArrayValue(type, "");
}
}
@@ -315,7 +465,7 @@
private Group createBindingsGroup() {
return new Group("bindings")
- .addMember(new GroupMember("bindings").defaultArrayEmpty(KeepBinding.class));
+ .addMember(new GroupMember("bindings").defaultArrayEmpty(KEEP_BINDING));
}
private Group createPreconditionsGroup() {
@@ -327,7 +477,7 @@
.setDocReturn(
"The list of preconditions. "
+ "Defaults to no conditions, thus trivially/unconditionally satisfied.")
- .defaultArrayEmpty(KeepCondition.class));
+ .defaultArrayEmpty(KEEP_CONDITION));
}
private Group createConsequencesGroup() {
@@ -336,7 +486,7 @@
new GroupMember("consequences")
.setDocTitle("Consequences that must be kept if the annotation is in effect.")
.setDocReturn("The list of target consequences.")
- .requiredArrayValue(KeepTarget.class));
+ .requiredArrayValue(KEEP_TARGET));
}
private Group createConsequencesAsValueGroup() {
@@ -345,7 +495,7 @@
new GroupMember("value")
.setDocTitle("Consequences that must be kept if the annotation is in effect.")
.setDocReturn("The list of target consequences.")
- .requiredArrayValue(KeepTarget.class));
+ .requiredArrayValue(KEEP_TARGET));
}
private Group createAdditionalPreconditionsGroup() {
@@ -356,7 +506,7 @@
.setDocReturn(
"The list of additional preconditions. "
+ "Defaults to no additional preconditions.")
- .defaultArrayEmpty(KeepCondition.class));
+ .defaultArrayEmpty(KEEP_CONDITION));
}
private Group createAdditionalTargetsGroup(String docTitle) {
@@ -367,7 +517,7 @@
.setDocReturn(
"List of additional target consequences. "
+ "Defaults to no additional target consequences.")
- .defaultArrayEmpty(KeepTarget.class));
+ .defaultArrayEmpty(KEEP_TARGET));
}
private Group stringPatternExactGroup() {
@@ -417,7 +567,7 @@
.addMember(
new GroupMember("classNamePattern")
.setDocTitle("Classes matching the class-name pattern.")
- .defaultValue(ClassNamePattern.class, DEFAULT_INVALID_CLASS_NAME_PATTERN));
+ .defaultValue(CLASS_NAME_PATTERN, DEFAULT_INVALID_CLASS_NAME_PATTERN));
// TODO(b/248408342): Add more injections on type pattern variants.
// /** Exact type name as a string to match any array with that type as member. */
// String arrayOf() default "";
@@ -468,25 +618,25 @@
private static GroupMember getKindMember() {
return new GroupMember("kind")
- .defaultValue(KeepItemKind.class, "KeepItemKind.DEFAULT")
+ .defaultValue(KEEP_ITEM_KIND, "KeepItemKind.DEFAULT")
.setDocTitle("Specify the kind of this item pattern.")
.setDocReturn("The kind for this pattern.")
.addParagraph("Possible values are:")
.addUnorderedList(
- docLink(KeepItemKind.ONLY_CLASS),
- docLink(KeepItemKind.ONLY_MEMBERS),
- docLink(KeepItemKind.ONLY_METHODS),
- docLink(KeepItemKind.ONLY_FIELDS),
- docLink(KeepItemKind.CLASS_AND_MEMBERS),
- docLink(KeepItemKind.CLASS_AND_METHODS),
- docLink(KeepItemKind.CLASS_AND_FIELDS))
+ docEnumLink(KIND_ONLY_CLASS),
+ docEnumLink(KIND_ONLY_MEMBERS),
+ docEnumLink(KIND_ONLY_METHODS),
+ docEnumLink(KIND_ONLY_FIELDS),
+ docEnumLink(KIND_CLASS_AND_MEMBERS),
+ docEnumLink(KIND_CLASS_AND_METHODS),
+ docEnumLink(KIND_CLASS_AND_FIELDS))
.addParagraph(
"If unspecified the default kind for an item depends on its member patterns:")
.addUnorderedList(
- docLink(KeepItemKind.ONLY_CLASS) + " if no member patterns are defined",
- docLink(KeepItemKind.ONLY_METHODS) + " if method patterns are defined",
- docLink(KeepItemKind.ONLY_FIELDS) + " if field patterns are defined",
- docLink(KeepItemKind.ONLY_MEMBERS) + " otherwise.");
+ docEnumLink(KIND_ONLY_CLASS) + " if no member patterns are defined",
+ docEnumLink(KIND_ONLY_METHODS) + " if method patterns are defined",
+ docEnumLink(KIND_ONLY_FIELDS) + " if field patterns are defined",
+ docEnumLink(KIND_ONLY_MEMBERS) + " otherwise.");
}
private void forEachKeepConstraintGroups(Consumer<Group> fn) {
@@ -506,17 +656,17 @@
"The default constraints depend on the kind of the target.",
"For all targets the default constraints include:")
.addUnorderedList(
- docLink(KeepConstraint.LOOKUP),
- docLink(KeepConstraint.NAME),
- docLink(KeepConstraint.VISIBILITY_RELAX))
+ docEnumLink(CONSTRAINT_LOOKUP),
+ docEnumLink(CONSTRAINT_NAME),
+ docEnumLink(CONSTRAINT_VISIBILITY_RELAX))
.addParagraph("For classes the default constraints also include:")
- .addUnorderedList(docLink(KeepConstraint.CLASS_INSTANTIATE))
+ .addUnorderedList(docEnumLink(CONSTRAINT_CLASS_INSTANTIATE))
.addParagraph("For methods the default constraints also include:")
- .addUnorderedList(docLink(KeepConstraint.METHOD_INVOKE))
+ .addUnorderedList(docEnumLink(CONSTRAINT_METHOD_INVOKE))
.addParagraph("For fields the default constraints also include:")
- .addUnorderedList(docLink(KeepConstraint.FIELD_GET), docLink(KeepConstraint.FIELD_SET))
+ .addUnorderedList(docEnumLink(CONSTRAINT_FIELD_GET), docEnumLink(CONSTRAINT_FIELD_SET))
.setDocReturn("Usage constraints for the target.")
- .defaultArrayEmpty(KeepConstraint.class);
+ .defaultArrayEmpty(KEEP_CONSTRAINT);
}
private static GroupMember constraintAdditions() {
@@ -527,7 +677,7 @@
"in addition to the default constraints.")
.addParagraph("The default constraints are documented in " + docLink(constraints()))
.setDocReturn("Additional usage constraints for the target.")
- .defaultArrayEmpty(KeepConstraint.class);
+ .defaultArrayEmpty(KEEP_CONSTRAINT);
}
private static GroupMember constrainAnnotations() {
@@ -545,7 +695,7 @@
"By default no annotation patterns are defined and no annotations are required to",
"remain.")
.setDocReturn("Annotation patterns")
- .defaultArrayEmpty(AnnotationPattern.class);
+ .defaultArrayEmpty(ANNOTATION_PATTERN);
}
private Group annotationNameGroup() {
@@ -582,7 +732,7 @@
+ ANNOTATION_NAME_GROUP
+ " pattern by reference to a class-name pattern.")
.setDocReturn("The class-name pattern that defines the annotation.")
- .defaultValue(ClassNamePattern.class, DEFAULT_INVALID_CLASS_NAME_PATTERN);
+ .defaultValue(CLASS_NAME_PATTERN, DEFAULT_INVALID_CLASS_NAME_PATTERN);
}
private static GroupMember annotationRetention() {
@@ -590,7 +740,7 @@
.setDocTitle("Specify which retention policies must be set for the annotations.")
.addParagraph("Matches annotations with matching retention policies")
.setDocReturn("Retention policies. By default {@code RetentionPolicy.RUNTIME}.")
- .defaultArrayValue(RetentionPolicy.class, "RetentionPolicy.RUNTIME");
+ .defaultArrayValue(JAVA_RETENTION_POLICY, "RetentionPolicy.RUNTIME");
}
private GroupMember bindingName() {
@@ -636,7 +786,7 @@
.setDocTitle(
"Define the " + CLASS_NAME_GROUP + " pattern by reference to a class-name pattern.")
.setDocReturn("The class-name pattern that defines the class.")
- .defaultValue(ClassNamePattern.class, DEFAULT_INVALID_CLASS_NAME_PATTERN);
+ .defaultValue(CLASS_NAME_PATTERN, DEFAULT_INVALID_CLASS_NAME_PATTERN);
}
private Group createClassNamePatternGroup() {
@@ -732,7 +882,7 @@
.setDocTitle(
"Define the " + groupName + " pattern by reference to a class-name pattern.")
.setDocReturn("The class-name pattern that defines the annotation.")
- .defaultValue(ClassNamePattern.class, DEFAULT_INVALID_CLASS_NAME_PATTERN));
+ .defaultValue(CLASS_NAME_PATTERN, DEFAULT_INVALID_CLASS_NAME_PATTERN));
}
private Group createClassAnnotatedByPatternGroup() {
@@ -769,7 +919,7 @@
.setDocTitle("Define the member-access pattern by matching on access flags.")
.addParagraph(getMutuallyExclusiveForMemberProperties())
.setDocReturn("The member access-flag constraints that must be met.")
- .defaultArrayEmpty(MemberAccessFlags.class));
+ .defaultArrayEmpty(MEMBER_ACCESS_FLAGS));
}
private String getMutuallyExclusiveForMemberProperties() {
@@ -812,7 +962,7 @@
.addParagraph(getMutuallyExclusiveForMethodProperties())
.addParagraph(getMethodDefaultDoc("any method-access flags"))
.setDocReturn("The method access-flag constraints that must be met.")
- .defaultArrayEmpty(MethodAccessFlags.class));
+ .defaultArrayEmpty(METHOD_ACCESS_FLAGS));
}
private Group createMethodNameGroup() {
@@ -830,7 +980,7 @@
.addParagraph(getMutuallyExclusiveForMethodProperties())
.addParagraph(getMethodDefaultDoc("any method name"))
.setDocReturn("The string pattern of the method name.")
- .defaultValue(StringPattern.class, DEFAULT_INVALID_STRING_PATTERN));
+ .defaultValue(STRING_PATTERN, DEFAULT_INVALID_STRING_PATTERN));
}
private Group createMethodReturnTypeGroup() {
@@ -856,7 +1006,7 @@
.addParagraph(getMutuallyExclusiveForMethodProperties())
.addParagraph(getMethodDefaultDoc("any return type"))
.setDocReturn("The pattern of the method return type.")
- .defaultValue(TypePattern.class, DEFAULT_INVALID_TYPE_PATTERN));
+ .defaultValue(TYPE_PATTERN, DEFAULT_INVALID_TYPE_PATTERN));
}
private Group createMethodParametersGroup() {
@@ -868,7 +1018,7 @@
.addParagraph(getMutuallyExclusiveForMethodProperties())
.addParagraph(getMethodDefaultDoc("any parameters"))
.setDocReturn("The list of qualified type names of the method parameters.")
- .defaultArrayValue(String.class, quote("")))
+ .defaultArrayValue(JAVA_STRING, quote("")))
.addMember(
new GroupMember("methodParameterTypePatterns")
.setDocTitle(
@@ -876,7 +1026,7 @@
.addParagraph(getMutuallyExclusiveForMethodProperties())
.addParagraph(getMethodDefaultDoc("any parameters"))
.setDocReturn("The list of type patterns for the method parameters.")
- .defaultArrayValue(TypePattern.class, DEFAULT_INVALID_TYPE_PATTERN));
+ .defaultArrayValue(TYPE_PATTERN, DEFAULT_INVALID_TYPE_PATTERN));
}
private Group createFieldAnnotatedByGroup() {
@@ -894,7 +1044,7 @@
.addParagraph(getMutuallyExclusiveForFieldProperties())
.addParagraph(getFieldDefaultDoc("any field-access flags"))
.setDocReturn("The field access-flag constraints that must be met.")
- .defaultArrayEmpty(FieldAccessFlags.class));
+ .defaultArrayEmpty(FIELD_ACCESS_FLAGS));
}
private Group createFieldNameGroup() {
@@ -912,7 +1062,7 @@
.addParagraph(getMutuallyExclusiveForFieldProperties())
.addParagraph(getFieldDefaultDoc("any field name"))
.setDocReturn("The string pattern of the field name.")
- .defaultValue(StringPattern.class, DEFAULT_INVALID_STRING_PATTERN));
+ .defaultValue(STRING_PATTERN, DEFAULT_INVALID_STRING_PATTERN));
}
private Group createFieldTypeGroup() {
@@ -937,7 +1087,7 @@
.addParagraph(getMutuallyExclusiveForFieldProperties())
.addParagraph(getFieldDefaultDoc("any type"))
.setDocReturn("The type pattern for the field type.")
- .defaultValue(TypePattern.class, DEFAULT_INVALID_TYPE_PATTERN));
+ .defaultValue(TYPE_PATTERN, DEFAULT_INVALID_TYPE_PATTERN));
}
private void generateClassAndMemberPropertiesWithClassAndMemberBinding() {
@@ -1030,7 +1180,7 @@
.printDoc(this::println);
println("@Target(ElementType.ANNOTATION_TYPE)");
println("@Retention(RetentionPolicy.CLASS)");
- println("public @interface " + simpleName(StringPattern.class) + " {");
+ println("public @interface " + simpleName(STRING_PATTERN) + " {");
println();
withIndent(
() -> {
@@ -1059,7 +1209,7 @@
.printDoc(this::println);
println("@Target(ElementType.ANNOTATION_TYPE)");
println("@Retention(RetentionPolicy.CLASS)");
- println("public @interface " + simpleName(TypePattern.class) + " {");
+ println("public @interface " + simpleName(TYPE_PATTERN) + " {");
println();
withIndent(() -> typePatternGroup().generate(this));
println();
@@ -1078,7 +1228,7 @@
.printDoc(this::println);
println("@Target(ElementType.ANNOTATION_TYPE)");
println("@Retention(RetentionPolicy.CLASS)");
- println("public @interface " + simpleName(ClassNamePattern.class) + " {");
+ println("public @interface " + simpleName(CLASS_NAME_PATTERN) + " {");
println();
withIndent(
() -> {
@@ -1102,7 +1252,7 @@
.printDoc(this::println);
println("@Target(ElementType.ANNOTATION_TYPE)");
println("@Retention(RetentionPolicy.CLASS)");
- println("public @interface " + simpleName(AnnotationPattern.class) + " {");
+ println("public @interface " + simpleName(ANNOTATION_PATTERN) + " {");
println();
withIndent(
() -> {
@@ -1231,17 +1381,17 @@
.clearDocLines()
.addParagraph(
"Default kind is",
- KeepItemKind.CLASS_AND_MEMBERS.name(),
- ", meaning the annotated class and/or member is to be kept.",
+ docEnumLink(KIND_CLASS_AND_MEMBERS) + ",",
+ "meaning the annotated class and/or member is to be kept.",
"When annotating a class this can be set to",
- KeepItemKind.ONLY_CLASS.name(),
+ docEnumLink(KIND_ONLY_CLASS),
"to avoid patterns on any members.",
"That can be useful when the API members are themselves explicitly annotated.")
.addParagraph(
"It is not possible to use",
- KeepItemKind.ONLY_CLASS.name(),
+ docEnumLink(KIND_ONLY_CLASS),
"if annotating a member. Also, it is never valid to use kind",
- KeepItemKind.ONLY_MEMBERS.name(),
+ docEnumLink(KIND_ONLY_MEMBERS),
"as the API surface must keep the class if any member is to be accessible.")
.generate(this);
println();
@@ -1269,18 +1419,18 @@
+ " conditions that should be satisfied for the annotation to be in effect.")
.addParagraph(
"The translation of the "
- + docLink(UsesReflection.class)
+ + docLink(USES_REFLECTION)
+ " annotation into a "
- + docLink(KeepEdge.class)
+ + docLink(KEEP_EDGE)
+ " is as follows:")
.addParagraph(
"Assume the item of the annotation is denoted by 'CTX' and referred to as its"
+ " context.")
.addCodeBlock(
- annoSimpleName(UsesReflection.class)
+ annoSimpleName(USES_REFLECTION)
+ "(value = targets, [additionalPreconditions = preconditions])",
"==>",
- annoSimpleName(KeepEdge.class) + "(",
+ annoSimpleName(KEEP_EDGE) + "(",
" consequences = targets,",
" preconditions = {createConditionFromContext(CTX)} + preconditions",
")",
@@ -1310,7 +1460,7 @@
"@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD,"
+ " ElementType.CONSTRUCTOR})");
println("@Retention(RetentionPolicy.CLASS)");
- println("public @interface " + simpleName(UsesReflection.class) + " {");
+ println("public @interface " + simpleName(USES_REFLECTION) + " {");
println();
withIndent(
() -> {
@@ -1332,12 +1482,12 @@
.addParagraph(
"Note: Before using this annotation, consider if instead you can annotate the code"
+ " that is doing reflection with "
- + docLink(UsesReflection.class)
+ + docLink(USES_REFLECTION)
+ ". Annotating the"
+ " reflecting code is generally more clear and maintainable, and it also"
+ " naturally gives rise to edges that describe just the reflected aspects of the"
+ " program. The "
- + docLink(UsedByReflection.class)
+ + docLink(USED_BY_REFLECTION)
+ " annotation is suitable for cases where"
+ " the reflecting code is not under user control, or in migrating away from"
+ " rules.")
@@ -1371,19 +1521,18 @@
.addParagraph("If unspecified the default kind depends on the annotated item.")
.addParagraph("When annotating a class the default kind is:")
.addUnorderedList(
- docLink(KeepItemKind.ONLY_CLASS) + " if no member patterns are defined;",
- docLink(KeepItemKind.CLASS_AND_METHODS) + " if method patterns are defined;",
- docLink(KeepItemKind.CLASS_AND_FIELDS) + " if field patterns are defined;",
- docLink(KeepItemKind.CLASS_AND_MEMBERS) + "otherwise.")
+ docEnumLink(KIND_ONLY_CLASS) + " if no member patterns are defined;",
+ docEnumLink(KIND_CLASS_AND_METHODS) + " if method patterns are defined;",
+ docEnumLink(KIND_CLASS_AND_FIELDS) + " if field patterns are defined;",
+ docEnumLink(KIND_CLASS_AND_MEMBERS) + "otherwise.")
.addParagraph(
"When annotating a method the default kind is: "
- + docLink(KeepItemKind.ONLY_METHODS))
+ + docEnumLink(KIND_ONLY_METHODS))
.addParagraph(
- "When annotating a field the default kind is: "
- + docLink(KeepItemKind.ONLY_FIELDS))
+ "When annotating a field the default kind is: " + docEnumLink(KIND_ONLY_FIELDS))
.addParagraph(
"It is not possible to use "
- + docLink(KeepItemKind.ONLY_CLASS)
+ + docEnumLink(KIND_ONLY_CLASS)
+ " if annotating a member.")
.generate(this);
println();
@@ -1398,11 +1547,11 @@
println("}");
}
- private static String annoSimpleName(Class<?> clazz) {
+ private static String annoSimpleName(ClassReference clazz) {
return "@" + simpleName(clazz);
}
- private static String docLink(Class<?> clazz) {
+ private static String docLink(ClassReference clazz) {
return "{@link " + simpleName(clazz) + "}";
}
@@ -1410,12 +1559,12 @@
return "{@link #" + member.name + "}";
}
- private static String docLink(Enum<?> kind) {
- return "{@link " + simpleName(kind.getClass()) + "#" + kind.name() + "}";
+ private static String docEnumLink(EnumReference enumRef) {
+ return "{@link " + simpleName(enumRef.enumClass) + "#" + enumRef.enumValue + "}";
}
- private static String docLinkList(Enum<?>... values) {
- return StringUtils.join(", ", values, v -> docLink(v), BraceType.TUBORG);
+ private static String docEnumLinkList(EnumReference... values) {
+ return StringUtils.join(", ", values, v -> docEnumLink(v), BraceType.TUBORG);
}
private void generateConstants() {
@@ -1448,7 +1597,6 @@
generateTargetConstants();
generateKindConstants();
generateConstraintConstants();
- generateOptionConstants();
generateMemberAccessConstants();
generateMethodAccessConstants();
generateFieldAccessConstants();
@@ -1461,8 +1609,8 @@
println("}");
}
- private void generateAnnotationConstants(Class<?> clazz) {
- String desc = TestBase.descriptor(clazz);
+ private void generateAnnotationConstants(ClassReference clazz) {
+ String desc = clazz.getDescriptor();
println("public static final String DESCRIPTOR = " + quote(desc) + ";");
}
@@ -1470,7 +1618,7 @@
println("public static final class Edge {");
withIndent(
() -> {
- generateAnnotationConstants(KeepEdge.class);
+ generateAnnotationConstants(KEEP_EDGE);
createDescriptionGroup().generateConstants(this);
createBindingsGroup().generateConstants(this);
createPreconditionsGroup().generateConstants(this);
@@ -1484,7 +1632,7 @@
println("public static final class ForApi {");
withIndent(
() -> {
- generateAnnotationConstants(KeepForApi.class);
+ generateAnnotationConstants(KEEP_FOR_API);
createDescriptionGroup().generateConstants(this);
createAdditionalTargetsGroup(".").generateConstants(this);
createMemberAccessGroup().generateConstants(this);
@@ -1497,7 +1645,7 @@
println("public static final class UsesReflection {");
withIndent(
() -> {
- generateAnnotationConstants(UsesReflection.class);
+ generateAnnotationConstants(USES_REFLECTION);
createDescriptionGroup().generateConstants(this);
createConsequencesAsValueGroup().generateConstants(this);
createAdditionalPreconditionsGroup().generateConstants(this);
@@ -1510,7 +1658,7 @@
println("public static final class UsedByReflection {");
withIndent(
() -> {
- generateAnnotationConstants(UsedByReflection.class);
+ generateAnnotationConstants(USED_BY_REFLECTION);
createDescriptionGroup().generateConstants(this);
createPreconditionsGroup().generateConstants(this);
createAdditionalTargetsGroup(".").generateConstants(this);
@@ -1523,8 +1671,8 @@
println("public static final class UsedByNative {");
withIndent(
() -> {
- generateAnnotationConstants(UsedByNative.class);
- println("// Content is the same as " + simpleName(UsedByReflection.class) + ".");
+ generateAnnotationConstants(USED_BY_NATIVE);
+ println("// Content is the same as " + simpleName(USED_BY_REFLECTION) + ".");
});
println("}");
println();
@@ -1534,7 +1682,7 @@
println("public static final class CheckRemoved {");
withIndent(
() -> {
- generateAnnotationConstants(CheckRemoved.class);
+ generateAnnotationConstants(CHECK_REMOVED);
});
println("}");
println();
@@ -1544,7 +1692,7 @@
println("public static final class CheckOptimizedOut {");
withIndent(
() -> {
- generateAnnotationConstants(CheckOptimizedOut.class);
+ generateAnnotationConstants(CHECK_OPTIMIZED_OUT);
});
println("}");
println();
@@ -1587,7 +1735,7 @@
println("public static final class Binding {");
withIndent(
() -> {
- generateAnnotationConstants(KeepBinding.class);
+ generateAnnotationConstants(KEEP_BINDING);
bindingName().generateConstants(this);
});
println("}");
@@ -1598,7 +1746,7 @@
println("public static final class Condition {");
withIndent(
() -> {
- generateAnnotationConstants(KeepCondition.class);
+ generateAnnotationConstants(KEEP_CONDITION);
});
println("}");
println();
@@ -1608,7 +1756,7 @@
println("public static final class Target {");
withIndent(
() -> {
- generateAnnotationConstants(KeepTarget.class);
+ generateAnnotationConstants(KEEP_TARGET);
getKindGroup().generateConstants(this);
forEachKeepConstraintGroups(g -> g.generateConstants(this));
});
@@ -1620,7 +1768,7 @@
println("public static final class Kind {");
withIndent(
() -> {
- generateAnnotationConstants(KeepItemKind.class);
+ generateAnnotationConstants(KEEP_ITEM_KIND);
for (KeepItemKind value : KeepItemKind.values()) {
if (value != KeepItemKind.DEFAULT) {
println(
@@ -1640,33 +1788,27 @@
println("public static final class Constraints {");
withIndent(
() -> {
- generateAnnotationConstants(KeepConstraint.class);
- for (KeepConstraint value : KeepConstraint.values()) {
+ generateAnnotationConstants(KEEP_CONSTRAINT);
+ for (EnumReference constraint : KEEP_CONSTRAINT_VALUES) {
println(
- "public static final String " + value.name() + " = " + quote(value.name()) + ";");
+ "public static final String "
+ + constraint.enumValue
+ + " = "
+ + quote(constraint.enumValue)
+ + ";");
}
});
println("}");
println();
}
- private void generateOptionConstants() {
- println("public static final class Option {");
- withIndent(
- () -> {
- generateAnnotationConstants(KeepOption.class);
- for (KeepOption value : KeepOption.values()) {
- println(
- "public static final String " + value.name() + " = " + quote(value.name()) + ";");
- }
- });
- println("}");
- println();
+ private boolean isAccessPropertyNegation(EnumReference enumReference) {
+ return enumReference.name().startsWith("NON_");
}
- private boolean isMemberAccessProperty(String name) {
- for (MemberAccessFlags value : MemberAccessFlags.values()) {
- if (value.name().equals(name)) {
+ private boolean isMemberAccessProperty(EnumReference enumReference) {
+ for (EnumReference memberAccessValue : MEMBER_ACCESS_VALUES) {
+ if (memberAccessValue.enumValue.equals(enumReference.enumValue)) {
return true;
}
}
@@ -1677,17 +1819,13 @@
println("public static final class MemberAccess {");
withIndent(
() -> {
- generateAnnotationConstants(MemberAccessFlags.class);
+ generateAnnotationConstants(MEMBER_ACCESS_FLAGS);
println("public static final String NEGATION_PREFIX = \"NON_\";");
- for (MemberAccessFlags value : MemberAccessFlags.values()) {
- if (!value.name().startsWith("NON_")) {
- println(
- "public static final String "
- + value.name()
- + " = "
- + quote(value.name())
- + ";");
- }
+ for (EnumReference value : MEMBER_ACCESS_VALUES) {
+ assert !isAccessPropertyNegation(value);
+ assert isMemberAccessProperty(value);
+ println(
+ "public static final String " + value.name() + " = " + quote(value.name()) + ";");
}
});
println("}");
@@ -1698,11 +1836,10 @@
println("public static final class MethodAccess {");
withIndent(
() -> {
- generateAnnotationConstants(MethodAccessFlags.class);
- for (MethodAccessFlags value : MethodAccessFlags.values()) {
- if (value.name().startsWith("NON_") || isMemberAccessProperty(value.name())) {
- continue;
- }
+ generateAnnotationConstants(METHOD_ACCESS_FLAGS);
+ for (EnumReference value : METHOD_ACCESS_VALUES) {
+ assert !isAccessPropertyNegation(value);
+ assert !isMemberAccessProperty(value);
println(
"public static final String " + value.name() + " = " + quote(value.name()) + ";");
}
@@ -1715,11 +1852,10 @@
println("public static final class FieldAccess {");
withIndent(
() -> {
- generateAnnotationConstants(FieldAccessFlags.class);
- for (FieldAccessFlags value : FieldAccessFlags.values()) {
- if (value.name().startsWith("NON_") || isMemberAccessProperty(value.name())) {
- continue;
- }
+ generateAnnotationConstants(FIELD_ACCESS_FLAGS);
+ for (EnumReference value : FIELD_ACCESS_VALUES) {
+ assert !isAccessPropertyNegation(value);
+ assert !isMemberAccessProperty(value);
println(
"public static final String " + value.name() + " = " + quote(value.name()) + ";");
}
@@ -1732,7 +1868,7 @@
println("public static final class StringPattern {");
withIndent(
() -> {
- generateAnnotationConstants(StringPattern.class);
+ generateAnnotationConstants(STRING_PATTERN);
stringPatternExactGroup().generateConstants(this);
stringPatternPrefixGroup().generateConstants(this);
stringPatternSuffixGroup().generateConstants(this);
@@ -1745,7 +1881,7 @@
println("public static final class TypePattern {");
withIndent(
() -> {
- generateAnnotationConstants(TypePattern.class);
+ generateAnnotationConstants(TYPE_PATTERN);
typePatternGroup().generateConstants(this);
});
println("}");
@@ -1756,7 +1892,7 @@
println("public static final class ClassNamePattern {");
withIndent(
() -> {
- generateAnnotationConstants(ClassNamePattern.class);
+ generateAnnotationConstants(CLASS_NAME_PATTERN);
classNamePatternSimpleNameGroup().generateConstants(this);
classNamePatternPackageGroup().generateConstants(this);
});
@@ -1768,7 +1904,7 @@
println("public static final class AnnotationPattern {");
withIndent(
() -> {
- generateAnnotationConstants(AnnotationPattern.class);
+ generateAnnotationConstants(ANNOTATION_PATTERN);
annotationNameGroup().generateConstants(this);
annotationRetention().generateConstants(this);
});
@@ -1776,7 +1912,8 @@
println();
}
- private static void writeFile(Path file, Consumer<Generator> fn) throws IOException {
+ private static void writeFile(Path file, Consumer<Generator> fn, BiConsumer<Path, String> write)
+ throws IOException {
ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(byteStream);
Generator generator = new Generator(printStream);
@@ -1785,38 +1922,39 @@
if (file.toString().endsWith(".java")) {
formatted = CodeGenerationBase.formatRawOutput(formatted);
}
- Files.write(Paths.get(ToolHelper.getProjectRoot()).resolve(file), formatted.getBytes());
+ Path resolved = Paths.get(ToolHelper.getProjectRoot()).resolve(file);
+ write.accept(resolved, formatted);
}
- public static Path source(Path pkg, Class<?> clazz) {
- return pkg.resolve(simpleName(clazz) + ".java");
+ public static Path source(ClassReference clazz) {
+ return Paths.get("src", "keepanno", "java").resolve(clazz.getBinaryName() + ".java");
}
- public static void run() throws IOException {
- writeFile(Paths.get("doc/keepanno-guide.md"), KeepAnnoMarkdownGenerator::generateMarkdownDoc);
-
- Path keepAnnoRoot = Paths.get("src/keepanno/java/com/android/tools/r8/keepanno");
-
- Path astPkg = keepAnnoRoot.resolve("ast");
- writeFile(source(astPkg, AnnotationConstants.class), Generator::generateConstants);
-
- Path annoPkg = Paths.get("src/keepanno/java/com/android/tools/r8/keepanno/annotations");
- writeFile(source(annoPkg, StringPattern.class), Generator::generateStringPattern);
- writeFile(source(annoPkg, TypePattern.class), Generator::generateTypePattern);
- writeFile(source(annoPkg, ClassNamePattern.class), Generator::generateClassNamePattern);
- writeFile(source(annoPkg, AnnotationPattern.class), Generator::generateAnnotationPattern);
- writeFile(source(annoPkg, KeepBinding.class), Generator::generateKeepBinding);
- writeFile(source(annoPkg, KeepTarget.class), Generator::generateKeepTarget);
- writeFile(source(annoPkg, KeepCondition.class), Generator::generateKeepCondition);
- writeFile(source(annoPkg, KeepForApi.class), Generator::generateKeepForApi);
- writeFile(source(annoPkg, UsesReflection.class), Generator::generateUsesReflection);
+ public static void run(BiConsumer<Path, String> write) throws IOException {
+ Path projectRoot = Paths.get(ToolHelper.getProjectRoot());
writeFile(
- source(annoPkg, UsedByReflection.class),
- g -> g.generateUsedByX("UsedByReflection", "accessed reflectively"));
+ Paths.get("doc/keepanno-guide.md"),
+ generator -> KeepAnnoMarkdownGenerator.generateMarkdownDoc(generator, projectRoot),
+ write);
+
+ writeFile(source(ANNOTATION_CONSTANTS), Generator::generateConstants, write);
+ writeFile(source(STRING_PATTERN), Generator::generateStringPattern, write);
+ writeFile(source(TYPE_PATTERN), Generator::generateTypePattern, write);
+ writeFile(source(CLASS_NAME_PATTERN), Generator::generateClassNamePattern, write);
+ writeFile(source(ANNOTATION_PATTERN), Generator::generateAnnotationPattern, write);
+ writeFile(source(KEEP_BINDING), Generator::generateKeepBinding, write);
+ writeFile(source(KEEP_TARGET), Generator::generateKeepTarget, write);
+ writeFile(source(KEEP_CONDITION), Generator::generateKeepCondition, write);
+ writeFile(source(KEEP_FOR_API), Generator::generateKeepForApi, write);
+ writeFile(source(USES_REFLECTION), Generator::generateUsesReflection, write);
writeFile(
- source(annoPkg, UsedByNative.class),
- g -> g.generateUsedByX("UsedByNative", "accessed from native code via JNI"));
+ source(USED_BY_REFLECTION),
+ g -> g.generateUsedByX("UsedByReflection", "accessed reflectively"),
+ write);
+ writeFile(
+ source(USED_BY_NATIVE),
+ g -> g.generateUsedByX("UsedByNative", "accessed from native code via JNI"),
+ write);
}
}
-
}
diff --git a/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemGeneratedFilesTest.java b/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemGeneratedFilesTest.java
new file mode 100644
index 0000000..28f1c57
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/keepanno/utils/KeepItemGeneratedFilesTest.java
@@ -0,0 +1,29 @@
+// Copyright (c) 2024, 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.keepanno.utils;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.keepanno.utils.KeepItemAnnotationGenerator.Generator;
+import com.android.tools.r8.utils.FileUtils;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import org.junit.Test;
+
+public class KeepItemGeneratedFilesTest {
+
+ @Test
+ public void checkUpToDate() throws IOException {
+ Generator.run(
+ (file, content) -> {
+ try {
+ String expectedContent = FileUtils.readTextFile(file, StandardCharsets.UTF_8);
+ assertEquals(expectedContent, content);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/retraceproguard/CatchAllRangeWithNoLineNumberTest.java b/src/test/java/com/android/tools/r8/naming/retraceproguard/CatchAllRangeWithNoLineNumberTest.java
index f7f1410..a0ce500 100644
--- a/src/test/java/com/android/tools/r8/naming/retraceproguard/CatchAllRangeWithNoLineNumberTest.java
+++ b/src/test/java/com/android/tools/r8/naming/retraceproguard/CatchAllRangeWithNoLineNumberTest.java
@@ -119,10 +119,7 @@
return retraced5_2_1;
case V6_0_1:
return retraced6_0_1;
- case V7_0_0:
- return retraced7_0_0;
default:
- assertEquals(ProguardVersion.V7_3_2, proguardVersion);
return retraced7_0_0;
}
}
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/HorizontallyMergedConstructorMethodProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/HorizontallyMergedConstructorMethodProfileRewritingTest.java
index 1c3a805..faea413 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/HorizontallyMergedConstructorMethodProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/HorizontallyMergedConstructorMethodProfileRewritingTest.java
@@ -51,14 +51,36 @@
ClassSubject aClassSubject = inspector.clazz(A.class);
assertThat(aClassSubject, isPresent());
- MethodSubject syntheticConstructorSubject = aClassSubject.uniqueMethod();
+ MethodSubject syntheticConstructorSubject =
+ aClassSubject.uniqueMethodThatMatches(
+ method -> method.isInstanceInitializer() && method.isSynthetic());
assertThat(syntheticConstructorSubject, isPresent());
assertEquals(2, syntheticConstructorSubject.getParameters().size());
assertEquals(aClassSubject.asTypeSubject(), syntheticConstructorSubject.getParameter(0));
assertEquals("int", syntheticConstructorSubject.getParameter(1).getTypeName());
+ MethodSubject aConstructorSubject =
+ aClassSubject.uniqueMethodThatMatches(
+ method ->
+ method.isInstanceInitializer()
+ && !method.isSynthetic()
+ && method.getProgramMethod().getReference().getArity() == 1);
+ assertThat(syntheticConstructorSubject, isPresent());
+
+ MethodSubject bConstructorSubject =
+ aClassSubject.uniqueMethodThatMatches(
+ method ->
+ method.isInstanceInitializer()
+ && !method.isSynthetic()
+ && method.getProgramMethod().getReference().getArity() == 2);
+ assertThat(syntheticConstructorSubject, isPresent());
+
profileInspector
- .assertContainsMethodRule(syntheticConstructorSubject)
+ .assertContainsMethodRules(syntheticConstructorSubject)
+ .applyIf(
+ this == A_CONSTRUCTOR,
+ i -> i.assertContainsMethodRule(aConstructorSubject),
+ i -> i.assertContainsMethodRule(bConstructorSubject))
.assertContainsNoOtherRules();
}
}
@@ -83,7 +105,7 @@
.addArtProfileForRewriting(artProfileInputOutput.getArtProfile())
.addHorizontallyMergedClassesInspector(
inspector -> inspector.assertMergedInto(B.class, A.class).assertNoOtherClassesMerged())
- .addOptionsModification(InlinerOptions::setOnlyForceInlining)
+ .addOptionsModification(InlinerOptions::disableInlining)
.addOptionsModification(
options -> options.callSiteOptimizationOptions().disableOptimization())
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java b/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
index 43808b8..cd72b73 100644
--- a/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/profile/art/completeness/RecordProfileRewritingTest.java
@@ -166,6 +166,7 @@
inspector,
SyntheticItemsTestUtils.syntheticRecordTagClass(),
false,
+ false,
parameters.canUseNestBasedAccessesWhenDesugaring(),
!isRecordsDesugaredForD8(parameters));
}
@@ -176,6 +177,7 @@
inspector,
RECORD_REFERENCE,
parameters.canHaveNonReboundConstructorInvoke(),
+ true,
parameters.canUseNestBasedAccesses(),
!isRecordsDesugaredForR8(parameters));
}
@@ -185,6 +187,7 @@
CodeInspector inspector,
ClassReference recordClassReference,
boolean canHaveNonReboundConstructorInvoke,
+ boolean canMergeRecordTag,
boolean canUseNestBasedAccesses,
boolean canUseRecords) {
ClassSubject mainClassSubject = inspector.clazz(MAIN_REFERENCE);
@@ -194,8 +197,7 @@
assertThat(mainMethodSubject, isPresent());
ClassSubject recordTagClassSubject = inspector.clazz(recordClassReference);
- assertThat(
- recordTagClassSubject, isAbsentIf(canHaveNonReboundConstructorInvoke || canUseRecords));
+ assertThat(recordTagClassSubject, isAbsentIf(canMergeRecordTag || canUseRecords));
if (recordTagClassSubject.isPresent()) {
assertEquals(
canHaveNonReboundConstructorInvoke ? 0 : 1, recordTagClassSubject.allMethods().size());
@@ -207,16 +209,25 @@
ClassSubject personRecordClassSubject = inspector.clazz(PERSON_REFERENCE);
assertThat(personRecordClassSubject, isPresent());
assertEquals(
- canHaveNonReboundConstructorInvoke
- ? inspector.getTypeSubject(Object.class.getTypeName())
- : canUseRecords
- ? inspector.getTypeSubject(RECORD_REFERENCE.getTypeName())
+ canUseRecords
+ ? inspector.getTypeSubject(RECORD_REFERENCE.getTypeName())
+ : canMergeRecordTag
+ ? inspector.getTypeSubject(Object.class.getTypeName())
: recordTagClassSubject.asTypeSubject(),
personRecordClassSubject.getSuperType());
- assertEquals(canUseRecords ? 6 : 10, personRecordClassSubject.allMethods().size());
+ assertEquals(
+ canUseRecords ? 6 : canHaveNonReboundConstructorInvoke || !canMergeRecordTag ? 10 : 11,
+ personRecordClassSubject.allMethods().size());
+
+ MethodSubject personDefaultInstanceInitializerSubject = personRecordClassSubject.init();
+ assertThat(
+ personDefaultInstanceInitializerSubject,
+ isPresentIf(!canHaveNonReboundConstructorInvoke && canMergeRecordTag && !canUseRecords));
MethodSubject personInstanceInitializerSubject =
- personRecordClassSubject.uniqueInstanceInitializer();
+ canMergeRecordTag
+ ? personRecordClassSubject.init(String.class.getTypeName())
+ : personRecordClassSubject.init(String.class.getTypeName(), "int");
assertThat(personInstanceInitializerSubject, isPresent());
// Name getters.
@@ -306,6 +317,9 @@
i.assertContainsMethodRules(
nameNestAccessorMethodSubject, ageNestAccessorMethodSubject))
.applyIf(
+ !canHaveNonReboundConstructorInvoke && canMergeRecordTag && !canUseRecords,
+ i -> i.assertContainsMethodRule(personDefaultInstanceInitializerSubject))
+ .applyIf(
!canUseRecords,
i ->
i.assertContainsClassRules(hashCodeHelperClassSubject, toStringHelperClassSubject)
@@ -315,7 +329,7 @@
hashCodeHelperMethodSubject,
toStringHelperMethodSubject)
.applyIf(
- !canHaveNonReboundConstructorInvoke,
+ !canMergeRecordTag,
j ->
j.assertContainsClassRules(recordTagClassSubject)
.assertContainsMethodRule(recordTagInstanceInitializerSubject)))
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 3b75886..e6f9092 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,9 +30,22 @@
this.artProfile = artProfile;
}
- public ArtProfileInspector applyIf(boolean condition, Consumer<ArtProfileInspector> fn) {
+ public ArtProfileInspector applyIf(
+ boolean condition, Consumer<ArtProfileInspector> thenConsumer) {
if (condition) {
- fn.accept(this);
+ thenConsumer.accept(this);
+ }
+ return this;
+ }
+
+ public ArtProfileInspector applyIf(
+ boolean condition,
+ Consumer<ArtProfileInspector> thenConsumer,
+ Consumer<ArtProfileInspector> elseConsumer) {
+ if (condition) {
+ thenConsumer.accept(this);
+ } else {
+ elseConsumer.accept(this);
}
return this;
}
diff --git a/src/test/java/com/android/tools/r8/rewrite/arrays/B322478366RegressionTest.java b/src/test/java/com/android/tools/r8/rewrite/arrays/B322478366RegressionTest.java
new file mode 100644
index 0000000..d4b1d3d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/arrays/B322478366RegressionTest.java
@@ -0,0 +1,119 @@
+// Copyright (c) 2024, 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.rewrite.arrays;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+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 B322478366RegressionTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameter(1)
+ public CompilationMode mode;
+
+ @Parameters(name = "{0}, mode {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(), CompilationMode.values());
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ parameters.assumeDexRuntime();
+ testForD8()
+ .addInnerClasses(getClass())
+ .setMinApi(parameters)
+ .setMode(mode)
+ .compile()
+ .inspect(inspector -> inspect(inspector, true));
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters)
+ .setMode(mode)
+ .enableInliningAnnotations()
+ .compile()
+ .inspect(inspector -> inspect(inspector, false));
+ }
+
+ private void inspect(CodeInspector inspector, boolean isD8) {
+ if (isD8 || mode.isDebug()) {
+ MethodSubject m1 = inspector.clazz(Main.class).uniqueMethodWithOriginalName("m1");
+ assertEquals(0, m1.streamInstructions().filter(InstructionSubject::isNewArray).count());
+ MethodSubject m2 = inspector.clazz(Main.class).uniqueMethodWithOriginalName("m2");
+ // TODO(b/322478366): Cts test CtsPerfettoTestCases.HeapprofdJavaCtsTest#DebuggableAppOom
+ // requires that the array allocation stays.
+ assertEquals(
+ mode.isDebug() ? 1 : 0,
+ m2.streamInstructions().filter(InstructionSubject::isNewArray).count());
+ MethodSubject m3 = inspector.clazz(Main.class).uniqueMethodWithOriginalName("m3");
+ assertEquals(
+ mode.isDebug() ? 1 : 0,
+ m3.streamInstructions().filter(InstructionSubject::isNewArray).count());
+ } else {
+ assertThat(inspector.clazz(Main.class).uniqueMethodWithOriginalName("m1"), isAbsent());
+ assertThat(inspector.clazz(Main.class).uniqueMethodWithOriginalName("m2"), isAbsent());
+ assertThat(inspector.clazz(Main.class).uniqueMethodWithOriginalName("m3"), isAbsent());
+ }
+ }
+
+ public static class Main {
+ @NeverInline
+ public static void m1() {
+ try {
+ byte[] bytes = new byte[1];
+ // No local information from javac for bytes, as local not observable in a debugger.
+ } catch (OutOfMemoryError e) {
+ }
+ }
+
+ @NeverInline
+ public static void m2() {
+ try {
+ byte[] bytes = new byte[Integer.MAX_VALUE];
+ // No local information from javac for bytes, as local not observable in a debugger.
+ } catch (OutOfMemoryError e) {
+ }
+ }
+
+ @NeverInline
+ public static void m3() {
+ try {
+ byte[] bytes = new byte[1];
+ // Local information from javac for bytes, as the return statement makes it observable
+ // in a debugger.
+ return;
+ } catch (OutOfMemoryError e) {
+ }
+ }
+
+ public static void main(String[] args) {
+ m1();
+ m2();
+ m3();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/ConditionalKeepOnUsedFieldTest.java b/src/test/java/com/android/tools/r8/shaking/ConditionalKeepOnUsedFieldTest.java
new file mode 100644
index 0000000..7d8a957
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/ConditionalKeepOnUsedFieldTest.java
@@ -0,0 +1,64 @@
+// Copyright (c) 2024, 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.shaking;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ConditionalKeepOnUsedFieldTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("0");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDefaultRuntimes().withMinimumApiLevel().build();
+ }
+
+ public ConditionalKeepOnUsedFieldTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(ConditionalKeepOnUsedFieldTest.class)
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters)
+ .addKeepRules("-if class **$A { *** used; } -keepclassmembers class <1>$A { <2> x; }")
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(
+ inspector ->
+ assertThat(
+ inspector.clazz(A.class).uniqueFieldWithOriginalName("x"),
+ // TODO(b/322910135): The conditional rule should have kept x.
+ isAbsent()));
+ }
+
+ static class A {
+ // This field is used but its value trivial.
+ public final int used = 0;
+ public static final int x = 1;
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ A a = System.nanoTime() < 0 ? null : new A();
+ System.out.println(a.used);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/ConditionalKeepOnUsedMethodTest.java b/src/test/java/com/android/tools/r8/shaking/ConditionalKeepOnUsedMethodTest.java
new file mode 100644
index 0000000..8401f7b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/ConditionalKeepOnUsedMethodTest.java
@@ -0,0 +1,67 @@
+// Copyright (c) 2024, 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.shaking;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ConditionalKeepOnUsedMethodTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("0");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDefaultRuntimes().withMinimumApiLevel().build();
+ }
+
+ public ConditionalKeepOnUsedMethodTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(ConditionalKeepOnUsedMethodTest.class)
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters)
+ .addKeepRules("-if class **$A { *** used(); } -keepclassmembers class <1>$A { <2> x; }")
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(
+ inspector ->
+ assertThat(
+ inspector.clazz(A.class).uniqueFieldWithOriginalName("x"),
+ // TODO(b/322910135): The conditional rule should have kept x.
+ isAbsent()));
+ }
+
+ static class A {
+ // This method is used but its value trivial.
+ public static int used() {
+ return 0;
+ }
+
+ public static final int x = 1;
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ A a = System.nanoTime() < 0 ? null : new A();
+ System.out.println(a.used());
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java b/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
index c0211ef..86f4fd6 100644
--- a/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/KeepAnnotatedMemberTest.java
@@ -252,7 +252,8 @@
.apply(this::suppressZipFileAssignmentsToJavaLangAutoCloseable)
.compile()
.graphInspector();
- assertRetainedClassesEqual(referenceInspector, ifThenKeepClassesWithMembersInspector);
+ assertRetainedClassesEqual(
+ referenceInspector, ifThenKeepClassesWithMembersInspector, true, true);
GraphInspector ifHasMemberThenKeepClassInspector =
testForR8(Backend.CF)
@@ -273,7 +274,7 @@
.apply(this::suppressZipFileAssignmentsToJavaLangAutoCloseable)
.compile()
.graphInspector();
- assertRetainedClassesEqual(referenceInspector, ifHasMemberThenKeepClassInspector);
+ assertRetainedClassesEqual(referenceInspector, ifHasMemberThenKeepClassInspector, true, true);
}
private void configureHorizontalClassMerging(R8FullTestBuilder testBuilder) {
diff --git a/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java b/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java
index da8944c..dd7d5da 100644
--- a/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ParameterTypeTest.java
@@ -141,8 +141,7 @@
.inspector();
ClassSubject superInterface1 = inspector.clazz(B112452064SuperInterface1.class);
- assertThat(
- superInterface1, isAbsentIf(enableUnusedInterfaceRemoval && enableVerticalClassMerging));
+ assertThat(superInterface1, isAbsentIf(enableVerticalClassMerging));
MethodSubject foo = superInterface1.uniqueMethodWithOriginalName("foo");
assertThat(foo, isAbsent());
diff --git a/src/test/java/com/android/tools/r8/shaking/PrintUsageTest.java b/src/test/java/com/android/tools/r8/shaking/PrintUsageTest.java
index fdb513c..9f63d3a 100644
--- a/src/test/java/com/android/tools/r8/shaking/PrintUsageTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/PrintUsageTest.java
@@ -175,11 +175,11 @@
private static void inspectShaking9(PrintUsageInspector inspector) {
Optional<ClassSubject> superClass = inspector.clazz("shaking9.Superclass");
- assertFalse(superClass.isPresent());
+ assertTrue(superClass.isPresent());
Optional<ClassSubject> subClass = inspector.clazz("shaking9.Subclass");
assertTrue(subClass.isPresent());
assertTrue(subClass.get().method("void", "aMethod", ImmutableList.of()));
- assertFalse(subClass.get().method("void", "<init>", ImmutableList.of()));
+ assertTrue(subClass.get().method("void", "<init>", ImmutableList.of()));
}
private static void inspectShaking12(PrintUsageInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking14Test.java b/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking14Test.java
index 4733d3c..610a9c6 100644
--- a/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking14Test.java
+++ b/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking14Test.java
@@ -3,13 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking.examples;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.shaking.TreeShakingTest;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import java.util.List;
-import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -48,12 +50,9 @@
private static void shaking14EnsureRightStaticMethodsLive(CodeInspector inspector) {
ClassSubject superclass = inspector.clazz("shaking14.Superclass");
- Assert.assertFalse(superclass.method("int", "aMethod", ImmutableList.of("int")).isPresent());
- Assert.assertFalse(
- superclass.method("double", "anotherMethod", ImmutableList.of("double")).isPresent());
+ assertThat(superclass, isAbsent());
+
ClassSubject subclass = inspector.clazz("shaking14.Subclass");
- Assert.assertTrue(subclass.method("int", "aMethod", ImmutableList.of("int")).isPresent());
- Assert.assertTrue(
- subclass.method("double", "anotherMethod", ImmutableList.of("double")).isPresent());
+ assertThat(subclass, isAbsent());
}
}
diff --git a/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking9Test.java b/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking9Test.java
index 3b80981..99cbc57 100644
--- a/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking9Test.java
+++ b/src/test/java/com/android/tools/r8/shaking/examples/TreeShaking9Test.java
@@ -4,9 +4,7 @@
package com.android.tools.r8.shaking.examples;
import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isAbstract;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentIf;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.TestParameters;
@@ -45,10 +43,7 @@
@Test
public void testKeeprules() throws Exception {
runTest(
- this::shaking9OnlySuperMethodsKept,
- null,
- null,
- ImmutableList.of("src/test/examples/shaking9/keep-rules.txt"));
+ this::inspect, null, null, ImmutableList.of("src/test/examples/shaking9/keep-rules.txt"));
}
@Test
@@ -57,19 +52,12 @@
null, null, null, ImmutableList.of("src/test/examples/shaking9/keep-rules-printusage.txt"));
}
- private void shaking9OnlySuperMethodsKept(CodeInspector inspector) {
+ private void inspect(CodeInspector inspector) {
ClassSubject superclass = inspector.clazz("shaking9.Superclass");
- if (parameters.canHaveNonReboundConstructorInvoke()) {
- assertThat(superclass, isAbsent());
- } else {
- assertThat(superclass, isAbstract());
- assertThat(superclass.method("void", "aMethod", ImmutableList.of()), isPresent());
- }
+ assertThat(superclass, isAbsent());
ClassSubject subclass = inspector.clazz("shaking9.Subclass");
assertThat(subclass, isPresent());
- assertThat(
- subclass.method("void", "aMethod", ImmutableList.of()),
- isPresentIf(parameters.canHaveNonReboundConstructorInvoke() && !getMinify().isMinify()));
+ assertThat(subclass.method("void", "aMethod", ImmutableList.of()), isAbsent());
}
}
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
index e69bb0f..47d969c 100644
--- a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
@@ -139,10 +139,6 @@
return syntheticClass(reference, naming.RECORD_HELPER, id);
}
- public static ClassReference syntheticTwrCloseResourceClass(Class<?> clazz, int id) {
- return syntheticClass(clazz, naming.TWR_CLOSE_RESOURCE, id);
- }
-
public static ClassReference syntheticTwrCloseResourceClass(ClassReference reference, int id) {
return syntheticClass(reference, naming.TWR_CLOSE_RESOURCE, id);
}
@@ -302,12 +298,6 @@
reference, Phase.EXTERNAL, naming.NON_FIXED_INIT_TYPE_ARGUMENT);
}
- public static boolean isHorizontalInitializerTypeArgument(ClassReference reference) {
- return SyntheticNaming.isSynthetic(reference, null, naming.HORIZONTAL_INIT_TYPE_ARGUMENT_1)
- || SyntheticNaming.isSynthetic(reference, null, naming.HORIZONTAL_INIT_TYPE_ARGUMENT_2)
- || SyntheticNaming.isSynthetic(reference, null, naming.HORIZONTAL_INIT_TYPE_ARGUMENT_3);
- }
-
public static boolean isWrapper(ClassReference reference) {
return SyntheticNaming.isSynthetic(reference, null, naming.WRAPPER)
|| SyntheticNaming.isSynthetic(reference, null, naming.VIVIFIED_WRAPPER);
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesDefaultMethodInSubInterfaceTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesDefaultMethodInSubInterfaceTest.java
new file mode 100644
index 0000000..95ef480
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesDefaultMethodInSubInterfaceTest.java
@@ -0,0 +1,320 @@
+// Copyright (c) 2024, 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.tracereferences;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
+import com.google.common.collect.ImmutableSet;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+import org.junit.BeforeClass;
+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;
+
+// From b/319190998.
+@RunWith(Parameterized.class)
+public class TraceReferencesDefaultMethodInSubInterfaceTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ .withAllRuntimesAndApiLevels()
+ .withAllApiLevelsAlsoForCf()
+ .withNoneRuntime()
+ .build();
+ }
+
+ static Path targetJar;
+ static Path sourceJar;
+ private static final String EXPECTED_OUTPUT = StringUtils.lines("Hello, world!");
+
+ @BeforeClass
+ public static void setUp() throws Exception {
+ Path dir = getStaticTemp().newFolder().toPath();
+ targetJar =
+ ZipBuilder.builder(dir.resolve("target.jar"))
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(I.class),
+ ToolHelper.getClassFileForTestClass(J.class))
+ .build();
+ sourceJar =
+ ZipBuilder.builder(dir.resolve("source.jar"))
+ .addFilesRelative(
+ ToolHelper.getClassPathForTests(),
+ ToolHelper.getClassFileForTestClass(JImpl.class),
+ ToolHelper.getClassFileForTestClass(Main.class))
+ .build();
+ }
+
+ static class SeenReferencesConsumer implements TraceReferencesConsumer {
+
+ private final Set<MethodReference> seenMethods = new HashSet<>();
+
+ @Override
+ public void acceptType(TracedClass tracedClass, DiagnosticsHandler handler) {}
+
+ @Override
+ public void acceptField(TracedField tracedField, DiagnosticsHandler handler) {}
+
+ @Override
+ public void acceptMethod(TracedMethod tracedMethod, DiagnosticsHandler handler) {
+ seenMethods.add(tracedMethod.getReference());
+ }
+ }
+
+ @Test
+ public void testTracedReferences() throws Exception {
+ assumeTrue(parameters.isNoneRuntime());
+ SeenReferencesConsumer consumer = new SeenReferencesConsumer();
+ TraceReferences.run(
+ TraceReferencesCommand.builder()
+ .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+ .addSourceFiles(sourceJar)
+ .addTargetFiles(targetJar)
+ .setConsumer(consumer)
+ .build());
+
+ // TODO(b/319190998): Just tracing I.m is not enough.
+ ImmutableSet<MethodReference> expectedSet =
+ ImmutableSet.of(
+ Reference.method(
+ Reference.classFromClass(I.class),
+ "m",
+ Collections.emptyList(),
+ Reference.classFromClass(Object.class)));
+ assertEquals(expectedSet, consumer.seenMethods);
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ parameters.assumeJvmTestParameters();
+ testForJvm(parameters)
+ .addProgramFiles(sourceJar)
+ .addProgramFiles(targetJar)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ parameters.assumeDexRuntime();
+ Path targetDex =
+ testForD8().setMinApi(parameters).addProgramFiles(targetJar).compile().writeToZip();
+
+ testForD8()
+ .setMinApi(parameters)
+ .addClasspathFiles(targetJar)
+ .addProgramFiles(sourceJar)
+ .addRunClasspathFiles(targetDex)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ @Test
+ public void testGeneratedKeepRulesFollowedByR8() throws Exception {
+ parameters.assumeR8TestParameters();
+
+ Path generatedKeepRules = temp.newFile("keep.rules").toPath();
+ TraceReferencesKeepRules keepRulesConsumer =
+ TraceReferencesKeepRules.builder()
+ // The use of keeper in b/319190998 disables obfuscation of generated keep rules.
+ .setAllowObfuscation(false)
+ .setOutputPath(generatedKeepRules)
+ .build();
+ TraceReferences.run(
+ TraceReferencesCommand.builder()
+ .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+ .addSourceFiles(sourceJar)
+ .addTargetFiles(targetJar)
+ .setConsumer(keepRulesConsumer)
+ .build());
+
+ Path r8CompiledTarget =
+ testForR8(parameters.getBackend())
+ .setMinApi(parameters)
+ .addProgramFiles(targetJar)
+ .addKeepRuleFiles(generatedKeepRules)
+ .compile()
+ .writeToZip();
+
+ testForR8(parameters.getBackend())
+ .setMinApi(parameters)
+ .addClasspathFiles(targetJar)
+ .addProgramFiles(sourceJar)
+ .addRunClasspathFiles(r8CompiledTarget)
+ .addKeepMainRule(Main.class)
+ .run(parameters.getRuntime(), Main.class)
+ // TODO(b/319190998): This should not fail.
+ .applyIf(
+ hasDefaultInterfaceMethodsSupport(parameters),
+ r -> r.assertFailureWithErrorThatThrows(AbstractMethodError.class),
+ r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
+ }
+
+ @Test
+ public void testGeneratedKeepRulesWithMissingRuleFollowedByR8() throws Exception {
+ parameters.assumeR8TestParameters();
+
+ Path generatedKeepRules = temp.newFile("keep.rules").toPath();
+ TraceReferencesKeepRules keepRulesConsumer =
+ TraceReferencesKeepRules.builder()
+ .setAllowObfuscation(true)
+ .setOutputPath(generatedKeepRules)
+ .build();
+ TraceReferences.run(
+ TraceReferencesCommand.builder()
+ .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+ .addSourceFiles(sourceJar)
+ .addTargetFiles(targetJar)
+ .setConsumer(keepRulesConsumer)
+ .build());
+
+ Path proguardMap = temp.newFolder().toPath().resolve("mapping.txt");
+ Path r8CompiledTarget =
+ testForR8(parameters.getBackend())
+ .setMinApi(parameters)
+ .addProgramFiles(targetJar)
+ .addKeepRuleFiles(generatedKeepRules)
+ .addKeepRules("-keep class " + J.class.getTypeName() + " { m(); }")
+ .compile()
+ .apply(r -> r.writeProguardMap(proguardMap))
+ .writeToZip();
+
+ testForR8(parameters.getBackend())
+ .setMinApi(parameters)
+ .addClasspathFiles(targetJar)
+ .addProgramFiles(sourceJar)
+ .addApplyMapping(proguardMap)
+ .addKeepMainRule(Main.class)
+ .addRunClasspathFiles(r8CompiledTarget)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ @Test
+ public void testGeneratedKeepRulesWithMissingRuleFollowedByD8() throws Exception {
+ parameters.assumeDexRuntime();
+
+ Path generatedKeepRules = temp.newFile("keep.rules").toPath();
+ TraceReferencesKeepRules keepRulesConsumer =
+ TraceReferencesKeepRules.builder()
+ // Don't obfuscate as D8 does not support apply mapping.
+ .setAllowObfuscation(false)
+ .setOutputPath(generatedKeepRules)
+ .build();
+ TraceReferences.run(
+ TraceReferencesCommand.builder()
+ .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+ .addSourceFiles(sourceJar)
+ .addTargetFiles(targetJar)
+ .setConsumer(keepRulesConsumer)
+ .build());
+
+ Path r8CompiledTarget =
+ testForR8(Backend.DEX)
+ .setMinApi(parameters)
+ .addProgramFiles(targetJar)
+ .addKeepRuleFiles(generatedKeepRules)
+ .addKeepRules("-keep class " + J.class.getTypeName() + " { m(); }")
+ .compile()
+ .writeToZip();
+
+ testForD8(Backend.DEX)
+ .setMinApi(parameters)
+ .addClasspathFiles(targetJar)
+ .addProgramFiles(sourceJar)
+ .addRunClasspathFiles(r8CompiledTarget)
+ .run(parameters.getRuntime(), Main.class)
+ .applyIf(
+ hasDefaultInterfaceMethodsSupport(parameters),
+ r -> r.assertSuccessWithOutput(EXPECTED_OUTPUT),
+ // TODO(b/319190998): This should not fail.
+ r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
+ }
+
+ @Test
+ public void testGeneratedKeepRulesWithMissingRuleAndDontObfuscateFollowedByD8() throws Exception {
+ parameters.assumeDexRuntime();
+
+ Path generatedKeepRules = temp.newFile("keep.rules").toPath();
+ TraceReferencesKeepRules keepRulesConsumer =
+ TraceReferencesKeepRules.builder()
+ // Don't obfuscate as D8 does not support apply mapping.
+ .setAllowObfuscation(false)
+ .setOutputPath(generatedKeepRules)
+ .build();
+ TraceReferences.run(
+ TraceReferencesCommand.builder()
+ .addLibraryFiles(ToolHelper.getMostRecentAndroidJar())
+ .addSourceFiles(sourceJar)
+ .addTargetFiles(targetJar)
+ .setConsumer(keepRulesConsumer)
+ .build());
+
+ Path r8CompiledTarget =
+ testForR8(Backend.DEX)
+ .setMinApi(parameters)
+ .addProgramFiles(targetJar)
+ .addKeepRuleFiles(generatedKeepRules)
+ .addKeepRules("-keep class " + J.class.getTypeName() + " { m(); }")
+ // TODO(b/319190998): Adding dont obfuscate should not be needed as trace references is
+ // already asked to not allow obfuscation. Hwing this will cause the CC class to not
+ // get renamed.
+ .addDontObfuscate()
+ .compile()
+ .writeToZip();
+
+ testForD8(Backend.DEX)
+ .setMinApi(parameters)
+ .addClasspathFiles(targetJar)
+ .addProgramFiles(sourceJar)
+ .addRunClasspathFiles(r8CompiledTarget)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ // Interfaces I and J are in the target set for trace references.
+ interface I {
+ Object m();
+ }
+
+ interface J extends I {
+ default Object m() {
+ return "Hello, world!";
+ }
+ }
+
+ // Interfaces JImpl and Main are in the source set for trace references.
+ public static class JImpl implements J {}
+
+ public static class Main {
+
+ public static void m(I i) {
+ System.out.println(i.m());
+ }
+
+ public static void main(String[] args) {
+ m(new JImpl());
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java
index d711ac1..8c5bcb6 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java
@@ -151,6 +151,29 @@
};
}
+ public static Matcher<MethodSubject> containsConstString(String string) {
+ return new TypeSafeMatcher<MethodSubject>() {
+ @Override
+ protected boolean matchesSafely(MethodSubject subject) {
+ return subject.isPresent()
+ && subject.getMethod().hasCode()
+ && subject
+ .streamInstructions()
+ .anyMatch(instructionSubject -> instructionSubject.isConstString(string));
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("contains const-string");
+ }
+
+ @Override
+ public void describeMismatchSafely(MethodSubject subject, Description description) {
+ description.appendText("method did not");
+ }
+ };
+ }
+
public static Matcher<MethodSubject> instantiatesClass(Class<?> clazz) {
return instantiatesClass(clazz.getTypeName());
}
diff --git a/third_party/proguard/README.google b/third_party/proguard/README.google
index 0e6bb2e..4449832 100644
--- a/third_party/proguard/README.google
+++ b/third_party/proguard/README.google
@@ -2,9 +2,10 @@
URL: https://sourceforge.net/projects/proguard/files/proguard/6.0/
URL: https://github.com/Guardsquare/proguard/releases/download/v7.0.0/proguard-7.0.0.tar.gz
URL: https://github.com/Guardsquare/proguard/releases/download/v7.3.2/proguard-7.3.2.tar.gz
-Version: 5.2.1, 6.0.1, 7.0.0, 7.3.2
+URL: https://github.com/Guardsquare/proguard/releases/download/v7.4.1/proguard-7.4.1.tar.gz
+Version: 5.2.1, 6.0.1, 7.0.0, 7.3.2, 7.4.1
License: GPL
-License File: proguard5.2.1/docs/license.html, proguard6.0.1/docs/license.html, proguard-7.0.0/docs/license.md
+License File: proguard5.2.1/docs/license.html, proguard6.0.1/docs/license.html, proguard-7.0.0/docs/license.md, proguard-7.3.2/LICENSE, proguard-7.4.1/LICENSE
Description:
ProGuard Java Optimizer and Obfuscator
diff --git a/third_party/proguard/proguard-7.4.1.tar.gz.sha1 b/third_party/proguard/proguard-7.4.1.tar.gz.sha1
new file mode 100644
index 0000000..4c33fe2
--- /dev/null
+++ b/third_party/proguard/proguard-7.4.1.tar.gz.sha1
@@ -0,0 +1 @@
+95f547ec8e6d15338fb6c7c32cc7cf0b27e049d6
\ No newline at end of file
diff --git a/third_party/r8-releases/8.0.46.tar.gz.sha1 b/third_party/r8-releases/8.0.46.tar.gz.sha1
new file mode 100644
index 0000000..300d3fd
--- /dev/null
+++ b/third_party/r8-releases/8.0.46.tar.gz.sha1
@@ -0,0 +1 @@
+037a4cc645b882ecd6202f84220fd9d81c0a379e
\ No newline at end of file