Add some more tests for member lookup.
Bug: 69101406, 69152228
Change-Id: Icae6bbeb28dfb23f8b0b416b9f24fa4e9158c58f
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 139ee1f..ce46885 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -748,12 +748,25 @@
return runJava(ImmutableList.of(path.toString()), main);
}
+ public static ProcessResult runJavaNoVerify(Class clazz) throws Exception {
+ String main = clazz.getCanonicalName();
+ Path path = getClassPathForTests();
+ return runJavaNoVerify(ImmutableList.of(path.toString()), main);
+ }
+
public static ProcessResult runJava(List<String> classpath, String mainClass) throws IOException {
ProcessBuilder builder = new ProcessBuilder(
getJavaExecutable(), "-cp", String.join(PATH_SEPARATOR, classpath), mainClass);
return runProcess(builder);
}
+ public static ProcessResult runJavaNoVerify(List<String> classpath, String mainClass)
+ throws IOException {
+ ProcessBuilder builder = new ProcessBuilder(
+ getJavaExecutable(), "-cp", String.join(PATH_SEPARATOR, classpath), "-noverify", mainClass);
+ return runProcess(builder);
+ }
+
public static ProcessResult forkD8(Path dir, String... args)
throws IOException, InterruptedException {
return forkJava(dir, D8.class, args);
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java b/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
index 964f004..d44b460 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
@@ -55,6 +55,13 @@
public int getMajorVersion() {
return 48;
}
+ },
+ /** JSE 5 is not fully supported by Jasmin. Interfaces will not work. */
+ JSE_5 {
+ @Override
+ public int getMajorVersion() {
+ return 49;
+ }
};
public abstract int getMajorVersion();
@@ -71,6 +78,7 @@
private final List<String> methods = new ArrayList<>();
private final List<String> fields = new ArrayList<>();
private boolean makeInit = false;
+ private boolean hasInit = false;
private boolean isInterface = false;
private ClassBuilder(String name) {
@@ -180,7 +188,7 @@
for (String iface : interfaces) {
builder.append(".implements ").append(iface).append('\n');
}
- if (makeInit) {
+ if (makeInit && !hasInit) {
builder
.append(".method public <init>()V\n")
.append(".limit locals 1\n")
@@ -204,6 +212,8 @@
}
public MethodSignature addDefaultConstructor() {
+ assert !hasInit;
+ hasInit = true;
return addMethod("public", "<init>", Collections.emptyList(), "V",
".limit stack 1",
".limit locals 1",
@@ -245,6 +255,9 @@
}
public ClassBuilder addInterface(String name, String... interfaces) {
+ // Interfaces are broken in Jasmin (the ACC_SUPER access flag is set) and the JSE_5 and later
+ // will not load corresponding classes.
+ assert majorVersion <= ClassFileVersion.JDK_1_4.getMajorVersion();
ClassBuilder builder = new ClassBuilder(name, "java/lang/Object", interfaces);
builder.setIsInterface();
classes.add(builder);
diff --git a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
index 6d4a501..84b413a 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminTestBase.java
@@ -55,7 +55,7 @@
ByteStreams.copy(input, output);
}
}
- return ToolHelper.runJava(ImmutableList.of(out.getPath()), main);
+ return ToolHelper.runJavaNoVerify(ImmutableList.of(out.getPath()), main);
}
protected String runOnJava(JasminBuilder builder, String main) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java b/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
index 15d2a08..fb3c067 100644
--- a/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
+++ b/src/test/java/com/android/tools/r8/jasmin/MemberResolutionTest.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.jasmin;
+import static java.util.Collections.emptyList;
+
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
import com.android.tools.r8.jasmin.JasminBuilder.ClassFileVersion;
@@ -118,6 +120,189 @@
ensureICCE(builder);
}
+ @Test
+ @Ignore("b/69101406")
+ public void lookupVirtualMethodWithConflictingPrivate() throws Exception {
+ JasminBuilder builder = new JasminBuilder();
+
+ ClassBuilder superClass = builder.addClass("SuperClass");
+ superClass.addDefaultConstructor();
+ superClass.addVirtualMethod("aMethod", emptyList(), "V",
+ ".limit stack 2",
+ ".limit locals 1",
+ " getstatic java/lang/System/out Ljava/io/PrintStream;",
+ " bipush 42",
+ " invokevirtual java/io/PrintStream/println(I)V",
+ " return");
+
+ ClassBuilder subClass = builder.addClass("SubClass", "SuperClass");
+ subClass.addDefaultConstructor();
+ subClass.addPrivateVirtualMethod("aMethod", emptyList(), "V",
+ ".limit stack 2",
+ ".limit locals 1",
+ " getstatic java/lang/System/out Ljava/io/PrintStream;",
+ " bipush 123",
+ " invokevirtual java/io/PrintStream/println(I)V",
+ " return");
+
+ ClassBuilder mainClass = builder.addClass(MAIN_CLASS);
+ mainClass.addMainMethod(
+ ".limit stack 2",
+ ".limit locals 1",
+ " new SubClass",
+ " dup",
+ " invokespecial SubClass/<init>()V",
+ " invokevirtual SubClass/aMethod()V",
+ " return");
+ ensureIAEExceptJava(builder);
+ }
+
+ @Test
+ @Ignore("b/69152228")
+ public void lookupDirectMethodFromWrongContext() throws Exception {
+ JasminBuilder builder = new JasminBuilder();
+
+ ClassBuilder superClass = builder.addClass("SuperClass");
+ superClass.addDefaultConstructor();
+ superClass.addVirtualMethod("aMethod", emptyList(), "V",
+ ".limit stack 2",
+ ".limit locals 1",
+ " getstatic java/lang/System/out Ljava/io/PrintStream;",
+ " bipush 42",
+ " invokevirtual java/io/PrintStream/println(I)V",
+ " return");
+
+ ClassBuilder subClass = builder.addClass("SubClass", "SuperClass");
+ subClass.addDefaultConstructor();
+ subClass.addPrivateVirtualMethod("aMethod", emptyList(), "V",
+ ".limit stack 2",
+ ".limit locals 1",
+ " getstatic java/lang/System/out Ljava/io/PrintStream;",
+ " bipush 123",
+ " invokevirtual java/io/PrintStream/println(I)V",
+ " return");
+
+ ClassBuilder mainClass = builder.addClass(MAIN_CLASS);
+ mainClass.addMainMethod(
+ ".limit stack 2",
+ ".limit locals 1",
+ " new SubClass",
+ " dup",
+ " invokespecial SubClass/<init>()V",
+ " invokespecial SubClass/aMethod()V",
+ " return");
+ ensureIAEExceptJava(builder);
+ }
+
+ @Test
+ public void lookupPrivateSuperFromSubClass() throws Exception {
+ JasminBuilder builder = new JasminBuilder(ClassFileVersion.JSE_5);
+
+ ClassBuilder superClass = builder.addClass("SuperClass");
+ superClass.addDefaultConstructor();
+ superClass.addPrivateVirtualMethod("aMethod", emptyList(), "V",
+ ".limit stack 2",
+ ".limit locals 1",
+ " getstatic java/lang/System/out Ljava/io/PrintStream;",
+ " bipush 42",
+ " invokevirtual java/io/PrintStream/println(I)V",
+ " return");
+
+ ClassBuilder subClass = builder.addClass("SubClass", "SuperClass");
+ subClass.addDefaultConstructor();
+ subClass.addVirtualMethod("callAMethod", emptyList(), "V",
+ ".limit stack 1",
+ ".limit locals 1",
+ " aload 0",
+ " invokespecial SuperClass/aMethod()V",
+ " return");
+
+ ClassBuilder mainClass = builder.addClass(MAIN_CLASS);
+ mainClass.addMainMethod(
+ ".limit stack 2",
+ ".limit locals 1",
+ " new SubClass",
+ " dup",
+ " invokespecial SubClass/<init>()V",
+ " invokevirtual SubClass/callAMethod()V",
+ " return");
+
+ ensureIAEExceptJava(builder);
+ }
+
+ @Test
+ @Ignore("b/69101406")
+ public void lookupStaticMethodWithConflictingVirtual() throws Exception {
+ JasminBuilder builder = new JasminBuilder();
+
+ ClassBuilder superClass = builder.addClass("SuperClass");
+ superClass.addDefaultConstructor();
+ superClass.addStaticMethod("aMethod", emptyList(), "V",
+ ".limit stack 2",
+ ".limit locals 1",
+ " getstatic java/lang/System/out Ljava/io/PrintStream;",
+ " bipush 42",
+ " invokevirtual java/io/PrintStream/println(I)V",
+ " return");
+
+ ClassBuilder subClass = builder.addClass("SubClass", "SuperClass");
+ subClass.addDefaultConstructor();
+ subClass.addVirtualMethod("aMethod", emptyList(), "V",
+ ".limit stack 2",
+ ".limit locals 1",
+ " getstatic java/lang/System/out Ljava/io/PrintStream;",
+ " bipush 123",
+ " invokevirtual java/io/PrintStream/println(I)V",
+ " return");
+
+ ClassBuilder mainClass = builder.addClass(MAIN_CLASS);
+ mainClass.addMainMethod(
+ ".limit stack 2",
+ ".limit locals 1",
+ " new SubClass",
+ " dup",
+ " invokespecial SubClass/<init>()V",
+ " invokestatic SubClass/aMethod()V",
+ " return");
+ ensureICCE(builder);
+ }
+
+ @Test
+ @Ignore("b/69101406")
+ public void lookupVirtualMethodWithConflictingStatic() throws Exception {
+ JasminBuilder builder = new JasminBuilder();
+
+ ClassBuilder superClass = builder.addClass("SuperClass");
+ superClass.addDefaultConstructor();
+ superClass.addVirtualMethod("aMethod", emptyList(), "V",
+ ".limit stack 2",
+ ".limit locals 1",
+ " getstatic java/lang/System/out Ljava/io/PrintStream;",
+ " bipush 42",
+ " invokevirtual java/io/PrintStream/println(I)V",
+ " return");
+
+ ClassBuilder subClass = builder.addClass("SubClass", "SuperClass");
+ subClass.addDefaultConstructor();
+ subClass.addStaticMethod("aMethod", emptyList(), "V",
+ ".limit stack 2",
+ ".limit locals 1",
+ " getstatic java/lang/System/out Ljava/io/PrintStream;",
+ " bipush 123",
+ " invokevirtual java/io/PrintStream/println(I)V",
+ " return");
+
+ ClassBuilder mainClass = builder.addClass(MAIN_CLASS);
+ mainClass.addMainMethod(
+ ".limit stack 2",
+ ".limit locals 1",
+ " new SubClass",
+ " dup",
+ " invokespecial SubClass/<init>()V",
+ " invokevirtual SubClass/aMethod()V",
+ " return");
+ ensureICCE(builder);
+ }
private void ensureSameOutput(JasminBuilder app) throws Exception {
String dxOutput = runOnArtDx(app, MAIN_CLASS);
@@ -130,13 +315,23 @@
}
private void ensureICCE(JasminBuilder app) throws Exception {
+ ensureRuntimeException(app, IncompatibleClassChangeError.class);
+ }
+
+ private void ensureIAEExceptJava(JasminBuilder app)
+ throws Exception {
+ ensureRuntimeException(app, IllegalAccessError.class);
+ }
+
+ private void ensureRuntimeException(JasminBuilder app, Class exception) throws Exception {
+ String name = exception.getSimpleName();
ProcessResult dxOutput = runOnArtDxRaw(app, MAIN_CLASS);
- Assert.assertTrue(dxOutput.stderr.contains("IncompatibleClassChangeError"));
+ Assert.assertTrue(dxOutput.stderr.contains(name));
ProcessResult d8Output = runOnArtD8Raw(app, MAIN_CLASS);
- Assert.assertTrue(d8Output.stderr.contains("IncompatibleClassChangeError"));
+ Assert.assertTrue(d8Output.stderr.contains(name));
ProcessResult r8Output = runOnArtR8Raw(app, MAIN_CLASS, null);
- Assert.assertTrue(r8Output.stderr.contains("IncompatibleClassChangeError"));
+ Assert.assertTrue(r8Output.stderr.contains(name));
ProcessResult javaOutput = runOnJavaRaw(app, MAIN_CLASS);
- Assert.assertTrue(javaOutput.stderr.contains("IncompatibleClassChangeError"));
+ Assert.assertTrue(javaOutput.stderr.contains(name));
}
}