8165827: Support private interface methods in JNI, JDWP, JDI and JDB
authordholmes
Tue, 18 Oct 2016 20:03:17 -0400
changeset 41742 9ecf02bc1662
parent 41740 5ce9b71d69d4
child 41743 39d7567a68d4
8165827: Support private interface methods in JNI, JDWP, JDI and JDB Reviewed-by: dcubed, lfoltan, sspitsyn
hotspot/test/runtime/jni/PrivateInterfaceMethods/PrivateInterfaceMethods.java
hotspot/test/runtime/jni/PrivateInterfaceMethods/libPrivateInterfaceMethods.c
--- a/hotspot/test/runtime/jni/PrivateInterfaceMethods/PrivateInterfaceMethods.java	Tue Oct 18 17:38:17 2016 -0400
+++ b/hotspot/test/runtime/jni/PrivateInterfaceMethods/PrivateInterfaceMethods.java	Tue Oct 18 20:03:17 2016 -0400
@@ -22,7 +22,7 @@
  */
 
 /* @test
- * @bug 8081800
+ * @bug 8081800 8165827
  * @summary Add JNI invocation tests for private interface methods
  * @run main/native PrivateInterfaceMethods
  */
@@ -34,19 +34,23 @@
     }
 
     static native int callIntVoid(Object target, String definingClassName, String methodName, boolean virtual);
+    static native void lookupIntVoid(String definingClassName, String methodName);
 
     static interface A {
         static final int AmResult = 1;
         private int m() { return AmResult; }
+        private int onlyA() { return 0; }
     }
 
     static interface B extends A {
         // No m() here
+        private int onlyB() { return 0; }
     }
 
     static interface C extends B {
         static final int CmResult = 2;
         private int m() { return CmResult; }  // unrelated to A.m
+        private int onlyC() { return 0; }
     }
 
     public static class Impl implements C {
@@ -62,6 +66,29 @@
     }
 
     public static void main(String[] args) {
+
+        // JNI getMethodID only works for methods declared in or inherited by a type.
+        // Private interface methods are not inherited and so should only be found
+        // in the declaring interface.
+
+        lookup(A.class.getName(), "onlyA", null); // should succeed
+        lookup(B.class.getName(), "onlyA", NoSuchMethodError.class); // should fail
+        lookup(C.class.getName(), "onlyA", NoSuchMethodError.class); // should fail
+        lookup(Impl.class.getName(), "onlyA", NoSuchMethodError.class); // should fail
+        lookup(Impl2.class.getName(), "onlyA", NoSuchMethodError.class); // should fail
+
+        lookup(B.class.getName(), "onlyB", null); // should succeed
+        lookup(A.class.getName(), "onlyB", NoSuchMethodError.class); // should fail
+        lookup(C.class.getName(), "onlyB", NoSuchMethodError.class); // should fail
+        lookup(Impl.class.getName(), "onlyB", NoSuchMethodError.class); // should fail
+        lookup(Impl2.class.getName(), "onlyB", NoSuchMethodError.class); // should fail
+
+        lookup(C.class.getName(), "onlyC", null); // should succeed
+        lookup(A.class.getName(), "onlyC", NoSuchMethodError.class); // should fail
+        lookup(B.class.getName(), "onlyC", NoSuchMethodError.class); // should fail
+        lookup(Impl.class.getName(), "onlyC", NoSuchMethodError.class); // should fail
+        lookup(Impl2.class.getName(), "onlyC", NoSuchMethodError.class); // should fail
+
         Impl impl = new Impl();
 
         // Note: JNI doesn't enforce access control so we can make
@@ -106,6 +133,25 @@
         test(impl2, Impl2.class.getName(), "m", -1, false, NoSuchMethodError.class);
     }
 
+    static void lookup(String definingClass, String method, Class<?> expectedException) {
+
+        String desc = "Lookup of " + definingClass + "." + method;
+        try {
+            lookupIntVoid(definingClass, method);
+            if (expectedException != null)
+                throw new Error(desc + " succeeded - but expected exception "
+                                + expectedException.getSimpleName());
+            System.out.println(desc + " - passed");
+        }
+        catch (Throwable t) {
+           if (t.getClass() != expectedException)
+               throw new Error(desc + " failed: got exception " + t + " but expected exception "
+                               + expectedException.getSimpleName());
+           else
+              System.out.println(desc + " threw " + expectedException.getSimpleName() + " as expected");
+        }
+    }
+
     static void test(Object target, String definingClass, String method,
                      int expected, boolean virtual, Class<?> expectedException) {
 
@@ -115,16 +161,19 @@
         try {
             int res = callIntVoid(target, definingClass, method, virtual);
             if (expectedException != null)
-                throw new Error(desc + " succeeded - but expected exception " + expectedException.getSimpleName());
+                throw new Error(desc + " succeeded - but expected exception "
+                                + expectedException.getSimpleName());
             if (res != expected)
                 throw new Error(desc + " got wrong result: " + res + " instead of " + expected);
             System.out.println(desc + " - passed");
         }
         catch (Throwable t) {
            if (t.getClass() != expectedException)
-               throw new Error(desc + " failed", t);
+               throw new Error(desc + " failed: got exception " + t + " but expected exception "
+                               + expectedException.getSimpleName());
            else
               System.out.println(desc + " threw " + expectedException.getSimpleName() + " as expected");
         }
     }
+
 }
--- a/hotspot/test/runtime/jni/PrivateInterfaceMethods/libPrivateInterfaceMethods.c	Tue Oct 18 17:38:17 2016 -0400
+++ b/hotspot/test/runtime/jni/PrivateInterfaceMethods/libPrivateInterfaceMethods.c	Tue Oct 18 20:03:17 2016 -0400
@@ -52,3 +52,27 @@
     else
         return (*env)->CallIntMethod(env, impl, m_id);
 }
+
+// Private interface methods lookup test
+JNIEXPORT void JNICALL
+Java_PrivateInterfaceMethods_lookupIntVoid(JNIEnv *env, jclass unused,
+                                           jstring defining_class_name, jstring method_name) {
+
+    // Lookup int method_name() in defining_class_name
+
+    jmethodID m_id = NULL;
+    jclass clazz = NULL;
+    const char* name = NULL;
+
+    name = (*env)->GetStringUTFChars(env, defining_class_name, NULL);
+    if (name == NULL) return;
+    clazz = (*env)->FindClass(env, name);
+    (*env)->ReleaseStringUTFChars(env, defining_class_name, name);
+    if ((*env)->ExceptionCheck(env)) return;
+
+    name = (*env)->GetStringUTFChars(env, method_name, NULL);
+    if (name == NULL) return;
+    m_id = (*env)->GetMethodID(env, clazz, name, "()I");
+    (*env)->ReleaseStringUTFChars(env, method_name, name);
+}
+