555dd24642
Fix exclude command generation Reviewed-by: kvn
380 lines
13 KiB
Java
380 lines
13 KiB
Java
/*
|
|
* 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);
|
|
}
|
|
}
|