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