Custom conversion rewrites as gradle tasks
Bug: 222647019
Change-Id: Ifdddc41a608ec11044c50923843b126672925372
diff --git a/build.gradle b/build.gradle
index b2e669c..50fda5f 100644
--- a/build.gradle
+++ b/build.gradle
@@ -4,6 +4,7 @@
import dx.DexMergerTask
import dx.DxTask
+import desugaredlibrary.CustomConversionAsmRewriterTask
import net.ltgt.gradle.errorprone.CheckSeverity
import org.gradle.internal.os.OperatingSystem
import smali.SmaliTask
@@ -31,7 +32,7 @@
ext {
androidSupportVersion = '25.4.0'
- asmVersion = '9.3' // When updating update tools/asmifier.py and Toolhelper as well.
+ asmVersion = '9.3' // When updating update tools/asmifier.py, build.src and Toolhelper as well.
espressoVersion = '3.0.0'
fastutilVersion = '7.2.0'
guavaVersion = '30.1.1-jre'
@@ -1007,11 +1008,16 @@
}
}
-task buildLibraryDesugarConversions(type: Zip, dependsOn: downloadDeps) {
+task rawBuildLibraryDesugarConversions(type: Zip, dependsOn: downloadDeps) {
from sourceSets.libraryDesugarConversions.output
include "java/**/*.class"
- baseName 'library_desugar_conversions'
- destinationDir file('build/libs')
+ baseName 'library_desugar_conversions_raw'
+ destinationDir file('build/tmp/desugaredlibrary')
+}
+
+task buildLibraryDesugarConversions(type: CustomConversionAsmRewriterTask, dependsOn: rawBuildLibraryDesugarConversions) {
+ rawJar = file("tmp/library_desugar_conversions_raw.zip")
+ outputDirectory = file("build/libs")
}
task testJarSources(type: Jar, dependsOn: [testClasses, buildLibraryDesugarConversions]) {
diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle
index 74c5cfd..81527b4 100644
--- a/buildSrc/build.gradle
+++ b/buildSrc/build.gradle
@@ -7,10 +7,18 @@
repositories {
mavenCentral()
}
+ext {
+ asmVersion = '9.3'
+}
dependencies {
compile group: 'com.google.guava', name: 'guava', version: '19.0'
compile group: 'org.smali', name: 'smali', version: '2.2b4'
+ compile group: 'org.ow2.asm', name: 'asm', version: asmVersion
+ compile group: 'org.ow2.asm', name: 'asm-commons', version: asmVersion
+ compile group: 'org.ow2.asm', name: 'asm-tree', version: asmVersion
+ compile group: 'org.ow2.asm', name: 'asm-analysis', version: asmVersion
+ compile group: 'org.ow2.asm', name: 'asm-util', version: asmVersion
}
sourceCompatibility = JavaVersion.VERSION_1_8
diff --git a/buildSrc/src/main/java/desugaredlibrary/AsmRewriter.java b/buildSrc/src/main/java/desugaredlibrary/AsmRewriter.java
new file mode 100644
index 0000000..cc1fcf2
--- /dev/null
+++ b/buildSrc/src/main/java/desugaredlibrary/AsmRewriter.java
@@ -0,0 +1,53 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package desugaredlibrary;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+public abstract class AsmRewriter {
+
+ public static int ASM_VERSION = Opcodes.ASM9;
+
+ public static byte[] transformInvoke(byte[] bytes, MethodTransformer transformer) {
+ ClassReader reader = new ClassReader(bytes);
+ ClassWriter writer = new ClassWriter(reader, 0);
+ ClassVisitor subvisitor = new InvokeTransformer(writer, transformer);
+ reader.accept(subvisitor, 0);
+ return writer.toByteArray();
+ }
+
+ public static class InvokeTransformer extends ClassVisitor {
+
+ private final MethodTransformer transformer;
+
+ InvokeTransformer(ClassWriter writer, MethodTransformer transformer) {
+ super(ASM_VERSION, writer);
+ this.transformer = transformer;
+ }
+
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String descriptor, String signature, String[] exceptions) {
+ MethodVisitor sub = super.visitMethod(access, name, descriptor, signature, exceptions);
+ transformer.setMv(sub);
+ return transformer;
+ }
+ }
+
+ public static class MethodTransformer extends MethodVisitor {
+
+ protected MethodTransformer(int api) {
+ super(api);
+ }
+
+ public void setMv(MethodVisitor visitor) {
+ this.mv = visitor;
+ }
+ }
+}
diff --git a/buildSrc/src/main/java/desugaredlibrary/CustomConversionAsmRewriteDescription.java b/buildSrc/src/main/java/desugaredlibrary/CustomConversionAsmRewriteDescription.java
new file mode 100644
index 0000000..137ac12
--- /dev/null
+++ b/buildSrc/src/main/java/desugaredlibrary/CustomConversionAsmRewriteDescription.java
@@ -0,0 +1,54 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package desugaredlibrary;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class CustomConversionAsmRewriteDescription {
+
+ static final String WRAP_CONVERT = "wrap_convert";
+ static final String INVERTED_WRAP_CONVERT = "inverted_wrap_convert";
+ static final String CONVERT = "convert";
+
+ private static final Set<String> ENUM_WRAP_CONVERT_OWNER =
+ ImmutableSet.of(
+ "j$/nio/file/StandardOpenOption",
+ "j$/nio/file/LinkOption",
+ "j$/nio/file/attribute/PosixFilePermission",
+ "j$/util/stream/Collector$Characteristics");
+ private static final Set<String> WRAP_CONVERT_OWNER =
+ ImmutableSet.of(
+ "j$/nio/file/spi/FileSystemProvider",
+ "j$/nio/file/spi/FileTypeDetector",
+ "j$/nio/file/Path",
+ "j$/nio/file/WatchEvent",
+ "j$/nio/file/attribute/BasicFileAttributes",
+ "j$/nio/file/attribute/BasicFileAttributeView",
+ "j$/nio/file/attribute/FileOwnerAttributeView",
+ "j$/nio/file/attribute/PosixFileAttributes",
+ "j$/nio/file/attribute/PosixFileAttributeView");
+
+ static Map<String, String> getJavaWrapConvertOwnerMap() {
+ return computeConvertOwnerMap("$VivifiedWrapper");
+ }
+
+ static Map<String, String> getJ$WrapConvertOwnerMap() {
+ return computeConvertOwnerMap("$Wrapper");
+ }
+
+ private static HashMap<String, String> computeConvertOwnerMap(String suffix) {
+ HashMap<String, String> map = new HashMap<>();
+ for (String theEnum : ENUM_WRAP_CONVERT_OWNER) {
+ map.put(theEnum, theEnum + "$EnumConversion");
+ }
+ for (String owner : WRAP_CONVERT_OWNER) {
+ map.put(owner, owner + suffix);
+ }
+ return map;
+ }
+}
diff --git a/buildSrc/src/main/java/desugaredlibrary/CustomConversionAsmRewriter.java b/buildSrc/src/main/java/desugaredlibrary/CustomConversionAsmRewriter.java
new file mode 100644
index 0000000..6107e67
--- /dev/null
+++ b/buildSrc/src/main/java/desugaredlibrary/CustomConversionAsmRewriter.java
@@ -0,0 +1,183 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package desugaredlibrary;
+
+import static desugaredlibrary.AsmRewriter.ASM_VERSION;
+import static desugaredlibrary.CustomConversionAsmRewriteDescription.CONVERT;
+import static desugaredlibrary.CustomConversionAsmRewriteDescription.INVERTED_WRAP_CONVERT;
+import static desugaredlibrary.CustomConversionAsmRewriteDescription.WRAP_CONVERT;
+import static desugaredlibrary.CustomConversionAsmRewriter.CustomConversionVersion.LEGACY;
+import static org.objectweb.asm.Opcodes.INVOKESTATIC;
+
+import com.google.common.io.ByteStreams;
+import desugaredlibrary.AsmRewriter.MethodTransformer;
+import java.io.BufferedOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.OpenOption;
+import java.nio.file.Path;
+import java.nio.file.StandardOpenOption;
+import java.util.Enumeration;
+import java.util.Map;
+import java.util.zip.CRC32;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+
+public class CustomConversionAsmRewriter {
+
+ public enum CustomConversionVersion {
+ LEGACY,
+ LATEST
+ }
+
+ public CustomConversionAsmRewriter(CustomConversionVersion legacy) {
+ this.legacy = legacy;
+ }
+
+ private final CustomConversionVersion legacy;
+ private final Map<String, String> javaWrapConvertOwnerMap =
+ CustomConversionAsmRewriteDescription.getJavaWrapConvertOwnerMap();
+ private final Map<String, String> j$WrapConvertOwnerMap =
+ CustomConversionAsmRewriteDescription.getJ$WrapConvertOwnerMap();
+
+ public static void generateJars(Path jar, Path outputDirectory) throws IOException {
+ for (CustomConversionVersion version : CustomConversionVersion.values()) {
+ new CustomConversionAsmRewriter(version).convert(jar, outputDirectory);
+ }
+ }
+
+ private void convert(Path jar, Path outputDirectory) throws IOException {
+ String fileName = jar.getFileName().toString();
+ String newFileName =
+ fileName.substring(0, fileName.length() - "_raw.jar".length())
+ + (legacy == LEGACY ? "_legacy" : "")
+ + ".jar";
+ Path convertedJar = outputDirectory.resolve(newFileName);
+ internalConvert(jar, convertedJar);
+ }
+
+ private void internalConvert(Path jar, Path convertedJar) throws IOException {
+ OpenOption[] options =
+ new OpenOption[] {StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING};
+ try (ZipOutputStream out =
+ new ZipOutputStream(
+ new BufferedOutputStream(Files.newOutputStream(convertedJar, options)))) {
+ new CustomConversionAsmRewriter(legacy).convert(jar, out, legacy);
+ }
+ }
+
+ private void convert(
+ Path desugaredLibraryFiles, ZipOutputStream out, CustomConversionVersion legacy)
+ throws IOException {
+ try (ZipFile zipFile = new ZipFile(desugaredLibraryFiles.toFile(), StandardCharsets.UTF_8)) {
+ final Enumeration<? extends ZipEntry> entries = zipFile.entries();
+ while (entries.hasMoreElements()) {
+ ZipEntry entry = entries.nextElement();
+ try (InputStream entryStream = zipFile.getInputStream(entry)) {
+ handleFile(entry, entryStream, out, legacy);
+ }
+ }
+ }
+ }
+
+ private void handleFile(
+ ZipEntry entry, InputStream input, ZipOutputStream out, CustomConversionVersion legacy)
+ throws IOException {
+ if (!entry.getName().endsWith(".class")) {
+ return;
+ }
+ if (legacy == LEGACY
+ && (entry.getName().contains("java.nio.file")
+ || entry.getName().contains("ApiFlips")
+ || entry.getName().contains("java.adapter"))) {
+ return;
+ }
+ final byte[] bytes = ByteStreams.toByteArray(input);
+ input.close();
+ final byte[] rewrittenBytes = transformInvoke(bytes);
+ writeToZipStream(out, entry.getName(), rewrittenBytes, ZipEntry.STORED);
+ }
+
+ public static void writeToZipStream(
+ ZipOutputStream stream, String entry, byte[] content, int compressionMethod)
+ throws IOException {
+ int offset = 0;
+ int length = content.length;
+ CRC32 crc = new CRC32();
+ crc.update(content, offset, length);
+ ZipEntry zipEntry = new ZipEntry(entry);
+ zipEntry.setMethod(compressionMethod);
+ zipEntry.setSize(length);
+ zipEntry.setCrc(crc.getValue());
+ zipEntry.setTime(0);
+ stream.putNextEntry(zipEntry);
+ stream.write(content, offset, length);
+ stream.closeEntry();
+ }
+
+ private byte[] transformInvoke(byte[] bytes) {
+ return AsmRewriter.transformInvoke(bytes, new CustomConversionRewriter(ASM_VERSION));
+ }
+
+ class CustomConversionRewriter extends MethodTransformer {
+
+ protected CustomConversionRewriter(int api) {
+ super(api);
+ }
+
+ @Override
+ public void visitMethodInsn(
+ int opcode, String owner, String name, String descriptor, boolean isInterface) {
+ if (opcode == INVOKESTATIC) {
+ if (name.equals(WRAP_CONVERT)) {
+ convertInvoke(
+ opcode,
+ owner,
+ descriptor,
+ isInterface,
+ javaWrapConvertOwnerMap,
+ j$WrapConvertOwnerMap);
+ return;
+ }
+ if (name.equals(INVERTED_WRAP_CONVERT)) {
+ convertInvoke(
+ opcode,
+ owner,
+ descriptor,
+ isInterface,
+ j$WrapConvertOwnerMap,
+ javaWrapConvertOwnerMap);
+ return;
+ }
+ }
+ super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+
+ private void convertInvoke(
+ int opcode,
+ String owner,
+ String descriptor,
+ boolean isInterface,
+ Map<String, String> javaMap,
+ Map<String, String> j$Map) {
+ if (!javaMap.containsKey(owner)
+ || !j$Map.containsKey(owner)
+ || !(owner.startsWith("java") || owner.startsWith("j$"))) {
+ throw new RuntimeException("Cannot transform wrap_convert method for " + owner);
+ }
+ if (owner.startsWith("java")) {
+ String newOwner = j$Map.get(owner);
+ super.visitMethodInsn(opcode, newOwner, CONVERT, descriptor, isInterface);
+ return;
+ }
+ assert owner.startsWith("j$");
+ String newOwner = javaMap.get(owner);
+ super.visitMethodInsn(opcode, newOwner, CONVERT, descriptor, isInterface);
+ }
+ }
+}
diff --git a/buildSrc/src/main/java/desugaredlibrary/CustomConversionAsmRewriterTask.java b/buildSrc/src/main/java/desugaredlibrary/CustomConversionAsmRewriterTask.java
new file mode 100644
index 0000000..bae3c1c
--- /dev/null
+++ b/buildSrc/src/main/java/desugaredlibrary/CustomConversionAsmRewriterTask.java
@@ -0,0 +1,78 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package desugaredlibrary;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import javax.inject.Inject;
+import org.gradle.api.DefaultTask;
+import org.gradle.api.tasks.InputFile;
+import org.gradle.api.tasks.OutputDirectory;
+import org.gradle.api.tasks.TaskAction;
+import org.gradle.workers.IsolationMode;
+import org.gradle.workers.WorkerExecutor;
+
+public class CustomConversionAsmRewriterTask extends DefaultTask {
+
+ private final WorkerExecutor workerExecutor;
+
+ private File rawJar;
+ private File outputDirectory;
+
+ @Inject
+ public CustomConversionAsmRewriterTask(WorkerExecutor workerExecutor) {
+ this.workerExecutor = workerExecutor;
+ }
+
+ @InputFile
+ public File getRawJar() {
+ return rawJar;
+ }
+
+ public void setRawJar(File rawJar) {
+ this.rawJar = rawJar;
+ }
+
+ @OutputDirectory
+ public File getOutputDirectory() {
+ return outputDirectory;
+ }
+
+ public void setOutputDirectory(File outputDirectory) {
+ this.outputDirectory = outputDirectory;
+ }
+
+ @TaskAction
+ void exec() {
+ workerExecutor.submit(
+ Run.class,
+ config -> {
+ config.setIsolationMode(IsolationMode.NONE);
+ config.params(rawJar, outputDirectory);
+ });
+ }
+
+ public static class Run implements Runnable {
+
+ private final File rawJar;
+ private final File outputDirectory;
+
+ @Inject
+ public Run(File rawJar, File outputDirectory) {
+ this.rawJar = rawJar;
+ this.outputDirectory = outputDirectory;
+ }
+
+ @Override
+ public void run() {
+ try {
+ CustomConversionAsmRewriter.generateJars(rawJar.toPath(), outputDirectory.toPath());
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+ }
+}
diff --git a/src/library_desugar/java/j$/nio/file/Path.java b/src/library_desugar/java/j$/nio/file/Path.java
index 781ab5f..cb01ec0 100644
--- a/src/library_desugar/java/j$/nio/file/Path.java
+++ b/src/library_desugar/java/j$/nio/file/Path.java
@@ -6,7 +6,7 @@
public class Path {
- public static j$.nio.file.Path wrap_convert(java.nio.file.Path path) {
+ public static j$.nio.file.Path inverted_wrap_convert(java.nio.file.Path path) {
return null;
}
}
diff --git a/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java b/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java
index da93736..af2c8f7 100644
--- a/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java
+++ b/src/library_desugar/java/java/adapter/HybridFileTypeDetector.java
@@ -29,7 +29,7 @@
static class PlatformFileTypeDetector extends FileTypeDetector {
@Override
public String probeContentType(Path path) throws IOException {
- return j$.nio.file.Files.probeContentType(j$.nio.file.Path.wrap_convert(path));
+ return j$.nio.file.Files.probeContentType(j$.nio.file.Path.inverted_wrap_convert(path));
}
}
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index b9e0912..69f2167 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -15,7 +15,6 @@
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper.DexVm.Kind;
import com.android.tools.r8.benchmarks.BenchmarkResults;
-import com.android.tools.r8.desugar.desugaredlibrary.jdk11.ConversionConverter;
import com.android.tools.r8.desugar.desugaredlibrary.jdk11.DesugaredLibraryJDK11Undesugarer;
import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.CustomConversionVersion;
import com.android.tools.r8.dex.ApplicationReader;
@@ -180,8 +179,6 @@
public static final Path DEPS = Paths.get(LIBS_DIR, "deps_all.jar");
public static final Path R8_RETRACE_JAR = Paths.get(LIBS_DIR, "r8retrace.jar");
- public static final Path DESUGAR_LIB_CONVERSIONS =
- Paths.get(LIBS_DIR, "library_desugar_conversions.zip");
public static final String DESUGARED_LIB_RELEASES_DIR =
OPEN_JDK_DIR + "desugar_jdk_libs_releases/";
public static final Path DESUGARED_JDK_8_LIB_JAR =
@@ -189,8 +186,10 @@
public static final Path DESUGARED_JDK_11_LIB_JAR =
Paths.get(OPEN_JDK_DIR + "desugar_jdk_libs_11/desugar_jdk_libs.jar");
- public static Path getConvertedDesugaredLibConversions(CustomConversionVersion legacy) {
- return ConversionConverter.convertJar(DESUGAR_LIB_CONVERSIONS, legacy);
+ public static Path getDesugarLibConversions(CustomConversionVersion legacy) {
+ return legacy == CustomConversionVersion.LEGACY
+ ? Paths.get(LIBS_DIR, "library_desugar_conversions_legacy.jar")
+ : Paths.get(LIBS_DIR, "library_desugar_conversions.jar");
}
public static Path getUndesugaredJdk11LibJarForTesting() {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
index efee088..5a05e80 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
@@ -54,7 +54,7 @@
"JDK8_CL",
ImmutableSet.of(
DESUGARED_JDK_8_LIB_JAR,
- ToolHelper.getConvertedDesugaredLibConversions(LEGACY),
+ ToolHelper.getDesugarLibConversions(LEGACY),
ToolHelper.getCoreLambdaStubs()),
JDK8.getSpecification(),
ImmutableSet.of(ToolHelper.getAndroidJar(AndroidApiLevel.O)),
@@ -65,7 +65,7 @@
"JDK11_CL",
ImmutableSet.of(
ToolHelper.getUndesugaredJdk11LibJarForTesting(),
- ToolHelper.getConvertedDesugaredLibConversions(LATEST),
+ ToolHelper.getDesugarLibConversions(LATEST),
ToolHelper.getCoreLambdaStubs()),
JDK11.getSpecification(),
ImmutableSet.of(ToolHelper.getAndroidJar(AndroidApiLevel.R)),
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/ConversionConverter.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/ConversionConverter.java
deleted file mode 100644
index 746a1d2..0000000
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdk11/ConversionConverter.java
+++ /dev/null
@@ -1,179 +0,0 @@
-// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.desugar.desugaredlibrary.jdk11;
-
-import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.CustomConversionVersion.LEGACY;
-
-import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.CustomConversionVersion;
-import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.transformers.ClassFileTransformer;
-import com.android.tools.r8.transformers.MethodTransformer;
-import com.android.tools.r8.utils.StreamUtils;
-import com.android.tools.r8.utils.ZipUtils;
-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.StandardOpenOption;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
-import org.objectweb.asm.Opcodes;
-
-public class ConversionConverter {
-
- private static final Map<String, String> JAVA_WRAP_CONVERT_OWNER = new HashMap<>();
- private static final Map<String, String> J$_WRAP_CONVERT_OWNER = new HashMap<>();
-
- static {
- JAVA_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/spi/FileSystemProvider",
- "java/nio/file/spi/FileSystemProvider$VivifiedWrapper");
- JAVA_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/spi/FileTypeDetector", "java/nio/file/spi/FileTypeDetector$VivifiedWrapper");
- JAVA_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/StandardOpenOption", "java/nio/file/StandardOpenOption$EnumConversion");
- JAVA_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/LinkOption", "java/nio/file/LinkOption$EnumConversion");
- JAVA_WRAP_CONVERT_OWNER.put("j$/nio/file/Path", "java/nio/file/Path$Wrapper");
- JAVA_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/WatchEvent", "java/nio/file/WatchEvent$VivifiedWrapper");
- JAVA_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/attribute/BasicFileAttributes",
- "java/nio/file/attribute/BasicFileAttributes$VivifiedWrapper");
- JAVA_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/attribute/BasicFileAttributeView",
- "java/nio/file/attribute/BasicFileAttributeView$VivifiedWrapper");
- JAVA_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/attribute/FileOwnerAttributeView",
- "java/nio/file/attribute/FileOwnerAttributeView$VivifiedWrapper");
- JAVA_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/attribute/PosixFileAttributes",
- "java/nio/file/attribute/PosixFileAttributes$VivifiedWrapper");
- JAVA_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/attribute/PosixFileAttributeView",
- "java/nio/file/attribute/PosixFileAttributeView$VivifiedWrapper");
- JAVA_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/attribute/PosixFilePermission",
- "java/nio/file/attribute/PosixFilePermission$EnumConversion");
- JAVA_WRAP_CONVERT_OWNER.put(
- "j$/util/stream/Collector$Characteristics",
- "java/util/stream/Collector$Characteristics$EnumConversion");
-
- J$_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/spi/FileSystemProvider", "java/nio/file/spi/FileSystemProvider$Wrapper");
- J$_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/spi/FileTypeDetector", "java/nio/file/spi/FileTypeDetector$Wrapper");
- J$_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/StandardOpenOption", "java/nio/file/StandardOpenOption$EnumConversion");
- J$_WRAP_CONVERT_OWNER.put("j$/nio/file/LinkOption", "java/nio/file/LinkOption$EnumConversion");
- J$_WRAP_CONVERT_OWNER.put("j$/nio/file/Path", "java/nio/file/Path$VivifiedWrapper");
- J$_WRAP_CONVERT_OWNER.put("j$/nio/file/WatchEvent", "java/nio/file/WatchEvent$Wrapper");
- J$_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/attribute/BasicFileAttributes",
- "java/nio/file/attribute/BasicFileAttributes$Wrapper");
- J$_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/attribute/BasicFileAttributeView",
- "java/nio/file/attribute/BasicFileAttributeView$Wrapper");
- J$_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/attribute/FileOwnerAttributeView",
- "java/nio/file/attribute/FileOwnerAttributeView$Wrapper");
- J$_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/attribute/PosixFileAttributes",
- "java/nio/file/attribute/PosixFileAttributes$Wrapper");
- J$_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/attribute/PosixFileAttributeView",
- "java/nio/file/attribute/PosixFileAttributeView$Wrapper");
- J$_WRAP_CONVERT_OWNER.put(
- "j$/nio/file/attribute/PosixFilePermission",
- "java/nio/file/attribute/PosixFilePermission$EnumConversion");
- J$_WRAP_CONVERT_OWNER.put(
- "j$/util/stream/Collector$Characteristics",
- "java/util/stream/Collector$Characteristics$EnumConversion");
- }
-
- public static Path convertJar(Path jar, CustomConversionVersion legacy) {
- String fileName = jar.getFileName().toString();
- String newFileName =
- fileName.substring(0, fileName.length() - ".jar".length())
- + (legacy == LEGACY ? "_legacy" : "")
- + "_converted.jar";
- Path convertedJar = jar.getParent().resolve(newFileName);
- return internalConvert(jar, convertedJar, legacy);
- }
-
- private static synchronized Path internalConvert(
- Path jar, Path convertedJar, CustomConversionVersion legacy) {
- if (Files.exists(convertedJar)) {
- return convertedJar;
- }
-
- OpenOption[] options =
- new OpenOption[] {StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING};
- try (ZipOutputStream out =
- new ZipOutputStream(
- new BufferedOutputStream(Files.newOutputStream(convertedJar, options)))) {
- new ConversionConverter().convert(jar, out, legacy);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- return convertedJar;
- }
-
- private void convert(
- Path desugaredLibraryFiles, ZipOutputStream out, CustomConversionVersion legacy)
- throws IOException {
- ZipUtils.iter(
- desugaredLibraryFiles,
- ((entry, input) -> {
- if (!entry.getName().endsWith(".class")) {
- return;
- }
- if (legacy == LEGACY
- && (entry.getName().contains("nio.file") || entry.getName().contains("ApiFlips"))) {
- 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 ClassFileTransformer.create(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 && name.equals("wrap_convert")) {
- if (!JAVA_WRAP_CONVERT_OWNER.containsKey(owner)
- || !J$_WRAP_CONVERT_OWNER.containsKey(owner)) {
- throw new RuntimeException("Cannot transform wrap_convert method for " + owner);
- }
- if (owner.startsWith("java")) {
- String newOwner = J$_WRAP_CONVERT_OWNER.get(owner);
- super.visitMethodInsn(opcode, newOwner, "convert", descriptor, isInterface);
- return;
- } else if (owner.startsWith("j$")) {
- String newOwner = JAVA_WRAP_CONVERT_OWNER.get(owner);
- super.visitMethodInsn(opcode, newOwner, "convert", descriptor, isInterface);
- return;
- } else {
- throw new RuntimeException("Cannot transform wrap_convert method for " + owner);
- }
- }
- super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
- }
- };
- }
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
index 143a52d..b3cc9ab 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
@@ -168,7 +168,7 @@
CustomConversionVersion legacy) {
this(
name,
- ImmutableSet.of(desugarJdkLibs, ToolHelper.getConvertedDesugaredLibConversions(legacy)),
+ ImmutableSet.of(desugarJdkLibs, ToolHelper.getDesugarLibConversions(legacy)),
Paths.get("src/library_desugar/" + specificationPath),
ImmutableSet.of(ToolHelper.getAndroidJar(androidJarLevel)),
descriptor,