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