Fix JDK desugared lib 11 build
- Introduce an ASM rewriter to undo pre-desugaring
- Fix EmptyDesugaredLibraryTest
Bug: 203382252
Change-Id: I8937a1d0ee5469b5cae2003a64436fe71656d224
diff --git a/src/test/java/com/android/tools/r8/L8TestBuilder.java b/src/test/java/com/android/tools/r8/L8TestBuilder.java
index 072da5a..dc4a247 100644
--- a/src/test/java/com/android/tools/r8/L8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/L8TestBuilder.java
@@ -8,6 +8,7 @@
import static junit.framework.TestCase.assertTrue;
import com.android.tools.r8.TestBase.Backend;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryJDK11Undesugarer;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidAppConsumers;
@@ -38,7 +39,7 @@
private List<Path> additionalProgramFiles = new ArrayList<>();
private List<byte[]> additionalProgramClassFileData = new ArrayList<>();
private Consumer<InternalOptions> optionsModifier = ConsumerUtils.emptyConsumer();
- private Path desugarJDKLibs = ToolHelper.getDesugarJDKLibs();
+ private Path desugarJDKLibs = DesugaredLibraryJDK11Undesugarer.undesugaredJar();
private Path desugarJDKLibsConfiguration = null;
private StringResource desugaredLibraryConfiguration =
StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryJDK11Undesugarer.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryJDK11Undesugarer.java
new file mode 100644
index 0000000..f79db70
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryJDK11Undesugarer.java
@@ -0,0 +1,105 @@
+// Copyright (c) 2021, 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 com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.transformers.MethodTransformer;
+import com.android.tools.r8.utils.StreamUtils;
+import com.android.tools.r8.utils.ZipUtils;
+import com.google.common.collect.ImmutableMap;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import org.objectweb.asm.Opcodes;
+
+public class DesugaredLibraryJDK11Undesugarer extends DesugaredLibraryTestBase {
+
+ private static Map<String, String> ownerMap =
+ ImmutableMap.of(
+ "java/io/DesugarBufferedReader", "java/io/BufferedReader",
+ "java/io/DesugarInputStream", "java/io/InputStream");
+
+ public static void main(String[] args) throws Exception {
+ setUpDesugaredLibrary();
+ undesugaredJar();
+ }
+
+ public static Path undesugaredJar() {
+ if (!isJDK11DesugaredLibrary()) {
+ return ToolHelper.getDesugarJDKLibs();
+ }
+ Path desugaredLibJDK11Undesugared = Paths.get("build/libs/desugar_jdk_libs_11_undesugared.jar");
+ if (Files.exists(desugaredLibJDK11Undesugared)) {
+ return desugaredLibJDK11Undesugared;
+ }
+ OpenOption[] options =
+ new OpenOption[] {StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING};
+ try (ZipOutputStream out =
+ new ZipOutputStream(
+ new BufferedOutputStream(
+ Files.newOutputStream(desugaredLibJDK11Undesugared, options)))) {
+ new DesugaredLibraryJDK11Undesugarer().undesugar(ToolHelper.getDesugarJDKLibs(), out);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return desugaredLibJDK11Undesugared;
+ }
+
+ private void undesugar(Path desugaredLibraryFiles, ZipOutputStream out) throws IOException {
+ ZipUtils.iter(
+ desugaredLibraryFiles,
+ ((entry, input) -> {
+ if (!entry.getName().endsWith(".class")) {
+ return;
+ }
+ final byte[] bytes = StreamUtils.StreamToByteArrayClose(input);
+ final byte[] rewrittenBytes =
+ transformInvoke(entry.getName().substring(0, entry.getName().length() - 6), bytes);
+ ZipUtils.writeToZipStream(out, entry.getName(), rewrittenBytes, ZipEntry.STORED);
+ }));
+ }
+
+ private byte[] transformInvoke(String descriptor, byte[] bytes) {
+ return transformer(bytes, Reference.classFromDescriptor(descriptor))
+ .addMethodTransformer(getMethodTransformer())
+ .transform();
+ }
+
+ private MethodTransformer getMethodTransformer() {
+ return new MethodTransformer() {
+ @Override
+ public void visitMethodInsn(
+ int opcode, String owner, String name, String descriptor, boolean isInterface) {
+ if (opcode == Opcodes.INVOKESTATIC) {
+ for (String ownerToRewrite : ownerMap.keySet()) {
+ if (ownerToRewrite.equals(owner)) {
+ super.visitMethodInsn(
+ Opcodes.INVOKEVIRTUAL,
+ ownerMap.get(owner),
+ name,
+ withoutFirstObjectArg(descriptor),
+ isInterface);
+ return;
+ }
+ }
+ }
+ super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+ };
+ }
+
+ private String withoutFirstObjectArg(String descriptor) {
+ int i = descriptor.indexOf(";");
+ return "(" + descriptor.substring(i + 1);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
index fc35e73..1352a82 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
@@ -63,6 +63,13 @@
}
}
+ private int firstEmptyLevel() {
+ return isJDK11DesugaredLibrary()
+ // Some desugarings are required on all API levels including UNKNOWN.
+ ? AndroidApiLevel.NOT_SET.getLevel()
+ : AndroidApiLevel.O.getLevel();
+ }
+
@Test
public void testEmptyDesugaredLibrary() throws Exception {
for (AndroidApiLevel apiLevel : AndroidApiLevel.values()) {
@@ -72,8 +79,7 @@
}
CountingProgramConsumer programConsumer = new CountingProgramConsumer();
ToolHelper.runL8(prepareL8Builder(apiLevel).setProgramConsumer(programConsumer).build());
- assertEquals(
- apiLevel.getLevel() >= AndroidApiLevel.O.getLevel() ? 0 : 1, programConsumer.count);
+ assertEquals(apiLevel.getLevel() >= firstEmptyLevel() ? 0 : 1, programConsumer.count);
}
}
@@ -89,7 +95,7 @@
prepareL8Builder(apiLevel).setOutput(desugaredLibraryZip, OutputMode.DexIndexed).build());
assertTrue(Files.exists(desugaredLibraryZip));
assertEquals(
- apiLevel.getLevel() >= AndroidApiLevel.O.getLevel() ? 0 : 1,
+ apiLevel.getLevel() >= firstEmptyLevel() ? 0 : 1,
new ZipFile(desugaredLibraryZip.toFile(), StandardCharsets.UTF_8).size());
}
}
@@ -107,7 +113,7 @@
.setOutput(desugaredLibraryDirectory, OutputMode.DexIndexed)
.build());
assertEquals(
- apiLevel.getLevel() >= AndroidApiLevel.O.getLevel() ? 0 : 1,
+ apiLevel.getLevel() >= firstEmptyLevel() ? 0 : 1,
Files.walk(desugaredLibraryDirectory)
.filter(path -> path.toString().endsWith(".dex"))
.count());