blob: f79db700fb6501414b0246099876ebbda274400e [file] [log] [blame]
// 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);
}
}