8143308: Add inline checks and tests

Fix inlining state creation

Reviewed-by: twisti
This commit is contained in:
Pavel Punegov 2015-11-26 03:05:19 +03:00
parent d4170d0bba
commit 8f2fb74418
8 changed files with 193 additions and 73 deletions

View File

@ -31,6 +31,7 @@ import jdk.test.lib.OutputAnalyzer;
import jdk.test.lib.ProcessTools;
import jdk.test.lib.Utils;
import java.util.EnumSet;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
@ -80,19 +81,21 @@ public final class HugeDirectiveUtil {
// emit compiler block
file.emitCompiler(Utils.getRandomElement(
Scenario.Compiler.values()));
// add option inside the compiler block
file.option(Utils.getRandomElement(DirectiveWriter.Option.values()),
RANDOM.nextBoolean());
file.end(); // ends compiler block
// add standalone option
file.option(Utils.getRandomElement(DirectiveWriter.Option.values()),
RANDOM.nextBoolean());
// add standalone option, enable can't be used standalone
EnumSet<DirectiveWriter.Option> options = EnumSet.complementOf(
EnumSet.of(DirectiveWriter.Option.ENABLE));
file.option(Utils.getRandomElement(options), RANDOM.nextBoolean());
}
// add inline block with random inlinees
methods = getRandomDescriptors(descriptors).stream()
.map(s -> (RANDOM.nextBoolean() ? "+" : "-") + s)
.collect(Collectors.toList());
file.inline(methods.toArray(new String[methods.size()]));
file.inline(methods);
// end match block
file.end();

View File

@ -55,12 +55,16 @@ public class BaseAction {
pair -> pair.first));
}
public static void main(String[] args) {
new BaseAction().communicate(args);
}
/*
* args[0] is a port to connect
* args[1] is an optional parameter that shows that the state map should be
* passed
*/
public static void main(String[] args) {
protected void communicate(String[] args) {
if (args.length < 1) {
throw new Error("TESTBUG: requires port as parameter: "
+ Arrays.toString(args));
@ -102,7 +106,7 @@ public class BaseAction {
}
}
private static Map<Executable, State> decodeMap(List<String> lines) {
private Map<Executable, State> decodeMap(List<String> lines) {
if (lines == null || lines.size() == 0) {
throw new Error("TESTBUG: unexpected lines list");
}
@ -130,7 +134,7 @@ public class BaseAction {
return stateMap;
}
protected static void check(Map<Executable, State> methodStates) {
protected void check(Map<Executable, State> methodStates) {
// Check each method from the pool
METHODS.forEach(pair -> {
Executable x = pair.first;

View File

@ -46,9 +46,9 @@ public class DirectiveBuilder implements StateBuilder<CompileCommand> {
= new PoolHelper().getAllMethods();
private final Map<Executable, State> stateMap = new HashMap<>();
private final String fileName;
private Map<MethodDescriptor, List<CompileCommand>> matchBlocks
private final Map<MethodDescriptor, List<CompileCommand>> matchBlocks
= new LinkedHashMap<>();
private List<String> inlineMatch = new ArrayList<>();
private final List<CompileCommand> inlines = new ArrayList<>();
private boolean isFileValid = true;
public DirectiveBuilder(String fileName) {
@ -81,20 +81,36 @@ public class DirectiveBuilder implements StateBuilder<CompileCommand> {
@Override
public Map<Executable, State> getStates() {
writeDirectiveFile();
if (isFileValid) {
// Build states for each method according to match blocks
for (Pair<Executable, Callable<?>> pair : METHODS) {
State state = getState(pair);
if (state != null) {
stateMap.put(pair.first, state);
}
}
return stateMap;
} else {
// return empty map because invalid file doesn't change states
return new HashMap<>();
}
}
private void writeDirectiveFile() {
try (DirectiveWriter dirFile = new DirectiveWriter(fileName)) {
for (MethodDescriptor matchDescriptor : matchBlocks.keySet()) {
// Write match block with all options converted from commands
dirFile.match(matchDescriptor);
for (CompileCommand compileCommand :
matchBlocks.get(matchDescriptor)) {
isFileValid &= compileCommand.isValid();
handleCommand(dirFile, compileCommand);
}
if ("Inlinee.caller".matches((matchDescriptor.getRegexp()))) {
if ("Inlinee.caller()".matches(matchDescriptor.getRegexp())
&& !inlines.isEmpty()) {
// Got a *.* match block, where inline would be written
dirFile.inline(inlineMatch.toArray(
new String[inlineMatch.size()]));
inlineMatch.clear();
writeInlines(dirFile);
inlines.clear();
}
dirFile.end(); // ends match block
}
@ -104,12 +120,12 @@ public class DirectiveBuilder implements StateBuilder<CompileCommand> {
* if we didn't do this before
* Inlinee caller methods should match this block only
*/
if (!inlineMatch.isEmpty()) {
if (!inlines.isEmpty()) {
Pair<Executable, Callable<?>> pair = METHODS.get(0);
MethodDescriptor md = MethodGenerator.anyMatchDescriptor(
pair.first);
CompileCommand cc = new CompileCommand(Command.QUIET, md, null,
Scenario.Type.DIRECTIVE);
CompileCommand cc = new CompileCommand(Command.QUIET, md,
null, Scenario.Type.DIRECTIVE);
List<CompileCommand> commands = new ArrayList<>();
// Add appropriate "*.*" match block
@ -117,8 +133,7 @@ public class DirectiveBuilder implements StateBuilder<CompileCommand> {
matchBlocks.put(md, commands);
// Add match block for this descriptor with inlines
dirFile.match(md);
dirFile.inline(inlineMatch.toArray(
new String[inlineMatch.size()]));
writeInlines(dirFile);
dirFile.end();
}
if (!matchBlocks.isEmpty()) {
@ -126,19 +141,6 @@ public class DirectiveBuilder implements StateBuilder<CompileCommand> {
dirFile.end();
}
// Build states for each method according to match blocks
for (Pair<Executable, Callable<?>> pair : METHODS) {
State state = getState(pair);
if (state != null) {
stateMap.put(pair.first, state);
}
}
}
if (isFileValid) {
return stateMap;
} else {
// return empty map because invalid file doesn't change states
return new HashMap<>();
}
}
@ -158,7 +160,9 @@ public class DirectiveBuilder implements StateBuilder<CompileCommand> {
* then apply commands from this match to the state
*/
for (CompileCommand cc : matchBlocks.get(matchDesc)) {
state = new State();
if (state == null) {
state = new State();
}
if (!isMatchFound) {
// this is a first found match, apply all commands
state.apply(cc);
@ -188,16 +192,23 @@ public class DirectiveBuilder implements StateBuilder<CompileCommand> {
case EXCLUDE:
dirFile.excludeCompile(cmd.compiler, true);
break;
case QUIET:
/* there are no appropriate directive for this, just make
match be enabled */
case INLINE:
case DONTINLINE:
// Inline commands will be written later
/* Inline commands will be written later.
Just make this match be enabled */
dirFile.emitCompiler(Scenario.Compiler.C1);
dirFile.option(DirectiveWriter.Option.ENABLE, true);
dirFile.end();
dirFile.emitCompiler(Scenario.Compiler.C2);
dirFile.option(DirectiveWriter.Option.ENABLE, true);
dirFile.end();
break;
case LOG:
dirFile.option(DirectiveWriter.Option.LOG, true);
break;
case QUIET:
// there are no appropriate directive for this
break;
case PRINT:
dirFile.option(DirectiveWriter.Option.PRINT_ASSEMBLY, true);
break;
@ -214,16 +225,59 @@ public class DirectiveBuilder implements StateBuilder<CompileCommand> {
}
}
private void writeInlines(DirectiveWriter dirFile) {
List<String> c1Block = new ArrayList<>();
List<String> c2Block = new ArrayList<>();
List<String> allBlock = new ArrayList<>();
for (CompileCommand cc : inlines) {
String inlineMethodPattern;
switch (cc.command) {
case INLINE:
inlineMethodPattern = "+" + cc.methodDescriptor.getString();
break;
case DONTINLINE:
inlineMethodPattern = "-" + cc.methodDescriptor.getString();
break;
default:
throw new Error("TESTBUG: incorrect command got in "
+ "the list: " + cc.command);
}
if (cc.compiler == Scenario.Compiler.C1) {
c1Block.add(inlineMethodPattern);
} else if (cc.compiler == Scenario.Compiler.C2) {
c2Block.add(inlineMethodPattern);
} else {
allBlock.add(inlineMethodPattern);
}
}
dirFile.emitCompiler(Scenario.Compiler.C1);
if (!c1Block.isEmpty()) {
dirFile.inline(c1Block);
} else {
dirFile.option(DirectiveWriter.Option.ENABLE, true);
}
dirFile.end();
dirFile.emitCompiler(Scenario.Compiler.C2);
if (!c2Block.isEmpty()) {
dirFile.inline(c2Block);
} else {
dirFile.option(DirectiveWriter.Option.ENABLE, true);
}
dirFile.end();
if (!allBlock.isEmpty()) {
dirFile.inline(allBlock);
}
}
@Override
public void add(CompileCommand compileCommand) {
isFileValid &= compileCommand.isValid();
MethodDescriptor methodDescriptor = compileCommand.methodDescriptor;
switch (compileCommand.command) {
case INLINE:
inlineMatch.add("+" + methodDescriptor.getString());
break;
case DONTINLINE:
inlineMatch.add("-" + methodDescriptor.getString());
inlines.add(compileCommand);
break;
}
for (MethodDescriptor md: matchBlocks.keySet()) {

View File

@ -26,6 +26,8 @@ package compiler.compilercontrol.share.scenario;
import compiler.compilercontrol.share.JSONFile;
import compiler.compilercontrol.share.method.MethodDescriptor;
import java.util.List;
/**
* Simple directive file writer.
*/
@ -86,6 +88,20 @@ public class DirectiveWriter implements AutoCloseable {
return this;
}
/**
* Emits inline block with a given methods to be inlined or not.
* Each method should be prepended with + or - to show if it should be
* inlined or not.
*
* @param methods methods used for the inline
* @return this DirectiveWriter instance
*/
public DirectiveWriter inline(List<String> methods) {
write(JSONFile.Element.PAIR, "inline");
writeMethods(methods.toArray(new String[methods.size()]));
return this;
}
private void writeMethods(String[] methods) {
if (methods.length == 0) {
throw new IllegalArgumentException("ERROR: empty methods array");
@ -111,16 +127,15 @@ public class DirectiveWriter implements AutoCloseable {
*/
public DirectiveWriter excludeCompile(Scenario.Compiler compiler,
boolean exclude) {
if (compiler != null) {
emitCompiler(compiler);
option(Option.EXCLUDE, exclude);
end();
} else {
for (Scenario.Compiler comp : Scenario.Compiler.values()) {
emitCompiler(comp);
for (Scenario.Compiler comp : Scenario.Compiler.values()) {
emitCompiler(comp);
if (comp == compiler || compiler == null) {
option(Option.EXCLUDE, exclude);
end(); // end compiler block
} else {
// just make this block be enabled
option(Option.ENABLE, true);
}
end(); // end compiler block
}
return this;
}
@ -176,7 +191,8 @@ public class DirectiveWriter implements AutoCloseable {
public enum Option {
PRINT_ASSEMBLY("PrintAssembly"),
LOG("Log"),
EXCLUDE("Exclude");
EXCLUDE("Exclude"),
ENABLE("Enable");
public final String string;

View File

@ -47,6 +47,9 @@ public class Executor {
private final List<String> vmOptions;
private final Map<Executable, State> states;
private final List<String> jcmdCommands;
private final String execClass = System.getProperty("compiler."
+ "compilercontrol.share.executor.executeClass",
BaseAction.class.getName());
private OutputAnalyzer[] jcmdOutputAnalyzers;
/**
@ -77,8 +80,7 @@ public class Executor {
*/
public List<OutputAnalyzer> execute() {
// Add class name that would be executed in a separate VM
String classCmd = BaseAction.class.getName();
vmOptions.add(classCmd);
vmOptions.add(execClass);
OutputAnalyzer output;
try (ServerSocket serverSocket = new ServerSocket(0)) {
if (isValid) {

View File

@ -43,8 +43,9 @@ public class JcmdStateBuilder implements StateBuilder<JcmdCommand> {
= new PoolHelper().getAllMethods();
private final Map<Executable, State> stateMap = new HashMap<>();
private final DirectiveBuilder directiveBuilder;
private Map<MethodDescriptor, List<CompileCommand>> matchBlocks
private final Map<MethodDescriptor, List<CompileCommand>> matchBlocks
= new LinkedHashMap<>();
private final List<CompileCommand> inlines = new ArrayList<>();
private boolean isFileValid = true;
public JcmdStateBuilder(String fileName) {
@ -63,6 +64,7 @@ public class JcmdStateBuilder implements StateBuilder<JcmdCommand> {
break;
case CLEAR:
matchBlocks.clear();
inlines.clear();
break;
case REMOVE:
removeDirective();
@ -72,15 +74,24 @@ public class JcmdStateBuilder implements StateBuilder<JcmdCommand> {
private void addCommand(JcmdCommand compileCommand) {
isFileValid &= compileCommand.isValid();
MethodDescriptor methodDescriptor = compileCommand.methodDescriptor;
switch (compileCommand.command) {
case INLINE:
case DONTINLINE:
inlines.add(compileCommand);
break;
}
for (MethodDescriptor md: matchBlocks.keySet()) {
if (compileCommand.methodDescriptor.getCanonicalString()
.matches(md.getRegexp())) {
if (methodDescriptor.getCanonicalString().matches(md.getRegexp())) {
matchBlocks.get(md).add(compileCommand);
}
}
List<CompileCommand> commands = new ArrayList<>();
commands.add(compileCommand);
matchBlocks.put(compileCommand.methodDescriptor, commands);
if (!matchBlocks.containsKey(compileCommand.methodDescriptor)) {
List<CompileCommand> commands = new ArrayList<>();
commands.add(compileCommand);
matchBlocks.put(compileCommand.methodDescriptor, commands);
}
}
private void removeDirective() {
@ -100,14 +111,38 @@ public class JcmdStateBuilder implements StateBuilder<JcmdCommand> {
@Override
public Map<Executable, State> getStates() {
directiveBuilder.getStates();
// Build states for each method according to match blocks
for (Pair<Executable, Callable<?>> pair : METHODS) {
State state = getState(pair);
if (state != null) {
stateMap.put(pair.first, state);
for (MethodDescriptor matchDescriptor : matchBlocks.keySet()) {
if ("Inlinee.caller()".matches(matchDescriptor.getRegexp())
&& !inlines.isEmpty()) {
// Got a *.* match block, where inline would be written
inlines.clear();
}
}
/*
* Write inline directive in the end to the latest match block
* if we didn't do this before
* Inlinee caller methods should match this block only
*/
if (!inlines.isEmpty()) {
Pair<Executable, Callable<?>> pair = METHODS.get(0);
MethodDescriptor md = MethodGenerator.anyMatchDescriptor(
pair.first);
CompileCommand cc = new CompileCommand(Command.QUIET, md,
null, Scenario.Type.DIRECTIVE);
List<CompileCommand> commands = new ArrayList<>();
// Add appropriate "*.*" match block
commands.add(cc);
matchBlocks.put(md, commands);
}
if (isFileValid) {
// Build states for each method according to match blocks
for (Pair<Executable, Callable<?>> pair : METHODS) {
State state = getState(pair);
if (state != null) {
stateMap.put(pair.first, state);
}
}
return stateMap;
} else {
// return empty map because invalid file doesn't change states
@ -131,7 +166,9 @@ public class JcmdStateBuilder implements StateBuilder<JcmdCommand> {
* then apply commands from this match to the state
*/
for (CompileCommand cc : matchBlocks.get(matchDesc)) {
state = new State();
if (state == null) {
state = new State();
}
if (!isMatchFound) {
// this is a first found match, apply all commands
state.apply(cc);

View File

@ -253,13 +253,13 @@ public final class Scenario {
State st = State.merge(commandOptionState, commandFileState);
if (!isClearedState) {
State directiveState = directiveFileStates.get(x);
if (directiveState != null) {
st = directiveState;
State jcmdState = jcmdStates.get(x);
if (jcmdState != null) {
st = State.merge(st, jcmdState);
} else if (directiveState != null) {
st = State.merge(st, directiveState);
}
}
State jcmdState = jcmdStates.get(x);
st = State.merge(st, jcmdState);
finalStates.put(x, st);
}

View File

@ -182,11 +182,13 @@ public class State {
}
public boolean isC1Inlinable() {
return ! dontInline[Scenario.Compiler.C1.ordinal()].orElse(false);
return ! dontInline[Scenario.Compiler.C1.ordinal()].orElse(false)
&& isC1Compilable();
}
public boolean isC2Inlinable() {
return ! dontInline[Scenario.Compiler.C2.ordinal()].orElse(false);
return ! dontInline[Scenario.Compiler.C2.ordinal()].orElse(false)
&& isC2Compilable();
}
public boolean isInlinable() {
@ -206,11 +208,13 @@ public class State {
}
public boolean isC1ForceInline() {
return forceInline[Scenario.Compiler.C1.ordinal()].orElse(false);
return forceInline[Scenario.Compiler.C1.ordinal()].orElse(false)
&& isC1Compilable();
}
public boolean isC2ForceInline() {
return forceInline[Scenario.Compiler.C2.ordinal()].orElse(false);
return forceInline[Scenario.Compiler.C2.ordinal()].orElse(false)
&& isC2Compilable();
}
public boolean isForceInline() {
@ -229,7 +233,7 @@ public class State {
if (value && isC2Compilable()) {
setForceInline(Scenario.Compiler.C2.ordinal());
} else {
setDontInline(Scenario.Compiler.C1.ordinal());
setDontInline(Scenario.Compiler.C2.ordinal());
}
}