8143308: Add inline checks and tests
authorppunegov
Thu, 26 Nov 2015 03:05:19 +0300
changeset 34226 db9dea22fbfc
parent 34222 57d99d1614e0
child 34227 001483ee066c
8143308: Add inline checks and tests Summary: Fix inlining state creation Reviewed-by: twisti
hotspot/test/compiler/compilercontrol/parser/HugeDirectiveUtil.java
hotspot/test/compiler/compilercontrol/share/actions/BaseAction.java
hotspot/test/compiler/compilercontrol/share/scenario/DirectiveBuilder.java
hotspot/test/compiler/compilercontrol/share/scenario/DirectiveWriter.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
hotspot/test/compiler/compilercontrol/share/scenario/State.java
--- 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());
         }
     }