blob: 82a46e7dc6993c346ba8b85bd498331390d66146 [file] [log] [blame]
/*
* 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<Boolean>[] compile =
(Optional<Boolean>[]) new Optional[Scenario.Compiler.values().length];
private Optional<Boolean>[] forceInline =
(Optional<Boolean>[]) new Optional[Scenario.Compiler.values().length];
private Optional<Boolean>[] dontInline =
(Optional<Boolean>[]) new Optional[Scenario.Compiler.values().length];
private Optional<Boolean> printAssembly = Optional.empty();
private Optional<Boolean> printInline = Optional.empty();
private Optional<Boolean> 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<Boolean>[] 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<Boolean> 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 Optional<Boolean> getCompilableOptional(Scenario.Compiler compiler) {
return compile[compiler.ordinal()];
}
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)
&& isC1Compilable();
}
public boolean isC2Inlinable() {
return ! dontInline[Scenario.Compiler.C2.ordinal()].orElse(false)
&& isC2Compilable();
}
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)
&& isC1Compilable();
}
public boolean isC2ForceInline() {
return forceInline[Scenario.Compiler.C2.ordinal()].orElse(false)
&& isC2Compilable();
}
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.C2.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 <T> Optional<T> mergeOptional(Optional<T> high,
Optional<T> low) {
T val = high.orElse(low.orElse(null));
return Optional.ofNullable(val);
}
}