1 /*
  2  * Copyright (c) 2014, 2021, 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 package compiler.rtm.cli;
 25 
 26 import jdk.test.lib.process.ExitCode;
 27 import jdk.test.lib.Platform;
 28 import jdk.test.lib.cli.CommandLineOptionTest;
 29 
 30 import java.util.function.BooleanSupplier;
 31 
 32 /**
 33  * Base for all RTM-related CLI tests.
 34  */
 35 public abstract class RTMGenericCommandLineOptionTest {
 36 
 37     protected static final String RTM_INSTR_ERROR
 38             = "RTM instructions are not available on this CPU";
 39     protected static final String RTM_UNSUPPORTED_VM_ERROR
 40             = "RTM locking optimization is not supported in this VM";
 41     protected static final String RTM_FOR_STACK_LOCKS_WARNING
 42             = "UseRTMForStackLocks flag should be off when UseRTMLocking "
 43             + "flag is off";
 44     protected static final String RTM_COUNT_INCR_WARNING
 45             = "must be a power of 2, resetting it to 64";
 46 
 47     protected final String optionName;
 48     protected final String errorMessage;
 49     protected final String experimentalOptionError;
 50     protected final boolean isExperimental;
 51     protected final boolean isBoolean;
 52     protected final String defaultValue;
 53     protected final String[] optionValues;
 54 
 55     /**
 56      * Constructs new genetic RTM CLI test, for option {@code optionName} which
 57      * has default value {@code defaultValue}. Test cases will use option's
 58      * values passed via {@code optionValues} for verification of correct
 59      * option processing.
 60      *
 61      * Test constructed using this ctor will be started on any cpu regardless
 62      * it's architecture and supported/unsupported features.
 63      *
 64      * @param optionName name of option to be tested
 65      * @param isBoolean {@code true} if option is binary
 66      * @param isExperimental {@code true} if option is experimental
 67      * @param defaultValue default value of tested option
 68      * @param optionValues different option values
 69      */
 70     public RTMGenericCommandLineOptionTest(
 71             String optionName, boolean isBoolean, boolean isExperimental,
 72             String defaultValue, String... optionValues) {
 73         this.optionName = optionName;
 74         this.isExperimental = isExperimental;
 75         this.isBoolean = isBoolean;
 76         this.defaultValue = defaultValue;
 77         this.optionValues = optionValues;
 78         this.errorMessage = CommandLineOptionTest.
 79                 getUnrecognizedOptionErrorMessage(optionName);
 80         this.experimentalOptionError = CommandLineOptionTest.
 81                 getExperimentalOptionErrorMessage(optionName);
 82     }
 83 
 84     public void runTestCases() throws Throwable {
 85         if (Platform.isX86() || Platform.isX64()) {
 86             if (Platform.isServer()) {
 87                 runX86SupportedVMTestCases();
 88             } else {
 89                 runX86UnsupportedVMTestCases();
 90             }
 91         } else {
 92             runNonX86TestCases();
 93         }
 94     }
 95 
 96     /**
 97      * Runs test cases on X86 CPU if VM supports RTM locking.
 98      * @throws Throwable
 99      */
100     protected void runX86SupportedVMTestCases() throws Throwable {
101         runGenericX86TestCases();
102     }
103 
104     /**
105      * Runs test cases on X86 CPU if VM does not support RTM locking.
106      * @throws Throwable
107      */
108     protected void runX86UnsupportedVMTestCases() throws Throwable {
109         runGenericX86TestCases();
110     }
111 
112     /**
113      * Runs test cases on non-X86 CPU.
114      * @throws Throwable
115      */
116     protected void runNonX86TestCases() throws Throwable {
117         CommandLineOptionTest.verifySameJVMStartup(
118                 new String[] { errorMessage }, null,
119                 String.format("Option '%s' should be unknown on non-X86CPUs.%n"
120                 + "JVM startup should fail", optionName), "", ExitCode.FAIL,
121                 prepareOptionValue(defaultValue));
122     }
123 
124     /**
125      * Runs generic X86 test cases.
126      * @throws Throwable
127      */
128     protected void runGenericX86TestCases() throws Throwable {
129         verifyJVMStartup();
130         verifyOptionValues();
131     }
132 
133     protected void verifyJVMStartup() throws Throwable {
134         String optionValue = prepareOptionValue(defaultValue);
135         String shouldFailMessage = String.format("VM option '%s' is "
136                 + "experimental.%nVM startup expected to fail without "
137                 + "-XX:+UnlockExperimentalVMOptions option", optionName);
138         String shouldPassMessage = String.format("VM option '%s' is "
139                 + "experimental%nVM startup should pass with "
140                 + "-XX:+UnlockExperimentalVMOptions option", optionName);
141         if (isExperimental) {
142             // verify that option is experimental
143             CommandLineOptionTest.verifySameJVMStartup(
144                     new String[] { experimentalOptionError },
145                     new String[] { errorMessage }, shouldFailMessage,
146                     shouldFailMessage, ExitCode.FAIL, optionValue);
147             // verify that it could be passed if experimental options
148             // are unlocked
149             CommandLineOptionTest.verifySameJVMStartup(null,
150                     new String[] {
151                             experimentalOptionError,
152                             errorMessage
153                     },
154                     shouldPassMessage,
155                     "JVM should start without any warnings or errors",
156                     ExitCode.OK,
157                     CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
158                     optionValue);
159         } else {
160             // verify that option could be passed
161             CommandLineOptionTest.verifySameJVMStartup(null,
162                     new String[]{errorMessage},
163                     String.format("VM startup shuld pass with '%s' option",
164                             optionName),
165                     "JVM should start without any warnings or errors",
166                     ExitCode.OK, optionValue);
167         }
168     }
169 
170     protected void verifyOptionValues() throws Throwable {
171         // verify default value
172         if (isExperimental) {
173             CommandLineOptionTest.verifyOptionValueForSameVM(optionName,
174                     defaultValue,
175                     String.format("Option '%s' is expected to have '%s' "
176                             + "default value", optionName, defaultValue),
177                     CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS);
178         } else {
179             CommandLineOptionTest.verifyOptionValueForSameVM(optionName,
180                     defaultValue,
181                     String.format("Option '%s' is expected to have '%s' "
182                             + "default value", optionName, defaultValue));
183         }
184         // verify other specified option values
185         if (optionValues == null) {
186             return;
187         }
188 
189         for (String value : optionValues) {
190             if (isExperimental) {
191                 CommandLineOptionTest.verifyOptionValueForSameVM(optionName,
192                         value,
193                         String.format("Option '%s' is set to have '%s' value",
194                                 optionName, value),
195                         CommandLineOptionTest.UNLOCK_EXPERIMENTAL_VM_OPTIONS,
196                         prepareOptionValue(value));
197             } else {
198                 CommandLineOptionTest.verifyOptionValueForSameVM(optionName,
199                         value,
200                         String.format("Option '%s' is set to have '%s' value",
201                                 optionName, value), prepareOptionValue(value));
202             }
203         }
204     }
205 
206     protected String prepareOptionValue(String value) {
207         if (isBoolean) {
208             return CommandLineOptionTest.prepareBooleanFlag(optionName,
209                     Boolean.valueOf(value));
210         } else {
211             return String.format("-XX:%s=%s", optionName, value);
212         }
213     }
214 }