1 /* 2 * Copyright (c) 2012, 2017, 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.virtual.phases.ea; 24 25 import java.util.ArrayList; 26 27 import org.graalvm.compiler.debug.DebugContext; 28 import org.graalvm.compiler.graph.Node; 29 import org.graalvm.compiler.nodes.ControlSinkNode; 30 import org.graalvm.compiler.nodes.FixedNode; 31 import org.graalvm.compiler.nodes.FixedWithNextNode; 32 import org.graalvm.compiler.nodes.FrameState; 33 import org.graalvm.compiler.nodes.IfNode; 34 import org.graalvm.compiler.nodes.NodeView; 35 import org.graalvm.compiler.nodes.PhiNode; 36 import org.graalvm.compiler.nodes.PiNode; 37 import org.graalvm.compiler.nodes.ProxyNode; 38 import org.graalvm.compiler.nodes.StructuredGraph; 39 import org.graalvm.compiler.nodes.ValueNode; 40 import org.graalvm.compiler.nodes.debug.DynamicCounterNode; 41 import org.graalvm.compiler.nodes.debug.WeakCounterNode; 42 import org.graalvm.compiler.nodes.util.GraphUtil; 43 import org.graalvm.compiler.nodes.virtual.EscapeObjectState; 44 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase; 45 46 public final class GraphEffectList extends EffectList { 47 48 public GraphEffectList(DebugContext debug) { 49 super(debug); 50 } 51 52 /** 53 * Determines how many objects are virtualized (positive) or materialized (negative) by this 54 * effect. 55 */ 56 private int virtualizationDelta; 57 58 @Override 59 public void clear() { 60 super.clear(); 61 virtualizationDelta = 0; 62 } 63 64 public void addCounterBefore(String group, String name, int increment, boolean addContext, FixedNode position) { 65 add("add counter", graph -> DynamicCounterNode.addCounterBefore(group, name, increment, addContext, position)); 66 } 67 68 public void addCounterAfter(String group, String name, int increment, boolean addContext, FixedWithNextNode position) { 69 FixedNode nextPosition = position.next(); 70 add("add counter after", graph -> DynamicCounterNode.addCounterBefore(group, name, increment, addContext, nextPosition)); 71 } 72 73 public void addWeakCounterCounterBefore(String group, String name, int increment, boolean addContext, ValueNode checkedValue, FixedNode position) { 74 add("add weak counter", graph -> WeakCounterNode.addCounterBefore(group, name, increment, addContext, checkedValue, position)); 75 } 76 77 /** 78 * Adds the given fixed node to the graph's control flow, before position (so that the original 79 * predecessor of position will then be node's predecessor). 80 * 81 * @param node The fixed node to be added to the graph. 82 * @param position The fixed node before which the node should be added. 83 */ 84 public void addFixedNodeBefore(FixedWithNextNode node, FixedNode position) { 85 add("add fixed node", graph -> { 86 assert !node.isAlive() && !node.isDeleted() && position.isAlive(); 87 graph.addBeforeFixed(position, graph.add(node)); 88 }); 89 } 90 91 public void ensureAdded(ValueNode node, FixedNode position) { 92 add("ensure added", graph -> { 93 assert position.isAlive(); 94 assert node instanceof FixedNode; 95 if (!node.isAlive()) { 96 graph.addOrUniqueWithInputs(node); 97 if (node instanceof FixedWithNextNode) { 98 graph.addBeforeFixed(position, (FixedWithNextNode) node); 99 } 100 } 101 }); 102 } 103 104 public void addVirtualizationDelta(int delta) { 105 virtualizationDelta += delta; 106 } 107 108 public int getVirtualizationDelta() { 109 return virtualizationDelta; 110 } 111 112 /** 113 * Add the given floating node to the graph. 114 * 115 * @param node The floating node to be added. 116 */ 117 public void addFloatingNode(ValueNode node, @SuppressWarnings("unused") String cause) { 118 add("add floating node", graph -> { 119 if (node instanceof ProxyNode) { 120 ProxyNode proxyNode = (ProxyNode) node; 121 ValueNode value = proxyNode.value(); 122 if (!value.isAlive()) { 123 graph.addWithoutUnique(value); 124 } 125 } 126 graph.addWithoutUnique(node); 127 }); 128 } 129 130 /** 131 * Sets the phi node's input at the given index to the given value, adding new phi inputs as 132 * needed. 133 * 134 * @param node The phi node whose input should be changed. 135 * @param index The index of the phi input to be changed. 136 * @param value The new value for the phi input. 137 */ 138 public void initializePhiInput(PhiNode node, int index, ValueNode value) { 139 add("set phi input", (graph, obsoleteNodes) -> { 140 assert node.isAlive() && index >= 0; 141 node.initializeValueAt(index, graph.addOrUniqueWithInputs(value)); 142 }); 143 } 144 145 /** 146 * Adds a virtual object's state to the given frame state. If the given reusedVirtualObjects set 147 * contains the virtual object then old states for this object will be removed. 148 * 149 * @param node The frame state to which the state should be added. 150 * @param state The virtual object state to add. 151 */ 152 public void addVirtualMapping(FrameState node, EscapeObjectState state) { 153 add("add virtual mapping", new Effect() { 154 @Override 155 public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) { 156 if (node.isAlive()) { 157 assert !state.isDeleted(); 158 FrameState stateAfter = node; 159 for (int i = 0; i < stateAfter.virtualObjectMappingCount(); i++) { 160 if (stateAfter.virtualObjectMappingAt(i).object() == state.object()) { 161 stateAfter.virtualObjectMappings().remove(i); 162 } 163 } 164 stateAfter.addVirtualObjectMapping(graph.addOrUniqueWithInputs(state)); 165 } 166 } 167 168 @Override 169 public boolean isVisible() { 170 return false; 171 } 172 }); 173 } 174 175 /** 176 * Removes the given fixed node from the control flow and deletes it. 177 * 178 * @param node The fixed node that should be deleted. 179 */ 180 public void deleteNode(Node node) { 181 add("delete fixed node", (graph, obsoleteNodes) -> { 182 if (node instanceof FixedWithNextNode) { 183 GraphUtil.unlinkFixedNode((FixedWithNextNode) node); 184 } 185 obsoleteNodes.add(node); 186 }); 187 } 188 189 public void killIfBranch(IfNode ifNode, boolean constantCondition) { 190 add("kill if branch", new Effect() { 191 @Override 192 public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) { 193 graph.removeSplitPropagate(ifNode, ifNode.getSuccessor(constantCondition)); 194 } 195 196 @Override 197 public boolean isCfgKill() { 198 return true; 199 } 200 }); 201 } 202 203 public void replaceWithSink(FixedWithNextNode node, ControlSinkNode sink) { 204 add("kill if branch", new Effect() { 205 @Override 206 public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) { 207 graph.addWithoutUnique(sink); 208 node.replaceAtPredecessor(sink); 209 GraphUtil.killCFG(node); 210 } 211 212 @Override 213 public boolean isCfgKill() { 214 return true; 215 } 216 }); 217 } 218 219 /** 220 * Replaces the given node at its usages without deleting it. If the current node is a fixed 221 * node it will be disconnected from the control flow, so that it will be deleted by a 222 * subsequent {@link DeadCodeEliminationPhase} 223 * 224 * @param node The node to be replaced. 225 * @param replacement The node that should replace the original value. If the replacement is a 226 * non-connected {@link FixedWithNextNode} it will be added to the control flow. 227 * @param insertBefore 228 * 229 */ 230 public void replaceAtUsages(ValueNode node, ValueNode replacement, FixedNode insertBefore) { 231 assert node != null && replacement != null : node + " " + replacement; 232 assert node.stamp(NodeView.DEFAULT).isCompatible(replacement.stamp(NodeView.DEFAULT)) : "Replacement node stamp not compatible " + node.stamp(NodeView.DEFAULT) + " vs " + 233 replacement.stamp(NodeView.DEFAULT); 234 add("replace at usages", (graph, obsoleteNodes) -> { 235 assert node.isAlive(); 236 ValueNode replacementNode = graph.addOrUniqueWithInputs(replacement); 237 assert replacementNode.isAlive(); 238 assert insertBefore != null; 239 if (replacementNode instanceof FixedWithNextNode && ((FixedWithNextNode) replacementNode).next() == null) { 240 graph.addBeforeFixed(insertBefore, (FixedWithNextNode) replacementNode); 241 } 242 /* 243 * Keep the (better) stamp information when replacing a node with another one if the 244 * replacement has a less precise stamp than the original node. This can happen for 245 * example in the context of read nodes and unguarded pi nodes where the pi will be used 246 * to improve the stamp information of the read. Such a read might later be replaced 247 * with a read with a less precise stamp. 248 */ 249 if (!node.stamp(NodeView.DEFAULT).equals(replacementNode.stamp(NodeView.DEFAULT))) { 250 replacementNode = graph.unique(new PiNode(replacementNode, node.stamp(NodeView.DEFAULT))); 251 } 252 node.replaceAtUsages(replacementNode); 253 if (node instanceof FixedWithNextNode) { 254 GraphUtil.unlinkFixedNode((FixedWithNextNode) node); 255 } 256 obsoleteNodes.add(node); 257 }); 258 } 259 260 /** 261 * Replaces the first occurrence of oldInput in node with newInput. 262 * 263 * @param node The node whose input should be changed. 264 * @param oldInput The value to look for. 265 * @param newInput The value to replace with. 266 */ 267 public void replaceFirstInput(Node node, Node oldInput, Node newInput) { 268 assert node.isAlive() && oldInput.isAlive() && !newInput.isDeleted(); 269 add("replace first input", new Effect() { 270 @Override 271 public void apply(StructuredGraph graph, ArrayList<Node> obsoleteNodes) { 272 if (node.isAlive()) { 273 assert oldInput.isAlive() && newInput.isAlive(); 274 node.replaceFirstInput(oldInput, newInput); 275 } 276 } 277 278 @Override 279 public boolean isVisible() { 280 return !(node instanceof FrameState); 281 } 282 }); 283 } 284 }