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