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