1 /* 2 * Copyright (c) 2016, 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 * @summary tests on constant folding of unsafe get operations from stable arrays 27 * @library /test/lib 28 * @build sun.hotspot.WhiteBox 29 * @requires vm.flavor == "server" & !vm.emulatedClient 30 * 31 * @modules java.base/jdk.internal.vm.annotation 32 * java.base/jdk.internal.misc 33 * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox 34 * 35 * @run main/bootclasspath/othervm -XX:+UnlockDiagnosticVMOptions 36 * -Xbatch -XX:-TieredCompilation 37 * -XX:+FoldStableValues 38 * -XX:+WhiteBoxAPI 39 * -XX:CompileCommand=dontinline,*Test::test* 40 * compiler.unsafe.UnsafeGetStableArrayElement 41 */ 42 43 package compiler.unsafe; 44 45 import jdk.internal.misc.Unsafe; 46 import jdk.internal.vm.annotation.Stable; 47 import jdk.test.lib.Platform; 48 49 import java.util.concurrent.Callable; 50 51 import static jdk.internal.misc.Unsafe.*; 52 import static jdk.test.lib.Asserts.assertEQ; 53 import static jdk.test.lib.Asserts.assertNE; 54 55 import sun.hotspot.code.Compiler; 56 57 public class UnsafeGetStableArrayElement { 58 @Stable static final boolean[] STABLE_BOOLEAN_ARRAY = new boolean[16]; 59 @Stable static final byte[] STABLE_BYTE_ARRAY = new byte[16]; 60 @Stable static final short[] STABLE_SHORT_ARRAY = new short[8]; 61 @Stable static final char[] STABLE_CHAR_ARRAY = new char[8]; 62 @Stable static final int[] STABLE_INT_ARRAY = new int[4]; 63 @Stable static final long[] STABLE_LONG_ARRAY = new long[2]; 64 @Stable static final float[] STABLE_FLOAT_ARRAY = new float[4]; 65 @Stable static final double[] STABLE_DOUBLE_ARRAY = new double[2]; 66 @Stable static final Object[] STABLE_OBJECT_ARRAY = new Object[4]; 67 68 static { Setter.reset()69 Setter.reset(); 70 } 71 static final Unsafe U = Unsafe.getUnsafe(); 72 73 static class Setter { setZ(boolean defaultVal)74 private static void setZ(boolean defaultVal) { STABLE_BOOLEAN_ARRAY[0] = defaultVal ? false : true; } setB(boolean defaultVal)75 private static void setB(boolean defaultVal) { STABLE_BYTE_ARRAY[0] = defaultVal ? 0 : Byte.MAX_VALUE; } setS(boolean defaultVal)76 private static void setS(boolean defaultVal) { STABLE_SHORT_ARRAY[0] = defaultVal ? 0 : Short.MAX_VALUE; } setC(boolean defaultVal)77 private static void setC(boolean defaultVal) { STABLE_CHAR_ARRAY[0] = defaultVal ? 0 : Character.MAX_VALUE; } setI(boolean defaultVal)78 private static void setI(boolean defaultVal) { STABLE_INT_ARRAY[0] = defaultVal ? 0 : Integer.MAX_VALUE; } setJ(boolean defaultVal)79 private static void setJ(boolean defaultVal) { STABLE_LONG_ARRAY[0] = defaultVal ? 0 : Long.MAX_VALUE; } setF(boolean defaultVal)80 private static void setF(boolean defaultVal) { STABLE_FLOAT_ARRAY[0] = defaultVal ? 0 : Float.MAX_VALUE; } setD(boolean defaultVal)81 private static void setD(boolean defaultVal) { STABLE_DOUBLE_ARRAY[0] = defaultVal ? 0 : Double.MAX_VALUE; } setL(boolean defaultVal)82 private static void setL(boolean defaultVal) { STABLE_OBJECT_ARRAY[0] = defaultVal ? null : new Object(); } 83 reset()84 static void reset() { 85 setZ(false); 86 setB(false); 87 setS(false); 88 setC(false); 89 setI(false); 90 setJ(false); 91 setF(false); 92 setD(false); 93 setL(false); 94 } 95 } 96 97 static class Test { changeZ()98 static void changeZ() { Setter.setZ(true); } changeB()99 static void changeB() { Setter.setB(true); } changeS()100 static void changeS() { Setter.setS(true); } changeC()101 static void changeC() { Setter.setC(true); } changeI()102 static void changeI() { Setter.setI(true); } changeJ()103 static void changeJ() { Setter.setJ(true); } changeF()104 static void changeF() { Setter.setF(true); } changeD()105 static void changeD() { Setter.setD(true); } changeL()106 static void changeL() { Setter.setL(true); } 107 testZ_Z()108 static boolean testZ_Z() { return U.getBoolean(STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } testZ_B()109 static byte testZ_B() { return U.getByte( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } testZ_S()110 static short testZ_S() { return U.getShort( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } testZ_C()111 static char testZ_C() { return U.getChar( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } testZ_I()112 static int testZ_I() { return U.getInt( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } testZ_J()113 static long testZ_J() { return U.getLong( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } testZ_F()114 static float testZ_F() { return U.getFloat( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } testZ_D()115 static double testZ_D() { return U.getDouble( STABLE_BOOLEAN_ARRAY, ARRAY_BOOLEAN_BASE_OFFSET); } 116 testB_Z()117 static boolean testB_Z() { return U.getBoolean(STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } testB_B()118 static byte testB_B() { return U.getByte( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } testB_S()119 static short testB_S() { return U.getShort( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } testB_C()120 static char testB_C() { return U.getChar( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } testB_I()121 static int testB_I() { return U.getInt( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } testB_J()122 static long testB_J() { return U.getLong( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } testB_F()123 static float testB_F() { return U.getFloat( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } testB_D()124 static double testB_D() { return U.getDouble( STABLE_BYTE_ARRAY, ARRAY_BYTE_BASE_OFFSET); } 125 testS_Z()126 static boolean testS_Z() { return U.getBoolean(STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } testS_B()127 static byte testS_B() { return U.getByte( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } testS_S()128 static short testS_S() { return U.getShort( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } testS_C()129 static char testS_C() { return U.getChar( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } testS_I()130 static int testS_I() { return U.getInt( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } testS_J()131 static long testS_J() { return U.getLong( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } testS_F()132 static float testS_F() { return U.getFloat( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } testS_D()133 static double testS_D() { return U.getDouble( STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET); } 134 testC_Z()135 static boolean testC_Z() { return U.getBoolean(STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } testC_B()136 static byte testC_B() { return U.getByte( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } testC_S()137 static short testC_S() { return U.getShort( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } testC_C()138 static char testC_C() { return U.getChar( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } testC_I()139 static int testC_I() { return U.getInt( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } testC_J()140 static long testC_J() { return U.getLong( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } testC_F()141 static float testC_F() { return U.getFloat( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } testC_D()142 static double testC_D() { return U.getDouble( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET); } 143 testI_Z()144 static boolean testI_Z() { return U.getBoolean(STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } testI_B()145 static byte testI_B() { return U.getByte( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } testI_S()146 static short testI_S() { return U.getShort( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } testI_C()147 static char testI_C() { return U.getChar( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } testI_I()148 static int testI_I() { return U.getInt( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } testI_J()149 static long testI_J() { return U.getLong( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } testI_F()150 static float testI_F() { return U.getFloat( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } testI_D()151 static double testI_D() { return U.getDouble( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET); } 152 testJ_Z()153 static boolean testJ_Z() { return U.getBoolean(STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } testJ_B()154 static byte testJ_B() { return U.getByte( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } testJ_S()155 static short testJ_S() { return U.getShort( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } testJ_C()156 static char testJ_C() { return U.getChar( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } testJ_I()157 static int testJ_I() { return U.getInt( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } testJ_J()158 static long testJ_J() { return U.getLong( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } testJ_F()159 static float testJ_F() { return U.getFloat( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } testJ_D()160 static double testJ_D() { return U.getDouble( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET); } 161 testF_Z()162 static boolean testF_Z() { return U.getBoolean(STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } testF_B()163 static byte testF_B() { return U.getByte( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } testF_S()164 static short testF_S() { return U.getShort( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } testF_C()165 static char testF_C() { return U.getChar( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } testF_I()166 static int testF_I() { return U.getInt( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } testF_J()167 static long testF_J() { return U.getLong( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } testF_F()168 static float testF_F() { return U.getFloat( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } testF_D()169 static double testF_D() { return U.getDouble( STABLE_FLOAT_ARRAY, ARRAY_FLOAT_BASE_OFFSET); } 170 testD_Z()171 static boolean testD_Z() { return U.getBoolean(STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } testD_B()172 static byte testD_B() { return U.getByte( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } testD_S()173 static short testD_S() { return U.getShort( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } testD_C()174 static char testD_C() { return U.getChar( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } testD_I()175 static int testD_I() { return U.getInt( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } testD_J()176 static long testD_J() { return U.getLong( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } testD_F()177 static float testD_F() { return U.getFloat( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } testD_D()178 static double testD_D() { return U.getDouble( STABLE_DOUBLE_ARRAY, ARRAY_DOUBLE_BASE_OFFSET); } 179 testL_L()180 static Object testL_L() { return U.getReference( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } testL_Z()181 static boolean testL_Z() { return U.getBoolean(STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } testL_B()182 static byte testL_B() { return U.getByte( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } testL_S()183 static short testL_S() { return U.getShort( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } testL_C()184 static char testL_C() { return U.getChar( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } testL_I()185 static int testL_I() { return U.getInt( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } testL_J()186 static long testL_J() { return U.getLong( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } testL_F()187 static float testL_F() { return U.getFloat( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } testL_D()188 static double testL_D() { return U.getDouble( STABLE_OBJECT_ARRAY, ARRAY_OBJECT_BASE_OFFSET); } 189 testS_U()190 static short testS_U() { return U.getShortUnaligned(STABLE_SHORT_ARRAY, ARRAY_SHORT_BASE_OFFSET + 1); } testC_U()191 static char testC_U() { return U.getCharUnaligned( STABLE_CHAR_ARRAY, ARRAY_CHAR_BASE_OFFSET + 1); } testI_U()192 static int testI_U() { return U.getIntUnaligned( STABLE_INT_ARRAY, ARRAY_INT_BASE_OFFSET + 1); } testJ_U()193 static long testJ_U() { return U.getLongUnaligned( STABLE_LONG_ARRAY, ARRAY_LONG_BASE_OFFSET + 1); } 194 } 195 run(Callable<?> c)196 static void run(Callable<?> c) throws Exception { 197 run(c, null, null); 198 } 199 run(Callable<?> c, Runnable sameResultAction, Runnable changeResultAction)200 static void run(Callable<?> c, Runnable sameResultAction, Runnable changeResultAction) throws Exception { 201 Object first = c.call(); 202 203 // Trigger compilation. 204 for (int i = 0; i < 20_000; i++) { 205 // Don't compare results here, since most of Test::testL_* results vary across iterations (due to GC). 206 c.call(); 207 } 208 209 if (sameResultAction != null) { 210 sameResultAction.run(); 211 assertEQ(first, c.call()); 212 } 213 214 if (changeResultAction != null) { 215 changeResultAction.run(); 216 assertNE(first, c.call()); 217 assertEQ(c.call(), c.call()); 218 } 219 } 220 testMatched(Callable<?> c, Runnable setDefaultAction)221 static void testMatched(Callable<?> c, Runnable setDefaultAction) throws Exception { 222 run(c, setDefaultAction, null); 223 Setter.reset(); 224 } 225 testMismatched(Callable<?> c, Runnable setDefaultAction)226 static void testMismatched(Callable<?> c, Runnable setDefaultAction) throws Exception { 227 testMismatched(c, setDefaultAction, false); 228 } 229 testMismatched(Callable<?> c, Runnable setDefaultAction, boolean objectArray)230 static void testMismatched(Callable<?> c, Runnable setDefaultAction, boolean objectArray) throws Exception { 231 if (Compiler.isGraalEnabled() && !objectArray) { 232 // Graal will constant fold mismatched reads from primitive stable arrays 233 run(c, setDefaultAction, null); 234 } else { 235 run(c, null, setDefaultAction); 236 } 237 Setter.reset(); 238 } 239 testUnsafeAccess()240 static void testUnsafeAccess() throws Exception { 241 // boolean[], aligned accesses 242 testMatched( Test::testZ_Z, Test::changeZ); 243 testMismatched(Test::testZ_B, Test::changeZ); 244 testMismatched(Test::testZ_S, Test::changeZ); 245 testMismatched(Test::testZ_C, Test::changeZ); 246 testMismatched(Test::testZ_I, Test::changeZ); 247 testMismatched(Test::testZ_J, Test::changeZ); 248 testMismatched(Test::testZ_F, Test::changeZ); 249 testMismatched(Test::testZ_D, Test::changeZ); 250 251 // byte[], aligned accesses 252 testMismatched(Test::testB_Z, Test::changeB); 253 testMatched( Test::testB_B, Test::changeB); 254 testMismatched(Test::testB_S, Test::changeB); 255 testMismatched(Test::testB_C, Test::changeB); 256 testMismatched(Test::testB_I, Test::changeB); 257 testMismatched(Test::testB_J, Test::changeB); 258 testMismatched(Test::testB_F, Test::changeB); 259 testMismatched(Test::testB_D, Test::changeB); 260 261 // short[], aligned accesses 262 testMismatched(Test::testS_Z, Test::changeS); 263 testMismatched(Test::testS_B, Test::changeS); 264 testMatched( Test::testS_S, Test::changeS); 265 testMismatched(Test::testS_C, Test::changeS); 266 testMismatched(Test::testS_I, Test::changeS); 267 testMismatched(Test::testS_J, Test::changeS); 268 testMismatched(Test::testS_F, Test::changeS); 269 testMismatched(Test::testS_D, Test::changeS); 270 271 // char[], aligned accesses 272 testMismatched(Test::testC_Z, Test::changeC); 273 testMismatched(Test::testC_B, Test::changeC); 274 testMismatched(Test::testC_S, Test::changeC); 275 testMatched( Test::testC_C, Test::changeC); 276 testMismatched(Test::testC_I, Test::changeC); 277 testMismatched(Test::testC_J, Test::changeC); 278 testMismatched(Test::testC_F, Test::changeC); 279 testMismatched(Test::testC_D, Test::changeC); 280 281 // int[], aligned accesses 282 testMismatched(Test::testI_Z, Test::changeI); 283 testMismatched(Test::testI_B, Test::changeI); 284 testMismatched(Test::testI_S, Test::changeI); 285 testMismatched(Test::testI_C, Test::changeI); 286 testMatched( Test::testI_I, Test::changeI); 287 testMismatched(Test::testI_J, Test::changeI); 288 testMismatched(Test::testI_F, Test::changeI); 289 testMismatched(Test::testI_D, Test::changeI); 290 291 // long[], aligned accesses 292 testMismatched(Test::testJ_Z, Test::changeJ); 293 testMismatched(Test::testJ_B, Test::changeJ); 294 testMismatched(Test::testJ_S, Test::changeJ); 295 testMismatched(Test::testJ_C, Test::changeJ); 296 testMismatched(Test::testJ_I, Test::changeJ); 297 testMatched( Test::testJ_J, Test::changeJ); 298 testMismatched(Test::testJ_F, Test::changeJ); 299 testMismatched(Test::testJ_D, Test::changeJ); 300 301 // float[], aligned accesses 302 testMismatched(Test::testF_Z, Test::changeF); 303 testMismatched(Test::testF_B, Test::changeF); 304 testMismatched(Test::testF_S, Test::changeF); 305 testMismatched(Test::testF_C, Test::changeF); 306 testMismatched(Test::testF_I, Test::changeF); 307 testMismatched(Test::testF_J, Test::changeF); 308 testMatched( Test::testF_F, Test::changeF); 309 testMismatched(Test::testF_D, Test::changeF); 310 311 // double[], aligned accesses 312 testMismatched(Test::testD_Z, Test::changeD); 313 testMismatched(Test::testD_B, Test::changeD); 314 testMismatched(Test::testD_S, Test::changeD); 315 testMismatched(Test::testD_C, Test::changeD); 316 testMismatched(Test::testD_I, Test::changeD); 317 testMismatched(Test::testD_J, Test::changeD); 318 testMismatched(Test::testD_F, Test::changeD); 319 testMatched( Test::testD_D, Test::changeD); 320 321 // Object[], aligned accesses 322 testMismatched(Test::testL_J, Test::changeL, true); // long & double are always as large as an OOP 323 testMismatched(Test::testL_D, Test::changeL, true); 324 testMatched( Test::testL_L, Test::changeL); 325 326 // Unaligned accesses 327 testMismatched(Test::testS_U, Test::changeS); 328 testMismatched(Test::testC_U, Test::changeC); 329 testMismatched(Test::testI_U, Test::changeI); 330 testMismatched(Test::testJ_U, Test::changeJ); 331 332 // No way to reliably check the expected behavior: 333 // (1) OOPs change during GC; 334 // (2) there's no way to reliably change some part of an OOP (e.g., when reading a byte from it). 335 // 336 // Just trigger the compilation hoping to catch any problems with asserts. 337 run(Test::testL_B); 338 run(Test::testL_Z); 339 run(Test::testL_S); 340 run(Test::testL_C); 341 run(Test::testL_I); 342 run(Test::testL_F); 343 } 344 main(String[] args)345 public static void main(String[] args) throws Exception { 346 if (!Platform.isServer() || Platform.isEmulatedClient()) { 347 throw new Error("TESTBUG: Not server mode"); 348 } 349 testUnsafeAccess(); 350 System.out.println("TEST PASSED"); 351 } 352 } 353