1/*
2 * Copyright (c) 2015, 2016, 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 8138651
27 * @modules java.base/jdk.internal.misc
28 * @library /test/lib /
29 *
30 * @build sun.hotspot.WhiteBox
31 * @run driver ClassFileInstaller sun.hotspot.WhiteBox
32 *                                sun.hotspot.WhiteBox$WhiteBoxPermission
33 * @run main/othervm -Xbootclasspath/a:.
34 *                   -XX:+UnlockDiagnosticVMOptions
35 *                   -XX:+WhiteBoxAPI
36 *                   -XX:DisableIntrinsic=_putCharVolatile,_putInt
37 *                   -XX:DisableIntrinsic=_putIntVolatile
38 *                   -XX:CompileCommand=option,jdk.internal.misc.Unsafe::putChar,ccstrlist,DisableIntrinsic,_getCharVolatile,_getInt
39 *                   -XX:CompileCommand=option,jdk.internal.misc.Unsafe::putCharVolatile,ccstrlist,DisableIntrinsic,_getIntVolatile
40 *                   compiler.intrinsics.IntrinsicDisabledTest
41 */
42
43package compiler.intrinsics;
44
45import jdk.test.lib.Platform;
46import sun.hotspot.WhiteBox;
47import compiler.whitebox.CompilerWhiteBoxTest;
48
49import java.lang.reflect.Executable;
50import java.util.Objects;
51
52public class IntrinsicDisabledTest {
53
54    private static final WhiteBox wb = WhiteBox.getWhiteBox();
55
56    /* Determine if tiered compilation is enabled. */
57    private static final boolean TIERED_COMPILATION = wb.getBooleanVMFlag("TieredCompilation");
58
59    private static final int TIERED_STOP_AT_LEVEL = wb.getIntxVMFlag("TieredStopAtLevel").intValue();
60
61    /* This test uses several methods from jdk.internal.misc.Unsafe. The method
62     * getMethod() returns a different Executable for each different
63     * combination of its input parameters. There are eight possible
64     * combinations, getMethod can return an Executable representing
65     * the following methods: putChar, putCharVolatile, getChar,
66     * getCharVolatile, putInt, putIntVolatile, getInt,
67     * getIntVolatile. These methods were selected because they can
68     * be intrinsified by both the C1 and the C2 compiler.
69     */
70    static Executable getMethod(boolean isChar, boolean isPut, boolean isVolatile) throws RuntimeException {
71        Executable aMethod;
72        String methodTypeName = isChar ? "Char" : "Int";
73
74        try {
75            Class aClass = Class.forName("jdk.internal.misc.Unsafe");
76            if (isPut) {
77                aMethod = aClass.getDeclaredMethod("put" + methodTypeName + (isVolatile ? "Volatile" : ""),
78                                                   Object.class,
79                                                   long.class,
80                                                   isChar ? char.class : int.class);
81            } else {
82                aMethod = aClass.getDeclaredMethod("get" + methodTypeName + (isVolatile ? "Volatile" : ""),
83                                                   Object.class,
84                                                   long.class);
85            }
86        } catch (NoSuchMethodException e) {
87            throw new RuntimeException("Test bug, method is unavailable. " + e);
88        } catch (ClassNotFoundException e) {
89            throw new RuntimeException("Test bug, class is unavailable. " + e);
90        }
91
92        return aMethod;
93    }
94
95    public static void test(int compLevel) {
96
97        Executable putChar = getMethod(true, /*isPut =*/ true, /*isVolatile = */ false);
98        Executable getChar = getMethod(true, /*isPut =*/ false, /*isVolatile = */ false);
99        Executable putCharVolatile = getMethod(true, /*isPut =*/ true, /*isVolatile = */ true);
100        Executable getCharVolatile = getMethod(true, /*isPut =*/ false, /*isVolatile = */ true);
101        Executable putInt = getMethod(false, /*isPut =*/ true, /*isVolatile = */ false);
102        Executable getInt = getMethod(false, /*isPut =*/ false, /*isVolatile = */ false);
103        Executable putIntVolatile = getMethod(false, /*isPut =*/ true, /*isVolatile = */ true);
104        Executable getIntVolatile = getMethod(false, /*isPut =*/ false, /*isVolatile = */ true);
105
106        /* Test if globally disabling intrinsics works. */
107        if (!wb.isIntrinsicAvailable(putChar, compLevel)) {
108            throw new RuntimeException("Intrinsic for [" + putChar.toGenericString() +
109                                       "] is not available globally although it should be.");
110        }
111
112        if (wb.isIntrinsicAvailable(putCharVolatile, compLevel)) {
113            throw new RuntimeException("Intrinsic for [" + putCharVolatile.toGenericString() +
114                                       "] is available globally although it should not be.");
115        }
116
117        if (wb.isIntrinsicAvailable(putInt, compLevel)) {
118            throw new RuntimeException("Intrinsic for [" + putInt.toGenericString() +
119                                       "] is available globally although it should not be.");
120        }
121
122        if (wb.isIntrinsicAvailable(putIntVolatile, compLevel)) {
123            throw new RuntimeException("Intrinsic for [" + putIntVolatile.toGenericString() +
124                                       "] is available globally although it should not be.");
125        }
126
127        /* Test if disabling intrinsics on a per-method level
128         * works. The method for which intrinsics are
129         * disabled (the compilation context) is putChar. */
130        if (!wb.isIntrinsicAvailable(getChar, putChar, compLevel)) {
131            throw new RuntimeException("Intrinsic for [" + getChar.toGenericString() +
132                                       "] is not available for intrinsification in [" +
133                                       putChar.toGenericString() + "] although it should be.");
134        }
135
136        if (wb.isIntrinsicAvailable(getCharVolatile, putChar, compLevel)) {
137            throw new RuntimeException("Intrinsic for [" + getCharVolatile.toGenericString() +
138                                       "] is available for intrinsification in [" +
139                                       putChar.toGenericString() + "] although it should not be.");
140        }
141
142        if (wb.isIntrinsicAvailable(getInt, putChar, compLevel)) {
143            throw new RuntimeException("Intrinsic for [" + getInt.toGenericString() +
144                                       "] is available for intrinsification in [" +
145                                       putChar.toGenericString() + "] although it should not be.");
146        }
147
148        if (wb.isIntrinsicAvailable(getIntVolatile, putCharVolatile, compLevel)) {
149            throw new RuntimeException("Intrinsic for [" + getIntVolatile.toGenericString() +
150                                       "] is available for intrinsification in [" +
151                                       putCharVolatile.toGenericString() + "] although it should not be.");
152        }
153
154        /* Test if disabling intrinsics on a per-method level
155         * leaves those intrinsics enabled globally. */
156        if (!wb.isIntrinsicAvailable(getCharVolatile, compLevel)) {
157            throw new RuntimeException("Intrinsic for [" + getCharVolatile.toGenericString() +
158                                       "] is not available globally although it should be.");
159        }
160
161        if (!wb.isIntrinsicAvailable(getInt, compLevel)) {
162            throw new RuntimeException("Intrinsic for [" + getInt.toGenericString() +
163                                       "] is not available globally although it should be.");
164        }
165
166
167        if (!wb.isIntrinsicAvailable(getIntVolatile, compLevel)) {
168            throw new RuntimeException("Intrinsic for [" + getIntVolatile.toGenericString() +
169                                       "] is not available globally although it should be.");
170        }
171
172        /* Test if disabling an intrinsic globally disables it on a
173         * per-method level as well. */
174        if (!wb.isIntrinsicAvailable(putChar, getChar, compLevel)) {
175            throw new RuntimeException("Intrinsic for [" + putChar.toGenericString() +
176                                       "] is not available for intrinsification in [" +
177                                       getChar.toGenericString() + "] although it should be.");
178        }
179
180        if (wb.isIntrinsicAvailable(putCharVolatile, getChar, compLevel)) {
181            throw new RuntimeException("Intrinsic for [" + putCharVolatile.toGenericString() +
182                                       "] is available for intrinsification in [" +
183                                       getChar.toGenericString() + "] although it should not be.");
184        }
185
186        if (wb.isIntrinsicAvailable(putInt, getChar, compLevel)) {
187            throw new RuntimeException("Intrinsic for [" + putInt.toGenericString() +
188                                       "] is available for intrinsification in [" +
189                                       getChar.toGenericString() + "] although it should not be.");
190        }
191
192        if (wb.isIntrinsicAvailable(putIntVolatile, getChar, compLevel)) {
193            throw new RuntimeException("Intrinsic for [" + putIntVolatile.toGenericString() +
194                                       "] is available for intrinsification in [" +
195                                       getChar.toGenericString() + "] although it should not be.");
196        }
197    }
198
199    public static void main(String args[]) {
200        if (Platform.isServer() && !Platform.isEmulatedClient() &&
201                                   (TIERED_STOP_AT_LEVEL == CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION)) {
202            if (TIERED_COMPILATION) {
203                test(CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
204            }
205            test(CompilerWhiteBoxTest.COMP_LEVEL_FULL_OPTIMIZATION);
206        } else {
207            test(CompilerWhiteBoxTest.COMP_LEVEL_SIMPLE);
208        }
209    }
210}
211