8138993: JEP-JDK-8046155: Test task: add check for Compiler.directives_print diagnostic command
authorppunegov
Tue, 24 Nov 2015 20:55:46 +0300
changeset 34216 2818af1ce748
parent 34215 ae6ba67d6420
child 34217 fb4d7b34e67e
8138993: JEP-JDK-8046155: Test task: add check for Compiler.directives_print diagnostic command Summary: Test Compiler.directive_print command Reviewed-by: iignatyev, neliasso
hotspot/test/compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java
hotspot/test/compiler/compilercontrol/jcmd/ClearDirectivesStackTest.java
hotspot/test/compiler/compilercontrol/jcmd/PrintDirectivesTest.java
hotspot/test/compiler/compilercontrol/jcmd/StressAddJcmdBase.java
hotspot/test/compiler/compilercontrol/share/processors/PrintDirectivesProcessor.java
hotspot/test/compiler/compilercontrol/share/scenario/DirectiveBuilder.java
hotspot/test/compiler/compilercontrol/share/scenario/Executor.java
hotspot/test/compiler/compilercontrol/share/scenario/JcmdStateBuilder.java
hotspot/test/compiler/compilercontrol/share/scenario/Scenario.java
--- 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;
                 }
             }