1 /* 2 * Copyright (c) 2014, 2015, 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 NullCheckDroppingsTest 26 * @bug 8054492 27 * @summary Casting can result in redundant null checks in generated code 28 * @requires vm.flavor == "server" 29 * @library /testlibrary /test/lib 30 * @modules java.base/jdk.internal.misc 31 * java.management 32 * 33 * @build ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.* 34 * @build compiler.intrinsics.klass.CastNullCheckDroppingsTest 35 * @run driver ClassFileInstaller sun.hotspot.WhiteBox 36 * sun.hotspot.WhiteBox$WhiteBoxPermission 37 * jdk.test.lib.Platform 38 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 39 * -Xmixed -XX:-BackgroundCompilation -XX:-TieredCompilation -XX:CompileThreshold=1000 40 * -XX:CompileCommand=exclude,compiler.intrinsics.klass.CastNullCheckDroppingsTest::runTest 41 * compiler.intrinsics.klass.CastNullCheckDroppingsTest 42 */ 43 44 package compiler.intrinsics.klass; 45 46 import jdk.test.lib.Platform; 47 import sun.hotspot.WhiteBox; 48 import sun.hotspot.code.NMethod; 49 50 import java.lang.invoke.MethodHandle; 51 import java.lang.invoke.MethodHandles; 52 import java.lang.invoke.MethodType; 53 import java.lang.reflect.Method; 54 import java.util.function.BiFunction; 55 56 public class CastNullCheckDroppingsTest { 57 58 private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 59 60 static final BiFunction<Class, Object, Object> fCast = (c, o) -> c.cast(o); 61 62 static final MethodHandle SET_SSINK; 63 static final MethodHandle MH_CAST; 64 65 static { 66 try { 67 SET_SSINK = MethodHandles.lookup().findSetter(CastNullCheckDroppingsTest.class, "ssink", String.class); 68 MH_CAST = MethodHandles.lookup().findVirtual(Class.class, 69 "cast", 70 MethodType.methodType(Object.class, Object.class)); 71 } 72 catch (Exception e) { 73 throw new Error(e); 74 } 75 } 76 77 static volatile String svalue = "A"; 78 static volatile String snull = null; 79 static volatile Integer iobj = new Integer(0); 80 static volatile int[] arr = new int[2]; 81 static volatile Class objClass = String.class; 82 static volatile Class nullClass = null; 83 84 String ssink; 85 Integer isink; 86 int[] asink; 87 88 public static void main(String[] args) throws Exception { 89 if (!Platform.isServer()) { 90 throw new Error("TESTBUG: Not server VM"); 91 } 92 // Make sure background compilation is disabled 93 if (WHITE_BOX.getBooleanVMFlag("BackgroundCompilation")) { 94 throw new Error("TESTBUG: Background compilation enabled"); 95 } 96 // Make sure Tiered compilation is disabled 97 if (WHITE_BOX.getBooleanVMFlag("TieredCompilation")) { 98 throw new Error("TESTBUG: Tiered compilation enabled"); 99 } 100 101 Method methodClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCast", String.class); 102 Method methodMHCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testMHCast", String.class); 103 Method methodMHSetter = CastNullCheckDroppingsTest.class.getDeclaredMethod("testMHSetter", String.class); 104 Method methodFunction = CastNullCheckDroppingsTest.class.getDeclaredMethod("testFunction", String.class); 105 106 CastNullCheckDroppingsTest t = new CastNullCheckDroppingsTest(); 107 t.runTest(methodClassCast, false); 108 t.runTest(methodMHCast, false); 109 t.runTest(methodMHSetter, false); 110 t.runTest(methodFunction, false); 111 112 // Edge cases 113 Method methodClassCastNull = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastNull", String.class); 114 Method methodNullClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testNullClassCast", String.class); 115 Method methodClassCastObj = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastObj", Object.class); 116 Method methodObjClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testObjClassCast", String.class); 117 Method methodVarClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testVarClassCast", String.class); 118 Method methodClassCastInt = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastInt", Object.class); 119 Method methodIntClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testIntClassCast", Object.class); 120 Method methodClassCastint = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastint", Object.class); 121 Method methodintClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testintClassCast", Object.class); 122 Method methodClassCastPrim = CastNullCheckDroppingsTest.class.getDeclaredMethod("testClassCastPrim", Object.class); 123 Method methodPrimClassCast = CastNullCheckDroppingsTest.class.getDeclaredMethod("testPrimClassCast", Object.class); 124 125 t.runTest(methodClassCastNull, false); 126 t.runTest(methodNullClassCast, false); 127 t.runTest(methodClassCastObj, false); 128 t.runTest(methodObjClassCast, true); 129 t.runTest(methodVarClassCast, true); 130 t.runTest(methodClassCastInt, false); 131 t.runTest(methodIntClassCast, true); 132 t.runTest(methodClassCastint, false); 133 t.runTest(methodintClassCast, false); 134 t.runTest(methodClassCastPrim, false); 135 t.runTest(methodPrimClassCast, true); 136 } 137 138 void testClassCast(String s) { 139 try { 140 ssink = String.class.cast(s); 141 } catch (Throwable t) { 142 throw new Error(t); 143 } 144 } 145 146 void testClassCastNull(String s) { 147 try { 148 ssink = String.class.cast(null); 149 } catch (Throwable t) { 150 throw new Error(t); 151 } 152 } 153 154 void testNullClassCast(String s) { 155 try { 156 ssink = (String)nullClass.cast(s); 157 throw new AssertionError("NullPointerException is not thrown"); 158 } catch (NullPointerException t) { 159 // Ignore NullPointerException 160 } catch (Throwable t) { 161 throw new Error(t); 162 } 163 } 164 165 void testClassCastObj(Object s) { 166 try { 167 ssink = String.class.cast(s); 168 } catch (Throwable t) { 169 throw new Error(t); 170 } 171 } 172 173 void testObjClassCast(String s) { 174 try { 175 ssink = (String)objClass.cast(s); 176 } catch (Throwable t) { 177 throw new Error(t); 178 } 179 } 180 181 void testVarClassCast(String s) { 182 Class cl = (s == null) ? null : String.class; 183 try { 184 ssink = (String)cl.cast(svalue); 185 if (s == null) { 186 throw new AssertionError("NullPointerException is not thrown"); 187 } 188 } catch (NullPointerException t) { 189 // Ignore NullPointerException 190 } catch (Throwable t) { 191 throw new Error(t); 192 } 193 } 194 195 void testClassCastInt(Object s) { 196 try { 197 ssink = String.class.cast(iobj); 198 throw new AssertionError("ClassCastException is not thrown"); 199 } catch (ClassCastException t) { 200 // Ignore ClassCastException: Cannot cast java.lang.Integer to java.lang.String 201 } catch (Throwable t) { 202 throw new Error(t); 203 } 204 } 205 206 void testIntClassCast(Object s) { 207 try { 208 isink = Integer.class.cast(s); 209 if (s != null) { 210 throw new AssertionError("ClassCastException is not thrown"); 211 } 212 } catch (ClassCastException t) { 213 // Ignore ClassCastException: Cannot cast java.lang.String to java.lang.Integer 214 } catch (Throwable t) { 215 throw new Error(t); 216 } 217 } 218 219 void testClassCastint(Object s) { 220 try { 221 ssink = String.class.cast(45); 222 throw new AssertionError("ClassCastException is not thrown"); 223 } catch (ClassCastException t) { 224 // Ignore ClassCastException: Cannot cast java.lang.Integer to java.lang.String 225 } catch (Throwable t) { 226 throw new Error(t); 227 } 228 } 229 230 void testintClassCast(Object s) { 231 try { 232 isink = int.class.cast(s); 233 if (s != null) { 234 throw new AssertionError("ClassCastException is not thrown"); 235 } 236 } catch (ClassCastException t) { 237 // Ignore ClassCastException: Cannot cast java.lang.String to java.lang.Integer 238 } catch (Throwable t) { 239 throw new Error(t); 240 } 241 } 242 243 void testClassCastPrim(Object s) { 244 try { 245 ssink = String.class.cast(arr); 246 throw new AssertionError("ClassCastException is not thrown"); 247 } catch (ClassCastException t) { 248 // Ignore ClassCastException: Cannot cast [I to java.lang.String 249 } catch (Throwable t) { 250 throw new Error(t); 251 } 252 } 253 254 void testPrimClassCast(Object s) { 255 try { 256 asink = int[].class.cast(s); 257 if (s != null) { 258 throw new AssertionError("ClassCastException is not thrown"); 259 } 260 } catch (ClassCastException t) { 261 // Ignore ClassCastException: Cannot cast java.lang.String to [I 262 } catch (Throwable t) { 263 throw new Error(t); 264 } 265 } 266 267 void testMHCast(String s) { 268 try { 269 ssink = (String) (Object) MH_CAST.invokeExact(String.class, (Object) s); 270 } catch (Throwable t) { 271 throw new Error(t); 272 } 273 } 274 275 void testMHSetter(String s) { 276 try { 277 SET_SSINK.invokeExact(this, s); 278 } catch (Throwable t) { 279 throw new Error(t); 280 } 281 } 282 283 void testFunction(String s) { 284 try { 285 ssink = (String) fCast.apply(String.class, s); 286 } catch (Throwable t) { 287 throw new Error(t); 288 } 289 } 290 291 void runTest(Method method, boolean deopt) { 292 if (method == null) { 293 throw new AssertionError("method was not found"); 294 } 295 // Ensure method is compiled 296 WHITE_BOX.testSetDontInlineMethod(method, true); 297 for (int i = 0; i < 3000; i++) { 298 try { 299 method.invoke(this, svalue); 300 } catch (Exception e) { 301 throw new Error("Unexpected exception: ", e); 302 } 303 } 304 NMethod nm = getNMethod(method); 305 306 // Passing null should cause a de-optimization 307 // if method is compiled with a null-check. 308 try { 309 method.invoke(this, snull); 310 } catch (Exception e) { 311 throw new Error("Unexpected exception: ", e); 312 } 313 checkDeoptimization(method, nm, deopt); 314 } 315 316 static NMethod getNMethod(Method test) { 317 // Because background compilation is disabled, method should now be compiled 318 if (!WHITE_BOX.isMethodCompiled(test)) { 319 throw new AssertionError(test + " not compiled"); 320 } 321 322 NMethod nm = NMethod.get(test, false); // not OSR nmethod 323 if (nm == null) { 324 throw new AssertionError(test + " missing nmethod?"); 325 } 326 if (nm.comp_level != 4) { 327 throw new AssertionError(test + " compiled by not C2: " + nm); 328 } 329 return nm; 330 } 331 332 static void checkDeoptimization(Method method, NMethod nmOrig, boolean deopt) { 333 // Check deoptimization event (intrinsic Class.cast() works). 334 if (WHITE_BOX.isMethodCompiled(method) == deopt) { 335 throw new AssertionError(method + " was" + (deopt ? " not" : "") + " deoptimized"); 336 } 337 if (deopt) { 338 return; 339 } 340 // Ensure no recompilation when no deoptimization is expected. 341 NMethod nm = NMethod.get(method, false); // not OSR nmethod 342 if (nm == null) { 343 throw new AssertionError(method + " missing nmethod?"); 344 } 345 if (nm.comp_level != 4) { 346 throw new AssertionError(method + " compiled by not C2: " + nm); 347 } 348 if (nm.compile_id != nmOrig.compile_id) { 349 throw new AssertionError(method + " was recompiled: old nmethod=" + nmOrig + ", new nmethod=" + nm); 350 } 351 } 352 }