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 }