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