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