--- /dev/null 2018-04-28 00:26:07.190086997 -0400 +++ new/test/hotspot/jtreg/runtime/Nestmates/privateMethods/TestJNIHierarchy.java 2018-05-30 08:10:56.045132041 -0400 @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8046171 + * @summary Test access to private methods between nestmates where there + * is an inheritance hierarchy and we invoke private methods that + * exist in specific classes in the hierarchy. + * @compile ../NestmatesJNI.java + * @run main/othervm/native TestJNIHierarchy + * @run main/othervm/native -Xcheck:jni TestJNIHierarchy + */ + +public class TestJNIHierarchy { + + // Unlike reflection, the calling context is not relevant to JNI + // calls, but we keep the same structure as the reflection tests. + + static final String METHOD = "priv_invoke"; + + static class NestedA extends ExternalSuper { + static final String ID = "NestedA::priv_invoke"; + private String priv_invoke() { + return ID; + } + static void checkA(NestedA a) { + String res = NestmatesJNI.callStringVoid(a, + NestedA.class.getName(), + METHOD, + true); + verifyEquals(res, NestedA.ID); + res = NestmatesJNI.callStringVoid(a, + NestedA.class.getName(), + METHOD, + false); + verifyEquals(res, NestedA.ID); + } + } + + static class NestedB extends NestedA { + static final String ID = "NestedB::priv_invoke"; + private String priv_invoke() { + return ID; + } + static void checkA(NestedA a) { + String res = NestmatesJNI.callStringVoid(a, + NestedA.class.getName(), + METHOD, + true); + verifyEquals(res, NestedA.ID); + + res = NestmatesJNI.callStringVoid(a, + NestedA.class.getName(), + METHOD, + false); + verifyEquals(res, NestedA.ID); + } + } + + static class NestedC extends NestedB { + static final String ID = "NestedC::priv_invoke"; + private String priv_invoke() { + return ID; + } + static void checkA(NestedA a) { + String res = NestmatesJNI.callStringVoid(a, + NestedA.class.getName(), + METHOD, + true); + verifyEquals(res, NestedA.ID); + } + } + + static void checkA(NestedA a) { + String res = NestmatesJNI.callStringVoid(a, + NestedA.class.getName(), + METHOD, + true); + verifyEquals(res, NestedA.ID); + + res = NestmatesJNI.callStringVoid(a, + NestedA.class.getName(), + METHOD, + false); + verifyEquals(res, NestedA.ID); + } + + static void checkB(NestedB b) { + String res = NestmatesJNI.callStringVoid(b, + NestedB.class.getName(), + METHOD, + true); + verifyEquals(res, NestedB.ID); + + res = NestmatesJNI.callStringVoid(b, + NestedB.class.getName(), + METHOD, + false); + verifyEquals(res, NestedB.ID); + + } + + static void checkC(NestedC c) { + String res = NestmatesJNI.callStringVoid(c, + NestedC.class.getName(), + METHOD, + true); + verifyEquals(res, NestedC.ID); + + res = NestmatesJNI.callStringVoid(c, + NestedC.class.getName(), + METHOD, + false); + verifyEquals(res, NestedC.ID); + } + + + // Access to private members of classes outside the nest is + // not permitted in general, but JNI ignores all access checks. + + static void checkExternalSuper(ExternalSuper s) { + String res = NestmatesJNI.callStringVoid(s, + ExternalSuper.class.getName(), + METHOD, + true); + verifyEquals(res, ExternalSuper.ID); + + res = NestmatesJNI.callStringVoid(s, + ExternalSuper.class.getName(), + METHOD, + false); + verifyEquals(res, ExternalSuper.ID); + } + + static void checkExternalSub(ExternalSub s) { + String res = NestmatesJNI.callStringVoid(s, + ExternalSub.class.getName(), + METHOD, + true); + verifyEquals(res, ExternalSub.ID); + + res = NestmatesJNI.callStringVoid(s, + ExternalSub.class.getName(), + METHOD, + false); + verifyEquals(res, ExternalSub.ID); + } + + static void verifyEquals(String actual, String expected) { + if (!actual.equals(expected)) { + throw new Error("Expected " + expected + " but got " + actual); + } + System.out.println("Check passed for " + expected); + } + + public static void main(String[] args) { + NestedA a = new NestedA(); + NestedB b = new NestedB(); + NestedC c = new NestedC(); + ExternalSub sub = new ExternalSub(); + ExternalSuper sup = new ExternalSuper(); + + checkExternalSuper(sup); + checkExternalSuper(a); + checkExternalSuper(b); + checkExternalSuper(c); + checkExternalSuper(sub); + + checkA(a); + checkA(b); + checkA(c); + checkA(sub); + + NestedA.checkA(a); + NestedA.checkA(b); + NestedA.checkA(c); + NestedA.checkA(sub); + + NestedB.checkA(a); + NestedB.checkA(b); + NestedB.checkA(c); + NestedB.checkA(sub); + + NestedC.checkA(a); + NestedC.checkA(b); + NestedC.checkA(c); + NestedC.checkA(sub); + + checkB(b); + checkB(c); + checkB(sub); + + checkC(c); + checkC(sub); + + checkExternalSub(sub); + } +} + +// Classes that are not part of the nest. +// Being non-public allows us to declare them in this file. + +class ExternalSuper { + static final String ID = "ExternalSuper::priv_invoke"; + private String priv_invoke() { + return ID; + } +} + + +class ExternalSub extends TestJNIHierarchy.NestedC { + static final String ID = "ExternalSub::priv_invoke"; + private String priv_invoke() { + return ID; + } +}