8138993: JEP-JDK-8046155: Test task: add check for Compiler.directives_print diagnostic command
Summary: Test Compiler.directive_print command
Reviewed-by: iignatyev, neliasso
--- a/hotspot/test/compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java Tue Nov 24 20:52:15 2015 +0300
+++ b/hotspot/test/compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java Tue Nov 24 20:55:46 2015 +0300
@@ -26,7 +26,7 @@
* @bug 8137167
* @ignore 8140405
* @summary Tests jcmd to be able to clear directives added via options
- * @library /testlibrary /../../test/lib /compiler/testlibrary ../share /
+ * @library /testlibrary /test/lib /compiler/testlibrary ../share /
* @build ClearDirectivesFileStackTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox
* compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.*
* @run main ClassFileInstaller sun.hotspot.WhiteBox
@@ -73,9 +73,6 @@
compileCommand.print();
builder.add(compileCommand);
}
- // print all directives before
- builder.add(new JcmdCommand(Command.NONEXISTENT, null, null,
- Scenario.Type.JCMD, Scenario.JcmdType.PRINT));
// clear the stack
builder.add(new JcmdCommand(Command.NONEXISTENT, null, null,
Scenario.Type.JCMD, Scenario.JcmdType.CLEAR));
--- a/hotspot/test/compiler/compilercontrol/jcmd/ClearDirectivesStackTest.java Tue Nov 24 20:52:15 2015 +0300
+++ b/hotspot/test/compiler/compilercontrol/jcmd/ClearDirectivesStackTest.java Tue Nov 24 20:55:46 2015 +0300
@@ -25,7 +25,7 @@
* @test
* @bug 8137167
* @summary Tests clear JCMD command
- * @library /testlibrary /../../test/lib /compiler/testlibrary ../share /
+ * @library /testlibrary /test/lib /compiler/testlibrary ../share /
* @build ClearDirectivesStackTest pool.sub.* pool.subpack.* sun.hotspot.WhiteBox
* compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.*
* @run main ClassFileInstaller sun.hotspot.WhiteBox
@@ -68,9 +68,6 @@
compileCommand.print();
builder.add(compileCommand);
}
- // print all directives before
- builder.add(new JcmdCommand(Command.NONEXISTENT, null, null,
- Scenario.Type.JCMD, Scenario.JcmdType.PRINT));
// clear the stack
builder.add(new JcmdCommand(Command.NONEXISTENT, null, null,
Scenario.Type.JCMD, Scenario.JcmdType.CLEAR));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/compilercontrol/jcmd/PrintDirectivesTest.java Tue Nov 24 20:55:46 2015 +0300
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+/*
+ * @test
+ * @bug 8137167
+ * @summary Tests jcmd to be able to add a directive to compile only specified methods
+ * @library /testlibrary /test/lib /compiler/testlibrary ../share /
+ * @build pool.sub.* pool.subpack.* sun.hotspot.WhiteBox
+ * compiler.testlibrary.CompilerUtils compiler.compilercontrol.share.actions.*
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * sun.hotspot.WhiteBox$WhiteBoxPermission
+ * @run main/othervm compiler.compilercontrol.jcmd.PrintDirectivesTest
+ */
+
+package compiler.compilercontrol.jcmd;
+
+import compiler.compilercontrol.share.AbstractTestBase;
+import compiler.compilercontrol.share.method.MethodDescriptor;
+import compiler.compilercontrol.share.scenario.Command;
+import compiler.compilercontrol.share.scenario.CommandGenerator;
+import compiler.compilercontrol.share.scenario.CompileCommand;
+import compiler.compilercontrol.share.scenario.JcmdCommand;
+import compiler.compilercontrol.share.scenario.Scenario;
+import jdk.test.lib.Utils;
+
+import java.lang.reflect.Executable;
+
+public class PrintDirectivesTest extends AbstractTestBase {
+ private static final int AMOUNT = Utils.getRandomInstance().nextInt(
+ Integer.getInteger("compiler.compilercontrol.jcmd."
+ + "PrintDirectivesTest.amount", 20));
+ private final CommandGenerator cmdGen = new CommandGenerator();
+
+ public static void main(String[] args) {
+ new PrintDirectivesTest().test();
+ }
+
+ @Override
+ public void test() {
+ Scenario.Builder builder = Scenario.getBuilder();
+ // Add some commands with directives file
+ for (int i = 0; i < AMOUNT; i++) {
+ Executable exec = Utils.getRandomElement(METHODS).first;
+ MethodDescriptor methodDescriptor = getValidMethodDescriptor(exec);
+ Command command = cmdGen.generateCommand();
+ if (command == Command.NONEXISTENT) {
+ // skip invalid command
+ command = Command.COMPILEONLY;
+ }
+ CompileCommand compileCommand = new CompileCommand(command,
+ methodDescriptor, cmdGen.generateCompiler(),
+ Scenario.Type.DIRECTIVE);
+ compileCommand.print();
+ builder.add(compileCommand);
+ }
+ // print all directives
+ builder.add(new JcmdCommand(Command.NONEXISTENT, null, null,
+ Scenario.Type.JCMD, Scenario.JcmdType.PRINT));
+ Scenario scenario = builder.build();
+ scenario.execute();
+ }
+}
\ No newline at end of file
--- a/hotspot/test/compiler/compilercontrol/jcmd/StressAddJcmdBase.java Tue Nov 24 20:52:15 2015 +0300
+++ b/hotspot/test/compiler/compilercontrol/jcmd/StressAddJcmdBase.java Tue Nov 24 20:55:46 2015 +0300
@@ -55,8 +55,8 @@
public void test() {
List<String> commands = prepareCommands();
Executor executor = new TimeLimitedExecutor(commands);
- OutputAnalyzer outputAnalyzer = executor.execute();
- outputAnalyzer.shouldHaveExitValue(0);
+ List<OutputAnalyzer> outputAnalyzers = executor.execute();
+ outputAnalyzers.get(0).shouldHaveExitValue(0);
}
/**
@@ -95,7 +95,7 @@
}
@Override
- protected void executeJCMD(int pid) {
+ protected OutputAnalyzer[] executeJCMD(int pid) {
TimeLimitedRunner runner = new TimeLimitedRunner(
Utils.DEFAULT_TEST_TIMEOUT,
Utils.TIMEOUT_FACTOR,
@@ -106,6 +106,7 @@
throw new Error("Exception during the execution: " + e, e);
}
finish();
+ return new OutputAnalyzer[0];
}
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/compiler/compilercontrol/share/processors/PrintDirectivesProcessor.java Tue Nov 24 20:55:46 2015 +0300
@@ -0,0 +1,99 @@
+/*
+ * 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.processors;
+
+import compiler.compilercontrol.share.method.MethodDescriptor;
+import compiler.compilercontrol.share.scenario.CompileCommand;
+import jdk.test.lib.Asserts;
+import jdk.test.lib.OutputAnalyzer;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+
+public class PrintDirectivesProcessor
+ implements Consumer<List<OutputAnalyzer>> {
+ private final List<CompileCommand> commands;
+ private static final Pattern MATCH_PATTERN
+ = Pattern.compile(" matching: (.*)");
+
+ public PrintDirectivesProcessor(List<CompileCommand> commands) {
+ this.commands = commands;
+ }
+
+ @Override
+ public void accept(List<OutputAnalyzer> outputAnalyzers) {
+ List<String> directives = new ArrayList<>();
+ outputAnalyzers.forEach(outputAnalyzer ->
+ directives.addAll(getDirectives(outputAnalyzer)));
+ List<String> expectedDirectives = commands.stream()
+ .map(cc -> cc.methodDescriptor)
+ .map(MethodDescriptor::getCanonicalString)
+ .collect(Collectors.toList());
+
+ if (directives.size() != expectedDirectives.size()) {
+ printDirectives(directives, expectedDirectives);
+ throw new AssertionError(String.format("Different number of "
+ + "directives. Expected: %d, actual: %d",
+ expectedDirectives.size(), directives.size()));
+ }
+ for (int i = 0; i < directives.size(); i++) {
+ if (!directives.get(i).equals(expectedDirectives.get(i))) {
+ printDirectives(directives, expectedDirectives);
+ throw new AssertionError(
+ String.format("Directives differ at %d, expected:%s%n",
+ i, expectedDirectives.get(i)));
+ }
+ }
+ }
+
+ private List<String> getDirectives(OutputAnalyzer outputAnalyzer) {
+ List<String> directives = new ArrayList<>();
+ List<String> inputStrings = outputAnalyzer.asLines();
+ Iterator<String> iterator = inputStrings.iterator();
+ while (iterator.hasNext()) {
+ String input = iterator.next();
+ if (input.equals("Directive:")) {
+ Asserts.assertTrue(iterator.hasNext(), "inconsistent directive"
+ + "printed into the output");
+ String matchString = iterator.next();
+ Matcher matcher = MATCH_PATTERN.matcher(matchString);
+ Asserts.assertTrue(matcher.matches(), "Incorrect matching "
+ + "string in directive");
+ directives.add(matcher.group(1));
+ }
+ }
+ return directives;
+ }
+
+ private void printDirectives(List<String> directives,
+ List<String> expected) {
+ System.err.println("Actual directives: " + directives);
+ System.err.println("Expected directives: " + expected);
+ }
+}
--- a/hotspot/test/compiler/compilercontrol/share/scenario/DirectiveBuilder.java Tue Nov 24 20:52:15 2015 +0300
+++ b/hotspot/test/compiler/compilercontrol/share/scenario/DirectiveBuilder.java Tue Nov 24 20:55:46 2015 +0300
@@ -36,6 +36,7 @@
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.concurrent.Callable;
+import java.util.stream.Collectors;
/**
* Directive file and state builder class
@@ -66,7 +67,10 @@
@Override
public List<CompileCommand> getCompileCommands() {
- throw new Error("TESTBUG: isn't applicable for directives");
+ return matchBlocks.keySet().stream()
+ // only method descriptor is required to check print_directives
+ .map(md -> new CompileCommand(null, md, null, null))
+ .collect(Collectors.toList());
}
@Override
--- a/hotspot/test/compiler/compilercontrol/share/scenario/Executor.java Tue Nov 24 20:52:15 2015 +0300
+++ b/hotspot/test/compiler/compilercontrol/share/scenario/Executor.java Tue Nov 24 20:55:46 2015 +0300
@@ -38,6 +38,7 @@
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -46,6 +47,7 @@
private final List<String> vmOptions;
private final Map<Executable, State> states;
private final List<String> jcmdCommands;
+ private OutputAnalyzer[] jcmdOutputAnalyzers;
/**
* Constructor
@@ -73,7 +75,7 @@
* Executes separate VM a gets an OutputAnalyzer instance with the results
* of execution
*/
- public OutputAnalyzer execute() {
+ public List<OutputAnalyzer> execute() {
// Add class name that would be executed in a separate VM
String classCmd = BaseAction.class.getName();
vmOptions.add(classCmd);
@@ -99,7 +101,13 @@
} catch (Throwable thr) {
throw new Error("Execution failed: " + thr.getMessage(), thr);
}
- return output;
+
+ List<OutputAnalyzer> outputList = new ArrayList<>();
+ outputList.add(output);
+ if (jcmdOutputAnalyzers != null) {
+ Collections.addAll(outputList, jcmdOutputAnalyzers);
+ }
+ return outputList;
}
/*
@@ -121,7 +129,7 @@
// Get pid of the executed process
int pid = Integer.parseInt(in.readLine());
Asserts.assertNE(pid, 0, "Got incorrect pid");
- executeJCMD(pid);
+ jcmdOutputAnalyzers = executeJCMD(pid);
if (states != null) {
// serialize and send state map
states.forEach((executable, state) -> {
@@ -139,10 +147,13 @@
}
// Executes all diagnostic commands
- protected void executeJCMD(int pid) {
+ protected OutputAnalyzer[] executeJCMD(int pid) {
+ int size = jcmdCommands.size();
+ OutputAnalyzer[] outputArray = new OutputAnalyzer[size];
CommandExecutor jcmdExecutor = new PidJcmdExecutor(String.valueOf(pid));
- for (String command : jcmdCommands) {
- jcmdExecutor.execute(command);
+ for (int i = 0; i < size; i++) {
+ outputArray[i] = jcmdExecutor.execute(jcmdCommands.get(i));
}
+ return outputArray;
}
}
--- a/hotspot/test/compiler/compilercontrol/share/scenario/JcmdStateBuilder.java Tue Nov 24 20:52:15 2015 +0300
+++ b/hotspot/test/compiler/compilercontrol/share/scenario/JcmdStateBuilder.java Tue Nov 24 20:55:46 2015 +0300
@@ -36,6 +36,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
+import java.util.stream.Collectors;
public class JcmdStateBuilder implements StateBuilder<JcmdCommand> {
private static final List<Pair<Executable, Callable<?>>> METHODS
@@ -44,7 +45,6 @@
private final DirectiveBuilder directiveBuilder;
private Map<MethodDescriptor, List<CompileCommand>> matchBlocks
= new LinkedHashMap<>();
- private List<JcmdCommand> commands = new ArrayList<>();
private boolean isFileValid = true;
public JcmdStateBuilder(String fileName) {
@@ -53,7 +53,6 @@
@Override
public void add(JcmdCommand compileCommand) {
- commands.add(compileCommand);
switch (compileCommand.jcmdType) {
case ADD:
directiveBuilder.add(compileCommand);
@@ -159,6 +158,15 @@
@Override
public List<JcmdCommand> getCompileCommands() {
- return commands;
+ if (isFileValid) {
+ return matchBlocks.keySet().stream()
+ /* only method descriptor is required
+ to check print_directives */
+ .map(md -> new JcmdCommand(null, md, null, null,
+ Scenario.JcmdType.ADD))
+ .collect(Collectors.toList());
+ } else {
+ return new ArrayList<>();
+ }
}
}
--- a/hotspot/test/compiler/compilercontrol/share/scenario/Scenario.java Tue Nov 24 20:52:15 2015 +0300
+++ b/hotspot/test/compiler/compilercontrol/share/scenario/Scenario.java Tue Nov 24 20:55:46 2015 +0300
@@ -26,6 +26,7 @@
import compiler.compilercontrol.share.method.MethodDescriptor;
import compiler.compilercontrol.share.processors.CommandProcessor;
import compiler.compilercontrol.share.processors.LogProcessor;
+import compiler.compilercontrol.share.processors.PrintDirectivesProcessor;
import compiler.compilercontrol.share.processors.PrintProcessor;
import compiler.compilercontrol.share.processors.QuietProcessor;
import jdk.test.lib.Asserts;
@@ -52,12 +53,14 @@
private final Map<Executable, State> states;
private final List<Consumer<OutputAnalyzer>> processors;
private final Executor executor;
+ private final Consumer<List<OutputAnalyzer>> jcmdProcessor;
private Scenario(boolean isValid,
List<String> vmopts,
Map<Executable, State> states,
List<CompileCommand> compileCommands,
- List<JcmdCommand> jcmdCommands) {
+ List<JcmdCommand> jcmdCommands,
+ List<CompileCommand> directives) {
this.isValid = isValid;
this.states = states;
processors = new ArrayList<>();
@@ -78,6 +81,7 @@
processors.add(new QuietProcessor(quieted));
List<String> jcmdExecCommands = new ArrayList<>();
boolean addCommandMet = false;
+ boolean printCommandMet = false;
for (JcmdCommand cmd : jcmdCommands) {
switch (cmd.jcmdType) {
case ADD:
@@ -86,11 +90,19 @@
}
addCommandMet = true;
break;
+ case PRINT:
+ printCommandMet = true;
+ break;
default:
jcmdExecCommands.add(cmd.jcmdType.command);
break;
}
}
+ // Add print command only in the end to get directives printed
+ if (printCommandMet) {
+ jcmdExecCommands.add(JcmdType.PRINT.command);
+ }
+ jcmdProcessor = new PrintDirectivesProcessor(directives);
executor = new Executor(isValid, vmopts, states, jcmdExecCommands);
}
@@ -98,14 +110,20 @@
* Executes scenario
*/
public void execute() {
- OutputAnalyzer output = executor.execute();
+ List<OutputAnalyzer> outputList = executor.execute();
+ // The first one contains output from the test VM
+ OutputAnalyzer mainOuput = outputList.get(0);
if (isValid) {
- output.shouldHaveExitValue(0);
- processors.forEach(processor -> processor.accept(output));
+ mainOuput.shouldHaveExitValue(0);
+ processors.forEach(processor -> processor.accept(mainOuput));
+ // only the last output contains directives got from print command
+ List<OutputAnalyzer> last = new ArrayList<>();
+ last.add(outputList.get(outputList.size() - 1));
+ jcmdProcessor.accept(last);
} else {
- Asserts.assertNE(output.getExitValue(), 0, "VM should exit with "
+ Asserts.assertNE(mainOuput.getExitValue(), 0, "VM should exit with "
+ "error for incorrect directives");
- output.shouldContain("Parsing of compiler directives failed");
+ mainOuput.shouldContain("Parsing of compiler directives failed");
}
}
@@ -181,6 +199,7 @@
private final Map<Type, StateBuilder<CompileCommand>> builders
= new HashMap<>();
private final JcmdStateBuilder jcmdStateBuilder;
+ private final List<JcmdCommand> jcmdCommands = new ArrayList<>();
public Builder() {
builders.put(Type.FILE, new CommandFileBuilder(Type.FILE.fileName));
@@ -195,6 +214,7 @@
Collections.addAll(vmopts, vmOptions);
if (compileCommand.type == Type.JCMD) {
jcmdStateBuilder.add((JcmdCommand) compileCommand);
+ jcmdCommands.add((JcmdCommand) compileCommand);
} else {
StateBuilder<CompileCommand> builder = builders.get(
compileCommand.type);
@@ -217,11 +237,9 @@
Map<Executable, State> directiveFileStates
= builders.get(Type.DIRECTIVE).getStates();
- // get all jcmd commands
- List<JcmdCommand> jcmdCommands = jcmdStateBuilder
- .getCompileCommands();
+ // check if directives stack was cleared by jcmd
boolean isClearedState = false;
- if (jcmdClearedState(jcmdCommands)) {
+ if (jcmdContainsCommand(JcmdType.CLEAR)) {
isClearedState = true;
}
@@ -255,6 +273,18 @@
ccList.addAll(builders.get(Type.OPTION).getCompileCommands());
ccList.addAll(builders.get(Type.FILE).getCompileCommands());
+ /*
+ * Create a list of directives to check which one was printed
+ */
+ List<CompileCommand> directives = new ArrayList<>();
+ if (jcmdContainsCommand(JcmdType.PRINT)) {
+ if (!isClearedState) {
+ directives.addAll(builders.get(Type.DIRECTIVE)
+ .getCompileCommands());
+ }
+ directives.addAll(jcmdStateBuilder.getCompileCommands());
+ }
+
// Get all VM options after we build all states and files
List<String> options = new ArrayList<>();
options.addAll(vmopts);
@@ -264,13 +294,13 @@
}
options.addAll(jcmdStateBuilder.getOptions());
return new Scenario(isValid, options, finalStates, ccList,
- jcmdCommands);
+ jcmdCommands, directives);
}
- // shows if jcmd have passed a clear command
- private boolean jcmdClearedState(List<JcmdCommand> jcmdCommands) {
+ // shows if jcmd have passed a specified jcmd command type
+ private boolean jcmdContainsCommand(JcmdType type) {
for (JcmdCommand jcmdCommand : jcmdCommands) {
- if (jcmdCommand.jcmdType == JcmdType.CLEAR) {
+ if (jcmdCommand.jcmdType == type) {
return true;
}
}