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 compiler.compilercontrol.share.pool.PoolHelper; 29 import jdk.test.lib.util.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 final Map<MethodDescriptor, List<CompileCommand>> matchBlocks 47 = new LinkedHashMap<>(); 48 private final List<CompileCommand> inlines = new ArrayList<>(); 49 private boolean isFileValid = true; 50 51 public JcmdStateBuilder(String fileName) { 52 directiveBuilder = new DirectiveBuilder(fileName); 53 } 54 55 @Override 56 public void add(JcmdCommand 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 inlines.clear(); 68 break; 69 case REMOVE: 70 removeDirective(); 71 break; 72 } 73 } 74 75 private void addCommand(JcmdCommand compileCommand) { 76 isFileValid &= compileCommand.isValid(); 77 MethodDescriptor methodDescriptor = compileCommand.methodDescriptor; 78 79 switch (compileCommand.command) { 80 case INLINE: 81 case DONTINLINE: 82 inlines.add(compileCommand); 83 break; 84 } 85 for (MethodDescriptor md: matchBlocks.keySet()) { 86 if (methodDescriptor.getCanonicalString().matches(md.getRegexp())) { 87 matchBlocks.get(md).add(compileCommand); 88 } 89 } 90 if (!matchBlocks.containsKey(compileCommand.methodDescriptor)) { 91 List<CompileCommand> commands = new ArrayList<>(); 92 commands.add(compileCommand); 93 matchBlocks.put(compileCommand.methodDescriptor, commands); 94 } 95 } 96 97 private void removeDirective() { 98 Iterator<MethodDescriptor> iterator = matchBlocks.keySet().iterator(); 99 if (iterator.hasNext()) { 100 MethodDescriptor md = iterator.next(); 101 matchBlocks.remove(md); 102 } 103 } 104 105 @Override 106 public boolean isValid() { 107 // VM skips invalid directive file added via jcmd command 108 return true; 109 } 110 111 @Override 112 public Map<Executable, State> getStates() { 113 directiveBuilder.getStates(); 114 for (MethodDescriptor matchDescriptor : matchBlocks.keySet()) { 115 if ("Inlinee.caller()".matches(matchDescriptor.getRegexp()) 116 && !inlines.isEmpty()) { 117 // Got a *.* match block, where inline would be written 118 inlines.clear(); 119 } 120 } 121 /* 122 * Write inline directive in the end to the latest match block 123 * if we didn't do this before 124 * Inlinee caller methods should match this block only 125 */ 126 if (!inlines.isEmpty()) { 127 Pair<Executable, Callable<?>> pair = METHODS.get(0); 128 MethodDescriptor md = MethodGenerator.anyMatchDescriptor( 129 pair.first); 130 CompileCommand cc = new CompileCommand(Command.QUIET, md, 131 null, Scenario.Type.DIRECTIVE); 132 List<CompileCommand> commands = new ArrayList<>(); 133 134 // Add appropriate "*.*" match block 135 commands.add(cc); 136 matchBlocks.put(md, commands); 137 } 138 if (isFileValid) { 139 // Build states for each method according to match blocks 140 for (Pair<Executable, Callable<?>> pair : METHODS) { 141 State state = getState(pair); 142 if (state != null) { 143 stateMap.put(pair.first, state); 144 } 145 } 146 return stateMap; 147 } else { 148 // return empty map because invalid file doesn't change states 149 return new HashMap<>(); 150 } 151 } 152 153 private State getState(Pair<Executable, Callable<?>> pair) { 154 State state = null; 155 MethodDescriptor execDesc = MethodGenerator.commandDescriptor( 156 pair.first); 157 boolean isMatchFound = false; 158 159 if (stateMap.containsKey(pair.first)) { 160 state = stateMap.get(pair.first); 161 } 162 for (MethodDescriptor matchDesc : matchBlocks.keySet()) { 163 if (execDesc.getCanonicalString().matches(matchDesc.getRegexp())) { 164 /* 165 * if executable matches regex 166 * then apply commands from this match to the state 167 */ 168 for (CompileCommand cc : matchBlocks.get(matchDesc)) { 169 if (state == null) { 170 state = new State(); 171 } 172 if (!isMatchFound) { 173 // this is a first found match, apply all commands 174 state.apply(cc); 175 } else { 176 // apply only inline directives 177 switch (cc.command) { 178 case INLINE: 179 case DONTINLINE: 180 state.apply(cc); 181 break; 182 } 183 } 184 } 185 isMatchFound = true; 186 } 187 } 188 return state; 189 } 190 191 @Override 192 public List<String> getOptions() { 193 return new ArrayList<>(); 194 } 195 196 @Override 197 public List<JcmdCommand> getCompileCommands() { 198 if (isFileValid) { 199 return matchBlocks.keySet().stream() 200 /* only method descriptor is required 201 to check print_directives */ 202 .map(md -> new JcmdCommand(null, md, null, null, 203 Scenario.JcmdType.ADD)) 204 .collect(Collectors.toList()); 205 } else { 206 return new ArrayList<>(); 207 } 208 } 209 }