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 
  40 public class JcmdStateBuilder implements StateBuilder<JcmdCommand> {
  41     private static final List<Pair<Executable, Callable<?>>> METHODS
  42             = new PoolHelper().getAllMethods();
  43     private final Map<Executable, State> stateMap = new HashMap<>();
  44     private final DirectiveBuilder directiveBuilder;
  45     private Map<MethodDescriptor, List<CompileCommand>> matchBlocks
  46             = new LinkedHashMap<>();
  47     private List<JcmdCommand> commands = new ArrayList<>();
  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         commands.add(compileCommand);
  57         switch (compileCommand.jcmdType) {
  58             case ADD:
  59                 directiveBuilder.add(compileCommand);
  60                 addCommand(compileCommand);
  61                 break;
  62             case PRINT:
  63                 // doesn't change the state
  64                 break;
  65             case CLEAR:
  66                 matchBlocks.clear();
  67                 break;
  68             case REMOVE:
  69                 removeDirective();
  70                 break;
  71         }
  72     }
  73 
  74     private void addCommand(JcmdCommand compileCommand) {
  75         isFileValid &= compileCommand.isValid();
  76         for (MethodDescriptor md: matchBlocks.keySet()) {
  77             if (compileCommand.methodDescriptor.getCanonicalString()
  78                     .matches(md.getRegexp())) {
  79                 matchBlocks.get(md).add(compileCommand);
  80             }
  81         }
  82         List<CompileCommand> commands = new ArrayList<>();
  83         commands.add(compileCommand);
  84         matchBlocks.put(compileCommand.methodDescriptor, commands);
  85     }
  86 
  87     private void removeDirective() {
  88         Iterator<MethodDescriptor> iterator = matchBlocks.keySet().iterator();
  89         if (iterator.hasNext()) {
  90             MethodDescriptor md = iterator.next();
  91             matchBlocks.remove(md);
  92         }
  93     }
  94 
  95     @Override
  96     public boolean isValid() {
  97         // VM skips invalid directive file added via jcmd command
  98         return true;
  99     }
 100 
 101     @Override
 102     public Map<Executable, State> getStates() {
 103         directiveBuilder.getStates();
 104         // Build states for each method according to match blocks
 105         for (Pair<Executable, Callable<?>> pair : METHODS) {
 106             State state = getState(pair);
 107             if (state != null) {
 108                 stateMap.put(pair.first, state);
 109             }
 110         }
 111         if (isFileValid) {
 112             return stateMap;
 113         } else {
 114             // return empty map because invalid file doesn't change states
 115             return new HashMap<>();
 116         }
 117     }
 118 
 119     private State getState(Pair<Executable, Callable<?>> pair) {
 120         State state = null;
 121         MethodDescriptor execDesc = MethodGenerator.commandDescriptor(
 122                 pair.first);
 123         boolean isMatchFound = false;
 124 
 125         if (stateMap.containsKey(pair.first)) {
 126             state = stateMap.get(pair.first);
 127         }
 128         for (MethodDescriptor matchDesc : matchBlocks.keySet()) {
 129             if (execDesc.getCanonicalString().matches(matchDesc.getRegexp())) {
 130                 /*
 131                  * if executable matches regex
 132                  * then apply commands from this match to the state
 133                  */
 134                 for (CompileCommand cc : matchBlocks.get(matchDesc)) {
 135                     state = new State();
 136                     if (!isMatchFound) {
 137                         // this is a first found match, apply all commands
 138                         state.apply(cc);
 139                     } else {
 140                         // apply only inline directives
 141                         switch (cc.command) {
 142                             case INLINE:
 143                             case DONTINLINE:
 144                                 state.apply(cc);
 145                                 break;
 146                         }
 147                     }
 148                 }
 149                 isMatchFound = true;
 150             }
 151         }
 152         return state;
 153     }
 154 
 155     @Override
 156     public List<String> getOptions() {
 157         return new ArrayList<>();
 158     }
 159 
 160     @Override
 161     public List<JcmdCommand> getCompileCommands() {
 162         return commands;
 163     }
 164 }