1 /*
   2  * Copyright (c) 2011, 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.graph;
  24 
  25 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
  26 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
  27 
  28 import java.util.ArrayList;
  29 import java.util.Arrays;
  30 import java.util.Iterator;
  31 import java.util.function.Consumer;
  32 
  33 import org.graalvm.compiler.debug.CounterKey;
  34 import org.graalvm.compiler.debug.DebugCloseable;
  35 import org.graalvm.compiler.debug.DebugContext;
  36 import org.graalvm.compiler.debug.GraalError;
  37 import org.graalvm.compiler.debug.TimerKey;
  38 import org.graalvm.compiler.graph.Node.ValueNumberable;
  39 import org.graalvm.compiler.graph.iterators.NodeIterable;
  40 import org.graalvm.compiler.options.Option;
  41 import org.graalvm.compiler.options.OptionKey;
  42 import org.graalvm.compiler.options.OptionType;
  43 import org.graalvm.compiler.options.OptionValues;
  44 import org.graalvm.util.EconomicMap;
  45 import org.graalvm.util.Equivalence;
  46 import org.graalvm.util.UnmodifiableEconomicMap;
  47 
  48 /**
  49  * This class is a graph container, it contains the set of nodes that belong to this graph.
  50  */
  51 public class Graph {
  52 
  53     public static class Options {
  54         @Option(help = "Verify graphs often during compilation when assertions are turned on", type = OptionType.Debug)//
  55         public static final OptionKey<Boolean> VerifyGraalGraphs = new OptionKey<>(true);
  56         @Option(help = "Perform expensive verification of graph inputs, usages, successors and predecessors", type = OptionType.Debug)//
  57         public static final OptionKey<Boolean> VerifyGraalGraphEdges = new OptionKey<>(false);
  58         @Option(help = "Graal graph compression is performed when percent of live nodes falls below this value", type = OptionType.Debug)//
  59         public static final OptionKey<Integer> GraphCompressionThreshold = new OptionKey<>(70);
  60     }
  61 
  62     private enum FreezeState {
  63         Unfrozen,
  64         TemporaryFreeze,
  65         DeepFreeze
  66     }
  67 
  68     public final String name;
  69 
  70     /**
  71      * The set of nodes in the graph, ordered by {@linkplain #register(Node) registration} time.
  72      */
  73     Node[] nodes;
  74 
  75     /**
  76      * Source information to associate with newly created nodes.
  77      */
  78     NodeSourcePosition currentNodeSourcePosition;
  79 
  80     /**
  81      * Records if updating of node source information is required when performing inlining.
  82      */
  83     boolean seenNodeSourcePosition;
  84 
  85     /**
  86      * The number of valid entries in {@link #nodes}.
  87      */
  88     int nodesSize;
  89 
  90     /**
  91      * Records the modification count for nodes. This is only used in assertions.
  92      */
  93     private int[] nodeModCounts;
  94 
  95     /**
  96      * Records the modification count for nodes' usage lists. This is only used in assertions.
  97      */
  98     private int[] nodeUsageModCounts;
  99 
 100     // these two arrays contain one entry for each NodeClass, indexed by NodeClass.iterableId.
 101     // they contain the first and last pointer to a linked list of all nodes with this type.
 102     private final ArrayList<Node> iterableNodesFirst;
 103     private final ArrayList<Node> iterableNodesLast;
 104 
 105     private int nodesDeletedSinceLastCompression;
 106     private int nodesDeletedBeforeLastCompression;
 107 
 108     /**
 109      * The number of times this graph has been compressed.
 110      */
 111     int compressions;
 112 
 113     NodeEventListener nodeEventListener;
 114 
 115     /**
 116      * Used to global value number {@link ValueNumberable} {@linkplain NodeClass#isLeafNode() leaf}
 117      * nodes.
 118      */
 119     private EconomicMap<Node, Node>[] cachedLeafNodes;
 120 
 121     private static final Equivalence NODE_VALUE_COMPARE = new Equivalence() {
 122 
 123         @Override
 124         public boolean equals(Object a, Object b) {
 125             if (a == b) {
 126                 return true;
 127             }
 128 
 129             assert a.getClass() == b.getClass();
 130             return ((Node) a).valueEquals((Node) b);
 131         }
 132 
 133         @Override
 134         public int hashCode(Object k) {
 135             return ((Node) k).getNodeClass().valueNumber((Node) k);
 136         }
 137     };
 138 
 139     /**
 140      * Indicates that the graph should no longer be modified. Frozen graphs can be used by multiple
 141      * threads so it's only safe to read them.
 142      */
 143     private FreezeState freezeState = FreezeState.Unfrozen;
 144 
 145     /**
 146      * The option values used while compiling this graph.
 147      */
 148     private final OptionValues options;
 149 
 150     /**
 151      * The {@link DebugContext} used while compiling this graph.
 152      */
 153     private DebugContext debug;
 154 
 155     private class NodeSourcePositionScope implements DebugCloseable {
 156         private final NodeSourcePosition previous;
 157 
 158         NodeSourcePositionScope(NodeSourcePosition sourcePosition) {
 159             previous = currentNodeSourcePosition;
 160             currentNodeSourcePosition = sourcePosition;
 161         }
 162 
 163         @Override
 164         public DebugContext getDebug() {
 165             return debug;
 166         }
 167 
 168         @Override
 169         public void close() {
 170             currentNodeSourcePosition = previous;
 171         }
 172     }
 173 
 174     public NodeSourcePosition currentNodeSourcePosition() {
 175         return currentNodeSourcePosition;
 176     }
 177 
 178     /**
 179      * Opens a scope in which the source information from {@code node} is copied into nodes created
 180      * within the scope. If {@code node} has no source information information, no scope is opened
 181      * and {@code null} is returned.
 182      *
 183      * @return a {@link DebugCloseable} for managing the opened scope or {@code null} if no scope
 184      *         was opened
 185      */
 186     public DebugCloseable withNodeSourcePosition(Node node) {
 187         return withNodeSourcePosition(node.sourcePosition);
 188     }
 189 
 190     /**
 191      * Opens a scope in which {@code sourcePosition} is copied into nodes created within the scope.
 192      * If {@code sourcePosition == null}, no scope is opened and {@code null} is returned.
 193      *
 194      * @return a {@link DebugCloseable} for managing the opened scope or {@code null} if no scope
 195      *         was opened
 196      */
 197     public DebugCloseable withNodeSourcePosition(NodeSourcePosition sourcePosition) {
 198         return sourcePosition != null ? new NodeSourcePositionScope(sourcePosition) : null;
 199     }
 200 
 201     /**
 202      * Opens a scope in which newly created nodes do not get any source information added.
 203      *
 204      * @return a {@link DebugCloseable} for managing the opened scope
 205      */
 206     public DebugCloseable withoutNodeSourcePosition() {
 207         return new NodeSourcePositionScope(null);
 208     }
 209 
 210     /**
 211      * Determines if this graph might contain nodes with source information. This is mainly useful
 212      * to short circuit logic for updating those positions after inlining since that requires
 213      * visiting every node in the graph.
 214      */
 215     public boolean mayHaveNodeSourcePosition() {
 216         assert seenNodeSourcePosition || verifyHasNoSourcePosition();
 217         return seenNodeSourcePosition;
 218     }
 219 
 220     private boolean verifyHasNoSourcePosition() {
 221         for (Node node : getNodes()) {
 222             assert node.getNodeSourcePosition() == null;
 223         }
 224         return true;
 225     }
 226 
 227     /**
 228      * Creates an empty Graph with no name.
 229      */
 230     public Graph(OptionValues options, DebugContext debug) {
 231         this(null, options, debug);
 232     }
 233 
 234     /**
 235      * We only want the expensive modification count tracking when assertions are enabled for the
 236      * {@link Graph} class.
 237      */
 238     @SuppressWarnings("all")
 239     public static boolean isModificationCountsEnabled() {
 240         boolean enabled = false;
 241         assert enabled = true;
 242         return enabled;
 243     }
 244 
 245     private static final int INITIAL_NODES_SIZE = 32;
 246 
 247     /**
 248      * Creates an empty Graph with a given name.
 249      *
 250      * @param name the name of the graph, used for debugging purposes
 251      */
 252     public Graph(String name, OptionValues options, DebugContext debug) {
 253         nodes = new Node[INITIAL_NODES_SIZE];
 254         iterableNodesFirst = new ArrayList<>(NodeClass.allocatedNodeIterabledIds());
 255         iterableNodesLast = new ArrayList<>(NodeClass.allocatedNodeIterabledIds());
 256         this.name = name;
 257         this.options = options;
 258         assert debug != null;
 259         this.debug = debug;
 260 
 261         if (isModificationCountsEnabled()) {
 262             nodeModCounts = new int[INITIAL_NODES_SIZE];
 263             nodeUsageModCounts = new int[INITIAL_NODES_SIZE];
 264         }
 265     }
 266 
 267     int extractOriginalNodeId(Node node) {
 268         int id = node.id;
 269         if (id <= Node.DELETED_ID_START) {
 270             id = Node.DELETED_ID_START - id;
 271         }
 272         return id;
 273     }
 274 
 275     int modCount(Node node) {
 276         int id = extractOriginalNodeId(node);
 277         if (id >= 0 && id < nodeModCounts.length) {
 278             return nodeModCounts[id];
 279         }
 280         return 0;
 281     }
 282 
 283     void incModCount(Node node) {
 284         int id = extractOriginalNodeId(node);
 285         if (id >= 0) {
 286             if (id >= nodeModCounts.length) {
 287                 nodeModCounts = Arrays.copyOf(nodeModCounts, id * 2 + 30);
 288             }
 289             nodeModCounts[id]++;
 290         } else {
 291             assert false;
 292         }
 293     }
 294 
 295     int usageModCount(Node node) {
 296         int id = extractOriginalNodeId(node);
 297         if (id >= 0 && id < nodeUsageModCounts.length) {
 298             return nodeUsageModCounts[id];
 299         }
 300         return 0;
 301     }
 302 
 303     void incUsageModCount(Node node) {
 304         int id = extractOriginalNodeId(node);
 305         if (id >= 0) {
 306             if (id >= nodeUsageModCounts.length) {
 307                 nodeUsageModCounts = Arrays.copyOf(nodeUsageModCounts, id * 2 + 30);
 308             }
 309             nodeUsageModCounts[id]++;
 310         } else {
 311             assert false;
 312         }
 313     }
 314 
 315     /**
 316      * Creates a copy of this graph.
 317      *
 318      * @param debugForCopy the debug context for the graph copy. This must not be the debug for this
 319      *            graph if this graph can be accessed from multiple threads (e.g., it's in a cache
 320      *            accessed by multiple threads).
 321      */
 322     public final Graph copy(DebugContext debugForCopy) {
 323         return copy(name, null, debugForCopy);
 324     }
 325 
 326     /**
 327      * Creates a copy of this graph.
 328      *
 329      * @param duplicationMapCallback consumer of the duplication map created during the copying
 330      * @param debugForCopy the debug context for the graph copy. This must not be the debug for this
 331      *            graph if this graph can be accessed from multiple threads (e.g., it's in a cache
 332      *            accessed by multiple threads).
 333      */
 334     public final Graph copy(Consumer<UnmodifiableEconomicMap<Node, Node>> duplicationMapCallback, DebugContext debugForCopy) {
 335         return copy(name, duplicationMapCallback, debugForCopy);
 336     }
 337 
 338     /**
 339      * Creates a copy of this graph.
 340      *
 341      * @param newName the name of the copy, used for debugging purposes (can be null)
 342      * @param debugForCopy the debug context for the graph copy. This must not be the debug for this
 343      *            graph if this graph can be accessed from multiple threads (e.g., it's in a cache
 344      *            accessed by multiple threads).
 345      */
 346     public final Graph copy(String newName, DebugContext debugForCopy) {
 347         return copy(newName, null, debugForCopy);
 348     }
 349 
 350     /**
 351      * Creates a copy of this graph.
 352      *
 353      * @param newName the name of the copy, used for debugging purposes (can be null)
 354      * @param duplicationMapCallback consumer of the duplication map created during the copying
 355      * @param debugForCopy the debug context for the graph copy. This must not be the debug for this
 356      *            graph if this graph can be accessed from multiple threads (e.g., it's in a cache
 357      *            accessed by multiple threads).
 358      */
 359     protected Graph copy(String newName, Consumer<UnmodifiableEconomicMap<Node, Node>> duplicationMapCallback, DebugContext debugForCopy) {
 360         Graph copy = new Graph(newName, options, debugForCopy);
 361         UnmodifiableEconomicMap<Node, Node> duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), (EconomicMap<Node, Node>) null);
 362         if (duplicationMapCallback != null) {
 363             duplicationMapCallback.accept(duplicates);
 364         }
 365         return copy;
 366     }
 367 
 368     public final OptionValues getOptions() {
 369         return options;
 370     }
 371 
 372     public DebugContext getDebug() {
 373         return debug;
 374     }
 375 
 376     /**
 377      * Resets the {@link DebugContext} for this graph to a new value. This is useful when a graph is
 378      * "handed over" from its creating thread to another thread.
 379      *
 380      * This must only be done when the current thread is no longer using the graph. This is in
 381      * general impossible to test due to races and since metrics can be updated at any time. As
 382      * such, this method only performs a weak sanity check that at least the current debug context
 383      * does not have a nested scope open (the top level scope will always be open if scopes are
 384      * enabled).
 385      */
 386     public void resetDebug(DebugContext newDebug) {
 387         assert newDebug == debug || !debug.inNestedScope() : String.format("Cannot reset the debug context for %s while it has the nested scope \"%s\" open", this, debug.getCurrentScopeName());
 388         this.debug = newDebug;
 389     }
 390 
 391     @Override
 392     public String toString() {
 393         return name == null ? super.toString() : "Graph " + name;
 394     }
 395 
 396     /**
 397      * Gets the number of live nodes in this graph. That is the number of nodes which have been
 398      * added to the graph minus the number of deleted nodes.
 399      *
 400      * @return the number of live nodes in this graph
 401      */
 402     public int getNodeCount() {
 403         return nodesSize - getNodesDeletedSinceLastCompression();
 404     }
 405 
 406     /**
 407      * Gets the number of times this graph has been {@linkplain #maybeCompress() compressed}. Node
 408      * identifiers are only stable between compressions. To ensure this constraint is observed, any
 409      * entity relying upon stable node identifiers should use {@link NodeIdAccessor}.
 410      */
 411     public int getCompressions() {
 412         return compressions;
 413     }
 414 
 415     /**
 416      * Gets the number of nodes which have been deleted from this graph since it was last
 417      * {@linkplain #maybeCompress() compressed}.
 418      */
 419     public int getNodesDeletedSinceLastCompression() {
 420         return nodesDeletedSinceLastCompression;
 421     }
 422 
 423     /**
 424      * Gets the total number of nodes which have been deleted from this graph.
 425      */
 426     public int getTotalNodesDeleted() {
 427         return nodesDeletedSinceLastCompression + nodesDeletedBeforeLastCompression;
 428     }
 429 
 430     /**
 431      * Adds a new node to the graph.
 432      *
 433      * @param node the node to be added
 434      * @return the node which was added to the graph
 435      */
 436     public <T extends Node> T add(T node) {
 437         if (node.getNodeClass().valueNumberable()) {
 438             throw new IllegalStateException("Using add for value numberable node. Consider using either unique or addWithoutUnique.");
 439         }
 440         return addHelper(node);
 441     }
 442 
 443     public <T extends Node> T addWithoutUnique(T node) {
 444         return addHelper(node);
 445     }
 446 
 447     public <T extends Node> T addOrUnique(T node) {
 448         if (node.getNodeClass().valueNumberable()) {
 449             return uniqueHelper(node);
 450         }
 451         return add(node);
 452     }
 453 
 454     public <T extends Node> T maybeAddOrUnique(T node) {
 455         if (node.isAlive()) {
 456             return node;
 457         }
 458         return addOrUnique(node);
 459     }
 460 
 461     public <T extends Node> T addOrUniqueWithInputs(T node) {
 462         if (node.isAlive()) {
 463             assert node.graph() == this;
 464             return node;
 465         } else {
 466             assert node.isUnregistered();
 467             addInputs(node);
 468             if (node.getNodeClass().valueNumberable()) {
 469                 return uniqueHelper(node);
 470             }
 471             return add(node);
 472         }
 473     }
 474 
 475     private final class AddInputsFilter extends Node.EdgeVisitor {
 476 
 477         @Override
 478         public Node apply(Node self, Node input) {
 479             if (!input.isAlive()) {
 480                 assert !input.isDeleted();
 481                 return addOrUniqueWithInputs(input);
 482             } else {
 483                 return input;
 484             }
 485         }
 486 
 487     }
 488 
 489     private AddInputsFilter addInputsFilter = new AddInputsFilter();
 490 
 491     private <T extends Node> void addInputs(T node) {
 492         node.applyInputs(addInputsFilter);
 493     }
 494 
 495     private <T extends Node> T addHelper(T node) {
 496         node.initialize(this);
 497         return node;
 498     }
 499 
 500     /**
 501      * The type of events sent to a {@link NodeEventListener}.
 502      */
 503     public enum NodeEvent {
 504         /**
 505          * A node's input is changed.
 506          */
 507         INPUT_CHANGED,
 508 
 509         /**
 510          * A node's {@linkplain Node#usages() usages} count dropped to zero.
 511          */
 512         ZERO_USAGES,
 513 
 514         /**
 515          * A node was added to a graph.
 516          */
 517         NODE_ADDED;
 518     }
 519 
 520     /**
 521      * Client interested in one or more node related events.
 522      */
 523     public interface NodeEventListener {
 524 
 525         /**
 526          * Default handler for events.
 527          *
 528          * @param e an event
 529          * @param node the node related to {@code e}
 530          */
 531         default void event(NodeEvent e, Node node) {
 532         }
 533 
 534         /**
 535          * Notifies this listener of a change in a node's inputs.
 536          *
 537          * @param node a node who has had one of its inputs changed
 538          */
 539         default void inputChanged(Node node) {
 540             event(NodeEvent.INPUT_CHANGED, node);
 541         }
 542 
 543         /**
 544          * Notifies this listener of a node becoming unused.
 545          *
 546          * @param node a node whose {@link Node#usages()} just became empty
 547          */
 548         default void usagesDroppedToZero(Node node) {
 549             event(NodeEvent.ZERO_USAGES, node);
 550         }
 551 
 552         /**
 553          * Notifies this listener of an added node.
 554          *
 555          * @param node a node that was just added to the graph
 556          */
 557         default void nodeAdded(Node node) {
 558             event(NodeEvent.NODE_ADDED, node);
 559         }
 560     }
 561 
 562     /**
 563      * Registers a given {@link NodeEventListener} with the enclosing graph until this object is
 564      * {@linkplain #close() closed}.
 565      */
 566     public final class NodeEventScope implements AutoCloseable {
 567         NodeEventScope(NodeEventListener listener) {
 568             if (nodeEventListener == null) {
 569                 nodeEventListener = listener;
 570             } else {
 571                 nodeEventListener = new ChainedNodeEventListener(listener, nodeEventListener);
 572             }
 573         }
 574 
 575         @Override
 576         public void close() {
 577             assert nodeEventListener != null;
 578             if (nodeEventListener instanceof ChainedNodeEventListener) {
 579                 nodeEventListener = ((ChainedNodeEventListener) nodeEventListener).next;
 580             } else {
 581                 nodeEventListener = null;
 582             }
 583         }
 584     }
 585 
 586     private static class ChainedNodeEventListener implements NodeEventListener {
 587 
 588         NodeEventListener head;
 589         NodeEventListener next;
 590 
 591         ChainedNodeEventListener(NodeEventListener head, NodeEventListener next) {
 592             this.head = head;
 593             this.next = next;
 594         }
 595 
 596         @Override
 597         public void nodeAdded(Node node) {
 598             head.nodeAdded(node);
 599             next.nodeAdded(node);
 600         }
 601 
 602         @Override
 603         public void inputChanged(Node node) {
 604             head.inputChanged(node);
 605             next.inputChanged(node);
 606         }
 607 
 608         @Override
 609         public void usagesDroppedToZero(Node node) {
 610             head.usagesDroppedToZero(node);
 611             next.usagesDroppedToZero(node);
 612         }
 613     }
 614 
 615     /**
 616      * Registers a given {@link NodeEventListener} with this graph. This should be used in
 617      * conjunction with try-with-resources statement as follows:
 618      *
 619      * <pre>
 620      * try (NodeEventScope nes = graph.trackNodeEvents(listener)) {
 621      *     // make changes to the graph
 622      * }
 623      * </pre>
 624      */
 625     public NodeEventScope trackNodeEvents(NodeEventListener listener) {
 626         return new NodeEventScope(listener);
 627     }
 628 
 629     /**
 630      * Looks for a node <i>similar</i> to {@code node} and returns it if found. Otherwise
 631      * {@code node} is added to this graph and returned.
 632      *
 633      * @return a node similar to {@code node} if one exists, otherwise {@code node}
 634      */
 635     public <T extends Node & ValueNumberable> T unique(T node) {
 636         return uniqueHelper(node);
 637     }
 638 
 639     <T extends Node> T uniqueHelper(T node) {
 640         assert node.getNodeClass().valueNumberable();
 641         T other = this.findDuplicate(node);
 642         if (other != null) {
 643             return other;
 644         } else {
 645             T result = addHelper(node);
 646             if (node.getNodeClass().isLeafNode()) {
 647                 putNodeIntoCache(result);
 648             }
 649             return result;
 650         }
 651     }
 652 
 653     void removeNodeFromCache(Node node) {
 654         assert node.graph() == this || node.graph() == null;
 655         assert node.getNodeClass().valueNumberable();
 656         assert node.getNodeClass().isLeafNode() : node.getClass();
 657 
 658         int leafId = node.getNodeClass().getLeafId();
 659         if (cachedLeafNodes != null && cachedLeafNodes.length > leafId && cachedLeafNodes[leafId] != null) {
 660             cachedLeafNodes[leafId].removeKey(node);
 661         }
 662     }
 663 
 664     @SuppressWarnings({"unchecked", "rawtypes"})
 665     void putNodeIntoCache(Node node) {
 666         assert node.graph() == this || node.graph() == null;
 667         assert node.getNodeClass().valueNumberable();
 668         assert node.getNodeClass().isLeafNode() : node.getClass();
 669 
 670         int leafId = node.getNodeClass().getLeafId();
 671         if (cachedLeafNodes == null || cachedLeafNodes.length <= leafId) {
 672             EconomicMap[] newLeafNodes = new EconomicMap[leafId + 1];
 673             if (cachedLeafNodes != null) {
 674                 System.arraycopy(cachedLeafNodes, 0, newLeafNodes, 0, cachedLeafNodes.length);
 675             }
 676             cachedLeafNodes = newLeafNodes;
 677         }
 678 
 679         if (cachedLeafNodes[leafId] == null) {
 680             cachedLeafNodes[leafId] = EconomicMap.create(NODE_VALUE_COMPARE);
 681         }
 682 
 683         cachedLeafNodes[leafId].put(node, node);
 684     }
 685 
 686     Node findNodeInCache(Node node) {
 687         int leafId = node.getNodeClass().getLeafId();
 688         if (cachedLeafNodes == null || cachedLeafNodes.length <= leafId || cachedLeafNodes[leafId] == null) {
 689             return null;
 690         }
 691 
 692         Node result = cachedLeafNodes[leafId].get(node);
 693         assert result == null || result.isAlive() : result;
 694         return result;
 695     }
 696 
 697     /**
 698      * Returns a possible duplicate for the given node in the graph or {@code null} if no such
 699      * duplicate exists.
 700      */
 701     @SuppressWarnings("unchecked")
 702     public <T extends Node> T findDuplicate(T node) {
 703         NodeClass<?> nodeClass = node.getNodeClass();
 704         assert nodeClass.valueNumberable();
 705         if (nodeClass.isLeafNode()) {
 706             // Leaf node: look up in cache
 707             Node cachedNode = findNodeInCache(node);
 708             if (cachedNode != null && cachedNode != node) {
 709                 return (T) cachedNode;
 710             } else {
 711                 return null;
 712             }
 713         } else {
 714             /*
 715              * Non-leaf node: look for another usage of the node's inputs that has the same data,
 716              * inputs and successors as the node. To reduce the cost of this computation, only the
 717              * input with lowest usage count is considered. If this node is the only user of any
 718              * input then the search can terminate early. The usage count is only incremented once
 719              * the Node is in the Graph, so account for that in the test.
 720              */
 721             final int earlyExitUsageCount = node.graph() != null ? 1 : 0;
 722             int minCount = Integer.MAX_VALUE;
 723             Node minCountNode = null;
 724             for (Node input : node.inputs()) {
 725                 int usageCount = input.getUsageCount();
 726                 if (usageCount == earlyExitUsageCount) {
 727                     return null;
 728                 } else if (usageCount < minCount) {
 729                     minCount = usageCount;
 730                     minCountNode = input;
 731                 }
 732             }
 733             if (minCountNode != null) {
 734                 for (Node usage : minCountNode.usages()) {
 735                     if (usage != node && nodeClass == usage.getNodeClass() && node.valueEquals(usage) && nodeClass.equalInputs(node, usage) &&
 736                                     nodeClass.equalSuccessors(node, usage)) {
 737                         return (T) usage;
 738                     }
 739                 }
 740                 return null;
 741             }
 742             return null;
 743         }
 744     }
 745 
 746     public boolean isNew(Mark mark, Node node) {
 747         return node.id >= mark.getValue();
 748     }
 749 
 750     /**
 751      * A snapshot of the {@linkplain Graph#getNodeCount() live node count} in a graph.
 752      */
 753     public static class Mark extends NodeIdAccessor {
 754         private final int value;
 755 
 756         Mark(Graph graph) {
 757             super(graph);
 758             this.value = graph.nodeIdCount();
 759         }
 760 
 761         @Override
 762         public boolean equals(Object obj) {
 763             if (obj instanceof Mark) {
 764                 Mark other = (Mark) obj;
 765                 return other.getValue() == getValue() && other.getGraph() == getGraph();
 766             }
 767             return false;
 768         }
 769 
 770         @Override
 771         public int hashCode() {
 772             return value ^ (epoch + 11);
 773         }
 774 
 775         /**
 776          * Determines if this mark is positioned at the first live node in the graph.
 777          */
 778         public boolean isStart() {
 779             return value == 0;
 780         }
 781 
 782         /**
 783          * Gets the {@linkplain Graph#getNodeCount() live node count} of the associated graph when
 784          * this object was created.
 785          */
 786         int getValue() {
 787             return value;
 788         }
 789 
 790         /**
 791          * Determines if this mark still represents the {@linkplain Graph#getNodeCount() live node
 792          * count} of the graph.
 793          */
 794         public boolean isCurrent() {
 795             return value == graph.nodeIdCount();
 796         }
 797     }
 798 
 799     /**
 800      * Gets a mark that can be used with {@link #getNewNodes}.
 801      */
 802     public Mark getMark() {
 803         return new Mark(this);
 804     }
 805 
 806     /**
 807      * Returns an {@link Iterable} providing all nodes added since the last {@link Graph#getMark()
 808      * mark}.
 809      */
 810     public NodeIterable<Node> getNewNodes(Mark mark) {
 811         final int index = mark == null ? 0 : mark.getValue();
 812         return new NodeIterable<Node>() {
 813 
 814             @Override
 815             public Iterator<Node> iterator() {
 816                 return new GraphNodeIterator(Graph.this, index);
 817             }
 818         };
 819     }
 820 
 821     /**
 822      * Returns an {@link Iterable} providing all the live nodes.
 823      *
 824      * @return an {@link Iterable} providing all the live nodes.
 825      */
 826     public NodeIterable<Node> getNodes() {
 827         return new NodeIterable<Node>() {
 828 
 829             @Override
 830             public Iterator<Node> iterator() {
 831                 return new GraphNodeIterator(Graph.this);
 832             }
 833 
 834             @Override
 835             public int count() {
 836                 return getNodeCount();
 837             }
 838         };
 839     }
 840 
 841     // Fully qualified annotation name is required to satisfy javac
 842     @org.graalvm.compiler.nodeinfo.NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
 843     static final class PlaceHolderNode extends Node {
 844 
 845         public static final NodeClass<PlaceHolderNode> TYPE = NodeClass.create(PlaceHolderNode.class);
 846 
 847         protected PlaceHolderNode() {
 848             super(TYPE);
 849         }
 850 
 851     }
 852 
 853     private static final CounterKey GraphCompressions = DebugContext.counter("GraphCompressions");
 854 
 855     /**
 856      * If the {@linkplain Options#GraphCompressionThreshold compression threshold} is met, the list
 857      * of nodes is compressed such that all non-null entries precede all null entries while
 858      * preserving the ordering between the nodes within the list.
 859      */
 860     public boolean maybeCompress() {
 861         if (debug.isDumpEnabledForMethod() || debug.isLogEnabledForMethod()) {
 862             return false;
 863         }
 864         int liveNodeCount = getNodeCount();
 865         int liveNodePercent = liveNodeCount * 100 / nodesSize;
 866         int compressionThreshold = Options.GraphCompressionThreshold.getValue(options);
 867         if (compressionThreshold == 0 || liveNodePercent >= compressionThreshold) {
 868             return false;
 869         }
 870         GraphCompressions.increment(debug);
 871         int nextId = 0;
 872         for (int i = 0; nextId < liveNodeCount; i++) {
 873             Node n = nodes[i];
 874             if (n != null) {
 875                 assert n.id == i;
 876                 if (i != nextId) {
 877                     assert n.id > nextId;
 878                     n.id = nextId;
 879                     nodes[nextId] = n;
 880                     nodes[i] = null;
 881                 }
 882                 nextId++;
 883             }
 884         }
 885         if (isModificationCountsEnabled()) {
 886             // This will cause any current iteration to fail with an assertion
 887             Arrays.fill(nodeModCounts, 0);
 888             Arrays.fill(nodeUsageModCounts, 0);
 889         }
 890         nodesSize = nextId;
 891         compressions++;
 892         nodesDeletedBeforeLastCompression += nodesDeletedSinceLastCompression;
 893         nodesDeletedSinceLastCompression = 0;
 894         return true;
 895     }
 896 
 897     /**
 898      * Returns an {@link Iterable} providing all the live nodes whose type is compatible with
 899      * {@code type}.
 900      *
 901      * @param nodeClass the type of node to return
 902      * @return an {@link Iterable} providing all the matching nodes
 903      */
 904     public <T extends Node & IterableNodeType> NodeIterable<T> getNodes(final NodeClass<T> nodeClass) {
 905         return new NodeIterable<T>() {
 906 
 907             @Override
 908             public Iterator<T> iterator() {
 909                 return new TypedGraphNodeIterator<>(nodeClass, Graph.this);
 910             }
 911         };
 912     }
 913 
 914     /**
 915      * Returns whether the graph contains at least one node of the given type.
 916      *
 917      * @param type the type of node that is checked for occurrence
 918      * @return whether there is at least one such node
 919      */
 920     public <T extends Node & IterableNodeType> boolean hasNode(final NodeClass<T> type) {
 921         return getNodes(type).iterator().hasNext();
 922     }
 923 
 924     /**
 925      * @param iterableId
 926      * @return the first live Node with a matching iterableId
 927      */
 928     Node getIterableNodeStart(int iterableId) {
 929         if (iterableNodesFirst.size() <= iterableId) {
 930             return null;
 931         }
 932         Node start = iterableNodesFirst.get(iterableId);
 933         if (start == null || !start.isDeleted()) {
 934             return start;
 935         }
 936         return findFirstLiveIterable(iterableId, start);
 937     }
 938 
 939     private Node findFirstLiveIterable(int iterableId, Node node) {
 940         Node start = node;
 941         while (start != null && start.isDeleted()) {
 942             start = start.typeCacheNext;
 943         }
 944         /*
 945          * Multiple threads iterating nodes can update this cache simultaneously. This is a benign
 946          * race, since all threads update it to the same value.
 947          */
 948         iterableNodesFirst.set(iterableId, start);
 949         if (start == null) {
 950             iterableNodesLast.set(iterableId, start);
 951         }
 952         return start;
 953     }
 954 
 955     /**
 956      * @param node
 957      * @return return the first live Node with a matching iterableId starting from {@code node}
 958      */
 959     Node getIterableNodeNext(Node node) {
 960         if (node == null) {
 961             return null;
 962         }
 963         Node n = node;
 964         if (n == null || !n.isDeleted()) {
 965             return n;
 966         }
 967 
 968         return findNextLiveiterable(node);
 969     }
 970 
 971     private Node findNextLiveiterable(Node start) {
 972         Node n = start;
 973         while (n != null && n.isDeleted()) {
 974             n = n.typeCacheNext;
 975         }
 976         if (n == null) {
 977             // Only dead nodes after this one
 978             start.typeCacheNext = null;
 979             int nodeClassId = start.getNodeClass().iterableId();
 980             assert nodeClassId != Node.NOT_ITERABLE;
 981             iterableNodesLast.set(nodeClassId, start);
 982         } else {
 983             // Everything in between is dead
 984             start.typeCacheNext = n;
 985         }
 986         return n;
 987     }
 988 
 989     public NodeBitMap createNodeBitMap() {
 990         return new NodeBitMap(this);
 991     }
 992 
 993     public <T> NodeMap<T> createNodeMap() {
 994         return new NodeMap<>(this);
 995     }
 996 
 997     public NodeFlood createNodeFlood() {
 998         return new NodeFlood(this);
 999     }
1000 
1001     public NodeWorkList createNodeWorkList() {
1002         return new NodeWorkList.SingletonNodeWorkList(this);
1003     }
1004 
1005     public NodeWorkList createIterativeNodeWorkList(boolean fill, int iterationLimitPerNode) {
1006         return new NodeWorkList.IterativeNodeWorkList(this, fill, iterationLimitPerNode);
1007     }
1008 
1009     void register(Node node) {
1010         assert !isFrozen();
1011         assert node.id() == Node.INITIAL_ID;
1012         if (nodes.length == nodesSize) {
1013             grow();
1014         }
1015         int id = nodesSize++;
1016         nodes[id] = node;
1017         node.id = id;
1018         if (currentNodeSourcePosition != null) {
1019             node.setNodeSourcePosition(currentNodeSourcePosition);
1020         }
1021         seenNodeSourcePosition = seenNodeSourcePosition || node.getNodeSourcePosition() != null;
1022 
1023         updateNodeCaches(node);
1024 
1025         if (nodeEventListener != null) {
1026             nodeEventListener.nodeAdded(node);
1027         }
1028         afterRegister(node);
1029     }
1030 
1031     private void grow() {
1032         Node[] newNodes = new Node[(nodesSize * 2) + 1];
1033         System.arraycopy(nodes, 0, newNodes, 0, nodesSize);
1034         nodes = newNodes;
1035     }
1036 
1037     @SuppressWarnings("unused")
1038     protected void afterRegister(Node node) {
1039 
1040     }
1041 
1042     @SuppressWarnings("unused")
1043     private void postDeserialization() {
1044         recomputeIterableNodeLists();
1045     }
1046 
1047     /**
1048      * Rebuilds the lists used to support {@link #getNodes(NodeClass)}. This is useful for
1049      * serialization where the underlying {@linkplain NodeClass#iterableId() iterable ids} may have
1050      * changed.
1051      */
1052     private void recomputeIterableNodeLists() {
1053         iterableNodesFirst.clear();
1054         iterableNodesLast.clear();
1055         for (Node node : nodes) {
1056             if (node != null && node.isAlive()) {
1057                 updateNodeCaches(node);
1058             }
1059         }
1060     }
1061 
1062     private void updateNodeCaches(Node node) {
1063         int nodeClassId = node.getNodeClass().iterableId();
1064         if (nodeClassId != Node.NOT_ITERABLE) {
1065             while (iterableNodesFirst.size() <= nodeClassId) {
1066                 iterableNodesFirst.add(null);
1067                 iterableNodesLast.add(null);
1068             }
1069             Node prev = iterableNodesLast.get(nodeClassId);
1070             if (prev != null) {
1071                 prev.typeCacheNext = node;
1072             } else {
1073                 iterableNodesFirst.set(nodeClassId, node);
1074             }
1075             iterableNodesLast.set(nodeClassId, node);
1076         }
1077     }
1078 
1079     void unregister(Node node) {
1080         assert !isFrozen();
1081         assert !node.isDeleted() : node;
1082         if (node.getNodeClass().isLeafNode() && node.getNodeClass().valueNumberable()) {
1083             removeNodeFromCache(node);
1084         }
1085         nodes[node.id] = null;
1086         nodesDeletedSinceLastCompression++;
1087 
1088         // nodes aren't removed from the type cache here - they will be removed during iteration
1089     }
1090 
1091     public boolean verify() {
1092         if (Options.VerifyGraalGraphs.getValue(options)) {
1093             for (Node node : getNodes()) {
1094                 try {
1095                     try {
1096                         assert node.verify();
1097                     } catch (AssertionError t) {
1098                         throw new GraalError(t);
1099                     } catch (RuntimeException t) {
1100                         throw new GraalError(t);
1101                     }
1102                 } catch (GraalError e) {
1103                     throw GraalGraphError.transformAndAddContext(e, node).addContext(this);
1104                 }
1105             }
1106         }
1107         return true;
1108     }
1109 
1110     public Node getNode(int id) {
1111         return nodes[id];
1112     }
1113 
1114     /**
1115      * Returns the number of node ids generated so far.
1116      *
1117      * @return the number of node ids generated so far
1118      */
1119     int nodeIdCount() {
1120         return nodesSize;
1121     }
1122 
1123     /**
1124      * Adds duplicates of the nodes in {@code newNodes} to this graph. This will recreate any edges
1125      * between the duplicate nodes. The {@code replacement} map can be used to replace a node from
1126      * the source graph by a given node (which must already be in this graph). Edges between
1127      * duplicate and replacement nodes will also be recreated so care should be taken regarding the
1128      * matching of node types in the replacement map.
1129      *
1130      * @param newNodes the nodes to be duplicated
1131      * @param replacementsMap the replacement map (can be null if no replacement is to be performed)
1132      * @return a map which associates the original nodes from {@code nodes} to their duplicates
1133      */
1134     public UnmodifiableEconomicMap<Node, Node> addDuplicates(Iterable<? extends Node> newNodes, final Graph oldGraph, int estimatedNodeCount, EconomicMap<Node, Node> replacementsMap) {
1135         DuplicationReplacement replacements;
1136         if (replacementsMap == null) {
1137             replacements = null;
1138         } else {
1139             replacements = new MapReplacement(replacementsMap);
1140         }
1141         return addDuplicates(newNodes, oldGraph, estimatedNodeCount, replacements);
1142     }
1143 
1144     public interface DuplicationReplacement {
1145 
1146         Node replacement(Node original);
1147     }
1148 
1149     private static final class MapReplacement implements DuplicationReplacement {
1150 
1151         private final EconomicMap<Node, Node> map;
1152 
1153         MapReplacement(EconomicMap<Node, Node> map) {
1154             this.map = map;
1155         }
1156 
1157         @Override
1158         public Node replacement(Node original) {
1159             Node replacement = map.get(original);
1160             return replacement != null ? replacement : original;
1161         }
1162 
1163     }
1164 
1165     private static final TimerKey DuplicateGraph = DebugContext.timer("DuplicateGraph");
1166 
1167     @SuppressWarnings({"all", "try"})
1168     public EconomicMap<Node, Node> addDuplicates(Iterable<? extends Node> newNodes, final Graph oldGraph, int estimatedNodeCount, DuplicationReplacement replacements) {
1169         try (DebugCloseable s = DuplicateGraph.start(getDebug())) {
1170             return NodeClass.addGraphDuplicate(this, oldGraph, estimatedNodeCount, newNodes, replacements);
1171         }
1172     }
1173 
1174     public boolean isFrozen() {
1175         return freezeState != FreezeState.Unfrozen;
1176     }
1177 
1178     public void freeze() {
1179         this.freezeState = FreezeState.DeepFreeze;
1180     }
1181 
1182     public void temporaryFreeze() {
1183         if (this.freezeState == FreezeState.DeepFreeze) {
1184             throw new GraalError("Graph was permanetly frozen.");
1185         }
1186         this.freezeState = FreezeState.TemporaryFreeze;
1187     }
1188 
1189     public void unfreeze() {
1190         if (this.freezeState == FreezeState.DeepFreeze) {
1191             throw new GraalError("Graph was permanetly frozen.");
1192         }
1193         this.freezeState = FreezeState.Unfrozen;
1194     }
1195 }