1 /*
   2  * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package compiler.compilercontrol.share.scenario;
  25 
  26 import compiler.compilercontrol.share.method.MethodDescriptor;
  27 import compiler.compilercontrol.share.method.MethodGenerator;
  28 import pool.PoolHelper;
  29 import jdk.test.lib.Pair;
  30 
  31 import java.lang.reflect.Executable;
  32 import java.util.ArrayList;
  33 import java.util.HashMap;
  34 import java.util.Iterator;
  35 import java.util.LinkedHashMap;
  36 import java.util.List;
  37 import java.util.Map;
  38 import java.util.concurrent.Callable;
  39 import java.util.stream.Collectors;
  40 
  41 public class JcmdStateBuilder implements StateBuilder<JcmdCommand> {
  42     private static final List<Pair<Executable, Callable<?>>> METHODS
  43             = new PoolHelper().getAllMethods();
  44     private final Map<Executable, State> stateMap = new HashMap<>();
  45     private final DirectiveBuilder directiveBuilder;
  46     private Map<MethodDescriptor, List<CompileCommand>> matchBlocks
  47             = new LinkedHashMap<>();
  48     private boolean isFileValid = true;
  49 
  50     public JcmdStateBuilder(String fileName) {
  51         directiveBuilder = new DirectiveBuilder(fileName);
  52     }
  53 
  54     @Override
  55     public void add(JcmdCommand compileCommand) {
  56         switch (compileCommand.jcmdType) {
  57             case ADD:
  58                 directiveBuilder.add(compileCommand);
  59                 addCommand(compileCommand);
  60                 break;
  61             case PRINT:
  62                 // doesn't change the state
  63                 break;
  64             case CLEAR:
  65                 matchBlocks.clear();
  66                 break;
  67             case REMOVE:
  68                 removeDirective();
  69                 break;
  70         }
  71     }
  72 
  73     private void addCommand(JcmdCommand compileCommand) {
  74         isFileValid &= compileCommand.isValid();
  75         for (MethodDescriptor md: matchBlocks.keySet()) {
  76             if (compileCommand.methodDescriptor.getCanonicalString()
  77                     .matches(md.getRegexp())) {
  78                 matchBlocks.get(md).add(compileCommand);
  79             }
  80         }
  81         List<CompileCommand> commands = new ArrayList<>();
  82         commands.add(compileCommand);
  83         matchBlocks.put(compileCommand.methodDescriptor, commands);
  84     }
  85 
  86     private void removeDirective() {
  87         Iterator<MethodDescriptor> iterator = matchBlocks.keySet().iterator();
  88         if (iterator.hasNext()) {
  89             MethodDescriptor md = iterator.next();
  90             matchBlocks.remove(md);
  91         }
  92     }
  93 
  94     @Override
  95     public boolean isValid() {
  96         // VM skips invalid directive file added via jcmd command
  97         return true;
  98     }
  99 
 100     @Override
 101     public Map<Executable, State> getStates() {
 102         directiveBuilder.getStates();
 103         // Build states for each method according to match blocks
 104         for (Pair<Executable, Callable<?>> pair : METHODS) {
 105             State state = getState(pair);
 106             if (state != null) {
 107                 stateMap.put(pair.first, state);
 108             }
 109         }
 110         if (isFileValid) {
 111             return stateMap;
 112         } else {
 113             // return empty map because invalid file doesn't change states
 114             return new HashMap<>();
 115         }
 116     }
 117 
 118     private State getState(Pair<Executable, Callable<?>> pair) {
 119         State state = null;
 120         MethodDescriptor execDesc = MethodGenerator.commandDescriptor(
 121                 pair.first);
 122         boolean isMatchFound = false;
 123 
 124         if (stateMap.containsKey(pair.first)) {
 125             state = stateMap.get(pair.first);
 126         }
 127         for (MethodDescriptor matchDesc : matchBlocks.keySet()) {
 128             if (execDesc.getCanonicalString().matches(matchDesc.getRegexp())) {
 129                 /*
 130                  * if executable matches regex
 131                  * then apply commands from this match to the state
 132                  */
 133                 for (CompileCommand cc : matchBlocks.get(matchDesc)) {
 134                     state = new State();
 135                     if (!isMatchFound) {
 136                         // this is a first found match, apply all commands
 137                         state.apply(cc);
 138                     } else {
 139                         // apply only inline directives
 140                         switch (cc.command) {
 141                             case INLINE:
 142                             case DONTINLINE:
 143                                 state.apply(cc);
 144                                 break;
 145                         }
 146                     }
 147                 }
 148                 isMatchFound = true;
 149             }
 150         }
 151         return state;
 152     }
 153 
 154     @Override
 155     public List<String> getOptions() {
 156         return new ArrayList<>();
 157     }
 158 
 159     @Override
 160     public List<JcmdCommand> getCompileCommands() {
 161         if (isFileValid) {
 162             return matchBlocks.keySet().stream()
 163                     /* only method descriptor is required
 164                        to check print_directives */
 165                     .map(md -> new JcmdCommand(null, md, null, null,
 166                             Scenario.JcmdType.ADD))
 167                     .collect(Collectors.toList());
 168         } else {
 169             return new ArrayList<>();
 170         }
 171     }
 172 }