Use ASM to extract the class name from class files
The implementation using ClassLoader.defineClass only worked in
simple cases.
Change-Id: Ib253a32e860b26147f6490702146ce190f787d04
diff --git a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
index a846ea7..a8ec999 100644
--- a/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/DescriptorUtils.java
@@ -368,7 +368,7 @@
assert name.endsWith(CLASS_EXTENSION) :
"Name " + name + " must have " + CLASS_EXTENSION + " suffix";
String descriptor = name.substring(0, name.length() - CLASS_EXTENSION.length());
- if (descriptor.contains(".")) {
+ if (descriptor.indexOf(JAVA_PACKAGE_SEPARATOR) != -1) {
throw new CompilationError("Unexpected class file name: " + name);
}
return 'L' + descriptor + ';';
@@ -383,6 +383,6 @@
public static String getPathFromJavaType(String typeName) {
assert isValidJavaType(typeName);
- return typeName.replace(".", "/") + ".class";
+ return typeName.replace(JAVA_PACKAGE_SEPARATOR, DESCRIPTOR_PACKAGE_SEPARATOR) + ".class";
}
}
diff --git a/src/test/java/com/android/tools/r8/AsmTestBase.java b/src/test/java/com/android/tools/r8/AsmTestBase.java
index cb4a4af..35767fb 100644
--- a/src/test/java/com/android/tools/r8/AsmTestBase.java
+++ b/src/test/java/com/android/tools/r8/AsmTestBase.java
@@ -144,14 +144,6 @@
byte[] dump() throws Exception;
}
- protected static Class loadClassFromAsmClass(AsmDump asmDump) {
- try {
- return loadClassFromDump(asmDump.dump());
- } catch (Exception e) {
- throw new ClassFormatError(e.toString());
- }
- }
-
protected static byte[] getBytesFromAsmClass(AsmDump asmDump) {
try {
return asmDump.dump();
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 182326e..bf900a9 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -6,6 +6,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.objectweb.asm.Opcodes.ASM6;
import com.android.tools.r8.DataResourceProvider.Visitor;
import com.android.tools.r8.ToolHelper.ArtCommandBuilder;
@@ -52,6 +53,8 @@
import java.util.zip.ZipOutputStream;
import org.junit.Rule;
import org.junit.rules.TemporaryFolder;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
public class TestBase {
public enum Backend {
@@ -602,7 +605,7 @@
protected ProcessResult runOnJavaRawNoVerify(String main, List<byte[]> classes, List<String> args)
throws IOException {
- return ToolHelper.runJavaNoVerify(Collections.singletonList(writeToZip(classes)), main, args);
+ return ToolHelper.runJavaNoVerify(Collections.singletonList(writeToJar(classes)), main, args);
}
protected ProcessResult runOnJavaRaw(String main, byte[]... classes) throws IOException {
@@ -615,7 +618,7 @@
mainAndArgs.add(main);
mainAndArgs.addAll(args);
return ToolHelper.runJava(
- Collections.singletonList(writeToZip(classes)), mainAndArgs.toArray(new String[0]));
+ Collections.singletonList(writeToJar(classes)), mainAndArgs.toArray(new String[0]));
}
protected ProcessResult runOnJavaRaw(AndroidApp app, String mainClass, List<String> args)
@@ -628,33 +631,57 @@
return ToolHelper.runJava(out, mainAndArgs.toArray(new String[0]));
}
- protected Path writeToZip(List<byte[]> classes) throws IOException {
- File result = temp.newFile("tmp.zip");
- try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(result.toPath(),
- StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
+ private String extractClassName(byte[] ccc) {
+ class ClassNameExtractor extends ClassVisitor {
+ private String className;
+
+ private ClassNameExtractor() {
+ super(ASM6);
+ }
+
+ @Override
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ className =
+ name.replace(
+ DescriptorUtils.DESCRIPTOR_PACKAGE_SEPARATOR,
+ DescriptorUtils.JAVA_PACKAGE_SEPARATOR);
+ }
+
+ String getClassName() {
+ return className;
+ }
+ }
+
+ ClassReader reader = new ClassReader(ccc);
+ ClassNameExtractor extractor = new ClassNameExtractor();
+ reader.accept(
+ extractor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
+ return extractor.getClassName();
+ }
+
+ protected Path writeToJar(List<byte[]> classes) throws IOException {
+ Path result = File.createTempFile("junit", ".jar", temp.getRoot()).toPath();
+ try (ZipOutputStream out =
+ new ZipOutputStream(
+ Files.newOutputStream(
+ result, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING))) {
for (byte[] clazz : classes) {
- String name = loadClassFromDump(clazz).getTypeName();
+ String name = extractClassName(clazz);
ZipUtils.writeToZipStream(
out, DescriptorUtils.getPathFromJavaType(name), clazz, ZipEntry.STORED);
}
}
- return result.toPath();
+ return result;
}
- protected Path writeToZip(JasminBuilder jasminBuilder) throws Exception {
- return writeToZip(jasminBuilder.buildClasses());
- }
-
- protected static Class loadClassFromDump(byte[] dump) {
- return new DumpLoader().loadClass(dump);
- }
-
- private static class DumpLoader extends ClassLoader {
-
- @SuppressWarnings("deprecation")
- public Class loadClass(byte[] clazz) {
- return defineClass(clazz, 0, clazz.length);
- }
+ protected Path writeToJar(JasminBuilder jasminBuilder) throws Exception {
+ return writeToJar(jasminBuilder.buildClasses());
}
/**
diff --git a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
index 4405565..060d87b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -324,7 +324,7 @@
"return"
);
- Path output = writeToZip(builder);
+ Path output = writeToJar(builder);
addExtraClasspath(output);
return JASMIN_MAIN_CLASS;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
index a3aa5e1..036d960 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
@@ -476,7 +476,7 @@
"return"
);
- Path javaOutput = writeToZip(jasminBuilder);
+ Path javaOutput = writeToJar(jasminBuilder);
ProcessResult javaResult = ToolHelper.runJava(javaOutput, "Foo");
if (javaResult.exitCode != 0) {
System.err.println(javaResult.stderr);
diff --git a/src/test/java/com/android/tools/r8/shaking/MissingInterfaceTest.java b/src/test/java/com/android/tools/r8/shaking/MissingInterfaceTest.java
index a93db7a..acf4488 100644
--- a/src/test/java/com/android/tools/r8/shaking/MissingInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/MissingInterfaceTest.java
@@ -55,7 +55,7 @@
@Before
public void setUp() throws Exception {
- libJar = writeToZip(ImmutableList.of(ToolHelper.getClassAsBytes(GoingToBeMissed.class)));
+ libJar = writeToJar(ImmutableList.of(ToolHelper.getClassAsBytes(GoingToBeMissed.class)));
libDex = temp.getRoot().toPath().resolve("lib.zip");
AndroidApp libApp = ToolHelper.runD8(readClasses(GoingToBeMissed.class));
libApp.writeToZip(libDex, OutputMode.DexIndexed);