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