test/hotspot/jtreg/runtime/Nestmates/methodSelection/TestMethodSelection.java
changeset 50735 2f2af62dfac7
equal deleted inserted replaced
50734:0828a0f6676b 50735:2f2af62dfac7
       
     1 /*
       
     2  * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 /*
       
    25  * @test
       
    26  * @bug 8046171
       
    27  * @summary Test method selection process for private/public nestmate invocation
       
    28  * @compile TestMethodSelection.java
       
    29  * @compile PB_A.jcod \
       
    30  *          PC_B_A.jcod \
       
    31  *          PC_B_PA.jcod \
       
    32  *          PC_PB_A.jcod
       
    33  * @run main/othervm TestMethodSelection
       
    34  * @run main/othervm -Dsun.reflect.noInflation=true TestMethodSelection
       
    35  */
       
    36 
       
    37 // The first run will use NativeMethodAccessor and due to the limited number
       
    38 // of calls we will not reach the inflation threshold.
       
    39 // The second run disables inflation so we will use the GeneratedMethodAccessor
       
    40 // instead. In this way both sets of Reflection classes are tested.
       
    41 
       
    42 /*
       
    43 We are setting up a basic test structure as follows:
       
    44 
       
    45 class A {
       
    46   ?? String m() { return "A::m"; }
       
    47 }
       
    48 class B extends A {
       
    49   ?? String m() { return "B::m"; }
       
    50 }
       
    51 class C extends B {
       
    52   ?? String m() { return "C::m"; }
       
    53 }
       
    54 
       
    55 where the access modifier of m() is either public or private in all combinations.
       
    56 The only cases of interest here are private and non-private, so we use public for
       
    57 the non-private case.
       
    58 
       
    59 We then have a test function:
       
    60 
       
    61 void test(B target, String expected) {
       
    62   check(target.m() == expected);
       
    63 }
       
    64 
       
    65 where the call to target.m() is expressed as an invokevirtual B::m on target. We
       
    66 then pass either a B instance or a C instance and check that the expected method
       
    67 is invoked. In all cases the resolved method is B::m, so we are effectively
       
    68 testing the method selection rules. We are not testing resolution here.
       
    69 
       
    70 The expected behaviour is as follows (where P means m() is private and - means
       
    71 m() is public).
       
    72 
       
    73 Target  A.m  B.m  C.m     Result   Reason
       
    74 ------------------------------------------
       
    75  B       P    P   n/a      B.m       [1]
       
    76  B       P    -   n/a      B.m       [2]
       
    77  B       -    P   n/a      B.m       [1]
       
    78  B       -    -   n/a      B.m       [2]
       
    79  C       P    P    P       B.m       [1]
       
    80  C       P    P    -       B.m       [1]
       
    81  C       P    -    P       B.m       [3]
       
    82  C       P    -    -       C.m       [2]
       
    83  c       -    P    P       B.m       [1]
       
    84  C       -    P    -       B.m       [1]
       
    85  C       -    -    P       B.m       [3]
       
    86  C       -    -    -       C.m       [2]
       
    87 
       
    88 [1] Resolved method is private => selected method == resolved method
       
    89 [2] target-type.m() can override B.m => selected method == target-type.m()
       
    90 [3] private C.m does not override resolved public method B.m, but
       
    91     C has a superclass B, with B.m that (trivially) overrides resolved B.m
       
    92     => selected method = B.m
       
    93 
       
    94 To allow us to do this in source code we encode the inheritance hierarchy in the
       
    95 class name, and we use plain A (for example) when m() is public and PA when m()
       
    96 is private. So class C_B_A defines a public m() and inherits public m() from
       
    97 both B and A. While PC_PB_PA defines a private m() and also has private m()
       
    98 defined in its superclasses PB and PA.
       
    99 
       
   100 For cases where the subclass makes a public method private we can't write this
       
   101 directly in Java source code so we have to have jcod versions that change
       
   102 the access modifier to private. This occurs for:
       
   103 
       
   104 - PC_B_A
       
   105 - PB_A
       
   106 - PC_B_PA
       
   107 - PC_PB_A
       
   108 
       
   109 We test direct invocation from Java source, MethodHandle invocation and core
       
   110 reflection invocation. For MH and reflection we look for the method in "B" to
       
   111 maintain the same resolution process as in the direct case.
       
   112 */
       
   113 
       
   114 import java.lang.invoke.*;
       
   115 import static java.lang.invoke.MethodHandles.*;
       
   116 import static java.lang.invoke.MethodType.*;
       
   117 import java.lang.reflect.InvocationTargetException;
       
   118 
       
   119 public class TestMethodSelection {
       
   120 
       
   121     static final MethodType M_T = MethodType.methodType(String.class);
       
   122 
       
   123     static class A {
       
   124         public String m() { return "A::m"; }
       
   125     }
       
   126     static class PA {
       
   127         private String m() { return "PA::m"; }
       
   128     }
       
   129 
       
   130     static class B_A extends A {
       
   131         public String m() { return "B_A::m"; }
       
   132     }
       
   133     static class B_PA extends PA {
       
   134         public String m() { return "B_PA::m"; }
       
   135     }
       
   136     // jcod version will rewrite this to have private m()
       
   137     static class PB_A extends A {
       
   138         public String m() { return "PB_A::m"; }
       
   139     }
       
   140     static class PB_PA extends PA {
       
   141         private String m() { return "PB_PA::m"; }
       
   142     }
       
   143 
       
   144     static class C_B_A extends B_A {
       
   145         public String m() { return "C_B_A::m"; }
       
   146     }
       
   147     // jcod version will rewrite this to have private m()
       
   148     static class PC_B_A extends B_A {
       
   149         public String m() { return "PC_B_A"; }
       
   150     }
       
   151     static class C_PB_A extends PB_A {
       
   152         public String m() { return "C_PB_A::m"; }
       
   153     }
       
   154     // jcod version will rewrite this to have private m()
       
   155     static class PC_PB_A extends PB_A {
       
   156         public String m() { return "PC_PB_A"; }
       
   157     }
       
   158     static class C_B_PA extends B_PA {
       
   159         public String m() { return "C_B_PA::m"; }
       
   160     }
       
   161     // jcod version will rewrite this to have private m()
       
   162     static class PC_B_PA extends B_PA {
       
   163         public String m() { return "PC_B_PA"; }
       
   164     }
       
   165     static class C_PB_PA extends PB_PA {
       
   166         public String m() { return "C_PB_PA::m"; }
       
   167     }
       
   168     static class PC_PB_PA extends PB_PA {
       
   169         private String m() { return "PC_PB_PA::m"; }
       
   170     }
       
   171 
       
   172     // Need a test function for each of the "B" classes
       
   173 
       
   174     static void doInvoke(B_A target, String expected) throws Throwable {
       
   175         // Direct
       
   176         check(target.m(), expected);
       
   177         // MethodHandle
       
   178         MethodHandle mh = lookup().findVirtual(B_A.class, "m", M_T);
       
   179         check((String)mh.invoke(target), expected);
       
   180         // Reflection
       
   181         check((String)B_A.class.getDeclaredMethod("m", new Class<?>[0]).
       
   182               invoke(target, new Object[0]), expected);
       
   183     }
       
   184     static void doInvoke(B_PA target, String expected) throws Throwable {
       
   185         // Direct
       
   186         check(target.m(), expected);
       
   187         // MethodHandle
       
   188         MethodHandle mh = lookup().findVirtual(B_PA.class, "m", M_T);
       
   189         check((String)mh.invoke(target), expected);
       
   190         // Reflection
       
   191         check((String)B_PA.class.getDeclaredMethod("m", new Class<?>[0]).
       
   192               invoke(target, new Object[0]), expected);
       
   193     }
       
   194     static void doInvoke(PB_A target, String expected) throws Throwable {
       
   195         // Direct
       
   196         check(target.m(), expected);
       
   197         // MethodHandle
       
   198         MethodHandle mh = lookup().findVirtual(PB_A.class, "m", M_T);
       
   199         check((String)mh.invoke(target), expected);
       
   200         // Reflection
       
   201         check((String)PB_A.class.getDeclaredMethod("m", new Class<?>[0]).
       
   202               invoke(target, new Object[0]), expected);
       
   203     }
       
   204     static void doInvoke(PB_PA target, String expected) throws Throwable {
       
   205         // Direct
       
   206         check(target.m(), expected);
       
   207         // MethodHandle
       
   208         MethodHandle mh = lookup().findVirtual(PB_PA.class, "m", M_T);
       
   209         check((String)mh.invoke(target), expected);
       
   210         // Reflection
       
   211         check((String)PB_PA.class.getDeclaredMethod("m", new Class<?>[0]).
       
   212               invoke(target, new Object[0]), expected);
       
   213     }
       
   214 
       
   215     static void check(String actual, String expected) {
       
   216         if (!actual.equals(expected)) {
       
   217                 throw new Error("Selection error: expected " + expected +
       
   218                                 " but got " + actual);
       
   219         }
       
   220     }
       
   221 
       
   222     public static void main(String[] args) throws Throwable {
       
   223         // First pass a suitable "B" instance
       
   224         doInvoke(new PB_PA(), "PB_PA::m");
       
   225         doInvoke(new B_PA(),  "B_PA::m");
       
   226         doInvoke(new PB_A(),  "PB_A::m");
       
   227         doInvoke(new B_A(),   "B_A::m");
       
   228         // Now a "C" instance
       
   229         doInvoke(new PC_PB_PA(), "PB_PA::m");
       
   230         doInvoke(new C_PB_PA(),  "PB_PA::m");
       
   231         doInvoke(new PC_B_PA(),  "B_PA::m");
       
   232         doInvoke(new C_B_PA(),   "C_B_PA::m");
       
   233         doInvoke(new PC_PB_A(),  "PB_A::m");
       
   234         doInvoke(new C_PB_A(),   "PB_A::m");
       
   235         doInvoke(new PC_B_A(),   "B_A::m");
       
   236         doInvoke(new C_B_A(),    "C_B_A::m");
       
   237     }
       
   238 }
       
   239 
       
   240 
       
   241 
       
   242