/* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package compiler.compilercontrol.share.scenario; import jdk.test.lib.Asserts; import java.util.Arrays; import java.util.Optional; /** * Represents method compilation state */ public class State { // Each of the two-elements array contains a state for each compiler private Optional[] compile = (Optional[]) new Optional[Scenario.Compiler.values().length]; private Optional[] forceInline = (Optional[]) new Optional[Scenario.Compiler.values().length]; private Optional[] dontInline = (Optional[]) new Optional[Scenario.Compiler.values().length]; private Optional printAssembly = Optional.empty(); private Optional printInline = Optional.empty(); private Optional log = Optional.empty(); public State() { Arrays.fill(compile, Optional.empty()); Arrays.fill(forceInline, Optional.empty()); Arrays.fill(dontInline, Optional.empty()); } /** * Creates state from the string * * @param strings array of strings that represent the state * @return State instance * @see #toString() */ public static State fromString(String[] strings) { Asserts.assertNotNull(strings, "Non null array is required"); Asserts.assertNE(strings.length, 0, "Non empty array is required"); State st = new State(); for (String string : strings) { int i = string.indexOf(' '); String command = string.substring(0, i); String values = string.substring(i + 1); // skip space symbol switch (command) { case "compile" : parseArray(st.compile, values); break; case "force_inline" : parseArray(st.forceInline, values); break; case "dont_inline" : parseArray(st.dontInline, values); break; case "log" : st.log = parseElement(values); break; case "print_assembly" : st.printAssembly = parseElement(values); break; case "print_inline" : st.printInline = parseElement(values); break; default: throw new Error("TESTBUG: "); } } return st; } private static void parseArray(Optional[] array, String str) { Asserts.assertNotNull(str); int beginBrace = 0; int endBrace = str.length() - 1; if (str.charAt(beginBrace) != '[' || str.charAt(endBrace) != ']') { throw new Error("TESTBUG: not an array type: " + str); } // Get all elements divided with comma as an array String[] strValues = str.substring(beginBrace + 1, endBrace) .split(", "); Asserts.assertEQ(strValues.length, array.length, "Different amount of " + "elements in the string"); for (int i = 0; i < strValues.length; i++) { array[i] = parseElement(strValues[i]); } } private static Optional parseElement(String str) { Asserts.assertNotNull(str); Asserts.assertTrue(str.startsWith(Optional.class.getSimpleName()), "String is not of type Optional: " + str); if ("Optional.empty".equals(str)) { return Optional.empty(); } int begin = str.indexOf('['); Asserts.assertNE(begin, -1, "TEST BUG: Wrong Optional string"); int end = str.indexOf(']'); Asserts.assertEQ(end, str.length() - 1); boolean b = Boolean.parseBoolean(str.substring(begin + 1, end)); return Optional.of(b); } /** * Gets string representation of this state */ @Override public String toString() { return "compile " + Arrays.toString(compile) + "\nforce_inline " + Arrays.toString(forceInline) + "\ndont_inline " + Arrays.toString(dontInline) + "\nlog " + log + "\nprint_assembly " + printAssembly + "\nprint_inline " + printInline; } public boolean isC1Compilable() { return compile[Scenario.Compiler.C1.ordinal()].orElse(true); } public boolean isC2Compilable() { return compile[Scenario.Compiler.C2.ordinal()].orElse(true); } public boolean isCompilable() { return isC1Compilable() && isC2Compilable(); } public void setC1Compilable(boolean value) { setCompilable(Scenario.Compiler.C1.ordinal(), value); } public void setC2Compilable(boolean value) { setCompilable(Scenario.Compiler.C2.ordinal(), value); } public void setCompilable(Scenario.Compiler compiler, boolean value) { if (compiler == null) { setC1Compilable(value); setC2Compilable(value); return; } switch (compiler) { case C1: setC1Compilable(value); break; case C2: setC2Compilable(value); break; default: throw new Error("Unknown compiler"); } } private void setCompilable(int level, boolean value) { check(level); compile[level] = Optional.of(value); if (!value) { setDontInline(level); } } public boolean isC1Inlinable() { return ! dontInline[Scenario.Compiler.C1.ordinal()].orElse(false); } public boolean isC2Inlinable() { return ! dontInline[Scenario.Compiler.C2.ordinal()].orElse(false); } public boolean isInlinable() { return isC1Inlinable() && isC2Inlinable(); } private void setDontInline(int level) { check(level); dontInline[level] = Optional.of(true); forceInline[level] = Optional.of(false); } private void setForceInline(int level) { check(level); dontInline[level] = Optional.of(false); forceInline[level] = Optional.of(true); } public boolean isC1ForceInline() { return forceInline[Scenario.Compiler.C1.ordinal()].orElse(false); } public boolean isC2ForceInline() { return forceInline[Scenario.Compiler.C2.ordinal()].orElse(false); } public boolean isForceInline() { return isC1ForceInline() && isC2ForceInline(); } public void setC1Inline(boolean value) { if (value && isC1Compilable()) { setForceInline(Scenario.Compiler.C1.ordinal()); } else { setDontInline(Scenario.Compiler.C1.ordinal()); } } public void setC2Inline(boolean value) { if (value && isC2Compilable()) { setForceInline(Scenario.Compiler.C2.ordinal()); } else { setDontInline(Scenario.Compiler.C1.ordinal()); } } public void setInline(Scenario.Compiler compiler, boolean value) { if (compiler == null) { setC1Inline(value); setC2Inline(value); return; } switch (compiler) { case C1: setC1Inline(value); break; case C2: setC2Inline(value); break; default: throw new Error("Unknown compiler"); } } public boolean isPrintAssembly() { return printAssembly.orElse(false); } public void setPrintAssembly(boolean value) { printAssembly = Optional.of(value); } public boolean isPrintInline() { return printInline.orElse(false); } public void setPrintInline(boolean value) { printInline = Optional.of(value); } public boolean isLog() { return log.orElse(false); } public void setLog(boolean log) { this.log = Optional.of(log); } private void check(int level) { if (level < 0 || level > compile.length) { throw new IllegalArgumentException("TESTBUG: Wrong level " + level); } } /** * Applies given command to the state. * * @param compileCommand command to be applied */ public void apply(CompileCommand compileCommand) { switch (compileCommand.command) { case COMPILEONLY: setCompilable(compileCommand.compiler, true); break; case EXCLUDE: setCompilable(compileCommand.compiler, false); break; case INLINE: setInline(compileCommand.compiler, true); break; case DONTINLINE: setInline(compileCommand.compiler, false); break; case LOG: setLog(true); break; case PRINT: setPrintAssembly(true); break; case QUIET: case NONEXISTENT: // doesn't apply the state break; default: throw new Error("Wrong command: " + compileCommand.command); } } /** * Merges two given states with different priority * * @param low state with lower merge priority * @param high state with higher merge priority */ public static State merge(State low, State high) { if (high == null) { if (low == null) { return new State(); } return low; } if (low == null) { return high; } State result = new State(); // Compilable result.compile[Scenario.Compiler.C1.ordinal()] = mergeOptional( high.compile[Scenario.Compiler.C1.ordinal()], low.compile[Scenario.Compiler.C1.ordinal()]); result.compile[Scenario.Compiler.C2.ordinal()] = mergeOptional( high.compile[Scenario.Compiler.C2.ordinal()], low.compile[Scenario.Compiler.C2.ordinal()]); // Force inline result.forceInline[Scenario.Compiler.C1.ordinal()] = mergeOptional( high.forceInline[Scenario.Compiler.C1.ordinal()], low.forceInline[Scenario.Compiler.C1.ordinal()]); result.forceInline[Scenario.Compiler.C2.ordinal()] = mergeOptional( high.forceInline[Scenario.Compiler.C2.ordinal()], low.forceInline[Scenario.Compiler.C2.ordinal()]); // Don't inline result.dontInline[Scenario.Compiler.C1.ordinal()] = mergeOptional( high.dontInline[Scenario.Compiler.C1.ordinal()], low.dontInline[Scenario.Compiler.C1.ordinal()]); result.dontInline[Scenario.Compiler.C2.ordinal()] = mergeOptional( high.dontInline[Scenario.Compiler.C2.ordinal()], low.dontInline[Scenario.Compiler.C2.ordinal()]); // set PrintAssembly result.printAssembly = mergeOptional(high.printAssembly, low.printAssembly); // set PrintInline result.printInline = mergeOptional(high.printInline, low.printInline); // set LogCompilation result.log = mergeOptional(high.log, low.log); return result; } private static Optional mergeOptional(Optional high, Optional low) { T val = high.orElse(low.orElse(null)); return Optional.ofNullable(val); } }