--- /dev/null 2015-08-04 16:55:50.726524033 +0300 +++ new/test/compiler/compilercontrol/share/scenario/State.java 2015-09-28 15:03:28.168697220 +0300 @@ -0,0 +1,376 @@ +/* + * 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 { + public static enum Compiler { + C1, + C2 + } + + // Each of the two-elements array contains a state for each compiler + private Optional[] compile = + (Optional[]) new Optional[Compiler.values().length]; + private Optional[] forceInline = + (Optional[]) new Optional[Compiler.values().length]; + private Optional[] dontInline = + (Optional[]) new Optional[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[Compiler.C1.ordinal()].orElse(true); + } + + public boolean isC2Compilable() { + return compile[Compiler.C2.ordinal()].orElse(true); + } + + public boolean isCompilable() { + return isC1Compilable() && isC2Compilable(); + } + + public void setC1Compilable(boolean value) { + setCompilable(Compiler.C1.ordinal(), value); + } + + public void setC2Compilable(boolean value) { + setCompilable(Compiler.C2.ordinal(), value); + } + + public void setCompilable(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[Compiler.C1.ordinal()].orElse(false); + } + + public boolean isC2Inlinable() { + return ! dontInline[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[Compiler.C1.ordinal()].orElse(false); + } + + public boolean isC2ForceInline() { + return forceInline[Compiler.C2.ordinal()].orElse(false); + } + + public boolean isForceInline() { + return isC1ForceInline() && isC2ForceInline(); + } + + public void setC1Inline(boolean value) { + if (value && isC1Compilable()) { + setForceInline(Compiler.C1.ordinal()); + } else { + setDontInline(Compiler.C1.ordinal()); + } + } + + public void setC2Inline(boolean value) { + if (value && isC2Compilable()) { + setForceInline(Compiler.C2.ordinal()); + } else { + setDontInline(Compiler.C1.ordinal()); + } + } + + public void setInline(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[Compiler.C1.ordinal()] = mergeOptional( + high.compile[Compiler.C1.ordinal()], + low.compile[Compiler.C1.ordinal()]); + result.compile[Compiler.C2.ordinal()] = mergeOptional( + high.compile[Compiler.C2.ordinal()], + low.compile[Compiler.C2.ordinal()]); + // Force inline + result.forceInline[Compiler.C1.ordinal()] = mergeOptional( + high.forceInline[Compiler.C1.ordinal()], + low.forceInline[Compiler.C1.ordinal()]); + result.forceInline[Compiler.C2.ordinal()] = mergeOptional( + high.forceInline[Compiler.C2.ordinal()], + low.forceInline[Compiler.C2.ordinal()]); + // Don't inline + result.dontInline[Compiler.C1.ordinal()] = mergeOptional( + high.dontInline[Compiler.C1.ordinal()], + low.dontInline[Compiler.C1.ordinal()]); + result.dontInline[Compiler.C2.ordinal()] = mergeOptional( + high.dontInline[Compiler.C2.ordinal()], + low.dontInline[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); + } +}