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 package org.graalvm.compiler.phases.common.instrumentation; 24 25 import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID; 26 27 import java.util.Collections; 28 import java.util.Map; 29 30 import org.graalvm.compiler.core.common.type.StampPair; 31 import org.graalvm.compiler.debug.Debug; 32 import org.graalvm.compiler.debug.GraalError; 33 import org.graalvm.compiler.graph.Node; 34 import org.graalvm.compiler.graph.NodeBitMap; 35 import org.graalvm.compiler.graph.NodeFlood; 36 import org.graalvm.compiler.graph.Position; 37 import org.graalvm.compiler.nodeinfo.InputType; 38 import org.graalvm.compiler.nodes.AbstractEndNode; 39 import org.graalvm.compiler.nodes.AbstractLocalNode; 40 import org.graalvm.compiler.nodes.FixedNode; 41 import org.graalvm.compiler.nodes.FrameState; 42 import org.graalvm.compiler.nodes.LoopEndNode; 43 import org.graalvm.compiler.nodes.ParameterNode; 44 import org.graalvm.compiler.nodes.ReturnNode; 45 import org.graalvm.compiler.nodes.StructuredGraph; 46 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions; 47 import org.graalvm.compiler.nodes.ValueNode; 48 import org.graalvm.compiler.nodes.calc.FloatingNode; 49 import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationBeginNode; 50 import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationEndNode; 51 import org.graalvm.compiler.nodes.debug.instrumentation.InstrumentationNode; 52 import org.graalvm.compiler.nodes.util.GraphUtil; 53 import org.graalvm.compiler.nodes.virtual.EscapeObjectState; 54 import org.graalvm.compiler.phases.BasePhase; 55 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; 56 import org.graalvm.compiler.phases.tiers.HighTierContext; 57 58 /** 59 * The {@code ExtractInstrumentationPhase} extracts the instrumentation (whose boundary are 60 * indicated by instrumentationBegin and instrumentationEnd), and insert an 61 * {@link InstrumentationNode} in the graph to take place of the instrumentation. 62 */ 63 public class ExtractInstrumentationPhase extends BasePhase<HighTierContext> { 64 65 @Override 66 protected void run(StructuredGraph graph, HighTierContext context) { 67 for (InstrumentationBeginNode begin : graph.getNodes().filter(InstrumentationBeginNode.class)) { 68 Instrumentation instrumentation = new Instrumentation(begin); 69 if (begin.isAnchored() || begin.getTarget() != null) { 70 // we create InstrumentationNode when the instrumentation is anchored (when 0 is 71 // passed to instrumentationBegin), or when the instrumentation is associated with 72 // some target. 73 InstrumentationNode instrumentationNode = graph.addWithoutUnique(new InstrumentationNode(begin.getTarget(), begin.isAnchored())); 74 graph.addBeforeFixed(begin, instrumentationNode); 75 FrameState currentState = begin.stateAfter(); 76 FrameState newState = graph.addWithoutUnique(new FrameState(currentState.outerFrameState(), currentState.getCode(), currentState.bci, 0, 0, 77 0, currentState.rethrowException(), currentState.duringCall(), null, 78 Collections.<EscapeObjectState> emptyList())); 79 instrumentationNode.setStateBefore(newState); 80 81 StructuredGraph instrumentationGraph = instrumentation.genInstrumentationGraph(graph, instrumentationNode); 82 new DeadCodeEliminationPhase().apply(instrumentationGraph, false); 83 instrumentationNode.setInstrumentationGraph(instrumentationGraph); 84 Debug.dump(Debug.INFO_LOG_LEVEL, instrumentationGraph, "After extracted instrumentation at %s", instrumentation); 85 } 86 instrumentation.unlink(); 87 } 88 } 89 90 /** 91 * This class denotes the instrumentation code being detached from the graph. 92 */ 93 private static class Instrumentation { 94 95 private InstrumentationBeginNode begin; 96 private InstrumentationEndNode end; 97 private NodeBitMap nodes; 98 99 Instrumentation(InstrumentationBeginNode begin) { 100 this.begin = begin; 101 102 // travel along the control flow for the paired InstrumentationEndNode 103 NodeFlood cfgFlood = begin.graph().createNodeFlood(); 104 cfgFlood.add(begin.next()); 105 for (Node current : cfgFlood) { 106 if (current instanceof InstrumentationEndNode) { 107 this.end = (InstrumentationEndNode) current; 108 } else if (current instanceof LoopEndNode) { 109 // do nothing 110 } else if (current instanceof AbstractEndNode) { 111 cfgFlood.add(((AbstractEndNode) current).merge()); 112 } else { 113 cfgFlood.addAll(current.successors()); 114 } 115 } 116 117 if (this.end == null) { 118 // this may be caused by DeoptimizationReason.Unresolved 119 throw GraalError.shouldNotReachHere("could not find invocation to instrumentationEnd()"); 120 } 121 122 // all FloatingNodes (except AbstractLocalNodes), which the FixedNodes in the 123 // instrumentation depend on, are included in the instrumentation if they are not used 124 // by other nodes in the graph 125 NodeBitMap cfgNodes = cfgFlood.getVisited(); 126 NodeFlood dfgFlood = begin.graph().createNodeFlood(); 127 dfgFlood.addAll(cfgNodes); 128 dfgFlood.add(begin.stateAfter()); 129 for (Node current : dfgFlood) { 130 for (Position pos : current.inputPositions()) { 131 Node input = pos.get(current); 132 if (pos.getInputType() == InputType.Value) { 133 if (current instanceof FrameState) { 134 // don't include value input for the FrameState 135 continue; 136 } 137 if (!(input instanceof FloatingNode)) { 138 // we only consider FloatingNode for this input type 139 continue; 140 } 141 if (input instanceof AbstractLocalNode) { 142 // AbstractLocalNode is invalid in the instrumentation sub-graph 143 continue; 144 } 145 if (shouldIncludeValueInput((FloatingNode) input, cfgNodes)) { 146 dfgFlood.add(input); 147 } 148 } else { 149 dfgFlood.add(input); 150 } 151 } 152 } 153 this.nodes = dfgFlood.getVisited(); 154 } 155 156 /** 157 * Copy the instrumentation nodes into a separate graph. During the copying, this method 158 * updates the input of the given InstrumentationNode. Hence, it is essential that the given 159 * InstrumentationNode is alive. 160 */ 161 StructuredGraph genInstrumentationGraph(StructuredGraph oldGraph, InstrumentationNode instrumentationNode) { 162 StructuredGraph instrumentationGraph = new StructuredGraph(AllowAssumptions.YES, INVALID_COMPILATION_ID); 163 Map<Node, Node> replacements = Node.newMap(); 164 int index = 0; // for ParameterNode index 165 for (Node current : nodes) { 166 // mark any input that is not included in the instrumentation a weak dependency 167 for (Node input : current.inputs()) { 168 if (input instanceof ValueNode) { 169 ValueNode valueNode = (ValueNode) input; 170 if (!nodes.isMarked(input) && !replacements.containsKey(input)) { 171 // create a ParameterNode in case the input is not within the 172 // instrumentation 173 ParameterNode parameter = new ParameterNode(index++, StampPair.createSingle(valueNode.stamp())); 174 instrumentationGraph.addWithoutUnique(parameter); 175 instrumentationNode.addWeakDependency(valueNode); 176 replacements.put(input, parameter); 177 } 178 } 179 } 180 } 181 replacements = instrumentationGraph.addDuplicates(nodes, oldGraph, nodes.count(), replacements); 182 instrumentationGraph.start().setNext((FixedNode) replacements.get(begin.next())); 183 instrumentationGraph.start().setStateAfter((FrameState) replacements.get(begin.stateAfter())); 184 replacements.get(end).replaceAtPredecessor(instrumentationGraph.addWithoutUnique(new ReturnNode(null))); 185 return instrumentationGraph; 186 } 187 188 /** 189 * @return true if the given FloatingNode does not contain any FixedNode input of types 190 * other than InputType.Value. 191 */ 192 private static boolean shouldIncludeValueInput(FloatingNode node, NodeBitMap cfgNodes) { 193 for (Position pos : node.inputPositions()) { 194 if (pos.getInputType() == InputType.Value) { 195 continue; 196 } 197 Node input = pos.get(node); 198 if (input instanceof FixedNode && !cfgNodes.isMarked(input)) { 199 return false; 200 } 201 } 202 return true; 203 } 204 205 void unlink() { 206 FixedNode next = end.next(); 207 end.setNext(null); 208 begin.replaceAtPredecessor(next); 209 GraphUtil.killCFG(begin); 210 } 211 212 } 213 214 @Override 215 public boolean checkContract() { 216 return false; 217 } 218 219 }