Desugared library: add dump support
Bug: 171195238
Change-Id: I5ebf1ae4d055380b85030a544b22b06726a643fe
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
index 9896987..5627d6e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfiguration.java
@@ -1,7 +1,6 @@
// Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-
package com.android.tools.r8.ir.desugar;
import com.android.tools.r8.errors.CompilationError;
@@ -34,16 +33,15 @@
import java.util.stream.Collectors;
public class DesugaredLibraryConfiguration {
-
public static final String FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX = "j$/";
public static final boolean FALL_BACK_SUPPORT_ALL_CALLBACKS_FROM_LIBRARY = true;
-
public static final DesugaredLibraryConfiguration EMPTY_DESUGARED_LIBRARY_CONFIGURATION =
new DesugaredLibraryConfiguration(
AndroidApiLevel.B,
false,
FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX,
null,
+ null,
FALL_BACK_SUPPORT_ALL_CALLBACKS_FROM_LIBRARY,
ImmutableMap.of(),
ImmutableMap.of(),
@@ -53,11 +51,11 @@
ImmutableSet.of(),
ImmutableList.of(),
ImmutableList.of());
-
private final AndroidApiLevel requiredCompilationAPILevel;
private final boolean libraryCompilation;
private final String synthesizedLibraryClassesPackagePrefix;
private final String identifier;
+ private final String jsonSource;
// Setting supportAllCallbacksFromLibrary reduces the number of generated call-backs,
// more specifically:
// - no call-back is generated for emulated interface method overrides (forEach, etc.)
@@ -86,6 +84,7 @@
true,
FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX,
"testingOnlyVersion",
+ null,
FALL_BACK_SUPPORT_ALL_CALLBACKS_FROM_LIBRARY,
prefix,
ImmutableMap.of(),
@@ -106,6 +105,7 @@
boolean libraryCompilation,
String packagePrefix,
String identifier,
+ String jsonSource,
boolean supportAllCallbacksFromLibrary,
Map<String, String> rewritePrefix,
Map<DexType, DexType> emulateLibraryInterface,
@@ -119,6 +119,7 @@
this.libraryCompilation = libraryCompilation;
this.synthesizedLibraryClassesPackagePrefix = packagePrefix;
this.identifier = identifier;
+ this.jsonSource = jsonSource;
this.supportAllCallbacksFromLibrary = supportAllCallbacksFromLibrary;
this.rewritePrefix = rewritePrefix;
this.emulateLibraryInterface = emulateLibraryInterface;
@@ -159,7 +160,6 @@
public Map<DexType, DexType> getEmulateLibraryInterface() {
return emulateLibraryInterface;
}
-
// If the method is retargeted, answers the retargeted method, else null.
public DexMethod retargetMethod(DexEncodedMethod method, AppView<?> appView) {
Map<DexType, DexType> typeMap = retargetCoreLibMember.get(method.getName());
@@ -198,17 +198,20 @@
return extraKeepRules;
}
- public static class Builder {
+ public String getJsonSource() {
+ return jsonSource;
+ }
+ public static class Builder {
private final DexItemFactory factory;
private final Reporter reporter;
private final Origin origin;
-
private AndroidApiLevel requiredCompilationAPILevel;
private boolean libraryCompilation = false;
private String synthesizedLibraryClassesPackagePrefix =
FALL_BACK_SYNTHESIZED_CLASSES_PACKAGE_PREFIX;
private String identifier;
+ private String jsonSource;
private Map<String, String> rewritePrefix = new HashMap<>();
private Map<DexType, DexType> emulateLibraryInterface = new IdentityHashMap<>();
private Map<DexString, Map<DexType, DexType>> retargetCoreLibMember = new IdentityHashMap<>();
@@ -224,7 +227,6 @@
this.reporter = reporter;
this.origin = origin;
}
-
// Utility to set values. Currently assumes the key is fresh.
private <K, V> void put(Map<K, V> map, K key, V value, String desc) {
if (map.containsKey(key)) {
@@ -251,6 +253,11 @@
return this;
}
+ public Builder setJsonSource(String jsonSource) {
+ this.jsonSource = jsonSource;
+ return this;
+ }
+
public Builder setRequiredCompilationAPILevel(AndroidApiLevel requiredCompilationAPILevel) {
this.requiredCompilationAPILevel = requiredCompilationAPILevel;
return this;
@@ -369,6 +376,7 @@
libraryCompilation,
synthesizedLibraryClassesPackagePrefix,
identifier,
+ jsonSource,
supportAllCallbacksFromLibrary,
ImmutableMap.copyOf(rewritePrefix),
ImmutableMap.copyOf(emulateLibraryInterface),
@@ -392,6 +400,5 @@
origin));
}
}
-
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
index a20c8e0..9b0da2d 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryConfigurationParser.java
@@ -93,15 +93,18 @@
} else {
configurationBuilder.setProgramCompilation();
}
+ String jsonConfigString;
JsonObject jsonConfig;
try {
- String jsonConfigString = stringResource.getString();
+ jsonConfigString = stringResource.getString();
JsonParser parser = new JsonParser();
jsonConfig = parser.parse(jsonConfigString).getAsJsonObject();
} catch (Exception e) {
throw reporter.fatalError(new ExceptionDiagnostic(e, origin));
}
+ configurationBuilder.setJsonSource(jsonConfigString);
+
JsonElement formatVersionElement = required(jsonConfig, CONFIGURATION_FORMAT_VERSION_KEY);
int formatVersion = formatVersionElement.getAsInt();
if (formatVersion > MAX_SUPPORTED_VERSION) {
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index 2bbe3fe..c426a09 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -83,6 +83,7 @@
private static final String dumpVersionFileName = "r8-version";
private static final String dumpBuildPropertiesFileName = "build.properties";
+ private static final String dumpDesugaredLibraryFileName = "desugared-library.json";
private static final String dumpProgramFileName = "program.jar";
private static final String dumpClasspathFileName = "classpath.jar";
private static final String dumpLibraryFileName = "library.jar";
@@ -465,6 +466,18 @@
dumpBuildPropertiesFileName,
getBuildPropertiesContents(options).getBytes(),
ZipEntry.DEFLATED);
+ if (options.desugaredLibraryConfiguration.getJsonSource() != null) {
+ writeToZipStream(
+ out,
+ dumpDesugaredLibraryFileName,
+ options.desugaredLibraryConfiguration.getJsonSource().getBytes(),
+ ZipEntry.DEFLATED);
+ if (options.dumpInputToFile != null) {
+ options.reporter.warning(
+ "Dumping a compilation with desugared library on a file may prevent reproduction,"
+ + " use dumpInputToDirectory property instead.");
+ }
+ }
if (options.getProguardConfiguration() != null) {
String proguardConfig = options.getProguardConfiguration().getParsedConfiguration();
writeToZipStream(out, dumpConfigFileName, proguardConfig.getBytes(), ZipEntry.DEFLATED);
diff --git a/src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java b/src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java
index c230a6d..a32e296 100644
--- a/src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java
+++ b/src/main/java/com/android/tools/r8/utils/CompileDumpCompatR8.java
@@ -11,6 +11,8 @@
import com.android.tools.r8.R8;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.R8Command.Builder;
+import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
@@ -66,6 +68,7 @@
OutputMode outputMode = OutputMode.DexIndexed;
Path outputPath = null;
Path pgMapOutput = null;
+ Path desugaredLibJson = null;
CompilationMode compilationMode = CompilationMode.RELEASE;
List<Path> program = new ArrayList<>();
Map<Path, Path> features = new LinkedHashMap<>();
@@ -134,6 +137,11 @@
pgMapOutput = Paths.get(operand);
break;
}
+ case "--desugared-lib":
+ {
+ desugaredLibJson = Paths.get(operand);
+ break;
+ }
case "--threads":
{
threads = Integer.parseInt(operand);
@@ -172,6 +180,9 @@
.addProguardConfigurationFiles(config)
.setOutput(outputPath, outputMode)
.setMode(compilationMode);
+ if (desugaredLibJson != null) {
+ commandBuilder.addDesugaredLibraryConfiguration(readAllBytesJava7(desugaredLibJson));
+ }
if (outputMode != OutputMode.ClassFile) {
commandBuilder.setMinApiLevel(minApi);
}
@@ -198,4 +209,18 @@
R8.run(command);
}
}
+
+ // We cannot use StringResource since this class is added to the class path and has access only
+ // to the public APIs.
+ private static String readAllBytesJava7(Path filePath) {
+ String content = "";
+
+ try {
+ content = new String(Files.readAllBytes(filePath));
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return content;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
new file mode 100644
index 0000000..faba098
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
@@ -0,0 +1,131 @@
+// Copyright (c) 2019, 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.desugar.desugaredlibrary;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.ZipUtils;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.time.Duration;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DesugaredLibraryDumpInputsTest extends DesugaredLibraryTestBase {
+
+ private final TestParameters parameters;
+ private final boolean shrinkDesugaredLibrary;
+
+ @Parameterized.Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ }
+
+ public DesugaredLibraryDumpInputsTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
+ this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testD8DumpToDirectory() throws Exception {
+ Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
+ KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+ Path dumpDir = temp.newFolder().toPath();
+ testForD8(parameters.getBackend())
+ .addProgramClasses(TestClass.class)
+ .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(options -> options.dumpInputToDirectory = dumpDir.toString())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .compile()
+ .addDesugaredCoreLibraryRunClassPath(
+ (minAPILevel, keepRules, shrink) ->
+ this.buildDesugaredLibrary(
+ minAPILevel,
+ keepRules,
+ shrink,
+ ImmutableList.of(),
+ opt -> opt.dumpInputToDirectory = dumpDir.toString()),
+ parameters.getApiLevel(),
+ keepRuleConsumer.get(),
+ shrinkDesugaredLibrary)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("PT42S");
+ verifyDumpDir(dumpDir);
+ }
+
+ @Test
+ public void testR8DumpToDirectory() throws Exception {
+ Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
+ KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+ Path dumpDir = temp.newFolder().toPath();
+ testForR8(parameters.getBackend())
+ .addProgramClasses(TestClass.class)
+ .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
+ .setMinApi(parameters.getApiLevel())
+ .addKeepMainRule(TestClass.class)
+ .addOptionsModification(options -> options.dumpInputToDirectory = dumpDir.toString())
+ .allowDiagnosticInfoMessages()
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .compile()
+ .addDesugaredCoreLibraryRunClassPath(
+ (minAPILevel, keepRules, shrink) ->
+ this.buildDesugaredLibrary(
+ minAPILevel,
+ keepRules,
+ shrink,
+ ImmutableList.of(),
+ opt -> opt.dumpInputToDirectory = dumpDir.toString()),
+ parameters.getApiLevel(),
+ keepRuleConsumer.get(),
+ shrinkDesugaredLibrary)
+ .assertAllInfoMessagesMatch(containsString("Dumped compilation inputs to:"))
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("PT42S");
+ verifyDumpDir(dumpDir);
+ }
+
+ private void verifyDumpDir(Path dumpDir) throws IOException {
+ assertTrue(Files.isDirectory(dumpDir));
+ List<Path> paths = Files.walk(dumpDir, 1).collect(Collectors.toList());
+ boolean hasVerified = false;
+ for (Path path : paths) {
+ if (!path.equals(dumpDir)) {
+ // The non-external run here results in assert code calling application read.
+ verifyDump(path);
+ hasVerified = true;
+ }
+ }
+ assertTrue(hasVerified);
+ }
+
+ private void verifyDump(Path dumpFile) throws IOException {
+ assertTrue(Files.exists(dumpFile));
+ Path unzipped = temp.newFolder().toPath();
+ ZipUtils.unzip(dumpFile.toString(), unzipped.toFile());
+ assertTrue(Files.exists(unzipped.resolve("r8-version")));
+ assertTrue(Files.exists(unzipped.resolve("program.jar")));
+ assertTrue(Files.exists(unzipped.resolve("library.jar")));
+ assertTrue(Files.exists(unzipped.resolve("desugared-library.json")));
+ assertTrue(Files.exists(unzipped.resolve("build.properties")));
+ }
+
+ static class TestClass {
+ public static void main(String[] args) {
+ System.out.println(Duration.ofSeconds(42));
+ }
+ }
+}
diff --git a/tools/compiledump.py b/tools/compiledump.py
index 90a696d..fa9518c 100755
--- a/tools/compiledump.py
+++ b/tools/compiledump.py
@@ -78,6 +78,10 @@
help='Set min-api (default read from dump properties file)',
default=None)
parser.add_argument(
+ '--desugared-lib',
+ help='Set desugared-library (default set from dump)',
+ default=None)
+ parser.add_argument(
'--loop',
help='Run the compilation in a loop',
default=False,
@@ -119,6 +123,9 @@
def classpath_jar(self):
return self.if_exists('classpath.jar')
+ def desugared_library_json(self):
+ return self.if_exists('desugared-library.json')
+
def build_properties_file(self):
return self.if_exists('build.properties')
@@ -252,6 +259,8 @@
cmd.extend(['--lib', dump.library_jar()])
if dump.classpath_jar():
cmd.extend(['--classpath', dump.classpath_jar()])
+ if dump.desugared_library_json():
+ cmd.extend(['--desugared-lib', dump.desugared_library_json()])
if compiler != 'd8' and dump.config_file():
cmd.extend(['--pg-conf', dump.config_file()])
if compiler != 'd8':