Merge commit '2d30ea640b430b21798176dbdfde18b8dc855841' into dev-release
diff --git a/build.gradle b/build.gradle
index e614057..fe2980a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1027,6 +1027,7 @@
input,
"--output", output,
"--pg-map-output", output + ".map",
+ "--partition-map-output", output + "_map.zip",
"--lib", org.gradle.internal.jvm.Jvm.current().javaHome,
] + args + libs.collectMany { ["--lib", it] } + pgConfs.collectMany { ["--pg-conf", it] }
return baseR8CommandLine(allArgs)
diff --git a/infra/config/global/generated/luci-milo.cfg b/infra/config/global/generated/luci-milo.cfg
index 4073c3d..b1481fe 100644
--- a/infra/config/global/generated/luci-milo.cfg
+++ b/infra/config/global/generated/luci-milo.cfg
@@ -126,11 +126,6 @@
short_name: "kotlin_old"
}
builders {
- name: "buildbucket/luci.r8.ci/smali"
- category: "R8"
- short_name: "smali"
- }
- builders {
name: "buildbucket/luci.r8.ci/lib_desugar-archive-jdk11"
category: "library_desugar"
short_name: "jdk11"
diff --git a/infra/config/global/generated/luci-notify.cfg b/infra/config/global/generated/luci-notify.cfg
index 5417911..fa8d5b0 100644
--- a/infra/config/global/generated/luci-notify.cfg
+++ b/infra/config/global/generated/luci-notify.cfg
@@ -540,18 +540,6 @@
}
builders {
bucket: "ci"
- name: "smali"
- repository: "https://r8.googlesource.com/r8"
- }
-}
-notifiers {
- notifications {
- on_failure: true
- on_new_failure: true
- notify_blamelist {}
- }
- builders {
- bucket: "ci"
name: "windows"
repository: "https://r8.googlesource.com/r8"
}
diff --git a/infra/config/global/generated/luci-scheduler.cfg b/infra/config/global/generated/luci-scheduler.cfg
index 982d085..e59d20c 100644
--- a/infra/config/global/generated/luci-scheduler.cfg
+++ b/infra/config/global/generated/luci-scheduler.cfg
@@ -820,7 +820,6 @@
triggers: "linux-kotlin_old"
triggers: "linux-none"
triggers: "linux-run-on-app-dump"
- triggers: "smali"
triggers: "windows"
gitiles {
repo: "https://r8.googlesource.com/r8"
diff --git a/infra/config/global/main.star b/infra/config/global/main.star
index 1e374ed..d9201a8 100755
--- a/infra/config/global/main.star
+++ b/infra/config/global/main.star
@@ -147,7 +147,6 @@
refs = ["refs/heads/.*"]
)
-
view_builders = []
def builder_view(name, category, short_name):
@@ -412,6 +411,8 @@
r8_builder(
"smali",
+ category = "aux",
+ trigger = False,
dimensions = get_dimensions(smali=True),
triggering_policy = scheduler.policy(
kind = scheduler.GREEDY_BATCHING_KIND,
@@ -434,9 +435,15 @@
"Release|R8",
]
+categories_with_no_console = [
+ "aux",
+]
+
def add_view_entries():
# Ensure that all categories are ordered
for v in view_builders:
+ if v[1] in categories_with_no_console:
+ continue
if not v[1] in order_of_categories:
fail()
for category in order_of_categories:
diff --git a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
index cc62da7..890f3f9 100644
--- a/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
+++ b/src/main/java/com/android/tools/r8/BaseCompilerCommand.java
@@ -401,7 +401,7 @@
*
* @param partitionMapOutput File-system path to write output at.
*/
- B setPartitionMapOutputPath(Path partitionMapOutput) {
+ public B setPartitionMapOutputPath(Path partitionMapOutput) {
assert partitionMapOutput != null;
return setPartitionMapConsumer(MapConsumerUtils.createZipConsumer(partitionMapOutput));
}
@@ -414,7 +414,7 @@
*
* @param partitionMapConsumer Consumer to receive the content once produced.
*/
- B setPartitionMapConsumer(PartitionMapConsumer partitionMapConsumer) {
+ public B setPartitionMapConsumer(PartitionMapConsumer partitionMapConsumer) {
this.partitionMapConsumer = partitionMapConsumer;
return self();
}
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index a97ec22..e2c826a 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -4,6 +4,7 @@
package com.android.tools.r8;
import static com.android.tools.r8.utils.InternalOptions.DETERMINISTIC_DEBUGGING;
+import static com.android.tools.r8.utils.MapConsumerUtils.wrapExistingMapConsumerIfNotNull;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.dump.DumpOptions;
@@ -12,6 +13,7 @@
import com.android.tools.r8.inspector.Inspector;
import com.android.tools.r8.inspector.internal.InspectorImpl;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.naming.MapConsumer;
import com.android.tools.r8.naming.ProguardMapStringConsumer;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.profile.art.ArtProfileForRewriting;
@@ -88,7 +90,7 @@
private boolean intermediate = false;
private GlobalSyntheticsConsumer globalSyntheticsConsumer = null;
- private List<GlobalSyntheticsResourceProvider> globalSyntheticsResourceProviders =
+ private final List<GlobalSyntheticsResourceProvider> globalSyntheticsResourceProviders =
new ArrayList<>();
private DesugarGraphConsumer desugarGraphConsumer = null;
private SyntheticInfoConsumer syntheticInfoConsumer = null;
@@ -186,6 +188,43 @@
}
/**
+ * Set an output destination to which partition-map content should be written.
+ *
+ * <p>Note that when a proguard-map output is specified for a release build, the compiler will
+ * optimize the line-number information and obtaining a source-level stacktrace will require the
+ * use of a retrace tool exactly as is needed for programs built by R8.
+ *
+ * <p>This is a short-hand for setting a {@link PartitionMapConsumer} using {@link
+ * #setPartitionMapConsumer}. Note that any subsequent call to this method or {@link
+ * #setPartitionMapConsumer} will override the previous setting.
+ *
+ * @param partitionMapOutput File-system path to write output at.
+ */
+ @Override
+ public Builder setPartitionMapOutputPath(Path partitionMapOutput) {
+ assert partitionMapOutput != null;
+ return super.setPartitionMapOutputPath(partitionMapOutput);
+ }
+
+ /**
+ * Set a consumer for receiving the partition map content.
+ *
+ * <p>Note that when a proguard-map output is specified for a release build, the compiler will
+ * optimize the line-number information and obtaining a source-level stacktrace will require the
+ * use of a retrace tool exactly as is needed for programs built by R8.
+ *
+ * <p>Note that any subsequent call to this method or {@link #setPartitionMapOutputPath} will
+ * override the previous setting.
+ *
+ * @param partitionMapConsumer Consumer to receive the content once produced.
+ */
+ @Override
+ public Builder setPartitionMapConsumer(PartitionMapConsumer partitionMapConsumer) {
+ assert partitionMapConsumer != null;
+ return super.setPartitionMapConsumer(partitionMapConsumer);
+ }
+
+ /**
* Indicate if compilation is to intermediate results, i.e., intended for later merging.
*
* <p>When compiling to intermediate mode, the compiler will avoid sharing of synthetic items,
@@ -482,6 +521,7 @@
getDumpInputFlags(),
getMapIdProvider(),
proguardMapConsumer,
+ partitionMapConsumer,
enableMissingLibraryApiModeling,
getAndroidPlatformBuild(),
getArtProfilesForRewriting(),
@@ -503,6 +543,7 @@
private final boolean minimalMainDex;
private final ImmutableList<ProguardConfigurationRule> mainDexKeepRules;
private final StringConsumer proguardMapConsumer;
+ private final PartitionMapConsumer partitionMapConsumer;
private final boolean enableMissingLibraryApiModeling;
private final DexItemFactory factory;
@@ -578,6 +619,7 @@
DumpInputFlags dumpInputFlags,
MapIdProvider mapIdProvider,
StringConsumer proguardMapConsumer,
+ PartitionMapConsumer partitionMapConsumer,
boolean enableMissingLibraryApiModeling,
boolean isAndroidPlatformBuild,
List<ArtProfileForRewriting> artProfilesForRewriting,
@@ -618,6 +660,7 @@
this.minimalMainDex = minimalMainDex;
this.mainDexKeepRules = mainDexKeepRules;
this.proguardMapConsumer = proguardMapConsumer;
+ this.partitionMapConsumer = partitionMapConsumer;
this.enableMissingLibraryApiModeling = enableMissingLibraryApiModeling;
this.factory = factory;
}
@@ -635,6 +678,7 @@
minimalMainDex = false;
mainDexKeepRules = null;
proguardMapConsumer = null;
+ partitionMapConsumer = null;
enableMissingLibraryApiModeling = false;
factory = null;
}
@@ -665,10 +709,15 @@
internal.setSyntheticInfoConsumer(syntheticInfoConsumer);
internal.desugarGraphConsumer = desugarGraphConsumer;
internal.mainDexKeepRules = mainDexKeepRules;
+ MapConsumer mapConsumer =
+ wrapExistingMapConsumerIfNotNull(
+ internal.mapConsumer, partitionMapConsumer, MapConsumerToPartitionMapConsumer::new);
internal.mapConsumer =
- proguardMapConsumer == null
- ? null
- : ProguardMapStringConsumer.builder().setStringConsumer(proguardMapConsumer).build();
+ wrapExistingMapConsumerIfNotNull(
+ mapConsumer,
+ proguardMapConsumer,
+ nonNullStringConsumer ->
+ ProguardMapStringConsumer.builder().setStringConsumer(proguardMapConsumer).build());
internal.lineNumberOptimization =
!internal.debug && proguardMapConsumer != null
? LineNumberOptimization.ON
diff --git a/src/main/java/com/android/tools/r8/D8CommandParser.java b/src/main/java/com/android/tools/r8/D8CommandParser.java
index 7485cc8..fa30c4f 100644
--- a/src/main/java/com/android/tools/r8/D8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/D8CommandParser.java
@@ -34,6 +34,7 @@
"--classpath",
"--pg-map",
"--pg-map-output",
+ "--partition-map-output",
MIN_API_FLAG,
"--main-dex-rules",
"--main-dex-list",
@@ -60,6 +61,8 @@
"--pg-map", "<file>", "Use <file> as a mapping file for distribution."))
// TODO(b/183125319): Add help info once supported.
// " --pg-map-output <file> # Enable line optimization and output mapping to <file>.",
+ // " --partition-map-output <file> # Enable line optimization and output mapping to
+ // <file>.",
.add(
ParseFlagInfoImpl.flag0(
"--intermediate", "Compile an intermediate result intended for later", "merging."))
@@ -265,6 +268,8 @@
builder.setProguardInputMapFile(Paths.get(nextArg));
} else if (arg.equals("--pg-map-output")) {
builder.setProguardMapOutputPath(Paths.get(nextArg));
+ } else if (arg.equals("--partition-map-output")) {
+ builder.setPartitionMapOutputPath(Paths.get(nextArg));
} else if (arg.equals("--output")) {
if (outputPath != null) {
builder.error(
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index 6eb01b6..7847c1d 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -309,7 +309,7 @@
* @param proguardMapOutput File-system path to write output at.
*/
@Override
- public L8Command.Builder setProguardMapOutputPath(Path proguardMapOutput) {
+ public Builder setProguardMapOutputPath(Path proguardMapOutput) {
return super.setProguardMapOutputPath(proguardMapOutput);
}
@@ -322,7 +322,7 @@
* @param proguardMapConsumer Consumer to receive the content once produced.
*/
@Override
- public L8Command.Builder setProguardMapConsumer(StringConsumer proguardMapConsumer) {
+ public Builder setProguardMapConsumer(StringConsumer proguardMapConsumer) {
return super.setProguardMapConsumer(proguardMapConsumer);
}
@@ -351,7 +351,7 @@
if (isShrinking() && getProgramConsumer() instanceof ClassFileConsumer) {
reporter.error("L8 does not support shrinking when generating class files");
}
- if (!isShrinking() && proguardMapConsumer != null) {
+ if (!isShrinking() && (proguardMapConsumer != null || partitionMapConsumer != null)) {
reporter.error("L8 does not support defining a map consumer when not shrinking");
}
super.validate();
@@ -403,6 +403,9 @@
if (proguardMapConsumer != null) {
r8Builder.setProguardMapConsumer(proguardMapConsumer);
}
+ if (partitionMapConsumer != null) {
+ r8Builder.setPartitionMapConsumer(partitionMapConsumer);
+ }
r8Builder.addProguardConfiguration(
desugaredLibrarySpecification.getExtraKeepRules(), Origin.unknown());
// TODO(b/180903899): Remove rule when -dontwarn sun.misc.Unsafe is part of config.
diff --git a/src/main/java/com/android/tools/r8/L8CommandParser.java b/src/main/java/com/android/tools/r8/L8CommandParser.java
index af389fe..72d1d34 100644
--- a/src/main/java/com/android/tools/r8/L8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/L8CommandParser.java
@@ -29,6 +29,7 @@
THREAD_COUNT_FLAG,
"--pg-conf",
"--pg-map-output",
+ "--partition-map-output",
ART_PROFILE_FLAG);
// Note: this must be a subset of OPTIONS_WITH_ONE_PARAMETER.
@@ -64,6 +65,7 @@
.add(ParseFlagInfoImpl.getMinApi())
.add(ParseFlagInfoImpl.getPgConf())
.add(ParseFlagInfoImpl.getPgMapOutput())
+ .add(ParseFlagInfoImpl.getPartitionMapOutput())
.add(ParseFlagInfoImpl.getDesugaredLib())
.addAll(ParseFlagInfoImpl.getAssertionsFlags())
.add(ParseFlagInfoImpl.getThreadCount())
@@ -175,6 +177,8 @@
builder.addProguardConfigurationFiles(Paths.get(nextArg));
} else if (arg.equals("--pg-map-output")) {
builder.setProguardMapOutputPath(Paths.get(nextArg));
+ } else if (arg.equals("--partition-map-output")) {
+ builder.setPartitionMapOutputPath(Paths.get(nextArg));
} else if (arg.equals("--desugared-lib")) {
builder.addDesugaredLibraryConfiguration(StringResource.fromFile(Paths.get(nextArg)));
} else if (arg.equals("--classfile")) {
diff --git a/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java b/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java
index ef42ebd..91da498 100644
--- a/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/ParseFlagInfoImpl.java
@@ -104,6 +104,11 @@
"--pg-map-output", "<file>", "Output the resulting name and line mapping to <file>.");
}
+ public static ParseFlagInfoImpl getPartitionMapOutput() {
+ return ParseFlagInfoImpl.flag1(
+ "--partition-map-output", "<file>", "Output the resulting mapping to <file>.");
+ }
+
public static List<ParseFlagInfoImpl> getAssertionsFlags() {
return ImmutableList.of(
flag0a1(
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 39e7996..7ec72c1 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -301,34 +301,6 @@
}
/**
- * Set an output destination to which r8-map content should be written.
- *
- * <p>This is a short-hand for setting a {@link MapConsumerToPartitionMapConsumer} using {@link
- * #setPartitionMapConsumer}. Note that any subsequent call to this method or {@link
- * #setPartitionMapConsumer} will override the previous setting.
- *
- * @param partitionMapOutput File-system path to write output at.
- */
- @Override
- public Builder setPartitionMapOutputPath(Path partitionMapOutput) {
- assert partitionMapOutput != null;
- return super.setPartitionMapOutputPath(partitionMapOutput);
- }
-
- /**
- * Set a consumer for receiving the r8-map content.
- *
- * <p>Note that any subsequent call to this method or {@link #setPartitionMapOutputPath} will
- * override the previous setting.
- *
- * @param partitionMapConsumer Consumer to receive the content once produced.
- */
- @Override
- public Builder setPartitionMapConsumer(PartitionMapConsumer partitionMapConsumer) {
- return super.setPartitionMapConsumer(partitionMapConsumer);
- }
-
- /**
* Set a consumer for receiving the keep rules to use when compiling the desugared library for
* the program being compiled in this compilation.
*
diff --git a/src/main/java/com/android/tools/r8/R8CommandParser.java b/src/main/java/com/android/tools/r8/R8CommandParser.java
index f3fd1b8..f5f22bf 100644
--- a/src/main/java/com/android/tools/r8/R8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/R8CommandParser.java
@@ -43,6 +43,7 @@
"--pg-conf",
"--pg-conf-output",
"--pg-map-output",
+ "--partition-map-output",
"--desugared-lib",
"--desugared-lib-pg-conf-output",
"--map-id-template",
@@ -71,6 +72,7 @@
.add(ParseFlagInfoImpl.getPgConf())
.add(flag1("--pg-conf-output", "<file>", "Output the collective configuration to <file>."))
.add(ParseFlagInfoImpl.getPgMapOutput())
+ .add(ParseFlagInfoImpl.getPartitionMapOutput())
.add(ParseFlagInfoImpl.getDesugaredLib())
.add(
flag1(
@@ -294,6 +296,8 @@
builder.setProguardConfigurationConsumer(consumer);
} else if (arg.equals("--pg-map-output")) {
builder.setProguardMapOutputPath(Paths.get(nextArg));
+ } else if (arg.equals("--partition-map-output")) {
+ builder.setPartitionMapOutputPath(Paths.get(nextArg));
} else if (arg.equals("--desugared-lib")) {
builder.addDesugaredLibraryConfiguration(StringResource.fromFile(Paths.get(nextArg)));
} else if (arg.equals("--desugared-lib-pg-conf-output")) {
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 b71e8d2..dbed84f 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -419,24 +419,18 @@
private static class PrunePreambleMethodVisitor extends MethodVisitor {
- private final AppView<?> appView;
private boolean inPreamble = true;
- public PrunePreambleMethodVisitor(MethodVisitor methodVisitor, AppView<?> appView) {
+ public PrunePreambleMethodVisitor(MethodVisitor methodVisitor) {
super(InternalOptions.ASM_VERSION, methodVisitor);
- this.appView = appView;
}
@Override
public void visitLineNumber(int line, Label start) {
- if (line == 0) {
- if (inPreamble) {
- inPreamble = false;
- return;
- }
- // We must be in R8 if inserting a zero-line entry outside the method preamble.
- assert appView.enableWholeProgramOptimizations();
+ if (line == 0 && inPreamble) {
+ return;
}
+ inPreamble = false;
super.visitLineNumber(line, start);
}
}
@@ -466,8 +460,7 @@
|| (appView.enableWholeProgramOptimizations()
&& classFileVersion.isEqualTo(CfVersion.V1_6)
&& !options.shouldKeepStackMapTable());
- PrunePreambleMethodVisitor prunePreambleVisitor =
- new PrunePreambleMethodVisitor(visitor, appView);
+ PrunePreambleMethodVisitor prunePreambleVisitor = new PrunePreambleMethodVisitor(visitor);
for (CfInstruction instruction : instructions) {
if (discardFrames && instruction instanceof CfFrame) {
continue;
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 42dc600..a76bdf5 100644
--- a/src/main/java/com/android/tools/r8/graph/Code.java
+++ b/src/main/java/com/android/tools/r8/graph/Code.java
@@ -169,7 +169,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection collection) {
+ protected void collectMixedSectionItems(MixedSectionCollection collection) {
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index 25a5a97..968863a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -128,7 +128,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
mixedItems.add(this);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
index aa6aaec..6274296 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
@@ -66,7 +66,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
// Should never be visited.
assert false;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
index 1cd2f4b..5dfb273 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
@@ -129,7 +129,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
mixedItems.add(this);
collectAll(mixedItems, annotations);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexCallSite.java b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
index e3b49d1..f5d8cea 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCallSite.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
@@ -172,7 +172,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
getEncodedArray().collectMixedSectionItems(mixedItems);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 342a214..c79cb1b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -253,7 +253,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
throw new Unreachable();
}
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 9532f1e..4cb2a24 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -919,7 +919,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
// Should never be visited.
assert false;
}
@@ -971,7 +971,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
// Should never be visited.
assert false;
}
@@ -1034,7 +1034,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
// Should never be visited.
assert false;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
index a7cd5d1..8826ec4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
@@ -60,7 +60,7 @@
}
@Override
- abstract void collectMixedSectionItems(MixedSectionCollection collection);
+ protected abstract void collectMixedSectionItems(MixedSectionCollection collection);
@Override
public abstract DexDebugInfo self();
@@ -275,7 +275,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection collection) {
+ protected void collectMixedSectionItems(MixedSectionCollection collection) {
// Only writable info should be iterated for collection.
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
index 0d4f388..19aad9e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
@@ -63,7 +63,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
// Should never be called.
assert false;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java b/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java
index 4192720..663a2e5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedArray.java
@@ -22,7 +22,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
mixedItems.add(this);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 2b7a222..c6f2634 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -145,7 +145,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
annotations().collectMixedSectionItems(mixedItems);
}
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 1c502d5..a45d542 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -786,7 +786,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
mixedItems.visit(this);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexItem.java b/src/main/java/com/android/tools/r8/graph/DexItem.java
index f26e41a..928673f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItem.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItem.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.dex.MixedSectionCollection;
import java.util.Collection;
import java.util.function.Consumer;
-import java.util.stream.Stream;
public abstract class DexItem {
@@ -34,7 +33,7 @@
}
}
- abstract void collectMixedSectionItems(MixedSectionCollection collection);
+ protected abstract void collectMixedSectionItems(MixedSectionCollection collection);
protected void flushCachedValues() {
// Overwritten in subclasses.
@@ -48,7 +47,4 @@
return toString();
}
- static <T extends DexItem> Stream<T> filter(Stream<DexItem> stream, Class<T> clazz) {
- return stream.filter(clazz::isInstance).map(clazz::cast);
- }
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index cfa8347..ae3f0ac 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -1991,8 +1991,9 @@
return field == nameField || field == ordinalField;
}
- public boolean isEnumField(DexEncodedField staticField, DexType enumType) {
- return isEnumField(staticField, enumType, ImmutableSet.of());
+ public boolean isEnumFieldCandidate(DexEncodedField staticField) {
+ assert staticField.isStatic();
+ return staticField.isEnum() && staticField.isFinal();
}
// In some case, the enum field may be respecialized to an enum subtype. In this case, one
@@ -2001,8 +2002,7 @@
DexEncodedField staticField, DexType enumType, Set<DexType> subtypes) {
assert staticField.isStatic();
return (staticField.getType() == enumType || subtypes.contains(staticField.getType()))
- && staticField.isEnum()
- && staticField.isFinal();
+ && isEnumFieldCandidate(staticField);
}
public boolean isValuesFieldCandidate(DexEncodedField staticField, DexType enumType) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java
index 5bac75e..2679186 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMemberAnnotation.java
@@ -17,7 +17,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
annotations.collectMixedSectionItems(mixedItems);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index a448af0..fc4c4a6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -471,7 +471,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
assert getEnclosingMethodAttribute() == null;
assert getInnerClasses().isEmpty();
assert !classSignature.hasSignature();
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexTypeAnnotation.java
index 99dadb8..c343889 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeAnnotation.java
@@ -38,7 +38,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
throw new Unreachable("Should not collect type annotation in DEX");
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeList.java b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
index 7be2dce..3716f4e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -130,7 +130,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
mixedItems.add(this);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexValue.java b/src/main/java/com/android/tools/r8/graph/DexValue.java
index 5271c0a..0dc1d16 100644
--- a/src/main/java/com/android/tools/r8/graph/DexValue.java
+++ b/src/main/java/com/android/tools/r8/graph/DexValue.java
@@ -355,7 +355,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
// Should never be visited.
throw new Unreachable();
}
diff --git a/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java b/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java
index 96bfb47..f668585 100644
--- a/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java
+++ b/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java
@@ -9,7 +9,7 @@
public abstract class IndexedDexItem extends CachedHashValueDexItem {
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
// Should never be visited.
assert false;
}
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index d9158fc..8cb3ed0 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -36,7 +36,6 @@
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.jar.CfApplicationWriter;
import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.synthesis.SyntheticMarker;
import com.android.tools.r8.utils.AsmUtils;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -116,16 +115,6 @@
ClassReader reader = new ClassReader(bytes);
int parsingOptions = SKIP_FRAMES | SKIP_CODE;
-
- // If the source-file and source-debug-extension attributes are not kept we can skip all debug
- // related attributes when parsing the class structure.
- if (application.options.getProguardConfiguration() != null) {
- ProguardKeepAttributes keep =
- application.options.getProguardConfiguration().getKeepAttributes();
- if (!keep.sourceFile && !keep.sourceDebugExtension && !keep.methodParameters) {
- parsingOptions |= SKIP_DEBUG;
- }
- }
if (classKind != ClassKind.PROGRAM) {
parsingOptions |= SKIP_DEBUG;
}
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 e54e691..b3b5680 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -1195,7 +1195,8 @@
|| keep.localVariableTable
|| keep.localVariableTypeTable
|| reachabilitySensitive;
- boolean lineInfo = keep.lineNumberTable;
+ boolean lineInfo =
+ (keep.lineNumberTable || application.options.canUseNativeDexPcInsteadOfDebugInfo());
boolean methodParaeters = keep.methodParameters;
if (!localsInfo && !lineInfo && !methodParaeters) {
diff --git a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
index 5f7c865..7e21357 100644
--- a/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
+++ b/src/main/java/com/android/tools/r8/graph/ParameterAnnotationsList.java
@@ -126,7 +126,7 @@
}
@Override
- void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ protected void collectMixedSectionItems(MixedSectionCollection mixedItems) {
// Collect values first so that the annotation sets have sorted themselves before adding this.
collectAll(mixedItems, values);
mixedItems.add(this);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
index 0f40f03..8e5b4ca 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
@@ -79,7 +79,7 @@
enumObjectStateBuilder.put(
staticField.getReference(), value.asSingleFieldValue().getObjectState());
}
- } else if (factory.enumMembers.isEnumField(staticField, staticField.getHolderType())) {
+ } else if (factory.enumMembers.isEnumFieldCandidate(staticField)) {
if (value.isSingleFieldValue()
&& !value.asSingleFieldValue().getObjectState().isEmpty()) {
enumObjectStateBuilder.put(
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
index 9acf109..b78f18b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -145,11 +145,9 @@
public SingleValue rewrittenWithLens(
AppView<AppInfoWithLiveness> appView, GraphLens lens, GraphLens codeLens) {
AbstractValueFactory factory = appView.abstractValueFactory();
- if (field.holder == field.type) {
- EnumDataMap enumDataMap = appView.unboxedEnums();
- if (enumDataMap.hasUnboxedValueFor(field)) {
- return factory.createSingleNumberValue(enumDataMap.getUnboxedValue(field));
- }
+ EnumDataMap enumDataMap = appView.unboxedEnums();
+ if (enumDataMap.hasUnboxedValueFor(field)) {
+ return factory.createSingleNumberValue(enumDataMap.getUnboxedValue(field));
}
DexField rewrittenField = lens.lookupField(field, codeLens);
ObjectState rewrittenObjectState = getObjectState().rewrittenWithLens(appView, lens, codeLens);
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
index 2dfbc18..a42e312 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.lightir.LirBuilder;
public class ConstClass extends ConstInstruction {
@@ -220,6 +221,11 @@
registry.registerConstClass(clazz, null, ignoreCompatRules);
}
+ @Override
+ public void buildLir(LirBuilder<Value, ?> builder) {
+ builder.addConstClass(getType());
+ }
+
public static class Builder extends BuilderBase<Builder, ConstClass> {
private DexType type;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
index 52d38b3..ba020a4 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.lightir.LirBuilder;
import java.util.List;
public class InvokeNewArray extends Invoke {
@@ -226,4 +227,9 @@
public int size() {
return inValues.size();
}
+
+ @Override
+ public void buildLir(LirBuilder<Value, ?> builder) {
+ builder.addInvokeNewArray(getArrayType(), arguments());
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
index 15f7224..ddf7cba 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewArrayFilledData.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.lightir.LirBuilder;
import java.util.Arrays;
public class NewArrayFilledData extends Instruction {
@@ -66,6 +67,11 @@
}
@Override
+ public void buildLir(LirBuilder<Value, ?> builder) {
+ builder.addNewArrayFilledData(element_width, size, data, src());
+ }
+
+ @Override
public boolean identicalNonValueNonPositionParts(Instruction other) {
if (!other.isNewArrayFilledData()) {
return false;
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
index 98c55cc..ed5958c 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticPut.java
@@ -32,6 +32,7 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
+import com.android.tools.r8.lightir.LirBuilder;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
public class StaticPut extends FieldInstruction implements FieldPut, StaticFieldInstruction {
@@ -235,6 +236,11 @@
}
@Override
+ public void buildLir(LirBuilder<Value, ?> builder) {
+ builder.addStaticPut(getField(), value());
+ }
+
+ @Override
public boolean definitelyTriggersClassInitialization(
DexType clazz,
ProgramMethod context,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
index 6672c87..06cb686 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
@@ -4,18 +4,23 @@
package com.android.tools.r8.ir.optimize.enums;
+import static com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl.ordinalToUnboxedInt;
+
import com.android.tools.r8.errors.CheckEnumUnboxedDiagnostic;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramField;
+import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
+import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@@ -76,6 +81,15 @@
return map.containsKey(type);
}
+ public SingleNumberValue getSingleNumberValueFromEnumType(
+ AbstractValueFactory factory, DexType enumType) {
+ assert isUnboxedEnum(enumType);
+ EnumData enumData = get(enumType);
+ return isSuperUnboxedEnum(enumType)
+ ? enumData.superEnumTypeSingleValue(factory, enumType)
+ : enumData.subEnumTypeSingleValue(factory, enumType);
+ }
+
public boolean isUnboxedEnum(DexProgramClass clazz) {
return isUnboxedEnum(clazz.getType());
}
@@ -84,7 +98,7 @@
return map.containsKey(representativeType(type));
}
- private EnumData get(DexType type) {
+ public EnumData get(DexType type) {
EnumData enumData = map.get(representativeType(type));
assert enumData != null;
return enumData;
@@ -112,17 +126,19 @@
}
public boolean hasUnboxedValueFor(DexField enumStaticField) {
- return isUnboxedEnum(enumStaticField.getHolderType())
- && get(enumStaticField.getHolderType()).hasUnboxedValueFor(enumStaticField);
+ DexType representative = representativeType(enumStaticField.getHolderType());
+ return isSuperUnboxedEnum(representative)
+ && get(representative).hasUnboxedValueFor(enumStaticField);
}
public int getUnboxedValue(DexField enumStaticField) {
assert isUnboxedEnum(enumStaticField.getHolderType());
- return get(enumStaticField.getHolderType()).getUnboxedValue(enumStaticField);
+ return get(representativeType(enumStaticField.getHolderType()))
+ .getUnboxedValue(enumStaticField);
}
public int getValuesSize(DexType enumType) {
- assert isUnboxedEnum(enumType);
+ assert isSuperUnboxedEnum(enumType);
return get(enumType).getValuesSize();
}
@@ -137,7 +153,7 @@
}
public boolean matchesValuesField(DexField staticField) {
- assert isUnboxedEnum(staticField.getHolderType());
+ assert isSuperUnboxedEnum(staticField.getHolderType());
return get(staticField.getHolderType()).matchesValuesField(staticField);
}
@@ -202,5 +218,28 @@
assert hasValues();
return valuesSize;
}
+
+ public SingleNumberValue superEnumTypeSingleValue(AbstractValueFactory factory, DexType type) {
+ // If there is a single live enum instance, then return the unboxed value for this one.
+ if (hasValues()) {
+ if (valuesSize == 1) {
+ return factory.createSingleNumberValue(ordinalToUnboxedInt(0));
+ }
+ } else if (unboxedValues.size() == 1) {
+ Integer next = unboxedValues.values().iterator().next();
+ return factory.createSingleNumberValue(ordinalToUnboxedInt(next));
+ }
+ return null;
+ }
+
+ public SingleNumberValue subEnumTypeSingleValue(AbstractValueFactory factory, DexType type) {
+ assert valuesTypes.values().stream().filter(t -> t == type).count() <= 1;
+ for (Entry<DexType> entry : valuesTypes.int2ReferenceEntrySet()) {
+ if (entry.getValue() == type) {
+ return factory.createSingleNumberValue(ordinalToUnboxedInt(entry.getIntKey()));
+ }
+ }
+ return null;
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index 12e1f1e..df5d6b1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -181,6 +181,10 @@
appView.appInfo().resolveField(factory.enumMembers.ordinalField).getResolutionPair();
}
+ public static int unboxedIntToOrdinal(int unboxedInt) {
+ return unboxedInt - 1;
+ }
+
public static int ordinalToUnboxedInt(int ordinal) {
return ordinal + 1;
}
@@ -1280,7 +1284,8 @@
: Reason.ASSIGNMENT_OUTSIDE_INIT;
}
// The put value has to be of the field type.
- if (field.getReference().type.toBaseType(factory) != enumClass.type) {
+ if (!enumUnboxingCandidatesInfo.isAssignableTo(
+ field.getReference().type.toBaseType(factory), enumClass.type)) {
return Reason.TYPE_MISMATCH_FIELD_PUT;
}
return Reason.ELIGIBLE;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
index 3aaff49..53f7f63 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.ir.optimize.enums;
+import static com.android.tools.r8.ir.optimize.enums.EnumUnboxerImpl.unboxedIntToOrdinal;
+
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
@@ -16,8 +18,10 @@
import com.android.tools.r8.graph.proto.ArgumentInfoCollection;
import com.android.tools.r8.graph.proto.RewrittenPrototypeDescription;
import com.android.tools.r8.graph.proto.RewrittenTypeInfo;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.analysis.value.AbstractValueFactory;
import com.android.tools.r8.ir.analysis.value.SingleFieldValue;
+import com.android.tools.r8.ir.analysis.value.SingleNumberValue;
import com.android.tools.r8.ir.analysis.value.SingleValue;
import com.android.tools.r8.ir.code.InvokeType;
import com.android.tools.r8.ir.conversion.ExtraUnusedNullParameter;
@@ -41,6 +45,7 @@
private final AbstractValueFactory abstractValueFactory;
private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod;
private final EnumDataMap unboxedEnums;
+ private final Set<DexMethod> dispatchMethods;
EnumUnboxingLens(
AppView<?> appView,
@@ -48,12 +53,14 @@
BidirectionalOneToManyRepresentativeMap<DexMethod, DexMethod> renamedSignatures,
Map<DexType, DexType> typeMap,
Map<DexMethod, DexMethod> methodMap,
- Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod) {
+ Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod,
+ Set<DexMethod> dispatchMethods) {
super(appView, fieldMap, methodMap, typeMap, renamedSignatures);
assert !appView.unboxedEnums().isEmpty();
this.abstractValueFactory = appView.abstractValueFactory();
this.prototypeChangesPerMethod = prototypeChangesPerMethod;
this.unboxedEnums = appView.unboxedEnums();
+ this.dispatchMethods = dispatchMethods;
}
@Override
@@ -94,6 +101,35 @@
return true;
}
+ public DexMethod lookupRefinedDispatchMethod(
+ DexMethod method,
+ DexMethod context,
+ InvokeType type,
+ GraphLens codeLens,
+ AbstractValue unboxedEnumValue,
+ DexType enumType) {
+ assert codeLens == getPrevious();
+ DexMethod reference = lookupMethod(method, context, type, codeLens).getReference();
+ if (!dispatchMethods.contains(reference) || !unboxedEnumValue.isSingleNumberValue()) {
+ return null;
+ }
+ // We know the exact type of enum, so there is no need to go for the dispatch method. Instead,
+ // we compute the exact target from the enum instance.
+ int unboxedEnum = unboxedEnumValue.asSingleNumberValue().getIntValue();
+ DexType instanceType =
+ unboxedEnums
+ .get(enumType)
+ .valuesTypes
+ .getOrDefault(unboxedIntToOrdinal(unboxedEnum), enumType);
+ DexMethod specializedMethod = method.withHolder(instanceType, dexItemFactory());
+ DexMethod superEnumMethod = method.withHolder(enumType, dexItemFactory());
+ DexMethod refined =
+ newMethodSignatures.getRepresentativeValueOrDefault(
+ specializedMethod, newMethodSignatures.getRepresentativeValue(superEnumMethod));
+ assert refined != null;
+ return refined;
+ }
+
@Override
public MethodLookupResult internalDescribeLookupMethod(
MethodLookupResult previous, DexMethod context, GraphLens codeLens) {
@@ -187,13 +223,15 @@
return type;
}
- public static Builder enumUnboxingLensBuilder(AppView<AppInfoWithLiveness> appView) {
- return new Builder(appView);
+ public static Builder enumUnboxingLensBuilder(
+ AppView<AppInfoWithLiveness> appView, EnumDataMap enumDataMap) {
+ return new Builder(appView, enumDataMap);
}
static class Builder {
private final DexItemFactory dexItemFactory;
+ private final AbstractValueFactory abstractValueFactory;
private final Map<DexType, DexType> typeMap = new IdentityHashMap<>();
private final MutableBidirectionalOneToOneMap<DexField, DexField> newFieldSignatures =
new BidirectionalOneToOneHashMap<>();
@@ -204,8 +242,12 @@
private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod =
new IdentityHashMap<>();
- Builder(AppView<AppInfoWithLiveness> appView) {
+ private final EnumDataMap enumDataMap;
+
+ Builder(AppView<AppInfoWithLiveness> appView, EnumDataMap enumDataMap) {
this.dexItemFactory = appView.dexItemFactory();
+ this.abstractValueFactory = appView.abstractValueFactory();
+ this.enumDataMap = enumDataMap;
}
public Builder mapUnboxedEnums(Set<DexType> enumsToUnbox) {
@@ -279,14 +321,17 @@
assert toStatic;
offsetDiff = 1;
if (!virtualReceiverAlreadyRemapped) {
- builder
- .addArgumentInfo(
- 0,
- RewrittenTypeInfo.builder()
- .setOldType(from.getHolderType())
- .setNewType(to.getParameter(0))
- .build())
- .setIsConvertedToStaticMethod();
+ RewrittenTypeInfo.Builder typeInfoBuilder =
+ RewrittenTypeInfo.builder()
+ .setOldType(from.getHolderType())
+ .setNewType(to.getParameter(0));
+ SingleNumberValue singleValue =
+ enumDataMap.getSingleNumberValueFromEnumType(
+ abstractValueFactory, from.getHolderType());
+ if (singleValue != null) {
+ typeInfoBuilder.setSingleValue(singleValue);
+ }
+ builder.addArgumentInfo(0, typeInfoBuilder.build()).setIsConvertedToStaticMethod();
} else {
assert to.getParameter(0).isIntType();
assert !fromStatic;
@@ -327,7 +372,7 @@
originalCheckNotNullMethodSignature, checkNotNullMethod.getReference());
}
- public EnumUnboxingLens build(AppView<?> appView) {
+ public EnumUnboxingLens build(AppView<?> appView, Set<DexMethod> dispatchMethods) {
assert !typeMap.isEmpty();
return new EnumUnboxingLens(
appView,
@@ -335,7 +380,8 @@
newMethodSignatures,
typeMap,
methodMap,
- ImmutableMap.copyOf(prototypeChangesPerMethod));
+ ImmutableMap.copyOf(prototypeChangesPerMethod),
+ dispatchMethods);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
index cbbd4b9..789c542 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -37,6 +37,7 @@
import com.android.tools.r8.ir.code.NewUnboxedEnumInstance;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.StaticGet;
+import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
@@ -46,9 +47,9 @@
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -87,9 +88,10 @@
}
private Map<Instruction, DexType> createInitialConvertedEnums(
- IRCode code, RewrittenPrototypeDescription prototypeChanges) {
+ IRCode code, RewrittenPrototypeDescription prototypeChanges, Set<Phi> affectedPhis) {
Map<Instruction, DexType> convertedEnums = new IdentityHashMap<>();
- Iterator<Instruction> iterator = code.entryBlock().iterator();
+ List<Instruction> extraConstants = new ArrayList<>();
+ InstructionListIterator iterator = code.entryBlock().listIterator(code);
int originalNumberOfArguments =
code.getNumberOfArguments()
+ prototypeChanges.getArgumentInfoCollection().numberOfRemovedArguments();
@@ -105,11 +107,36 @@
RewrittenTypeInfo rewrittenTypeInfo = argumentInfo.asRewrittenTypeInfo();
DexType enumType =
getEnumClassTypeOrNull(rewrittenTypeInfo.getOldType().toBaseType(factory));
- if (enumType != null) {
+ if (rewrittenTypeInfo.hasSingleValue()
+ && rewrittenTypeInfo.getSingleValue().isSingleNumberValue()) {
+ assert rewrittenTypeInfo
+ .getSingleValue()
+ .isMaterializableInContext(appView, code.context());
+ Instruction materializingInstruction =
+ rewrittenTypeInfo
+ .getSingleValue()
+ .createMaterializingInstruction(
+ appView,
+ code,
+ TypeAndLocalInfoSupplier.create(
+ rewrittenTypeInfo.getNewType().toTypeElement(appView),
+ next.getLocalInfo()));
+ materializingInstruction.setPosition(next.getPosition());
+ extraConstants.add(materializingInstruction);
+ affectedPhis.addAll(next.outValue().uniquePhiUsers());
+ next.outValue().replaceUsers(materializingInstruction.outValue());
+ convertedEnums.put(materializingInstruction, enumType);
+ } else if (enumType != null) {
convertedEnums.put(next, enumType);
}
}
}
+ if (!extraConstants.isEmpty()) {
+ assert extraConstants.size() == 1; // So far this is used only for unboxed enums "this".
+ for (Instruction extraConstant : extraConstants) {
+ iterator.add(extraConstant);
+ }
+ }
return convertedEnums;
}
@@ -125,8 +152,9 @@
assert code.isConsistentSSABeforeTypesAreCorrect(appView);
ProgramMethod context = code.context();
EnumUnboxerMethodProcessorEventConsumer eventConsumer = methodProcessor.getEventConsumer();
- Map<Instruction, DexType> convertedEnums = createInitialConvertedEnums(code, prototypeChanges);
Set<Phi> affectedPhis = Sets.newIdentityHashSet();
+ Map<Instruction, DexType> convertedEnums =
+ createInitialConvertedEnums(code, prototypeChanges, affectedPhis);
BasicBlockIterator blocks = code.listIterator();
Set<BasicBlock> seenBlocks = Sets.newIdentityHashSet();
Set<Instruction> instructionsToRemove = Sets.newIdentityHashSet();
@@ -237,6 +265,23 @@
} else if (invokedMethod == factory.objectMembers.getClass) {
rewriteNullCheck(iterator, invoke, context, eventConsumer);
continue;
+ } else if (invoke.isInvokeVirtual() || invoke.isInvokeInterface()) {
+ DexMethod refinedDispatchMethodReference =
+ enumUnboxingLens.lookupRefinedDispatchMethod(
+ invokedMethod,
+ context.getReference(),
+ invoke.getType(),
+ enumUnboxingLens.getPrevious(),
+ invoke.getArgument(0).getAbstractValue(appView, context),
+ enumType);
+ if (refinedDispatchMethodReference != null) {
+ DexClassAndMethod refinedDispatchMethod =
+ appView.definitionFor(refinedDispatchMethodReference);
+ assert refinedDispatchMethod != null;
+ assert refinedDispatchMethod.isProgramMethod();
+ replaceEnumInvoke(iterator, invoke, refinedDispatchMethod.asProgramMethod());
+ }
+ continue;
}
} else if (invokedMethod == factory.stringBuilderMethods.appendObject
|| invokedMethod == factory.stringBufferMethods.appendObject) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
index 07a54e2..6ac7697 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -56,6 +56,7 @@
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfo;
import com.android.tools.r8.ir.synthetic.EnumUnboxingCfCodeProvider.EnumUnboxingMethodDispatchCfCodeProvider;
import com.android.tools.r8.ir.synthetic.EnumUnboxingCfCodeProvider.EnumUnboxingMethodDispatchCfCodeProvider.CfCodeWithLens;
+import com.android.tools.r8.profile.rewriting.ProfileCollectionAdditions;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.ImmutableArrayUtils;
import com.android.tools.r8.utils.OptionalBool;
@@ -100,6 +101,7 @@
private final ProgramMethodMap<CfCodeWithLens> dispatchMethods =
ProgramMethodMap.createConcurrent();
private final PrunedItems.Builder prunedItemsBuilder;
+ private final ProfileCollectionAdditions profileCollectionAdditions;
EnumUnboxingTreeFixer(
AppView<AppInfoWithLiveness> appView,
@@ -113,9 +115,11 @@
this.factory = appView.dexItemFactory();
this.unboxedEnumHierarchy = unboxedEnums;
this.lensBuilder =
- EnumUnboxingLens.enumUnboxingLensBuilder(appView).mapUnboxedEnums(getUnboxedEnums());
+ EnumUnboxingLens.enumUnboxingLensBuilder(appView, enumDataMap)
+ .mapUnboxedEnums(getUnboxedEnums());
this.utilityClasses = utilityClasses;
this.prunedItemsBuilder = PrunedItems.concurrentBuilder();
+ this.profileCollectionAdditions = ProfileCollectionAdditions.create(appView);
}
private Set<DexProgramClass> computeUnboxedEnumClasses() {
@@ -143,7 +147,9 @@
.fixupClassesConcurrentlyByConnectedProgramComponents(Timing.empty(), executorService);
// Install the new graph lens before processing any checkNotZero() methods.
- EnumUnboxingLens lens = lensBuilder.build(appView);
+ Set<DexMethod> dispatchMethodReferences = Sets.newIdentityHashSet();
+ dispatchMethods.forEach((method, code) -> dispatchMethodReferences.add(method.getReference()));
+ EnumUnboxingLens lens = lensBuilder.build(appView, dispatchMethodReferences);
appView.rewriteWithLens(lens);
// Rewrite outliner with lens.
@@ -160,6 +166,10 @@
code.setCodeLens(lens);
});
+ profileCollectionAdditions
+ .setArtProfileCollection(appView.getArtProfileCollection())
+ .commit(appView);
+
return new Result(
checkNotNullToCheckNotZeroMapping, dispatchMethodSet, lens, prunedItemsBuilder.build());
}
@@ -666,11 +676,14 @@
assert subEnumLocalUtilityMethod != null;
overrideToUtilityMethods.put(subMethod.getReference(), subEnumLocalUtilityMethod);
}
+ if (superMethod.isProgramMethod()) {
+ sortedSubimplementations.add(superMethod.asProgramMethod());
+ }
DexMethod dispatch =
installDispatchMethod(
localUtilityClass,
localUtilityMethods,
- sortedSubimplementations.iterator().next(),
+ sortedSubimplementations,
superUtilityMethod,
overrideToUtilityMethods)
.getReference();
@@ -713,10 +726,11 @@
private DexEncodedMethod installDispatchMethod(
LocalEnumUnboxingUtilityClass localUtilityClass,
Map<DexMethod, DexEncodedMethod> localUtilityMethods,
- ProgramMethod representative,
+ List<ProgramMethod> contexts,
DexMethod superUtilityMethod,
Map<DexMethod, DexMethod> map) {
assert !map.isEmpty();
+ ProgramMethod representative = contexts.iterator().next();
DexMethod newLocalUtilityMethodReference =
factory.createFreshMethodNameWithoutHolder(
"_dispatch_" + representative.getName().toString(),
@@ -752,8 +766,12 @@
.setApiLevelForDefinition(representative.getDefinition().getApiLevelForDefinition())
.setApiLevelForCode(representative.getDefinition().getApiLevelForCode())
.build();
- dispatchMethods.put(
- newLocalUtilityMethod.asProgramMethod(localUtilityClass.getDefinition()), codeWithLens);
+ ProgramMethod dispatchMethod =
+ newLocalUtilityMethod.asProgramMethod(localUtilityClass.getDefinition());
+ dispatchMethods.put(dispatchMethod, codeWithLens);
+ for (ProgramMethod context : contexts) {
+ profileCollectionAdditions.addMethodIfContextIsInProfile(dispatchMethod, context);
+ }
assert !localUtilityMethods.containsKey(newLocalUtilityMethodReference);
localUtilityMethods.put(newLocalUtilityMethodReference, newLocalUtilityMethod);
return newLocalUtilityMethod;
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 6d6d497..6dcfe40 100644
--- a/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
+++ b/src/main/java/com/android/tools/r8/lightir/Lir2IRConverter.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.ir.code.CheckCast;
import com.android.tools.r8.ir.code.Cmp;
import com.android.tools.r8.ir.code.Cmp.Bias;
+import com.android.tools.r8.ir.code.ConstClass;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.ConstString;
import com.android.tools.r8.ir.code.DebugLocalWrite;
@@ -38,6 +39,7 @@
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.code.InvokeInterface;
+import com.android.tools.r8.ir.code.InvokeNewArray;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.InvokeSuper;
import com.android.tools.r8.ir.code.InvokeVirtual;
@@ -47,6 +49,7 @@
import com.android.tools.r8.ir.code.MoveException;
import com.android.tools.r8.ir.code.Mul;
import com.android.tools.r8.ir.code.NewArrayEmpty;
+import com.android.tools.r8.ir.code.NewArrayFilledData;
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.NumberConversion;
import com.android.tools.r8.ir.code.NumberGenerator;
@@ -57,6 +60,7 @@
import com.android.tools.r8.ir.code.Rem;
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.StaticGet;
+import com.android.tools.r8.ir.code.StaticPut;
import com.android.tools.r8.ir.code.Sub;
import com.android.tools.r8.ir.code.Throw;
import com.android.tools.r8.ir.code.Value;
@@ -421,6 +425,14 @@
}
@Override
+ public void onConstClass(DexType type) {
+ Value dest =
+ getOutValueForNextInstruction(
+ type.toTypeElement(appView, Nullability.definitelyNotNull()));
+ addInstruction(new ConstClass(dest, type));
+ }
+
+ @Override
public void onNumberConversion(NumericType from, NumericType to, EV value) {
Value dest =
getOutValueForNextInstruction(
@@ -523,6 +535,11 @@
}
@Override
+ public void onStaticPut(DexField field, EV value) {
+ addInstruction(new StaticPut(getValue(value), field));
+ }
+
+ @Override
public void onInstanceGet(DexField field, EV object) {
Value dest = getOutValueForNextInstruction(field.getTypeElement(appView));
addInstruction(new InstanceGet(dest, getValue(object), field));
@@ -602,6 +619,19 @@
}
@Override
+ public void onInvokeNewArray(DexType type, List<EV> arguments) {
+ Value dest =
+ getOutValueForNextInstruction(
+ type.toTypeElement(appView, Nullability.definitelyNotNull()));
+ addInstruction(new InvokeNewArray(type, dest, getValues(arguments)));
+ }
+
+ @Override
+ public void onNewArrayFilledData(int elementWidth, long size, short[] data, EV src) {
+ addInstruction(new NewArrayFilledData(getValue(src), elementWidth, size, data));
+ }
+
+ @Override
public void onCmpInstruction(int opcode, EV leftIndex, EV rightIndex) {
NumericType type;
Bias bias;
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 8f41773..1239c11 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirBuilder.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.cf.code.CfArithmeticBinop.Opcode;
import com.android.tools.r8.cf.code.CfLogicalBinop;
import com.android.tools.r8.cf.code.CfNumberConversion;
+import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DebugLocalInfo;
@@ -78,9 +79,32 @@
// TODO(b/225838009): Reconsider this fixed space as the operand count for phis is much larger.
// Pre-allocated space for caching value indexes when writing instructions.
- private static final int MAX_VALUE_COUNT = 10;
+ private static final int MAX_VALUE_COUNT = 256;
private int[] valueIndexBuffer = new int[MAX_VALUE_COUNT];
+ /**
+ * Internal "DexItem" for the fill-array payloads such that they can be put in the pool.
+ *
+ * <p>The instruction encoding assumes the instruction operand payload size is u1, so the data
+ * payload is stored in the constant pool instead.
+ */
+ public static class FillArrayPayload extends DexItem {
+ public final int element_width;
+ public final long size;
+ public final short[] data;
+
+ public FillArrayPayload(int element_width, long size, short[] data) {
+ this.element_width = element_width;
+ this.size = size;
+ this.data = data;
+ }
+
+ @Override
+ protected void collectMixedSectionItems(MixedSectionCollection collection) {
+ throw new Unreachable();
+ }
+ }
+
public LirBuilder(DexMethod method, LirEncodingStrategy<V, EV> strategy, DexItemFactory factory) {
this.factory = factory;
constants = new Reference2IntOpenHashMap<>();
@@ -331,6 +355,10 @@
return addOneItemInstruction(LirOpcodes.LDC, string);
}
+ public LirBuilder<V, EV> addConstClass(DexType type) {
+ return addOneItemInstruction(LirOpcodes.LDC, type);
+ }
+
public LirBuilder<V, EV> addDiv(NumericType type, V leftValue, V rightValue) {
int opcode;
switch (type) {
@@ -377,6 +405,11 @@
return addOneItemInstruction(LirOpcodes.GETSTATIC, field);
}
+ public LirBuilder<V, EV> addStaticPut(DexField field, V value) {
+ return addInstructionTemplate(
+ LirOpcodes.PUTSTATIC, Collections.singletonList(field), ImmutableList.of(value));
+ }
+
public LirBuilder<V, EV> addInstanceGet(DexField field, V object) {
return addInstructionTemplate(
LirOpcodes.GETFIELD, Collections.singletonList(field), Collections.singletonList(object));
@@ -605,6 +638,19 @@
LirOpcodes.NEWARRAY, Collections.singletonList(type), Collections.singletonList(size));
}
+ public LirBuilder<V, EV> addInvokeNewArray(DexType type, List<V> arguments) {
+ return addInstructionTemplate(
+ LirOpcodes.INVOKENEWARRAY, Collections.singletonList(type), arguments);
+ }
+
+ public LirBuilder<V, EV> addNewArrayFilledData(int elementWidth, long size, short[] data, V src) {
+ FillArrayPayload payloadConstant = new FillArrayPayload(elementWidth, size, data);
+ return addInstructionTemplate(
+ LirOpcodes.NEWARRAYFILLEDDATA,
+ Collections.singletonList(payloadConstant),
+ Collections.singletonList(src));
+ }
+
public LirBuilder<V, EV> addNumberConversion(NumericType from, NumericType to, V value) {
int opcode = new CfNumberConversion(from, to).getAsmOpcode();
assert LirOpcodes.I2L <= opcode;
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 302e85d..c4f2076 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirOpcodes.java
@@ -194,6 +194,8 @@
int FALLTHROUGH = 211;
int MOVEEXCEPTION = 212;
int DEBUGLOCALWRITE = 213;
+ int INVOKENEWARRAY = 214;
+ int NEWARRAYFILLEDDATA = 215;
static String toString(int opcode) {
switch (opcode) {
@@ -506,6 +508,10 @@
return "MOVEEXCEPTION";
case DEBUGLOCALWRITE:
return "DEBUGLOCALWRITE";
+ case INVOKENEWARRAY:
+ return "INVOKENEWARRAY";
+ case NEWARRAYFILLEDDATA:
+ return "NEWARRAYFILLEDDATA";
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 1fca6a6..8d81728 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirParsedInstructionCallback.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.ir.code.IfType;
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.NumericType;
+import com.android.tools.r8.lightir.LirBuilder.FillArrayPayload;
import java.util.ArrayList;
import java.util.List;
@@ -85,6 +86,10 @@
onInstruction();
}
+ public void onConstClass(DexType type) {
+ onInstruction();
+ }
+
private void onArrayGetInternal(MemberType type, LirInstructionView view) {
if (type.isObject()) {
DexType destType = (DexType) getConstantItem(view.getNextConstantOperand());
@@ -295,6 +300,14 @@
onInstruction();
}
+ public void onInvokeNewArray(DexType type, List<EV> arguments) {
+ onInstruction();
+ }
+
+ public void onNewArrayFilledData(int elementWidth, long size, short[] data, EV src) {
+ onInstruction();
+ }
+
public void onInvokeMethodInstruction(DexMethod method, List<EV> arguments) {
onInstruction();
}
@@ -331,6 +344,10 @@
onFieldInstruction(field);
}
+ public void onStaticPut(DexField field, EV value) {
+ onFieldInstruction(field);
+ }
+
public abstract void onInstanceGet(DexField field, EV object);
public abstract void onInstancePut(DexField field, EV object, EV value);
@@ -392,6 +409,10 @@
onConstString((DexString) item);
return;
}
+ if (item instanceof DexType) {
+ onConstClass((DexType) item);
+ return;
+ }
throw new Unimplemented();
}
case LirOpcodes.ICONST_M1:
@@ -859,6 +880,13 @@
onStaticGet(field);
return;
}
+ case LirOpcodes.PUTSTATIC:
+ {
+ DexField field = (DexField) getConstantItem(view.getNextConstantOperand());
+ EV value = getNextValueOperand(view);
+ onStaticPut(field, value);
+ return;
+ }
case LirOpcodes.GETFIELD:
{
DexField field = (DexField) getConstantItem(view.getNextConstantOperand());
@@ -954,6 +982,21 @@
onDebugLocalWrite(srcIndex);
return;
}
+ case LirOpcodes.INVOKENEWARRAY:
+ {
+ DexType type = getNextDexTypeOperand(view);
+ List<EV> arguments = getInvokeInstructionArguments(view);
+ onInvokeNewArray(type, arguments);
+ return;
+ }
+ case LirOpcodes.NEWARRAYFILLEDDATA:
+ {
+ FillArrayPayload payload =
+ (FillArrayPayload) getConstantItem(view.getNextConstantOperand());
+ EV src = getNextValueOperand(view);
+ onNewArrayFilledData(payload.element_width, payload.size, payload.data, src);
+ return;
+ }
case LirOpcodes.LCMP:
case LirOpcodes.FCMPL:
case LirOpcodes.FCMPG:
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 132fc61..58ac9b2 100644
--- a/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
+++ b/src/main/java/com/android/tools/r8/lightir/LirPrinter.java
@@ -150,6 +150,11 @@
}
@Override
+ public void onConstClass(DexType type) {
+ appendOutValue().append("class(").append(type).append(")");
+ }
+
+ @Override
public void onAdd(NumericType type, EV leftValueIndex, EV rightValueIndex) {
appendOutValue();
appendValueArguments(leftValueIndex, rightValueIndex);
@@ -212,6 +217,19 @@
}
@Override
+ public void onInvokeNewArray(DexType type, List<EV> arguments) {
+ appendOutValue();
+ appendValueArguments(arguments);
+ builder.append(type);
+ }
+
+ @Override
+ public void onNewArrayFilledData(int elementWidth, long size, short[] data, EV src) {
+ appendValueArguments(src);
+ builder.append("w:").append(elementWidth).append(",s:").append(size);
+ }
+
+ @Override
public void onNewInstance(DexType clazz) {
appendOutValue();
builder.append(clazz);
@@ -227,14 +245,15 @@
}
@Override
- public void onFieldInstruction(DexField field) {
- builder.append(field);
+ public void onStaticGet(DexField field) {
+ appendOutValue();
+ builder.append(field).append(' ');
}
@Override
- public void onStaticGet(DexField field) {
- appendOutValue();
- super.onStaticGet(field);
+ public void onStaticPut(DexField field, EV value) {
+ builder.append(field).append(' ');
+ appendValueArguments(value);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
index d5fd889..cfd7b32 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
@@ -83,6 +83,10 @@
}
}
+ public boolean hasMapping(String obfuscatedName) {
+ return mapping.containsKey(obfuscatedName);
+ }
+
@Override
public ClassNameMapper build() {
return new ClassNameMapper(
diff --git a/src/main/java/com/android/tools/r8/naming/SeedMapper.java b/src/main/java/com/android/tools/r8/naming/SeedMapper.java
index dd2d150..536fd49 100644
--- a/src/main/java/com/android/tools/r8/naming/SeedMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/SeedMapper.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.utils.DescriptorUtils.descriptorToInternalName;
import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
import static com.android.tools.r8.utils.DescriptorUtils.javaTypeToDescriptor;
+import static com.android.tools.r8.utils.positions.MappedPositionToClassNameMapperBuilder.getPrunedInlinedClassObfuscatedPrefix;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.naming.MemberNaming.Signature;
@@ -56,8 +57,11 @@
ClassNamingForMapApplier.Builder classNamingBuilder =
ClassNamingForMapApplier.builder(
renamedDescriptorName, originalDescriptor, position, reporter);
- if (map.put(originalDescriptor, classNamingBuilder) != null) {
- reporter.error(ProguardMapError.duplicateSourceClass(originalDescriptor, position));
+ // Disallow renaming to a synthetic chosen name for pruned classes.
+ if (!renamedName.startsWith(getPrunedInlinedClassObfuscatedPrefix())) {
+ if (map.put(originalDescriptor, classNamingBuilder) != null) {
+ reporter.error(ProguardMapError.duplicateSourceClass(originalDescriptor, position));
+ }
}
return classNamingBuilder;
}
diff --git a/src/main/java/com/android/tools/r8/position/TextPosition.java b/src/main/java/com/android/tools/r8/position/TextPosition.java
index dcbc695..ebfd33a 100644
--- a/src/main/java/com/android/tools/r8/position/TextPosition.java
+++ b/src/main/java/com/android/tools/r8/position/TextPosition.java
@@ -24,9 +24,7 @@
private final int column;
public TextPosition(long offset, int line, int column) {
- assert (offset >= 0)
- && (line >= 1)
- && (column >= 1 || column == UNKNOWN_COLUMN);
+ assert (offset >= 0) && (line >= 0) && (column >= 1 || column == UNKNOWN_COLUMN);
this.offset = offset;
this.line = line;
this.column = column;
diff --git a/src/main/java/com/android/tools/r8/profile/art/ArtProfileCompletenessChecker.java b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCompletenessChecker.java
index 06464c7..d7fde7d 100644
--- a/src/main/java/com/android/tools/r8/profile/art/ArtProfileCompletenessChecker.java
+++ b/src/main/java/com/android/tools/r8/profile/art/ArtProfileCompletenessChecker.java
@@ -85,9 +85,7 @@
ProgramDefinition definition,
Set<CompletenessExceptions> completenessExceptions,
List<DexReference> missing) {
- // TODO(b/274030968): Fix profile for enum unboxing with subtypes.
- if (appView.options().testing.enableEnumWithSubtypesUnboxing
- || completenessExceptions.contains(ALLOW_MISSING_ENUM_UNBOXING_UTILITY_METHODS)) {
+ if (completenessExceptions.contains(ALLOW_MISSING_ENUM_UNBOXING_UTILITY_METHODS)) {
DexType contextType = definition.getContextType();
SyntheticItems syntheticItems = appView.getSyntheticItems();
if (syntheticItems.isSynthetic(contextType)) {
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index 5cca6e8..0150f83 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -9,6 +9,9 @@
import com.android.tools.r8.Diagnostic;
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.Keep;
+import com.android.tools.r8.ParseFlagInfo;
+import com.android.tools.r8.ParseFlagInfoImpl;
+import com.android.tools.r8.ParseFlagPrinter;
import com.android.tools.r8.Version;
import com.android.tools.r8.retrace.internal.RetraceAbortException;
import com.android.tools.r8.retrace.internal.RetraceBase;
@@ -21,6 +24,7 @@
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.Timing;
import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
@@ -42,11 +46,29 @@
@Keep
public class Retrace<T, ST extends StackTraceElementProxy<T, ST>> extends RetraceBase<T, ST> {
- public static final String USAGE_MESSAGE =
+ private static final String USAGE_MESSAGE =
StringUtils.lines(
- "Usage: retrace <proguard-map> [stack-trace-file] "
- + "[--regex <regexp>, --verbose, --info, --quiet, --verify-mapping-file-hash]",
- " where <proguard-map> is an r8 generated mapping file.");
+ "Usage: retrace [options] <proguard-map> [stack-trace-file] "
+ + "where <proguard-map> is a generated mapping file and options are:");
+
+ public static List<ParseFlagInfo> getFlags() {
+ return ImmutableList.<ParseFlagInfo>builder()
+ .add(
+ ParseFlagInfoImpl.flag1(
+ "--regex", "<regexp>", "Regular expression for parsing stack-trace-file as lines"))
+ .add(ParseFlagInfoImpl.flag0("--verbose", "Get verbose retraced output"))
+ .add(ParseFlagInfoImpl.flag0("--info", "Write information messages to stdout"))
+ .add(ParseFlagInfoImpl.flag0("--quiet", "Silence ordinary messages printed to stdout"))
+ .add(ParseFlagInfoImpl.flag0("--verify-mapping-file-hash", "Verify the mapping file hash"))
+ .build();
+ }
+
+ static String getUsageMessage() {
+ StringBuilder builder = new StringBuilder();
+ StringUtils.appendLines(builder, USAGE_MESSAGE);
+ new ParseFlagPrinter().addFlags(getFlags()).appendLinesToBuilder(builder);
+ return builder.toString();
+ }
private static RetraceCommand.Builder parseArguments(
String[] args, DiagnosticsHandler diagnosticsHandler) {
@@ -102,7 +124,7 @@
diagnosticsHandler.error(
new StringDiagnostic(
String.format("Too many arguments specified for builder at '%s'", context.head())));
- diagnosticsHandler.error(new StringDiagnostic(USAGE_MESSAGE));
+ diagnosticsHandler.error(new StringDiagnostic(getUsageMessage()));
throw new RetraceAbortException();
}
}
@@ -323,7 +345,7 @@
}
assert Arrays.asList(args).contains("--help");
System.out.println("Retrace " + Version.getVersionString());
- System.out.print(USAGE_MESSAGE);
+ System.out.print(getUsageMessage());
return;
}
builder.setRetracedStackTraceConsumer(
diff --git a/src/main/java/com/android/tools/r8/utils/positions/MappedPositionToClassNameMapperBuilder.java b/src/main/java/com/android/tools/r8/utils/positions/MappedPositionToClassNameMapperBuilder.java
index b4ec7c9..5578b1f 100644
--- a/src/main/java/com/android/tools/r8/utils/positions/MappedPositionToClassNameMapperBuilder.java
+++ b/src/main/java/com/android/tools/r8/utils/positions/MappedPositionToClassNameMapperBuilder.java
@@ -44,6 +44,7 @@
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.IntBox;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.OneShotCollectionConsumer;
@@ -65,6 +66,7 @@
public class MappedPositionToClassNameMapperBuilder {
private static final int MAX_LINE_NUMBER = 65535;
+ private static final String PRUNED_INLINED_CLASS_OBFUSCATED_PREFIX = "R8$$REMOVED$$CLASS$$";
private final OriginalSourceFiles originalSourceFiles;
private final AppView<?> appView;
@@ -87,6 +89,10 @@
appView.options().getMapFileVersion().toMapVersionMappingInformation());
}
+ public static String getPrunedInlinedClassObfuscatedPrefix() {
+ return PRUNED_INLINED_CLASS_OBFUSCATED_PREFIX;
+ }
+
public static int getMaxLineNumber() {
return MAX_LINE_NUMBER;
}
@@ -106,16 +112,24 @@
private void addSourceFileLinesForPrunedClasses() {
// Add all pruned inline classes to the mapping to recover source files.
List<Entry<DexType, String>> prunedEntries = new ArrayList<>(prunedInlinedClasses.entrySet());
+ IntBox counter = new IntBox();
prunedEntries.sort(Entry.comparingByKey());
prunedEntries.forEach(
entry -> {
DexType holder = entry.getKey();
- assert appView.appInfo().definitionForWithoutExistenceAssert(holder) == null;
+ assert appView.appInfo().definitionForWithoutExistenceAssert(holder) == null
+ || !appView.appInfo().definitionForWithoutExistenceAssert(holder).isProgramClass();
String typeName = holder.toSourceString();
String sourceFile = entry.getValue();
+ // We have to pick a right-hand side destination that does not overlap with an existing
+ // mapping.
+ String renamedName;
+ do {
+ renamedName = PRUNED_INLINED_CLASS_OBFUSCATED_PREFIX + counter.getAndIncrement();
+ } while (classNameMapperBuilder.hasMapping(renamedName));
classNameMapperBuilder
.classNamingBuilder(
- typeName, typeName, com.android.tools.r8.position.Position.UNKNOWN)
+ renamedName, typeName, com.android.tools.r8.position.Position.UNKNOWN)
.addMappingInformation(FileNameInformation.build(sourceFile), Unreachable::raise);
});
}
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
index c2a1ba2..2a5bb6c 100644
--- a/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
+++ b/src/test/java/com/android/tools/r8/R8RunExamplesTest.java
@@ -26,11 +26,6 @@
public static Collection<String[]> data() {
String[] tests = {
"arithmetic.Arithmetic",
- "constants.Constants",
- "controlflow.ControlFlow",
- "conversions.Conversions",
- "floating_point_annotations.FloatingPointValuedAnnotationTest",
- "filledarray.FilledArray",
"hello.Hello",
"ifstatements.IfStatements",
"inlining.Inlining",
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
index 3d2be09..5264b18 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
@@ -9,7 +9,6 @@
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
@@ -117,6 +116,14 @@
"classmerging.SuperClass"
);
+ private static void assertAbsentOrIdentity(ClassNameMapper mapper, String className) {
+ // The mapping should be absent or identity.
+ ClassNamingForNameMapper classNaming = mapper.getClassNaming(className);
+ if (classNaming != null) {
+ assertEquals(classNaming.originalName, classNaming.renamedName);
+ }
+ }
+
@Test
public void testClassesHaveNotBeenMerged() throws Throwable {
runR8(DONT_OPTIMIZE, null);
@@ -526,7 +533,7 @@
ClassNameMapper mappingWithClassMerging =
ClassNameMapper.mapperFromString(compileResultWithClassMerging.getProguardMap());
- assertNull(mappingWithClassMerging.getClassNaming("classmerging.ProguardFieldMapTest$A"));
+ assertAbsentOrIdentity(mappingWithClassMerging, "classmerging.ProguardFieldMapTest$A");
ClassNamingForNameMapper mappingsForClassBWithClassMerging =
mappingWithClassMerging.getClassNaming("classmerging.ProguardFieldMapTest$B");
@@ -607,7 +614,7 @@
ClassNameMapper mappingWithClassMerging =
ClassNameMapper.mapperFromString(compileResultWithClassMerging.getProguardMap());
- assertNull(mappingWithClassMerging.getClassNaming("classmerging.ProguardMethodMapTest$A"));
+ assertAbsentOrIdentity(mappingWithClassMerging, "classmerging.ProguardMethodMapTest$A");
ClassNamingForNameMapper mappingsForClassBWithClassMerging =
mappingWithClassMerging.getClassNaming("classmerging.ProguardMethodMapTest$B");
diff --git a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
index 71c9dc4..c59fda4 100644
--- a/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
+++ b/src/test/java/com/android/tools/r8/compilerapi/CompilerApiTestCollection.java
@@ -23,6 +23,7 @@
import com.android.tools.r8.compilerapi.mockdata.MockClass;
import com.android.tools.r8.compilerapi.mockdata.MockClassWithAssertion;
import com.android.tools.r8.compilerapi.mockdata.PostStartupMockClass;
+import com.android.tools.r8.compilerapi.partitionmap.PartitionMapCommandTest;
import com.android.tools.r8.compilerapi.sourcefile.CustomSourceFileTest;
import com.android.tools.r8.compilerapi.startupprofile.StartupProfileApiTest;
import com.android.tools.r8.compilerapi.syntheticscontexts.SyntheticContextsConsumerTest;
@@ -60,7 +61,8 @@
ClassConflictResolverTest.ApiTest.class,
ProguardKeepRuleDiagnosticsApiTest.ApiTest.class,
SyntheticContextsConsumerTest.ApiTest.class,
- ExtractMarkerApiTest.ApiTest.class);
+ ExtractMarkerApiTest.ApiTest.class,
+ PartitionMapCommandTest.ApiTest.class);
private static final List<Class<? extends CompilerApiTest>> CLASSES_PENDING_BINARY_COMPATIBILITY =
ImmutableList.of(CancelCompilationCheckerTest.ApiTest.class);
diff --git a/src/test/java/com/android/tools/r8/compilerapi/partitionmap/PartitionMapCommandTest.java b/src/test/java/com/android/tools/r8/compilerapi/partitionmap/PartitionMapCommandTest.java
new file mode 100644
index 0000000..47cb0c9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compilerapi/partitionmap/PartitionMapCommandTest.java
@@ -0,0 +1,158 @@
+// 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.compilerapi.partitionmap;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.D8;
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.PartitionMapConsumer;
+import com.android.tools.r8.ProgramConsumer;
+import com.android.tools.r8.R8;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.StringConsumer;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.compilerapi.CompilerApiTest;
+import com.android.tools.r8.compilerapi.CompilerApiTestRunner;
+import com.android.tools.r8.compilerapi.partitionmap.PartitionMapCommandTest.ApiTest.EnsurePartitionMapOutputConsumer;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.retrace.MappingPartition;
+import com.android.tools.r8.retrace.MappingPartitionMetadata;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+
+public class PartitionMapCommandTest extends CompilerApiTestRunner {
+
+ private static final int FIRST_API_LEVEL_WITH_NATIVE_MULTIDEX = 21;
+
+ public PartitionMapCommandTest(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ public Class<? extends CompilerApiTest> binaryTestClass() {
+ return ApiTest.class;
+ }
+
+ private interface Runner {
+ void run(
+ ProgramConsumer programConsumer,
+ StringConsumer pgMapConsumer,
+ PartitionMapConsumer partitionMapConsumer)
+ throws Exception;
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runTest(new ApiTest(CompilerApiTest.PARAMETERS)::runR8);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ runTest(new ApiTest(CompilerApiTest.PARAMETERS)::runD8);
+ }
+
+ private void runTest(Runner test) throws Exception {
+ EnsurePartitionMapOutputConsumer partitionConsumer = EnsurePartitionMapOutputConsumer.get();
+ test.run(DexIndexedConsumer.emptyConsumer(), StringConsumer.emptyConsumer(), partitionConsumer);
+ assertTrue(partitionConsumer.hasOutput());
+ }
+
+ public static class ApiTest extends CompilerApiTest {
+
+ public ApiTest(Object parameters) {
+ super(parameters);
+ }
+
+ public void runD8(
+ ProgramConsumer programConsumer,
+ StringConsumer pgMapConsumer,
+ PartitionMapConsumer partitionMapConsumer)
+ throws Exception {
+ D8.run(
+ D8Command.builder()
+ .addClassProgramData(getBytesForClass(getMockClass()), Origin.unknown())
+ .addClassProgramData(getBytesForClass(getPostStartupMockClass()), Origin.unknown())
+ .addLibraryFiles(getJava8RuntimeJar())
+ .setMinApiLevel(FIRST_API_LEVEL_WITH_NATIVE_MULTIDEX)
+ .setProguardMapConsumer(pgMapConsumer)
+ .setProgramConsumer(programConsumer)
+ .setPartitionMapConsumer(partitionMapConsumer)
+ .build());
+ }
+
+ public void runR8(
+ ProgramConsumer programConsumer,
+ StringConsumer pgMapConsumer,
+ PartitionMapConsumer partitionMapConsumer)
+ throws Exception {
+ R8.run(
+ R8Command.builder()
+ .addClassProgramData(getBytesForClass(getMockClass()), Origin.unknown())
+ .addProguardConfiguration(getKeepMainRules(getMockClass()), Origin.unknown())
+ .addLibraryFiles(getJava8RuntimeJar())
+ .setMinApiLevel(FIRST_API_LEVEL_WITH_NATIVE_MULTIDEX)
+ .setProgramConsumer(programConsumer)
+ .setProguardMapConsumer(pgMapConsumer)
+ .setPartitionMapConsumer(partitionMapConsumer)
+ .build());
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ EnsurePartitionMapOutputConsumer ensurePartitionMapOutputConsumer =
+ EnsurePartitionMapOutputConsumer.get();
+ runR8(
+ DexIndexedConsumer.emptyConsumer(),
+ StringConsumer.emptyConsumer(),
+ ensurePartitionMapOutputConsumer);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ EnsurePartitionMapOutputConsumer ensurePartitionMapOutputConsumer =
+ EnsurePartitionMapOutputConsumer.get();
+ runD8(
+ DexIndexedConsumer.emptyConsumer(),
+ StringConsumer.emptyConsumer(),
+ ensurePartitionMapOutputConsumer);
+ }
+
+ public static class EnsurePartitionMapOutputConsumer implements PartitionMapConsumer {
+
+ private final List<String> keys = new ArrayList<>();
+ private boolean finished = false;
+
+ private EnsurePartitionMapOutputConsumer() {}
+
+ private boolean hasOutput() {
+ return finished && !keys.isEmpty();
+ }
+
+ public static EnsurePartitionMapOutputConsumer get() {
+ return new EnsurePartitionMapOutputConsumer();
+ }
+
+ @Override
+ public void acceptMappingPartition(MappingPartition mappingPartition) {
+ keys.add(mappingPartition.getKey());
+ }
+
+ @Override
+ public void acceptMappingPartitionMetadata(
+ MappingPartitionMetadata mappingPartitionMetadata) {
+ keys.add("METADATA");
+ }
+
+ @Override
+ public void finished(DiagnosticsHandler handler) {
+ finished = true;
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
index 563fc09..7696491 100644
--- a/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
+++ b/src/test/java/com/android/tools/r8/debug/ExamplesDebugTest.java
@@ -60,31 +60,6 @@
}
@Test
- public void testConstants() throws Exception {
- testDebugging("constants", "Constants");
- }
-
- @Test
- public void testControlFlow() throws Exception {
- testDebugging("controlflow", "ControlFlow");
- }
-
- @Test
- public void testConversions() throws Exception {
- testDebugging("conversions", "Conversions");
- }
-
- @Test
- public void testFloatingPointValuedAnnotation() throws Exception {
- testDebugging("floating_point_annotations", "FloatingPointValuedAnnotationTest");
- }
-
- @Test
- public void testFilledArray() throws Exception {
- testDebugging("filledarray", "FilledArray");
- }
-
- @Test
public void testHello() throws Exception {
testDebugging("hello", "Hello");
}
diff --git a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
index 7a73a31..3a0a0f6 100644
--- a/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/debug/InterfaceMethodTest.java
@@ -7,7 +7,7 @@
import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getCompanionClassNameSuffix;
import static com.android.tools.r8.ir.desugar.itf.InterfaceDesugaringForTesting.getDefaultMethodPrefix;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
+import static org.junit.Assume.assumeFalse;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -47,12 +47,10 @@
@Test
public void testDefaultMethod() throws Throwable {
- // TODO(b/244683447): This test fails on Art 13 and Art 14 when checking current method in
- // doSomething.
- assumeTrue(
- parameters.isCfRuntime()
- || !(parameters.getDexRuntimeVersion().isEqualTo(Version.V13_0_0)
- || parameters.getDexRuntimeVersion().isEqualTo(Version.V14_0_0)));
+ assumeFalse(
+ "b/244683447: Incorrect behavior on Art 13 and 14",
+ parameters.isDexRuntimeVersion(Version.V13_0_0)
+ || parameters.isDexRuntimeVersion(Version.V14_0_0));
testForRuntime(parameters)
.addProgramFiles(JAR)
.run(parameters.getRuntime(), debuggeeClass)
diff --git a/src/test/java/com/android/tools/r8/debuginfo/NoKeepLineAttributeTest.java b/src/test/java/com/android/tools/r8/debuginfo/NoKeepLineAttributeTest.java
new file mode 100644
index 0000000..35ae932
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/NoKeepLineAttributeTest.java
@@ -0,0 +1,71 @@
+// 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.debuginfo;
+
+import static org.junit.Assert.assertEquals;
+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.ToolHelper.DexVm.Version;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class NoKeepLineAttributeTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ // Only run the test on VMs that have native pc support.
+ .withDexRuntimesStartingFromExcluding(Version.V7_0_0)
+ .withAllApiLevels()
+ .build();
+ }
+
+ public NoKeepLineAttributeTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(NoKeepLineAttributeTest.class)
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertFailureWithErrorThatThrows(RuntimeException.class)
+ .inspectStackTrace(
+ stacktrace -> {
+ List<StackTraceLine> stackTraceLines = stacktrace.getStackTraceLines();
+ assertEquals(1, stackTraceLines.size());
+ StackTraceLine stackTraceLine = stackTraceLines.get(0);
+ // The frame will always have a line as the VM is reporting the PC.
+ assertTrue(stackTraceLine.hasLineNumber());
+ if (parameters.getApiLevel().isLessThan(apiLevelWithPcAsLineNumberSupport())) {
+ // If the compile-time API is before native support then no line info is present.
+ // The "line" will be the PC and thus small.
+ assertTrue(stackTraceLine.lineNumber < 10);
+ } else {
+ // If the compile-time API is after native support then the compiler will retain and
+ // emit the mapping from PC to original line. Here line 50 is to ensure it is not a
+ // low PC value.
+ assertTrue(stackTraceLine.lineNumber > 50);
+ }
+ });
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ throw new RuntimeException("My Exception!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/NoKeepSourceFileAttributeTest.java b/src/test/java/com/android/tools/r8/debuginfo/NoKeepSourceFileAttributeTest.java
new file mode 100644
index 0000000..9a68a09
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/NoKeepSourceFileAttributeTest.java
@@ -0,0 +1,107 @@
+// 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.debuginfo;
+
+import static org.junit.Assert.assertEquals;
+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.naming.retrace.StackTrace.StackTraceLine;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class NoKeepSourceFileAttributeTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimesAndAllApiLevels().build();
+ }
+
+ public NoKeepSourceFileAttributeTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ public boolean isRuntimeWithPcAsLineNumberSupport() {
+ return parameters.isDexRuntime()
+ && parameters
+ .getRuntime()
+ .maxSupportedApiLevel()
+ .isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport());
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(NoKeepSourceFileAttributeTest.class)
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertFailureWithErrorThatThrows(RuntimeException.class)
+ .inspectOriginalStackTrace(
+ stacktrace -> {
+ List<StackTraceLine> stackTraceLines = stacktrace.getStackTraceLines();
+ assertEquals(1, stackTraceLines.size());
+ StackTraceLine stackTraceLine = stackTraceLines.get(0);
+ if (!isRuntimeWithPcAsLineNumberSupport()) {
+ assertEquals("SourceFile", stackTraceLine.fileName);
+ } else {
+ // VMs with native PC support and no debug info print "Unknown Source".
+ // TODO(b/146565491): This will need a check for new VMs once fixed.
+ assertEquals("Unknown Source", stackTraceLine.fileName);
+ }
+ })
+ .inspectStackTrace(
+ stacktrace -> {
+ List<StackTraceLine> stackTraceLines = stacktrace.getStackTraceLines();
+ assertEquals(1, stackTraceLines.size());
+ StackTraceLine stackTraceLine = stackTraceLines.get(0);
+ assertEquals("NoKeepSourceFileAttributeTest.java", stackTraceLine.fileName);
+ });
+ }
+
+ @Test
+ public void testNoOpt() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(NoKeepSourceFileAttributeTest.class)
+ .addKeepMainRule(TestClass.class)
+ // Keeping lines and not obfuscating or optimizing will retain original lines.
+ .addDontObfuscate()
+ .addDontOptimize()
+ .addKeepAttributeLineNumberTable()
+ .setMinApi(parameters)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertFailureWithErrorThatThrows(RuntimeException.class)
+ .inspectOriginalStackTrace(
+ stacktrace -> {
+ List<StackTraceLine> stackTraceLines = stacktrace.getStackTraceLines();
+ assertEquals(1, stackTraceLines.size());
+ StackTraceLine stackTraceLine = stackTraceLines.get(0);
+ assertEquals("SourceFile", stackTraceLine.fileName);
+ // The non-optimizing/obfuscating build will retain the original line info.
+ assertTrue(stackTraceLine.lineNumber > 50);
+ })
+ .inspectStackTrace(
+ stacktrace -> {
+ List<StackTraceLine> stackTraceLines = stacktrace.getStackTraceLines();
+ assertEquals(1, stackTraceLines.size());
+ StackTraceLine stackTraceLine = stackTraceLines.get(0);
+ assertEquals("NoKeepSourceFileAttributeTest.java", stackTraceLine.fileName);
+ assertTrue(stackTraceLine.lineNumber > 50);
+ });
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ throw new RuntimeException("My Exception!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/enummerging/EnumMergingInstantiatingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/enummerging/EnumMergingInstantiatingTest.java
new file mode 100644
index 0000000..074e0e9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/enummerging/EnumMergingInstantiatingTest.java
@@ -0,0 +1,190 @@
+// 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.enumunboxing.enummerging;
+
+import com.android.tools.r8.AlwaysInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.NoReturnTypeStrengthening;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.enumunboxing.EnumUnboxingTestBase;
+import com.android.tools.r8.utils.DescriptorUtils;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class EnumMergingInstantiatingTest extends EnumUnboxingTestBase {
+
+ private static Collection<byte[]> PROGRAM_CLASSES_DATA;
+
+ private final TestParameters parameters;
+ private final boolean enumValueOptimization;
+ private final EnumKeepRules enumKeepRules;
+
+ @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+ public static List<Object[]> data() {
+ return enumUnboxingTestParameters();
+ }
+
+ @BeforeClass
+ public static void setup() throws IOException {
+ PROGRAM_CLASSES_DATA = tranformedInputs();
+ }
+
+ public EnumMergingInstantiatingTest(
+ TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) {
+ this.parameters = parameters;
+ this.enumValueOptimization = enumValueOptimization;
+ this.enumKeepRules = enumKeepRules;
+ }
+
+ @Test
+ public void testEnumUnboxing() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClassFileData(PROGRAM_CLASSES_DATA)
+ .addKeepMainRule(Main.class)
+ .addKeepRules(enumKeepRules.getKeepRules())
+ .addOptionsModification(opt -> opt.testing.enableEnumWithSubtypesUnboxing = true)
+ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(InstantiatingEnum.class))
+ .enableInliningAnnotations()
+ .enableAlwaysInliningAnnotations()
+ .enableNoHorizontalClassMergingAnnotations()
+ .enableNoReturnTypeStrengtheningAnnotations()
+ .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
+ .setMinApi(parameters)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("AC/DC", "AC/DC", "AC/DC");
+ }
+
+ private static String getNewDescriptorForName(String name, String descriptor) {
+ String descr = DescriptorUtils.javaTypeToDescriptor(InstantiatingEnum.class.getTypeName());
+ String prefix = descr.substring(0, descr.length() - 1);
+ if (name.equals("A")) {
+ return prefix + "$1;";
+ }
+ if (name.equals("D")) {
+ return prefix + "$2;";
+ }
+ return descriptor;
+ }
+
+ public static Collection<byte[]> tranformedInputs() throws IOException {
+ Collection<Path> classFilesForInnerClasses =
+ ToolHelper.getClassFilesForInnerClasses(EnumMergingInstantiatingTest.class);
+ ArrayList<byte[]> bytes = new ArrayList<>();
+ for (Path classFilesForInnerClass : classFilesForInnerClasses) {
+ bytes.add(transform(classFilesForInnerClass));
+ }
+ return bytes;
+ }
+
+ public static byte[] transform(Path path) throws IOException {
+ return transformer(path, null)
+ .changeFieldType(
+ name -> name.equals("A") || name.equals("D"),
+ EnumMergingInstantiatingTest::getNewDescriptorForName)
+ .transform();
+ }
+
+ public static class C {
+
+ @AlwaysInline
+ public static C dispatch(InstantiatingEnum theEnum) {
+ // Only after inlining can the invoke be respecialized to each of the subtype.
+ return theEnum.newEntry();
+ }
+ }
+
+ @NoHorizontalClassMerging
+ public static class AC extends C {
+
+ @Override
+ public String toString() {
+ return "AC";
+ }
+ }
+
+ @NoHorizontalClassMerging
+ public static class DC extends C {
+
+ @Override
+ public String toString() {
+ return "DC";
+ }
+ }
+
+ enum InstantiatingEnum {
+ A {
+ @NeverInline
+ @Override
+ public C newEntry() {
+ return new AC();
+ }
+
+ @NeverInline
+ @Override
+ public C newEntryThroughDispatch() {
+ return C.dispatch(this);
+ }
+ },
+ D {
+ @NeverInline
+ @Override
+ public C newEntry() {
+ return new DC();
+ }
+
+ @NeverInline
+ @Override
+ public C newEntryThroughDispatch() {
+ return C.dispatch(this);
+ }
+ };
+
+ @NeverInline
+ public abstract C newEntry();
+
+ @NeverInline
+ public abstract C newEntryThroughDispatch();
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ System.out.println(getAC() + "/" + getDC());
+ System.out.println(getC(InstantiatingEnum.A) + "/" + getC(InstantiatingEnum.D));
+ System.out.println(
+ InstantiatingEnum.A.newEntryThroughDispatch()
+ + "/"
+ + InstantiatingEnum.D.newEntryThroughDispatch());
+ }
+
+ @NeverInline
+ @NoReturnTypeStrengthening
+ private static C getAC() {
+ return InstantiatingEnum.A.newEntry();
+ }
+
+ @NeverInline
+ @NoReturnTypeStrengthening
+ private static C getDC() {
+ return InstantiatingEnum.D.newEntry();
+ }
+
+ @NeverInline
+ private static C getC(InstantiatingEnum e) {
+ return e.newEntry();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/examples/ExamplesTestBase.java b/src/test/java/com/android/tools/r8/examples/ExamplesTestBase.java
index cd9e112..11576d6 100644
--- a/src/test/java/com/android/tools/r8/examples/ExamplesTestBase.java
+++ b/src/test/java/com/android/tools/r8/examples/ExamplesTestBase.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.examples;
import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
@@ -16,8 +17,8 @@
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
+import java.util.function.Consumer;
import org.junit.Assume;
-import org.junit.Test;
public abstract class ExamplesTestBase extends DebugTestBase {
@@ -43,12 +44,17 @@
}
public void runTestR8() throws Exception {
+ runTestR8(unused -> {});
+ }
+
+ public void runTestR8(Consumer<R8FullTestBuilder> modifier) throws Exception {
parameters.assumeR8TestParameters();
testForR8(parameters.getBackend())
.addOptionsModification(o -> o.testing.roundtripThroughLir = true)
.setMinApi(parameters)
.addProgramClasses(getTestClasses())
.addKeepMainRule(getMainClass())
+ .apply(modifier::accept)
.run(parameters.getRuntime(), getMainClass())
.assertSuccessWithOutput(getExpected());
}
@@ -99,6 +105,8 @@
.setMinApi(parameters)
.addProgramClasses(getTestClasses())
.addKeepMainRule(getMainClass())
+ .addKeepRules("-keep,allowshrinking class *")
+ .addKeepAllAttributes()
.debug()
.compile()
.debugConfig(parameters.getRuntime());
diff --git a/src/test/examples/constants/Constants.java b/src/test/java/com/android/tools/r8/examples/constants/Constants.java
similarity index 97%
rename from src/test/examples/constants/Constants.java
rename to src/test/java/com/android/tools/r8/examples/constants/Constants.java
index 6349749..83aed19 100644
--- a/src/test/examples/constants/Constants.java
+++ b/src/test/java/com/android/tools/r8/examples/constants/Constants.java
@@ -4,7 +4,7 @@
// This code is not run directly. It needs to be compiled to dex code.
// 'constants.dex' is what is run.
-package constants;
+package com.android.tools.r8.examples.constants;
class Constants {
diff --git a/src/test/java/com/android/tools/r8/examples/constants/ConstantsTestRunner.java b/src/test/java/com/android/tools/r8/examples/constants/ConstantsTestRunner.java
new file mode 100644
index 0000000..40432f5
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/constants/ConstantsTestRunner.java
@@ -0,0 +1,56 @@
+// 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.examples.constants;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.examples.ExamplesTestBase;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ConstantsTestRunner extends ExamplesTestBase {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+ }
+
+ public ConstantsTestRunner(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ public Class<?> getMainClass() {
+ return Constants.class;
+ }
+
+ @Override
+ public String getExpected() {
+ return "-8-1017-32768-9832767-65536-26843545625165824015728640983040-214748364865536-3276932768"
+ + "-65535-26843545525165824115728641983041-214748364765537-32768-10132767-32769"
+ + "-2147483648214748364732768-281474976710656"
+ + "-11529215046068469761080863910568919040675539944105574404222124650659840"
+ + "-92233720368547758082814749767106569223090561878065152-21474836492147483648"
+ + "-140737488355329-281474976710655"
+ + "-11529215046068469751080863910568919041675539944105574414222124650659841"
+ + "-922337203685477580728147497671065792233720368547758079223090561878065153";
+ }
+
+ @Test
+ public void testDesugaring() throws Exception {
+ runTestDesugaring();
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runTestR8();
+ }
+
+ @Test
+ public void testDebug() throws Exception {
+ runTestDebugComparator();
+ }
+}
diff --git a/src/test/examples/controlflow/ControlFlow.java b/src/test/java/com/android/tools/r8/examples/controlflow/ControlFlow.java
similarity index 97%
rename from src/test/examples/controlflow/ControlFlow.java
rename to src/test/java/com/android/tools/r8/examples/controlflow/ControlFlow.java
index ffdabe0..5296c77 100644
--- a/src/test/examples/controlflow/ControlFlow.java
+++ b/src/test/java/com/android/tools/r8/examples/controlflow/ControlFlow.java
@@ -5,7 +5,7 @@
// This code is not run directly. It needs to be compiled to dex code.
// 'controlflow.dex' is what is run.
-package controlflow;
+package com.android.tools.r8.examples.controlflow;
public class ControlFlow {
diff --git a/src/test/java/com/android/tools/r8/examples/controlflow/ControlFlowTestRunner.java b/src/test/java/com/android/tools/r8/examples/controlflow/ControlFlowTestRunner.java
new file mode 100644
index 0000000..770ec02
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/controlflow/ControlFlowTestRunner.java
@@ -0,0 +1,82 @@
+// 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.examples.controlflow;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.examples.ExamplesTestBase;
+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 ControlFlowTestRunner extends ExamplesTestBase {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+ }
+
+ public ControlFlowTestRunner(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ public Class<?> getMainClass() {
+ return ControlFlow.class;
+ }
+
+ @Override
+ public String getExpected() {
+ return StringUtils.lines(
+ "Fisk",
+ "Hest",
+ "Fisk 1 1.1 true",
+ "Hest 2 2.2 false",
+ "Fisk",
+ "Hep!",
+ "10",
+ "10",
+ "5",
+ "10",
+ "5",
+ "2",
+ "10",
+ "10",
+ "5",
+ "10",
+ "5",
+ "2",
+ "simpleLoop",
+ "simpleLoop",
+ "count: 0",
+ "simpleLoop",
+ "count: 0",
+ "count: 1",
+ "count: 2",
+ "count: 3",
+ "count: 4",
+ "count: 5",
+ "count: 6",
+ "count: 7",
+ "count: 8",
+ "count: 9");
+ }
+
+ @Test
+ public void testDesugaring() throws Exception {
+ runTestDesugaring();
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runTestR8();
+ }
+
+ @Test
+ public void testDebug() throws Exception {
+ runTestDebugComparator();
+ }
+}
diff --git a/src/test/examples/conversions/Conversions.java b/src/test/java/com/android/tools/r8/examples/conversions/Conversions.java
similarity index 96%
rename from src/test/examples/conversions/Conversions.java
rename to src/test/java/com/android/tools/r8/examples/conversions/Conversions.java
index 456972d..28f3c55 100644
--- a/src/test/examples/conversions/Conversions.java
+++ b/src/test/java/com/android/tools/r8/examples/conversions/Conversions.java
@@ -1,7 +1,7 @@
// Copyright (c) 2016, 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 conversions;
+package com.android.tools.r8.examples.conversions;
public class Conversions {
diff --git a/src/test/java/com/android/tools/r8/examples/conversions/ConversionsTestRunner.java b/src/test/java/com/android/tools/r8/examples/conversions/ConversionsTestRunner.java
new file mode 100644
index 0000000..15ccd76
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/conversions/ConversionsTestRunner.java
@@ -0,0 +1,51 @@
+// 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.examples.conversions;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.examples.ExamplesTestBase;
+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 ConversionsTestRunner extends ExamplesTestBase {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+ }
+
+ public ConversionsTestRunner(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ public Class<?> getMainClass() {
+ return Conversions.class;
+ }
+
+ @Override
+ public String getExpected() {
+ return StringUtils.lines(
+ "1", "1.0", "1.0", "1", "1.0", "1.0", "1", "1", "1.0", "1", "1", "1.0", "1", "\u0001", "1");
+ }
+
+ @Test
+ public void testDesugaring() throws Exception {
+ runTestDesugaring();
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runTestR8();
+ }
+
+ @Test
+ public void testDebug() throws Exception {
+ runTestDebugComparator();
+ }
+}
diff --git a/src/test/examples/filledarray/FilledArray.java b/src/test/java/com/android/tools/r8/examples/filledarray/FilledArray.java
similarity index 98%
rename from src/test/examples/filledarray/FilledArray.java
rename to src/test/java/com/android/tools/r8/examples/filledarray/FilledArray.java
index 46065e2..f25b76b 100644
--- a/src/test/examples/filledarray/FilledArray.java
+++ b/src/test/java/com/android/tools/r8/examples/filledarray/FilledArray.java
@@ -1,7 +1,7 @@
// Copyright (c) 2017, 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 filledarray;
+package com.android.tools.r8.examples.filledarray;
import java.util.Arrays;
diff --git a/src/test/java/com/android/tools/r8/examples/filledarray/FilledArrayTestRunner.java b/src/test/java/com/android/tools/r8/examples/filledarray/FilledArrayTestRunner.java
new file mode 100644
index 0000000..6c4deee
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/filledarray/FilledArrayTestRunner.java
@@ -0,0 +1,148 @@
+// 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.examples.filledarray;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.examples.ExamplesTestBase;
+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 FilledArrayTestRunner extends ExamplesTestBase {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+ }
+
+ public FilledArrayTestRunner(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ public Class<?> getMainClass() {
+ return FilledArray.class;
+ }
+
+ @Override
+ public String getExpected() {
+ return StringUtils.lines(
+ "booleans",
+ "true",
+ "true",
+ "false",
+ "false",
+ "false",
+ "true",
+ "false",
+ "false",
+ "bytes",
+ "0",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ "16",
+ "17",
+ "18",
+ "-19",
+ "-20",
+ "-96",
+ "127",
+ "-128",
+ "21",
+ "22",
+ "-23",
+ "chars",
+ "a",
+ "b",
+ "c",
+ "d",
+ "a",
+ "b",
+ "c",
+ "d",
+ "ints",
+ "2147483647",
+ "0",
+ "-42",
+ "42",
+ "-2147483648",
+ "2147483647",
+ "0",
+ "-42",
+ "42",
+ "-2147483648",
+ "shorts",
+ "32767",
+ "0",
+ "-42",
+ "42",
+ "-32768",
+ "32767",
+ "0",
+ "-42",
+ "42",
+ "-32768",
+ "longs",
+ "9223372036854775807",
+ "1311693406324658740",
+ "-1311693406324658740",
+ "-9223372036854775808",
+ "1311747200790041140",
+ "-1311693406324671263",
+ "floats",
+ "3.4028235E38",
+ "23.23",
+ "-43.123",
+ "1.4E-45",
+ "1.1754944E-38",
+ "23.23",
+ "-43.123",
+ "doubles",
+ "1.7976931348623157E308",
+ "1.23123123123E8",
+ "-43333.123",
+ "4.9E-324",
+ "2.2250738585072014E-308",
+ "1.23123123123E8",
+ "-43333.123",
+ "i = 1",
+ "ints = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]",
+ "ints2 = [0, 1, 2, 3, 4]",
+ "i = 7",
+ "ints = [0, 1, 2, 3, 4]",
+ "Exception: class java.lang.ArithmeticException",
+ "Exception: class java.lang.ArithmeticException");
+ }
+
+ @Test
+ public void testDesugaring() throws Exception {
+ runTestDesugaring();
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runTestR8();
+ }
+
+ @Test
+ public void testDebug() throws Exception {
+ runTestDebugComparator();
+ }
+}
diff --git a/src/test/examples/floating_point_annotations/FloatingPointValuedAnnotation.java b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotation.java
similarity index 87%
rename from src/test/examples/floating_point_annotations/FloatingPointValuedAnnotation.java
rename to src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotation.java
index 5d7fd8c..83b9d69 100644
--- a/src/test/examples/floating_point_annotations/FloatingPointValuedAnnotation.java
+++ b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotation.java
@@ -1,7 +1,7 @@
// Copyright (c) 2017, 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 floating_point_annotations;
+package com.android.tools.r8.examples.floating_point_annotations;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
diff --git a/src/test/examples/floating_point_annotations/FloatingPointValuedAnnotationTest.java b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTest.java
similarity index 92%
rename from src/test/examples/floating_point_annotations/FloatingPointValuedAnnotationTest.java
rename to src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTest.java
index 1772f23..d787b76 100644
--- a/src/test/examples/floating_point_annotations/FloatingPointValuedAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTest.java
@@ -1,7 +1,7 @@
// Copyright (c) 2017, 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 floating_point_annotations;
+package com.android.tools.r8.examples.floating_point_annotations;
public class FloatingPointValuedAnnotationTest {
diff --git a/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTestRunner.java b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTestRunner.java
new file mode 100644
index 0000000..fb097c0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/floating_point_annotations/FloatingPointValuedAnnotationTestRunner.java
@@ -0,0 +1,78 @@
+// 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.examples.floating_point_annotations;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.examples.ExamplesTestBase;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class FloatingPointValuedAnnotationTestRunner extends ExamplesTestBase {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().enableApiLevelsForCf().build();
+ }
+
+ public FloatingPointValuedAnnotationTestRunner(TestParameters parameters) {
+ super(parameters);
+ }
+
+ @Override
+ public Class<?> getMainClass() {
+ return FloatingPointValuedAnnotationTest.class;
+ }
+
+ @Override
+ public List<Class<?>> getTestClasses() {
+ return ImmutableList.of(
+ FloatingPointValuedAnnotation.class,
+ FloatingPointValuedAnnotationTest.class,
+ FloatingPointValuedAnnotationTest.A.class,
+ FloatingPointValuedAnnotationTest.B.class,
+ FloatingPointValuedAnnotationTest.C.class,
+ FloatingPointValuedAnnotationTest.D.class);
+ }
+
+ @Override
+ public String getExpected() {
+ return StringUtils.lines("false", "false");
+ }
+
+ @Test
+ public void testDesugaring() throws Exception {
+ runTestDesugaring();
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runTestR8(
+ builder ->
+ builder
+ .addKeepRuntimeVisibleAnnotations()
+ .addKeepClassAndMembersRules(
+ FloatingPointValuedAnnotation.class,
+ FloatingPointValuedAnnotationTest.A.class,
+ FloatingPointValuedAnnotationTest.B.class,
+ FloatingPointValuedAnnotationTest.C.class,
+ FloatingPointValuedAnnotationTest.D.class));
+ }
+
+ @Test
+ public void testDebug() throws Exception {
+ Assume.assumeFalse(
+ "VMs 13 and 14 step-out to the continuation (line 28) and not the call-site (line 25).",
+ parameters.isDexRuntimeVersion(Version.V13_0_0)
+ || parameters.isDexRuntimeVersion(Version.V14_0_0));
+ runTestDebugComparator();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
index cba424a..d32f6f9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
@@ -212,8 +212,11 @@
private boolean canSharePrintCallInSuccessorBlock() {
// With API level >= Q we get a register assignment that allows us to share the print call in a
// successor block. See also InternalOptions.canHaveThisJitCodeDebuggingBug().
+ // Due to including line-info (b/279555568) this is always false. Keeping the conflicting
+ // predicates here for documentation of the previously witnessed difference.
return parameters.isDexRuntime()
- && parameters.getApiLevel().getLevel() >= AndroidApiLevel.Q.getLevel();
+ && parameters.getApiLevel().getLevel() >= AndroidApiLevel.Q.getLevel()
+ && parameters.getApiLevel().isLessThan(apiLevelWithPcAsLineNumberSupport());
}
@Test
@@ -241,6 +244,7 @@
NonNullParamAfterInvokeInterface.class,
NonNullParamInterfaceImpl.class))
.addOptionsModification(this::disableDevirtualization)
+ .addKeepAttributeLineNumberTable()
.enableAlwaysInliningAnnotations()
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
@@ -252,8 +256,7 @@
MethodSubject checkViaCall = mainSubject.uniqueMethodWithOriginalName("checkViaCall");
assertThat(checkViaCall, isPresent());
assertEquals(0, countActCall(checkViaCall));
- // The DEX backend reuses the System.out.println invoke.
- assertEquals(parameters.isCfRuntime() ? 2 : 1, countPrintCall(checkViaCall));
+ assertEquals(2, countPrintCall(checkViaCall));
}
private long countCallToParamNullCheck(MethodSubject method) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderTests.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderTests.java
index 7464aec..a78dbbf 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderTests.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderTests.java
@@ -222,10 +222,14 @@
FoundMethodSubject foundMethodSubject = method.asFoundMethodSubject();
assertEquals(
stringBuilderTest.stringBuilders, countStringBuilderInits(foundMethodSubject));
- if (parameters.isCfRuntime()
+ if ((parameters.isCfRuntime()
+ || parameters
+ .getApiLevel()
+ .isGreaterThanOrEqualTo(apiLevelWithPcAsLineNumberSupport()))
&& (stringBuilderTest.getMethodName().equals("diamondWithUseTest")
|| stringBuilderTest.getMethodName().equals("intoPhiTest"))) {
- // We are not doing block suffix optimization in CF.
+ // We are not doing block suffix optimization in CF and line/pc info prohibits
+ // sharing.
assertEquals(
stringBuilderTest.appends + 1, countStringBuilderAppends(foundMethodSubject));
} else {
diff --git a/src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java b/src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java
index 6e9067c..b28280d 100644
--- a/src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ClassNameMinifierOriginalClassNameTest.java
@@ -55,6 +55,8 @@
FileUtils.writeTextFile(dictionary, "A");
return testForR8(getStaticTemp(), parameters.getBackend())
.addProgramClasses(A.class, B.class)
+ // Including the source file forces an map entry for the pruned class A. See b/279702361.
+ .addKeepAttributeSourceFile()
.addKeepClassAndMembersRulesWithAllowObfuscation(B.class)
.addKeepRules("-classobfuscationdictionary " + dictionary.toString(), "-keeppackagenames")
.setMinApi(parameters)
@@ -67,7 +69,7 @@
});
}
- @Test
+ @Test()
public void testR8() throws ExecutionException, CompilationFailedException, IOException {
R8TestCompileResult libraryCompileResult = compilationResults.apply(parameters);
testForR8(parameters.getBackend())
@@ -83,7 +85,7 @@
.assertSuccessWithOutputLines("B.foo");
}
- @Test
+ @Test()
public void testR8WithReferenceToNotMapped() {
assumeTrue(parameters.isDexRuntime());
R8TestCompileResult libraryCompileResult = compilationResults.apply(parameters);
diff --git a/src/test/java/com/android/tools/r8/naming/IdentityMappingFileTest.java b/src/test/java/com/android/tools/r8/naming/IdentityMappingFileTest.java
index 21ece10..6bffb78 100644
--- a/src/test/java/com/android/tools/r8/naming/IdentityMappingFileTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IdentityMappingFileTest.java
@@ -4,9 +4,9 @@
package com.android.tools.r8.naming;
import static org.hamcrest.CoreMatchers.containsString;
-import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.DiagnosticsHandler;
@@ -51,11 +51,20 @@
assertThat(mapping, containsString("# {\"id\":\"com.android.tools.r8.mapping\",\"version\":"));
assertThat(mapping, containsString("# pg_map_id: "));
assertThat(mapping, containsString("# pg_map_hash: SHA-256 "));
- // Check the mapping is the identity, e.g., only comments are defined.
- // Note, this could change if the mapping is ever changed to be complete, in which case the
- // mapping will have actual identity mappings.
+ // Check the mapping is the identity, e.g., only comments and identity entries are defined.
for (String line : StringUtils.splitLines(mapping)) {
- assertThat(line, startsWith("#"));
+ if (line.startsWith("#")) {
+ continue;
+ }
+ String[] parts = line.split(" -> ");
+ if (parts.length == 2 && line.endsWith(":")) {
+ String left = parts[0];
+ String right = parts[1];
+ if (left.equals(right.substring(0, right.length() - 1))) {
+ continue;
+ }
+ }
+ fail("Expected comment or identity, got: " + line);
}
}
diff --git a/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java b/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
index fa9de18..5b85343 100644
--- a/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
@@ -139,7 +139,7 @@
private static void verifyUniqueNaming(CodeInspector inspector, List<String> klasses) {
Set<String> renamedNames = Sets.newHashSet();
for (String klass : klasses) {
- String finalName = inspector.clazz(klass).getFinalName();
+ String finalName = inspector.getObfuscatedTypeName(klass);
assertFalse(renamedNames.contains(finalName));
renamedNames.add(finalName);
}
diff --git a/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java b/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java
index d56e49c..c4fa84b 100644
--- a/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java
+++ b/src/test/java/com/android/tools/r8/regress/Regress160394262Test.java
@@ -59,7 +59,13 @@
private void checkJoinerIsClassInlined(CodeInspector inspector) {
assertThat(inspector.clazz(Joiner.class.getTypeName() + "$1"), isAbsent());
// TODO(b/160640028): Joiner should be class inlined.
- assertThat(inspector.clazz(Joiner.class), isPresent());
+ // When line info tables are kept we appear to successfully inline Joiner. Reason unknown.
+ if (parameters.isCfRuntime()
+ || parameters.getApiLevel().isLessThan(apiLevelWithPcAsLineNumberSupport())) {
+ assertThat(inspector.clazz(Joiner.class), isPresent());
+ } else {
+ assertThat(inspector.clazz(Joiner.class), isAbsent());
+ }
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java
index 2852961..9e40d0e 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificMultiplePathsSuccessTest.java
@@ -139,7 +139,10 @@
@Test
public void testR8() throws Exception {
// TODO(b/230289235): Extend resolution to support multiple definition results.
- runTest(testForR8(parameters.getBackend()).addKeepMainRule(Main.class))
+ runTest(
+ testForR8(parameters.getBackend())
+ .addKeepAttributeSourceFile()
+ .addKeepMainRule(Main.class))
.assertFailureWithErrorThatThrowsIf(
parameters.canUseDefaultAndStaticInterfaceMethods(), NoSuchMethodError.class)
.assertSuccessWithOutputLinesIf(
diff --git a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java
index ca57c2f..abc79b4 100644
--- a/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/duplicatedefinitions/MaximallySpecificSingleProgramPartialTest.java
@@ -128,10 +128,13 @@
!parameters.canUseDefaultAndStaticInterfaceMethods(), UNEXPECTED);
}
- @Test
+ @Test()
public void testR8() throws Exception {
// TODO(b/230289235): Extend to support multiple definition results.
- runTest(testForR8(parameters.getBackend()).addKeepMainRule(Main.class))
+ runTest(
+ testForR8(parameters.getBackend())
+ .addKeepAttributeSourceFile()
+ .addKeepMainRule(Main.class))
.assertFailureWithErrorThatThrowsIf(
parameters.canUseDefaultAndStaticInterfaceMethods(), NoSuchMethodError.class)
.assertSuccessWithOutputLinesIf(
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
index b1e37b4..36cfc16 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceCommandLineTests.java
@@ -185,7 +185,7 @@
public void testHelp() throws IOException {
ProcessResult processResult = runRetraceCommandLine(null, Arrays.asList("--help"));
assertEquals(0, processResult.exitCode);
- assertThat(processResult.stdout, containsString(Retrace.USAGE_MESSAGE));
+ assertThat(processResult.stdout, containsString(Retrace.getUsageMessage()));
}
@Test
diff --git a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
index ce200a0..63573d2 100644
--- a/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
+++ b/src/test/java/com/android/tools/r8/transformers/ClassFileTransformer.java
@@ -37,6 +37,7 @@
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -887,6 +888,34 @@
});
}
+ public ClassFileTransformer changeFieldType(
+ Predicate<String> fieldPredicate,
+ BiFunction<String, String, String> newDescriptorTransformer) {
+ return addClassTransformer(
+ new ClassTransformer() {
+ @Override
+ public FieldVisitor visitField(
+ int access, String name, String descriptor, String signature, Object value) {
+ String newDescriptor =
+ fieldPredicate.test(name)
+ ? newDescriptorTransformer.apply(name, descriptor)
+ : descriptor;
+ return super.visitField(access, name, newDescriptor, signature, value);
+ }
+ })
+ .addMethodTransformer(
+ new MethodTransformer() {
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String descriptor) {
+ String newDescriptor =
+ fieldPredicate.test(name)
+ ? newDescriptorTransformer.apply(name, descriptor)
+ : descriptor;
+ super.visitFieldInsn(opcode, owner, name, newDescriptor);
+ }
+ });
+ }
+
public ClassFileTransformer renameAndRemapField(String oldName, String newName) {
FieldSignaturePredicate matchPredicate = (name, signature) -> oldName.equals(name);
remapField(matchPredicate, newName);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
index 21a12a2..74bdc47 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeInspector.java
@@ -359,15 +359,17 @@
String name = DescriptorUtils.descriptorToJavaType(descriptor);
ClassNamingForNameMapper naming = null;
if (mapping != null) {
- String obfuscated = originalToObfuscatedMapping.get(name);
- if (obfuscated != null) {
- naming = mapping.getClassNaming(obfuscated);
- name = obfuscated;
+ // Figure out if the name is an already obfuscated name. It is important to look up by
+ // residual name first to ensure that we do not accidentally find a class that has been
+ // pruned.
+ String original = obfuscatedToOriginalMapping.get(name);
+ if (original != null) {
+ naming = mapping.getClassNaming(name);
} else {
- // Figure out if the name is an already obfuscated name.
- String original = obfuscatedToOriginalMapping.get(name);
- if (original != null) {
- naming = mapping.getClassNaming(name);
+ String obfuscated = originalToObfuscatedMapping.get(name);
+ if (obfuscated != null) {
+ naming = mapping.getClassNaming(obfuscated);
+ name = obfuscated;
}
}
}
@@ -423,7 +425,7 @@
return clazz.method(method);
}
- String getObfuscatedTypeName(String originalTypeName) {
+ public String getObfuscatedTypeName(String originalTypeName) {
String obfuscatedTypeName = null;
if (mapping != null) {
obfuscatedTypeName = mapType(originalToObfuscatedMapping, originalTypeName);
@@ -431,7 +433,7 @@
return obfuscatedTypeName != null ? obfuscatedTypeName : originalTypeName;
}
- String getOriginalTypeName(String minifiedTypeName) {
+ public String getOriginalTypeName(String minifiedTypeName) {
String originalTypeName = null;
if (mapping != null) {
originalTypeName = mapType(obfuscatedToOriginalMapping, minifiedTypeName);
diff --git a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1 b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
index b83c4a2..e5b5e41 100644
--- a/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
+++ b/third_party/binary_compatibility_tests/compiler_api_tests.tar.gz.sha1
@@ -1 +1 @@
-ae9c0faab45cba310dbe57a3ce0dcba7bed355a3
\ No newline at end of file
+2aaa39dd57bf8c1c21393ae6b3181ae3a10da88e
\ No newline at end of file
diff --git a/tools/archive.py b/tools/archive.py
index 6a39594..d724b18 100755
--- a/tools/archive.py
+++ b/tools/archive.py
@@ -217,10 +217,12 @@
utils.R8_JAR,
utils.R8LIB_JAR,
utils.R8LIB_JAR + '.map',
+ utils.R8LIB_JAR + '_map.zip',
utils.R8_SRC_JAR,
utils.R8_FULL_EXCLUDE_DEPS_JAR,
utils.R8LIB_EXCLUDE_DEPS_JAR,
utils.R8LIB_EXCLUDE_DEPS_JAR + '.map',
+ utils.R8LIB_EXCLUDE_DEPS_JAR + '_map.zip',
utils.R8RETRACE_JAR,
utils.R8RETRACE_EXCLUDE_DEPS_JAR,
utils.MAVEN_ZIP,
diff --git a/tools/build_r8lib.py b/tools/build_r8lib.py
index 8dc0cb8..54cf915 100755
--- a/tools/build_r8lib.py
+++ b/tools/build_r8lib.py
@@ -58,6 +58,7 @@
if output_path is None:
output_path = target + 'lib.jar'
output_map_path = output_path + '.map'
+ r8_output_map_path = output_path + '_map.zip'
toolhelper.run(
'r8',
('--release',
@@ -67,7 +68,8 @@
temp_lib,
'--output', output_path,
'--pg-conf', keep_rules_path,
- '--pg-map-output', output_map_path),
+ '--pg-map-output', output_map_path,
+ '--partition-map-output', r8_output_map_path),
**kwargs)
if exclude_deps:
return [output_path, temp_deps]
diff --git a/tools/create_r8lib.py b/tools/create_r8lib.py
index b6189e6..51e2fd6 100755
--- a/tools/create_r8lib.py
+++ b/tools/create_r8lib.py
@@ -96,6 +96,7 @@
cmd.extend(['--source-file-template', source_file_template])
cmd.extend(['--output', args.output])
cmd.extend(['--pg-map-output', args.output + '.map'])
+ cmd.extend(['--partition-map-output', args.output + '_map.zip'])
cmd.extend(['--lib', jdk.GetJdkHome()])
if args.pg_conf:
for pgconf in args.pg_conf:
diff --git a/tools/trigger.py b/tools/trigger.py
index 0fd8b64..b3e09f2 100755
--- a/tools/trigger.py
+++ b/tools/trigger.py
@@ -104,7 +104,7 @@
'add',
'r8/ci/%s' % SMALI_BOT,
'-p',
- '\'test_options=["--version", "%s"]\'' % version
+ 'test_options=["--version", "%s"]' % version
]
subprocess.check_call(cmd)