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 package compiler.compilercontrol.share.scenario; 25 26 import jdk.test.lib.Asserts; 27 28 import java.util.Arrays; 29 import java.util.Optional; 30 31 /** 32 * Represents method compilation state 33 */ 34 public class State { 35 // Each of the two-elements array contains a state for each compiler 36 private Optional<Boolean>[] compile = 37 (Optional<Boolean>[]) new Optional[Scenario.Compiler.values().length]; 38 private Optional<Boolean>[] forceInline = 39 (Optional<Boolean>[]) new Optional[Scenario.Compiler.values().length]; 40 private Optional<Boolean>[] dontInline = 41 (Optional<Boolean>[]) new Optional[Scenario.Compiler.values().length]; 42 private Optional<Boolean> printAssembly = Optional.empty(); 43 private Optional<Boolean> printInline = Optional.empty(); 44 private Optional<Boolean> log = Optional.empty(); 45 46 public State() { 47 Arrays.fill(compile, Optional.empty()); 48 Arrays.fill(forceInline, Optional.empty()); 49 Arrays.fill(dontInline, Optional.empty()); 50 } 51 52 /** 53 * Creates state from the string 54 * 55 * @param strings array of strings that represent the state 56 * @return State instance 57 * @see #toString() 58 */ 59 public static State fromString(String[] strings) { 60 Asserts.assertNotNull(strings, "Non null array is required"); 61 Asserts.assertNE(strings.length, 0, "Non empty array is required"); 62 State st = new State(); 63 for (String string : strings) { 64 int i = string.indexOf(' '); 65 String command = string.substring(0, i); 66 String values = string.substring(i + 1); // skip space symbol 67 switch (command) { 68 case "compile" : 69 parseArray(st.compile, values); 70 break; 71 case "force_inline" : 72 parseArray(st.forceInline, values); 73 break; 74 case "dont_inline" : 75 parseArray(st.dontInline, values); 76 break; 77 case "log" : 78 st.log = parseElement(values); 79 break; 80 case "print_assembly" : 81 st.printAssembly = parseElement(values); 82 break; 83 case "print_inline" : 84 st.printInline = parseElement(values); 85 break; 86 default: 87 throw new Error("TESTBUG: "); 88 } 89 } 90 return st; 91 } 92 93 private static void parseArray(Optional<Boolean>[] array, String str) { 94 Asserts.assertNotNull(str); 95 int beginBrace = 0; 96 int endBrace = str.length() - 1; 97 if (str.charAt(beginBrace) != '[' || str.charAt(endBrace) != ']') { 98 throw new Error("TESTBUG: not an array type: " + str); 99 } 100 // Get all elements divided with comma as an array 101 String[] strValues = str.substring(beginBrace + 1, endBrace) 102 .split(", "); 103 Asserts.assertEQ(strValues.length, array.length, "Different amount of " 104 + "elements in the string"); 105 for (int i = 0; i < strValues.length; i++) { 106 array[i] = parseElement(strValues[i]); 107 } 108 } 109 110 private static Optional<Boolean> parseElement(String str) { 111 Asserts.assertNotNull(str); 112 Asserts.assertTrue(str.startsWith(Optional.class.getSimpleName()), 113 "String is not of type Optional: " + str); 114 if ("Optional.empty".equals(str)) { 115 return Optional.empty(); 116 } 117 int begin = str.indexOf('['); 118 Asserts.assertNE(begin, -1, "TEST BUG: Wrong Optional string"); 119 int end = str.indexOf(']'); 120 Asserts.assertEQ(end, str.length() - 1); 121 boolean b = Boolean.parseBoolean(str.substring(begin + 1, end)); 122 return Optional.of(b); 123 } 124 125 /** 126 * Gets string representation of this state 127 */ 128 @Override 129 public String toString() { 130 return "compile " + Arrays.toString(compile) 131 + "\nforce_inline " + Arrays.toString(forceInline) 132 + "\ndont_inline " + Arrays.toString(dontInline) 133 + "\nlog " + log 134 + "\nprint_assembly " + printAssembly 135 + "\nprint_inline " + printInline; 136 } 137 138 public boolean isC1Compilable() { 139 return compile[Scenario.Compiler.C1.ordinal()].orElse(true); 140 } 141 142 public boolean isC2Compilable() { 143 return compile[Scenario.Compiler.C2.ordinal()].orElse(true); 144 } 145 146 public boolean isCompilable() { 147 return isC1Compilable() && isC2Compilable(); 148 } 149 150 public void setC1Compilable(boolean value) { 151 setCompilable(Scenario.Compiler.C1.ordinal(), value); 152 } 153 154 public void setC2Compilable(boolean value) { 155 setCompilable(Scenario.Compiler.C2.ordinal(), value); 156 } 157 158 public void setCompilable(Scenario.Compiler compiler, boolean value) { 159 if (compiler == null) { 160 setC1Compilable(value); 161 setC2Compilable(value); 162 return; 163 } 164 switch (compiler) { 165 case C1: 166 setC1Compilable(value); 167 break; 168 case C2: 169 setC2Compilable(value); 170 break; 171 default: 172 throw new Error("Unknown compiler"); 173 } 174 } 175 176 private void setCompilable(int level, boolean value) { 177 check(level); 178 compile[level] = Optional.of(value); 179 if (!value) { 180 setDontInline(level); 181 } 182 } 183 184 public boolean isC1Inlinable() { 185 return ! dontInline[Scenario.Compiler.C1.ordinal()].orElse(false); 186 } 187 188 public boolean isC2Inlinable() { 189 return ! dontInline[Scenario.Compiler.C2.ordinal()].orElse(false); 190 } 191 192 public boolean isInlinable() { 193 return isC1Inlinable() && isC2Inlinable(); 194 } 195 196 private void setDontInline(int level) { 197 check(level); 198 dontInline[level] = Optional.of(true); 199 forceInline[level] = Optional.of(false); 200 } 201 202 private void setForceInline(int level) { 203 check(level); 204 dontInline[level] = Optional.of(false); 205 forceInline[level] = Optional.of(true); 206 } 207 208 public boolean isC1ForceInline() { 209 return forceInline[Scenario.Compiler.C1.ordinal()].orElse(false); 210 } 211 212 public boolean isC2ForceInline() { 213 return forceInline[Scenario.Compiler.C2.ordinal()].orElse(false); 214 } 215 216 public boolean isForceInline() { 217 return isC1ForceInline() && isC2ForceInline(); 218 } 219 220 public void setC1Inline(boolean value) { 221 if (value && isC1Compilable()) { 222 setForceInline(Scenario.Compiler.C1.ordinal()); 223 } else { 224 setDontInline(Scenario.Compiler.C1.ordinal()); 225 } 226 } 227 228 public void setC2Inline(boolean value) { 229 if (value && isC2Compilable()) { 230 setForceInline(Scenario.Compiler.C2.ordinal()); 231 } else { 232 setDontInline(Scenario.Compiler.C1.ordinal()); 233 } 234 } 235 236 public void setInline(Scenario.Compiler compiler, boolean value) { 237 if (compiler == null) { 238 setC1Inline(value); 239 setC2Inline(value); 240 return; 241 } 242 switch (compiler) { 243 case C1: 244 setC1Inline(value); 245 break; 246 case C2: 247 setC2Inline(value); 248 break; 249 default: 250 throw new Error("Unknown compiler"); 251 } 252 } 253 254 public boolean isPrintAssembly() { 255 return printAssembly.orElse(false); 256 } 257 258 public void setPrintAssembly(boolean value) { 259 printAssembly = Optional.of(value); 260 } 261 262 public boolean isPrintInline() { 263 return printInline.orElse(false); 264 } 265 266 public void setPrintInline(boolean value) { 267 printInline = Optional.of(value); 268 } 269 270 public boolean isLog() { 271 return log.orElse(false); 272 } 273 274 public void setLog(boolean log) { 275 this.log = Optional.of(log); 276 } 277 278 private void check(int level) { 279 if (level < 0 || level > compile.length) { 280 throw new IllegalArgumentException("TESTBUG: Wrong level " + level); 281 } 282 } 283 284 /** 285 * Applies given command to the state. 286 * 287 * @param compileCommand command to be applied 288 */ 289 public void apply(CompileCommand compileCommand) { 290 switch (compileCommand.command) { 291 case COMPILEONLY: 292 setCompilable(compileCommand.compiler, true); 293 break; 294 case EXCLUDE: 295 setCompilable(compileCommand.compiler, false); 296 break; 297 case INLINE: 298 setInline(compileCommand.compiler, true); 299 break; 300 case DONTINLINE: 301 setInline(compileCommand.compiler, false); 302 break; 303 case LOG: 304 setLog(true); 305 break; 306 case PRINT: 307 setPrintAssembly(true); 308 break; 309 case QUIET: 310 case NONEXISTENT: 311 // doesn't apply the state 312 break; 313 default: 314 throw new Error("Wrong command: " + compileCommand.command); 315 } 316 } 317 318 /** 319 * Merges two given states with different priority 320 * 321 * @param low state with lower merge priority 322 * @param high state with higher merge priority 323 */ 324 public static State merge(State low, State high) { 325 if (high == null) { 326 if (low == null) { 327 return new State(); 328 } 329 return low; 330 } 331 if (low == null) { 332 return high; 333 } 334 State result = new State(); 335 // Compilable 336 result.compile[Scenario.Compiler.C1.ordinal()] = mergeOptional( 337 high.compile[Scenario.Compiler.C1.ordinal()], 338 low.compile[Scenario.Compiler.C1.ordinal()]); 339 result.compile[Scenario.Compiler.C2.ordinal()] = mergeOptional( 340 high.compile[Scenario.Compiler.C2.ordinal()], 341 low.compile[Scenario.Compiler.C2.ordinal()]); 342 // Force inline 343 result.forceInline[Scenario.Compiler.C1.ordinal()] = mergeOptional( 344 high.forceInline[Scenario.Compiler.C1.ordinal()], 345 low.forceInline[Scenario.Compiler.C1.ordinal()]); 346 result.forceInline[Scenario.Compiler.C2.ordinal()] = mergeOptional( 347 high.forceInline[Scenario.Compiler.C2.ordinal()], 348 low.forceInline[Scenario.Compiler.C2.ordinal()]); 349 // Don't inline 350 result.dontInline[Scenario.Compiler.C1.ordinal()] = mergeOptional( 351 high.dontInline[Scenario.Compiler.C1.ordinal()], 352 low.dontInline[Scenario.Compiler.C1.ordinal()]); 353 result.dontInline[Scenario.Compiler.C2.ordinal()] = mergeOptional( 354 high.dontInline[Scenario.Compiler.C2.ordinal()], 355 low.dontInline[Scenario.Compiler.C2.ordinal()]); 356 // set PrintAssembly 357 result.printAssembly = mergeOptional(high.printAssembly, 358 low.printAssembly); 359 // set PrintInline 360 result.printInline = mergeOptional(high.printInline, low.printInline); 361 // set LogCompilation 362 result.log = mergeOptional(high.log, low.log); 363 return result; 364 } 365 366 private static <T> Optional<T> mergeOptional(Optional<T> high, 367 Optional<T> low) { 368 T val = high.orElse(low.orElse(null)); 369 return Optional.ofNullable(val); 370 } 371 }