8143308: Add inline checks and tests
Fix inlining state creation Reviewed-by: twisti
This commit is contained in:
parent
d4170d0bba
commit
8f2fb74418
@ -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();
|
||||
|
@ -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;
|
||||
|
@ -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()) {
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user