8143308: Add inline checks and tests
Summary: Fix inlining state creation
Reviewed-by: twisti
--- a/hotspot/test/compiler/compilercontrol/parser/HugeDirectiveUtil.java Wed Nov 25 00:40:04 2015 +0100
+++ b/hotspot/test/compiler/compilercontrol/parser/HugeDirectiveUtil.java Thu Nov 26 03:05:19 2015 +0300
@@ -31,6 +31,7 @@
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 @@
// 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();
--- a/hotspot/test/compiler/compilercontrol/share/actions/BaseAction.java Wed Nov 25 00:40:04 2015 +0100
+++ b/hotspot/test/compiler/compilercontrol/share/actions/BaseAction.java Thu Nov 26 03:05:19 2015 +0300
@@ -55,12 +55,16 @@
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 @@
}
}
- 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 @@
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;
--- a/hotspot/test/compiler/compilercontrol/share/scenario/DirectiveBuilder.java Wed Nov 25 00:40:04 2015 +0100
+++ b/hotspot/test/compiler/compilercontrol/share/scenario/DirectiveBuilder.java Thu Nov 26 03:05:19 2015 +0300
@@ -46,9 +46,9 @@
= 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 @@
@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 @@
* 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 @@
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 @@
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 @@
* 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 @@
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 @@
}
}
+ 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()) {
--- a/hotspot/test/compiler/compilercontrol/share/scenario/DirectiveWriter.java Wed Nov 25 00:40:04 2015 +0100
+++ b/hotspot/test/compiler/compilercontrol/share/scenario/DirectiveWriter.java Thu Nov 26 03:05:19 2015 +0300
@@ -26,6 +26,8 @@
import compiler.compilercontrol.share.JSONFile;
import compiler.compilercontrol.share.method.MethodDescriptor;
+import java.util.List;
+
/**
* Simple directive file writer.
*/
@@ -86,6 +88,20 @@
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 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 enum Option {
PRINT_ASSEMBLY("PrintAssembly"),
LOG("Log"),
- EXCLUDE("Exclude");
+ EXCLUDE("Exclude"),
+ ENABLE("Enable");
public final String string;
--- a/hotspot/test/compiler/compilercontrol/share/scenario/Executor.java Wed Nov 25 00:40:04 2015 +0100
+++ b/hotspot/test/compiler/compilercontrol/share/scenario/Executor.java Thu Nov 26 03:05:19 2015 +0300
@@ -47,6 +47,9 @@
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 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) {
--- a/hotspot/test/compiler/compilercontrol/share/scenario/JcmdStateBuilder.java Wed Nov 25 00:40:04 2015 +0100
+++ b/hotspot/test/compiler/compilercontrol/share/scenario/JcmdStateBuilder.java Thu Nov 26 03:05:19 2015 +0300
@@ -43,8 +43,9 @@
= 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 @@
break;
case CLEAR:
matchBlocks.clear();
+ inlines.clear();
break;
case REMOVE:
removeDirective();
@@ -72,15 +74,24 @@
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 @@
@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 @@
* 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);
--- a/hotspot/test/compiler/compilercontrol/share/scenario/Scenario.java Wed Nov 25 00:40:04 2015 +0100
+++ b/hotspot/test/compiler/compilercontrol/share/scenario/Scenario.java Thu Nov 26 03:05:19 2015 +0300
@@ -253,13 +253,13 @@
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);
}
--- a/hotspot/test/compiler/compilercontrol/share/scenario/State.java Wed Nov 25 00:40:04 2015 +0100
+++ b/hotspot/test/compiler/compilercontrol/share/scenario/State.java Thu Nov 26 03:05:19 2015 +0300
@@ -182,11 +182,13 @@
}
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 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 @@
if (value && isC2Compilable()) {
setForceInline(Scenario.Compiler.C2.ordinal());
} else {
- setDontInline(Scenario.Compiler.C1.ordinal());
+ setDontInline(Scenario.Compiler.C2.ordinal());
}
}