1 /* 2 * Copyright (c) 2014, 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.graph; 24 25 import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled; 26 import static org.graalvm.compiler.graph.Node.NOT_ITERABLE; 27 import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE; 28 29 import java.util.ArrayList; 30 import java.util.Iterator; 31 32 import org.graalvm.compiler.core.common.Fields; 33 import org.graalvm.compiler.core.common.FieldsScanner; 34 import org.graalvm.compiler.graph.NodeClass.EdgeInfo; 35 36 /** 37 * Describes {@link Node} fields representing the set of inputs for the node or the set of the 38 * node's successors. 39 */ 40 public abstract class Edges extends Fields { 41 42 /** 43 * Constants denoting whether a set of edges are inputs or successors. 44 */ 45 public enum Type { 46 Inputs, 47 Successors; 48 } 49 50 private final int directCount; 51 private final Type type; 52 53 public Edges(Type type, int directCount, ArrayList<? extends FieldsScanner.FieldInfo> edges) { 54 super(edges); 55 this.type = type; 56 this.directCount = directCount; 57 } 58 59 public static void translateInto(Edges edges, ArrayList<EdgeInfo> infos) { 60 for (int index = 0; index < edges.getCount(); index++) { 61 infos.add(new EdgeInfo(edges.offsets[index], edges.getName(index), edges.getType(index), edges.getDeclaringClass(index))); 62 } 63 } 64 65 public static Node getNodeUnsafe(Node node, long offset) { 66 return (Node) UNSAFE.getObject(node, offset); 67 } 68 69 @SuppressWarnings("unchecked") 70 public static NodeList<Node> getNodeListUnsafe(Node node, long offset) { 71 return (NodeList<Node>) UNSAFE.getObject(node, offset); 72 } 73 74 private static void putNodeUnsafe(Node node, long offset, Node value) { 75 UNSAFE.putObject(node, offset, value); 76 } 77 78 private static void putNodeListUnsafe(Node node, long offset, NodeList<?> value) { 79 UNSAFE.putObject(node, offset, value); 80 } 81 82 /** 83 * Get the number of direct edges represented by this object. A direct edge goes directly to 84 * another {@link Node}. An indirect edge goes via a {@link NodeList}. 85 */ 86 public int getDirectCount() { 87 return directCount; 88 } 89 90 /** 91 * Gets the {@link Node} at the end point of a {@linkplain #getDirectCount() direct} edge. 92 * 93 * @param node one end point of the edge 94 * @param index the index of a non-list the edge (must be less than {@link #getDirectCount()}) 95 * @return the Node at the other edge of the requested edge 96 */ 97 public static Node getNode(Node node, long[] offsets, int index) { 98 return getNodeUnsafe(node, offsets[index]); 99 } 100 101 /** 102 * Gets the {@link NodeList} at the end point of a {@linkplain #getDirectCount() direct} edge. 103 * 104 * @param node one end point of the edge 105 * @param index the index of a non-list the edge (must be equal to or greater than 106 * {@link #getDirectCount()}) 107 * @return the {@link NodeList} at the other edge of the requested edge 108 */ 109 public static NodeList<Node> getNodeList(Node node, long[] offsets, int index) { 110 return getNodeListUnsafe(node, offsets[index]); 111 } 112 113 /** 114 * Clear edges in a given node. This is accomplished by setting {@linkplain #getDirectCount() 115 * direct} edges to null and replacing the lists containing indirect edges with new lists. The 116 * latter is important so that this method can be used to clear the edges of cloned nodes. 117 * 118 * @param node the node whose edges are to be cleared 119 */ 120 public void clear(Node node) { 121 final long[] curOffsets = this.offsets; 122 final Type curType = this.type; 123 int index = 0; 124 int curDirectCount = getDirectCount(); 125 while (index < curDirectCount) { 126 initializeNode(node, index++, null); 127 } 128 int curCount = getCount(); 129 while (index < curCount) { 130 NodeList<Node> list = getNodeList(node, curOffsets, index); 131 if (list != null) { 132 int size = list.initialSize; 133 NodeList<Node> newList = curType == Edges.Type.Inputs ? new NodeInputList<>(node, size) : new NodeSuccessorList<>(node, size); 134 135 // replacing with a new list object is the expected behavior! 136 initializeList(node, index, newList); 137 } 138 index++; 139 } 140 } 141 142 /** 143 * Initializes the list edges in a given node based on the size of the list edges in a prototype 144 * node. 145 * 146 * @param node the node whose list edges are to be initialized 147 * @param prototype the node whose list edge sizes are used when creating new edge lists 148 */ 149 public void initializeLists(Node node, Node prototype) { 150 int index = getDirectCount(); 151 final long[] curOffsets = this.offsets; 152 final Edges.Type curType = this.type; 153 while (index < getCount()) { 154 NodeList<Node> list = getNodeList(prototype, curOffsets, index); 155 if (list != null) { 156 int size = list.initialSize; 157 NodeList<Node> newList = curType == Edges.Type.Inputs ? new NodeInputList<>(node, size) : new NodeSuccessorList<>(node, size); 158 initializeList(node, index, newList); 159 } 160 index++; 161 } 162 } 163 164 /** 165 * Copies edges from {@code fromNode} to {@code toNode}. The nodes are expected to be of the 166 * exact same type. 167 * 168 * @param fromNode the node from which the edges should be copied. 169 * @param toNode the node to which the edges should be copied. 170 */ 171 public void copy(Node fromNode, Node toNode) { 172 assert fromNode != toNode; 173 assert fromNode.getNodeClass().getClazz() == toNode.getNodeClass().getClazz(); 174 int index = 0; 175 final long[] curOffsets = this.offsets; 176 final Type curType = this.type; 177 int curDirectCount = getDirectCount(); 178 while (index < curDirectCount) { 179 initializeNode(toNode, index, getNode(fromNode, curOffsets, index)); 180 index++; 181 } 182 int curCount = getCount(); 183 while (index < curCount) { 184 NodeList<Node> list = getNodeList(toNode, curOffsets, index); 185 NodeList<Node> fromList = getNodeList(fromNode, curOffsets, index); 186 if (list == null || list == fromList) { 187 list = curType == Edges.Type.Inputs ? new NodeInputList<>(toNode, fromList) : new NodeSuccessorList<>(toNode, fromList); 188 initializeList(toNode, index, list); 189 } else { 190 list.copy(fromList); 191 } 192 index++; 193 } 194 } 195 196 @Override 197 public void set(Object node, int index, Object value) { 198 throw new IllegalArgumentException("Cannot call set on " + this); 199 } 200 201 /** 202 * Sets the value of a given edge without notifying the new and old nodes on the other end of 203 * the edge of the change. 204 * 205 * @param node the node whose edge is to be updated 206 * @param index the index of the edge (between 0 and {@link #getCount()}) 207 * @param value the node to be written to the edge 208 */ 209 public void initializeNode(Node node, int index, Node value) { 210 verifyUpdateValid(node, index, value); 211 putNodeUnsafe(node, offsets[index], value); 212 } 213 214 public void initializeList(Node node, int index, NodeList<Node> value) { 215 verifyUpdateValid(node, index, value); 216 putNodeListUnsafe(node, offsets[index], value); 217 } 218 219 private void verifyUpdateValid(Node node, int index, Object newValue) { 220 if (newValue != null && !getType(index).isAssignableFrom(newValue.getClass())) { 221 throw new IllegalArgumentException("Can not assign " + newValue.getClass() + " to " + getType(index) + " in " + node); 222 } 223 } 224 225 /** 226 * Sets the value of a given edge and notifies the new and old nodes on the other end of the 227 * edge of the change. 228 * 229 * @param node the node whose edge is to be updated 230 * @param index the index of the edge (between 0 and {@link #getCount()}) 231 * @param value the node to be written to the edge 232 */ 233 public void setNode(Node node, int index, Node value) { 234 assert index < directCount; 235 Node old = getNodeUnsafe(node, offsets[index]); 236 initializeNode(node, index, value); 237 update(node, old, value); 238 } 239 240 public abstract void update(Node node, Node oldValue, Node newValue); 241 242 public boolean contains(Node node, Node value) { 243 final long[] curOffsets = this.offsets; 244 for (int i = 0; i < directCount; i++) { 245 if (getNode(node, curOffsets, i) == value) { 246 return true; 247 } 248 } 249 for (int i = directCount; i < getCount(); i++) { 250 NodeList<?> curList = getNodeList(node, curOffsets, i); 251 if (curList != null && curList.contains(value)) { 252 return true; 253 } 254 } 255 return false; 256 } 257 258 /** 259 * An iterator that will iterate over edges. 260 * 261 * An iterator of this type will not return null values, unless edges are modified concurrently. 262 * Concurrent modifications are detected by an assertion on a best-effort basis. 263 */ 264 private static class EdgesIterator implements Iterator<Position> { 265 protected final Node node; 266 protected final Edges edges; 267 protected int index; 268 protected int subIndex; 269 protected boolean needsForward; 270 protected final int directCount; 271 protected final long[] offsets; 272 273 /** 274 * Creates an iterator that will iterate over some given edges in a given node. 275 */ 276 EdgesIterator(Node node, Edges edges) { 277 this.node = node; 278 this.edges = edges; 279 index = NOT_ITERABLE; 280 subIndex = 0; 281 needsForward = true; 282 this.directCount = edges.getDirectCount(); 283 this.offsets = edges.getOffsets(); 284 } 285 286 void forward() { 287 needsForward = false; 288 if (index < directCount) { 289 index++; 290 if (index < directCount) { 291 return; 292 } 293 } else { 294 subIndex++; 295 } 296 if (index < edges.getCount()) { 297 forwardNodeList(); 298 } 299 } 300 301 private void forwardNodeList() { 302 do { 303 NodeList<?> list = Edges.getNodeList(node, offsets, index); 304 if (list != null) { 305 if (subIndex < list.size()) { 306 return; 307 } 308 } 309 subIndex = 0; 310 index++; 311 } while (index < edges.getCount()); 312 } 313 314 @Override 315 public boolean hasNext() { 316 if (needsForward) { 317 forward(); 318 } 319 return index < edges.getCount(); 320 } 321 322 @Override 323 public Position next() { 324 if (needsForward) { 325 forward(); 326 } 327 needsForward = true; 328 if (index < directCount) { 329 return new Position(edges, index, NOT_ITERABLE); 330 } else { 331 return new Position(edges, index, subIndex); 332 } 333 } 334 335 @Override 336 public void remove() { 337 throw new UnsupportedOperationException(); 338 } 339 } 340 341 private static final class EdgesWithModCountIterator extends EdgesIterator { 342 private final int modCount; 343 344 private EdgesWithModCountIterator(Node node, Edges edges) { 345 super(node, edges); 346 assert isModificationCountsEnabled(); 347 this.modCount = node.modCount(); 348 } 349 350 @Override 351 public boolean hasNext() { 352 try { 353 return super.hasNext(); 354 } finally { 355 assert modCount == node.modCount() : "must not be modified"; 356 } 357 } 358 359 @Override 360 public Position next() { 361 try { 362 return super.next(); 363 } finally { 364 assert modCount == node.modCount() : "must not be modified"; 365 } 366 } 367 } 368 369 public Iterable<Position> getPositionsIterable(final Node node) { 370 return new Iterable<Position>() { 371 372 @Override 373 public Iterator<Position> iterator() { 374 if (isModificationCountsEnabled()) { 375 return new EdgesWithModCountIterator(node, Edges.this); 376 } else { 377 return new EdgesIterator(node, Edges.this); 378 } 379 } 380 }; 381 } 382 383 public Type type() { 384 return type; 385 } 386 }