Merge "[DexSplitter] Maintain old API surface."
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 2f1d3fd..e403c14 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -440,9 +440,7 @@
private static class CreateMethodVisitor extends MethodVisitor {
- private final int access;
private final String name;
- private final String desc;
final CreateDexClassVisitor parent;
private final int parameterCount;
private List<DexAnnotation> annotations = null;
@@ -458,9 +456,7 @@
public CreateMethodVisitor(int access, String name, String desc, String signature,
String[] exceptions, CreateDexClassVisitor parent) {
super(ASM6);
- this.access = access;
this.name = name;
- this.desc = desc;
this.parent = parent;
this.method = parent.application.getMethod(parent.type, name, desc);
this.flags = createMethodAccessFlags(name, access);
@@ -564,8 +560,7 @@
@Override
public void visitCode() {
- assert !flags.isAbstract() && !flags.isNative();
- if (parent.classKind == ClassKind.PROGRAM) {
+ if (!flags.isAbstract() && !flags.isNative() && parent.classKind == ClassKind.PROGRAM) {
if (parent.application.options.enableCfFrontend) {
code = new LazyCfCode(method, parent.origin, parent.context, parent.application);
} else {
diff --git a/src/test/java/com/android/tools/r8/code/ClassWithNativeMethodTest.java b/src/test/java/com/android/tools/r8/code/ClassWithNativeMethodTest.java
new file mode 100644
index 0000000..293485a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/code/ClassWithNativeMethodTest.java
@@ -0,0 +1,87 @@
+// Copyright (c) 2018, 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.code;
+
+import static com.android.tools.r8.utils.DexInspectorMatchers.isPresent;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.VmTestRunner;
+import com.android.tools.r8.jasmin.JasminBuilder;
+import com.android.tools.r8.jasmin.JasminBuilder.ClassBuilder;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.DexInspector;
+import com.android.tools.r8.utils.DexInspector.ClassSubject;
+import com.android.tools.r8.utils.DexInspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(VmTestRunner.class)
+public class ClassWithNativeMethodTest extends TestBase {
+
+ @Test
+ public void test() throws Exception {
+ JasminBuilder jasminBuilder = new JasminBuilder();
+
+ ClassBuilder cls = jasminBuilder.addClass("Main");
+ cls.addDefaultConstructor();
+ cls.addVirtualMethod("foo", ImmutableList.of("Ljava/lang/String;"), "V",
+ ".limit stack 3",
+ ".limit locals 2",
+ "getstatic java/lang/System/out Ljava/io/PrintStream;",
+ "aload_1",
+ "invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V",
+ "return");
+ cls.addNativeMethod("n1", ImmutableList.of("Ljava/lang/String;"), "V",
+ "return");
+ cls.addNativeMethod("n2", ImmutableList.of("Ljava/lang/String;"), "V",
+ "return");
+ cls.addNativeMethod("n3", ImmutableList.of("Ljava/lang/String;"), "V",
+ "return");
+ cls.addNativeMethod("n4", ImmutableList.of("Ljava/lang/String;"), "V",
+ "return");
+ cls.addMainMethod(
+ ".limit stack 4",
+ ".limit locals 2",
+ "new " + cls.name,
+ "dup",
+ "invokespecial " + cls.name + "/<init>()V",
+ "astore_0",
+ "aload_0",
+ "ldc \"foo\"",
+ "invokevirtual " + cls.name + "/foo(Ljava/lang/String;)V",
+ "return");
+
+ String mainClassName = cls.name;
+
+ Path outputDirectory = temp.newFolder().toPath();
+ jasminBuilder.writeClassFiles(outputDirectory);
+ ProcessResult javaResult = ToolHelper.runJava(outputDirectory, mainClassName);
+ // Native .o is not given. Expect to see JNI error.
+ assertNotEquals(0, javaResult.exitCode);
+ assertThat(javaResult.stderr, containsString("JNI"));
+
+ AndroidApp processedApp = compileWithD8(jasminBuilder.build());
+
+ DexInspector inspector = new DexInspector(processedApp);
+ ClassSubject mainSubject = inspector.clazz(cls.name);
+ MethodSubject nativeMethod =
+ mainSubject.method("void", "n1", ImmutableList.of("java.lang.String"));
+ assertThat(nativeMethod, isPresent());
+
+ ProcessResult artResult = runOnArtRaw(processedApp, mainClassName);
+ // ART can process main() even without native definitions.
+ assertEquals(0, artResult.exitCode);
+ assertThat(artResult.stdout, containsString("foo"));
+ }
+
+
+}
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 e5838c3..674fba8 100644
--- a/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
+++ b/src/test/java/com/android/tools/r8/jasmin/JasminBuilder.java
@@ -136,6 +136,15 @@
return addMethod("public", name, argumentTypes, returnType, lines);
}
+ public MethodSignature addNativeMethod(
+ String name,
+ List<String> argumentTypes,
+ String returnType,
+ String... lines) {
+ makeInit = true;
+ return addMethod("public static native", name, argumentTypes, returnType, lines);
+ }
+
public MethodSignature addBridgeMethod(
String name,
List<String> argumentTypes,