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 State()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 */ fromString(String[] strings)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 parseArray(Optional<Boolean>[] array, String str)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 parseElement(String str)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 toString()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 getCompilableOptional(Scenario.Compiler compiler)138 public Optional<Boolean> getCompilableOptional(Scenario.Compiler compiler) { 139 return compile[compiler.ordinal()]; 140 } 141 isC1Compilable()142 public boolean isC1Compilable() { 143 return compile[Scenario.Compiler.C1.ordinal()].orElse(true); 144 } 145 isC2Compilable()146 public boolean isC2Compilable() { 147 return compile[Scenario.Compiler.C2.ordinal()].orElse(true); 148 } 149 isCompilable()150 public boolean isCompilable() { 151 return isC1Compilable() && isC2Compilable(); 152 } 153 setC1Compilable(boolean value)154 public void setC1Compilable(boolean value) { 155 setCompilable(Scenario.Compiler.C1.ordinal(), value); 156 } 157 setC2Compilable(boolean value)158 public void setC2Compilable(boolean value) { 159 setCompilable(Scenario.Compiler.C2.ordinal(), value); 160 } 161 setCompilable(Scenario.Compiler compiler, boolean value)162 public void setCompilable(Scenario.Compiler compiler, boolean value) { 163 if (compiler == null) { 164 setC1Compilable(value); 165 setC2Compilable(value); 166 return; 167 } 168 switch (compiler) { 169 case C1: 170 setC1Compilable(value); 171 break; 172 case C2: 173 setC2Compilable(value); 174 break; 175 default: 176 throw new Error("Unknown compiler"); 177 } 178 } 179 setCompilable(int level, boolean value)180 private void setCompilable(int level, boolean value) { 181 check(level); 182 compile[level] = Optional.of(value); 183 if (!value) { 184 setDontInline(level); 185 } 186 } 187 isC1Inlinable()188 public boolean isC1Inlinable() { 189 return ! dontInline[Scenario.Compiler.C1.ordinal()].orElse(false) 190 && isC1Compilable(); 191 } 192 isC2Inlinable()193 public boolean isC2Inlinable() { 194 return ! dontInline[Scenario.Compiler.C2.ordinal()].orElse(false) 195 && isC2Compilable(); 196 } 197 isInlinable()198 public boolean isInlinable() { 199 return isC1Inlinable() && isC2Inlinable(); 200 } 201 setDontInline(int level)202 private void setDontInline(int level) { 203 check(level); 204 dontInline[level] = Optional.of(true); 205 forceInline[level] = Optional.of(false); 206 } 207 setForceInline(int level)208 private void setForceInline(int level) { 209 check(level); 210 dontInline[level] = Optional.of(false); 211 forceInline[level] = Optional.of(true); 212 } 213 isC1ForceInline()214 public boolean isC1ForceInline() { 215 return forceInline[Scenario.Compiler.C1.ordinal()].orElse(false) 216 && isC1Compilable(); 217 } 218 isC2ForceInline()219 public boolean isC2ForceInline() { 220 return forceInline[Scenario.Compiler.C2.ordinal()].orElse(false) 221 && isC2Compilable(); 222 } 223 isForceInline()224 public boolean isForceInline() { 225 return isC1ForceInline() && isC2ForceInline(); 226 } 227 setC1Inline(boolean value)228 public void setC1Inline(boolean value) { 229 if (value && isC1Compilable()) { 230 setForceInline(Scenario.Compiler.C1.ordinal()); 231 } else { 232 setDontInline(Scenario.Compiler.C1.ordinal()); 233 } 234 } 235 setC2Inline(boolean value)236 public void setC2Inline(boolean value) { 237 if (value && isC2Compilable()) { 238 setForceInline(Scenario.Compiler.C2.ordinal()); 239 } else { 240 setDontInline(Scenario.Compiler.C2.ordinal()); 241 } 242 } 243 setInline(Scenario.Compiler compiler, boolean value)244 public void setInline(Scenario.Compiler compiler, boolean value) { 245 if (compiler == null) { 246 setC1Inline(value); 247 setC2Inline(value); 248 return; 249 } 250 switch (compiler) { 251 case C1: 252 setC1Inline(value); 253 break; 254 case C2: 255 setC2Inline(value); 256 break; 257 default: 258 throw new Error("Unknown compiler"); 259 } 260 } 261 isPrintAssembly()262 public boolean isPrintAssembly() { 263 return printAssembly.orElse(false); 264 } 265 setPrintAssembly(boolean value)266 public void setPrintAssembly(boolean value) { 267 printAssembly = Optional.of(value); 268 } 269 isPrintInline()270 public boolean isPrintInline() { 271 return printInline.orElse(false); 272 } 273 setPrintInline(boolean value)274 public void setPrintInline(boolean value) { 275 printInline = Optional.of(value); 276 } 277 isLog()278 public boolean isLog() { 279 return log.orElse(false); 280 } 281 setLog(boolean log)282 public void setLog(boolean log) { 283 this.log = Optional.of(log); 284 } 285 check(int level)286 private void check(int level) { 287 if (level < 0 || level > compile.length) { 288 throw new IllegalArgumentException("TESTBUG: Wrong level " + level); 289 } 290 } 291 292 /** 293 * Applies given command to the state. 294 * 295 * @param compileCommand command to be applied 296 */ apply(CompileCommand compileCommand)297 public void apply(CompileCommand compileCommand) { 298 switch (compileCommand.command) { 299 case COMPILEONLY: 300 setCompilable(compileCommand.compiler, true); 301 break; 302 case EXCLUDE: 303 setCompilable(compileCommand.compiler, false); 304 break; 305 case INLINE: 306 setInline(compileCommand.compiler, true); 307 break; 308 case DONTINLINE: 309 setInline(compileCommand.compiler, false); 310 break; 311 case LOG: 312 setLog(true); 313 break; 314 case PRINT: 315 setPrintAssembly(true); 316 break; 317 case QUIET: 318 case NONEXISTENT: 319 // doesn't apply the state 320 break; 321 default: 322 throw new Error("Wrong command: " + compileCommand.command); 323 } 324 } 325 326 /** 327 * Merges two given states with different priority 328 * 329 * @param low state with lower merge priority 330 * @param high state with higher merge priority 331 */ merge(State low, State high)332 public static State merge(State low, State high) { 333 if (high == null) { 334 if (low == null) { 335 return new State(); 336 } 337 return low; 338 } 339 if (low == null) { 340 return high; 341 } 342 State result = new State(); 343 // Compilable 344 result.compile[Scenario.Compiler.C1.ordinal()] = mergeOptional( 345 high.compile[Scenario.Compiler.C1.ordinal()], 346 low.compile[Scenario.Compiler.C1.ordinal()]); 347 result.compile[Scenario.Compiler.C2.ordinal()] = mergeOptional( 348 high.compile[Scenario.Compiler.C2.ordinal()], 349 low.compile[Scenario.Compiler.C2.ordinal()]); 350 // Force inline 351 result.forceInline[Scenario.Compiler.C1.ordinal()] = mergeOptional( 352 high.forceInline[Scenario.Compiler.C1.ordinal()], 353 low.forceInline[Scenario.Compiler.C1.ordinal()]); 354 result.forceInline[Scenario.Compiler.C2.ordinal()] = mergeOptional( 355 high.forceInline[Scenario.Compiler.C2.ordinal()], 356 low.forceInline[Scenario.Compiler.C2.ordinal()]); 357 // Don't inline 358 result.dontInline[Scenario.Compiler.C1.ordinal()] = mergeOptional( 359 high.dontInline[Scenario.Compiler.C1.ordinal()], 360 low.dontInline[Scenario.Compiler.C1.ordinal()]); 361 result.dontInline[Scenario.Compiler.C2.ordinal()] = mergeOptional( 362 high.dontInline[Scenario.Compiler.C2.ordinal()], 363 low.dontInline[Scenario.Compiler.C2.ordinal()]); 364 // set PrintAssembly 365 result.printAssembly = mergeOptional(high.printAssembly, 366 low.printAssembly); 367 // set PrintInline 368 result.printInline = mergeOptional(high.printInline, low.printInline); 369 // set LogCompilation 370 result.log = mergeOptional(high.log, low.log); 371 return result; 372 } 373 mergeOptional(Optional<T> high, Optional<T> low)374 private static <T> Optional<T> mergeOptional(Optional<T> high, 375 Optional<T> low) { 376 T val = high.orElse(low.orElse(null)); 377 return Optional.ofNullable(val); 378 } 379 } 380