1 /*
2  * Copyright (c) 2011, 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.Edges.Type.Inputs;
28 import static org.graalvm.compiler.graph.Edges.Type.Successors;
29 import static org.graalvm.compiler.graph.Graph.isModificationCountsEnabled;
30 import static org.graalvm.compiler.graph.UnsafeAccess.UNSAFE;
31 
32 import java.lang.annotation.ElementType;
33 import java.lang.annotation.RetentionPolicy;
34 import java.util.Arrays;
35 import java.util.Collections;
36 import java.util.EnumSet;
37 import java.util.Formattable;
38 import java.util.FormattableFlags;
39 import java.util.Formatter;
40 import java.util.HashMap;
41 import java.util.Map;
42 import java.util.Objects;
43 import java.util.function.Predicate;
44 import java.util.function.Supplier;
45 
46 import org.graalvm.compiler.core.common.Fields;
47 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
48 import org.graalvm.compiler.core.common.type.Stamp;
49 import org.graalvm.compiler.debug.DebugCloseable;
50 import org.graalvm.compiler.debug.DebugContext;
51 import org.graalvm.compiler.graph.Graph.NodeEventListener;
52 import org.graalvm.compiler.graph.Graph.Options;
53 import org.graalvm.compiler.graph.iterators.NodeIterable;
54 import org.graalvm.compiler.graph.iterators.NodePredicate;
55 import org.graalvm.compiler.graph.spi.Simplifiable;
56 import org.graalvm.compiler.graph.spi.SimplifierTool;
57 import org.graalvm.compiler.nodeinfo.InputType;
58 import org.graalvm.compiler.nodeinfo.NodeCycles;
59 import org.graalvm.compiler.nodeinfo.NodeInfo;
60 import org.graalvm.compiler.nodeinfo.NodeSize;
61 import org.graalvm.compiler.nodeinfo.Verbosity;
62 import org.graalvm.compiler.options.OptionValues;
63 
64 import sun.misc.Unsafe;
65 
66 /**
67  * This class is the base class for all nodes. It represents a node that can be inserted in a
68  * {@link Graph}.
69  * <p>
70  * Once a node has been added to a graph, it has a graph-unique {@link #id()}. Edges in the
71  * subclasses are represented with annotated fields. There are two kind of edges : {@link Input} and
72  * {@link Successor}. If a field, of a type compatible with {@link Node}, annotated with either
73  * {@link Input} and {@link Successor} is not null, then there is an edge from this node to the node
74  * this field points to.
75  * <p>
76  * Nodes which are be value numberable should implement the {@link ValueNumberable} interface.
77  *
78  * <h1>Assertions and Verification</h1>
79  *
80  * The Node class supplies the {@link #assertTrue(boolean, String, Object...)} and
81  * {@link #assertFalse(boolean, String, Object...)} methods, which will check the supplied boolean
82  * and throw a VerificationError if it has the wrong value. Both methods will always either throw an
83  * exception or return true. They can thus be used within an assert statement, so that the check is
84  * only performed if assertions are enabled.
85  */
86 @NodeInfo
87 public abstract class Node implements Cloneable, Formattable, NodeInterface {
88 
89     public static final NodeClass<?> TYPE = null;
90 
91     public static final boolean TRACK_CREATION_POSITION = Boolean.getBoolean("debug.graal.TrackNodeCreationPosition");
92 
93     static final int DELETED_ID_START = -1000000000;
94     static final int INITIAL_ID = -1;
95     static final int ALIVE_ID_START = 0;
96 
97     // The use of fully qualified class names here and in the rest
98     // of this file works around a problem javac has resolving symbols
99 
100     /**
101      * Denotes a non-optional (non-null) node input. This should be applied to exactly the fields of
102      * a node that are of type {@link Node} or {@link NodeInputList}. Nodes that update fields of
103      * type {@link Node} outside of their constructor should call
104      * {@link Node#updateUsages(Node, Node)} just prior to doing the update of the input.
105      */
106     @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
107     @java.lang.annotation.Target(ElementType.FIELD)
108     public static @interface Input {
value()109         InputType value() default InputType.Value;
110     }
111 
112     /**
113      * Denotes an optional (nullable) node input. This should be applied to exactly the fields of a
114      * node that are of type {@link Node} or {@link NodeInputList}. Nodes that update fields of type
115      * {@link Node} outside of their constructor should call {@link Node#updateUsages(Node, Node)}
116      * just prior to doing the update of the input.
117      */
118     @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
119     @java.lang.annotation.Target(ElementType.FIELD)
120     public static @interface OptionalInput {
value()121         InputType value() default InputType.Value;
122     }
123 
124     @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
125     @java.lang.annotation.Target(ElementType.FIELD)
126     public static @interface Successor {
127     }
128 
129     /**
130      * Denotes that a parameter of an {@linkplain NodeIntrinsic intrinsic} method must be a compile
131      * time constant at all call sites to the intrinsic method.
132      */
133     @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
134     @java.lang.annotation.Target(ElementType.PARAMETER)
135     public static @interface ConstantNodeParameter {
136     }
137 
138     /**
139      * Denotes an injected parameter in a {@linkplain NodeIntrinsic node intrinsic} constructor. If
140      * the constructor is called as part of node intrinsification, the node intrinsifier will inject
141      * an argument for the annotated parameter. Injected parameters must precede all non-injected
142      * parameters in a constructor. If the type of the annotated parameter is {@link Stamp}, the
143      * {@linkplain Stamp#javaType type} of the injected stamp is the return type of the annotated
144      * method (which cannot be {@code void}).
145      */
146     @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
147     @java.lang.annotation.Target(ElementType.PARAMETER)
148     public static @interface InjectedNodeParameter {
149     }
150 
151     /**
152      * Annotates a method that can be replaced by a compiler intrinsic. A (resolved) call to the
153      * annotated method will be processed by a generated {@code InvocationPlugin} that calls either
154      * a factory method or a constructor corresponding with the annotated method.
155      * <p>
156      * A factory method corresponding to an annotated method is a static method named
157      * {@code intrinsify} defined in the class denoted by {@link #value()}. In order, its signature
158      * is as follows:
159      * <ol>
160      * <li>A {@code GraphBuilderContext} parameter.</li>
161      * <li>A {@code ResolvedJavaMethod} parameter.</li>
162      * <li>A sequence of zero or more {@linkplain InjectedNodeParameter injected} parameters.</li>
163      * <li>Remaining parameters that match the declared parameters of the annotated method.</li>
164      * </ol>
165      * A constructor corresponding to an annotated method is defined in the class denoted by
166      * {@link #value()}. In order, its signature is as follows:
167      * <ol>
168      * <li>A sequence of zero or more {@linkplain InjectedNodeParameter injected} parameters.</li>
169      * <li>Remaining parameters that match the declared parameters of the annotated method.</li>
170      * </ol>
171      * There must be exactly one such factory method or constructor corresponding to a
172      * {@link NodeIntrinsic} annotated method.
173      */
174     @java.lang.annotation.Retention(RetentionPolicy.RUNTIME)
175     @java.lang.annotation.Target(ElementType.METHOD)
176     public static @interface NodeIntrinsic {
177 
178         /**
179          * The class declaring the factory method or {@link Node} subclass declaring the constructor
180          * used to intrinsify a call to the annotated method. The default value is the class in
181          * which the annotated method is declared.
182          */
value()183         Class<?> value() default NodeIntrinsic.class;
184 
185         /**
186          * If {@code true}, the factory method or constructor selected by the annotation must have
187          * an {@linkplain InjectedNodeParameter injected} {@link Stamp} parameter. Calling
188          * {@link AbstractPointerStamp#nonNull()} on the injected stamp is guaranteed to return
189          * {@code true}.
190          */
injectedStampIsNonNull()191         boolean injectedStampIsNonNull() default false;
192     }
193 
194     /**
195      * Marker for a node that can be replaced by another node via global value numbering. A
196      * {@linkplain NodeClass#isLeafNode() leaf} node can be replaced by another node of the same
197      * type that has exactly the same {@linkplain NodeClass#getData() data} values. A non-leaf node
198      * can be replaced by another node of the same type that has exactly the same data values as
199      * well as the same {@linkplain Node#inputs() inputs} and {@linkplain Node#successors()
200      * successors}.
201      */
202     public interface ValueNumberable {
203     }
204 
205     /**
206      * Marker interface for nodes that contains other nodes. When the inputs to this node changes,
207      * users of this node should also be placed on the work list for canonicalization.
208      */
209     public interface IndirectCanonicalization {
210     }
211 
212     private Graph graph;
213     int id;
214 
215     // this next pointer is used in Graph to implement fast iteration over NodeClass types, it
216     // therefore points to the next Node of the same type.
217     Node typeCacheNext;
218 
219     static final int INLINE_USAGE_COUNT = 2;
220     private static final Node[] NO_NODES = {};
221 
222     /**
223      * Head of usage list. The elements of the usage list in order are {@link #usage0},
224      * {@link #usage1} and {@link #extraUsages}. The first null entry terminates the list.
225      */
226     Node usage0;
227     Node usage1;
228     Node[] extraUsages;
229     int extraUsagesCount;
230 
231     private Node predecessor;
232     private NodeClass<? extends Node> nodeClass;
233 
234     public static final int NODE_LIST = -2;
235     public static final int NOT_ITERABLE = -1;
236 
237     static class NodeStackTrace {
238         final StackTraceElement[] stackTrace;
239 
NodeStackTrace()240         NodeStackTrace() {
241             this.stackTrace = new Throwable().getStackTrace();
242         }
243 
getString(String label)244         private String getString(String label) {
245             StringBuilder sb = new StringBuilder();
246             if (label != null) {
247                 sb.append(label).append(": ");
248             }
249             for (StackTraceElement ste : stackTrace) {
250                 sb.append("at ").append(ste.toString()).append('\n');
251             }
252             return sb.toString();
253         }
254 
getStrackTraceString()255         String getStrackTraceString() {
256             return getString(null);
257         }
258 
259         @Override
toString()260         public String toString() {
261             return getString(getClass().getSimpleName());
262         }
263     }
264 
265     static class NodeCreationStackTrace extends NodeStackTrace {
266     }
267 
268     public static class NodeInsertionStackTrace extends NodeStackTrace {
269     }
270 
Node(NodeClass<? extends Node> c)271     public Node(NodeClass<? extends Node> c) {
272         init(c);
273     }
274 
init(NodeClass<? extends Node> c)275     final void init(NodeClass<? extends Node> c) {
276         assert c.getJavaClass() == this.getClass();
277         this.nodeClass = c;
278         id = INITIAL_ID;
279         extraUsages = NO_NODES;
280         if (TRACK_CREATION_POSITION) {
281             setCreationPosition(new NodeCreationStackTrace());
282         }
283     }
284 
id()285     final int id() {
286         return id;
287     }
288 
289     @Override
asNode()290     public Node asNode() {
291         return this;
292     }
293 
294     /**
295      * Gets the graph context of this node.
296      */
graph()297     public Graph graph() {
298         return graph;
299     }
300 
301     /**
302      * Gets the option values associated with this node's graph.
303      */
getOptions()304     public final OptionValues getOptions() {
305         return graph == null ? null : graph.getOptions();
306     }
307 
308     /**
309      * Gets the debug context associated with this node's graph.
310      */
getDebug()311     public final DebugContext getDebug() {
312         return graph.getDebug();
313     }
314 
315     /**
316      * Returns an {@link NodeIterable iterable} which can be used to traverse all non-null input
317      * edges of this node.
318      *
319      * @return an {@link NodeIterable iterable} for all non-null input edges.
320      */
inputs()321     public NodeIterable<Node> inputs() {
322         return nodeClass.getInputIterable(this);
323     }
324 
325     /**
326      * Returns an {@link Iterable iterable} which can be used to traverse all non-null input edges
327      * of this node.
328      *
329      * @return an {@link Iterable iterable} for all non-null input edges.
330      */
inputPositions()331     public Iterable<Position> inputPositions() {
332         return nodeClass.getInputEdges().getPositionsIterable(this);
333     }
334 
335     public abstract static class EdgeVisitor {
336 
apply(Node source, Node target)337         public abstract Node apply(Node source, Node target);
338 
339     }
340 
341     /**
342      * Applies the given visitor to all inputs of this node.
343      *
344      * @param visitor the visitor to be applied to the inputs
345      */
applyInputs(EdgeVisitor visitor)346     public void applyInputs(EdgeVisitor visitor) {
347         nodeClass.applyInputs(this, visitor);
348     }
349 
350     /**
351      * Applies the given visitor to all successors of this node.
352      *
353      * @param visitor the visitor to be applied to the successors
354      */
applySuccessors(EdgeVisitor visitor)355     public void applySuccessors(EdgeVisitor visitor) {
356         nodeClass.applySuccessors(this, visitor);
357     }
358 
359     /**
360      * Returns an {@link NodeIterable iterable} which can be used to traverse all non-null successor
361      * edges of this node.
362      *
363      * @return an {@link NodeIterable iterable} for all non-null successor edges.
364      */
successors()365     public NodeIterable<Node> successors() {
366         assert !this.isDeleted() : this;
367         return nodeClass.getSuccessorIterable(this);
368     }
369 
370     /**
371      * Returns an {@link Iterable iterable} which can be used to traverse all successor edge
372      * positions of this node.
373      *
374      * @return an {@link Iterable iterable} for all successor edge positoins.
375      */
successorPositions()376     public Iterable<Position> successorPositions() {
377         return nodeClass.getSuccessorEdges().getPositionsIterable(this);
378     }
379 
380     /**
381      * Gets the maximum number of usages this node has had at any point in time.
382      */
getUsageCount()383     public int getUsageCount() {
384         if (usage0 == null) {
385             return 0;
386         }
387         if (usage1 == null) {
388             return 1;
389         }
390         return INLINE_USAGE_COUNT + extraUsagesCount;
391     }
392 
393     /**
394      * Gets the list of nodes that use this node (i.e., as an input).
395      */
usages()396     public final NodeIterable<Node> usages() {
397         return new NodeUsageIterable(this);
398     }
399 
400     /**
401      * Checks whether this node has no usages.
402      */
hasNoUsages()403     public final boolean hasNoUsages() {
404         return this.usage0 == null;
405     }
406 
407     /**
408      * Checks whether this node has usages.
409      */
hasUsages()410     public final boolean hasUsages() {
411         return this.usage0 != null;
412     }
413 
414     /**
415      * Checks whether this node has more than one usages.
416      */
hasMoreThanOneUsage()417     public final boolean hasMoreThanOneUsage() {
418         return this.usage1 != null;
419     }
420 
421     /**
422      * Checks whether this node has exactly one usgae.
423      */
hasExactlyOneUsage()424     public final boolean hasExactlyOneUsage() {
425         return hasUsages() && !hasMoreThanOneUsage();
426     }
427 
428     /**
429      * Adds a given node to this node's {@linkplain #usages() usages}.
430      *
431      * @param node the node to add
432      */
addUsage(Node node)433     void addUsage(Node node) {
434         incUsageModCount();
435         if (usage0 == null) {
436             usage0 = node;
437         } else if (usage1 == null) {
438             usage1 = node;
439         } else {
440             int length = extraUsages.length;
441             if (length == 0) {
442                 extraUsages = new Node[4];
443             } else if (extraUsagesCount == length) {
444                 Node[] newExtraUsages = new Node[length * 2 + 1];
445                 System.arraycopy(extraUsages, 0, newExtraUsages, 0, length);
446                 extraUsages = newExtraUsages;
447             }
448             extraUsages[extraUsagesCount++] = node;
449         }
450     }
451 
movUsageFromEndTo(int destIndex)452     private void movUsageFromEndTo(int destIndex) {
453         if (destIndex >= INLINE_USAGE_COUNT) {
454             movUsageFromEndToExtraUsages(destIndex - INLINE_USAGE_COUNT);
455         } else if (destIndex == 1) {
456             movUsageFromEndToIndexOne();
457         } else {
458             assert destIndex == 0;
459             movUsageFromEndToIndexZero();
460         }
461     }
462 
movUsageFromEndToExtraUsages(int destExtraIndex)463     private void movUsageFromEndToExtraUsages(int destExtraIndex) {
464         this.extraUsagesCount--;
465         Node n = extraUsages[extraUsagesCount];
466         extraUsages[destExtraIndex] = n;
467         extraUsages[extraUsagesCount] = null;
468     }
469 
movUsageFromEndToIndexZero()470     private void movUsageFromEndToIndexZero() {
471         if (extraUsagesCount > 0) {
472             this.extraUsagesCount--;
473             usage0 = extraUsages[extraUsagesCount];
474             extraUsages[extraUsagesCount] = null;
475         } else if (usage1 != null) {
476             usage0 = usage1;
477             usage1 = null;
478         } else {
479             usage0 = null;
480         }
481     }
482 
movUsageFromEndToIndexOne()483     private void movUsageFromEndToIndexOne() {
484         if (extraUsagesCount > 0) {
485             this.extraUsagesCount--;
486             usage1 = extraUsages[extraUsagesCount];
487             extraUsages[extraUsagesCount] = null;
488         } else {
489             assert usage1 != null;
490             usage1 = null;
491         }
492     }
493 
494     /**
495      * Removes a given node from this node's {@linkplain #usages() usages}.
496      *
497      * @param node the node to remove
498      * @return whether or not {@code usage} was in the usage list
499      */
removeUsage(Node node)500     public boolean removeUsage(Node node) {
501         assert node != null;
502         // For large graphs, usage removal is performance critical.
503         // Furthermore, it is critical that this method maintains the invariant that the usage list
504         // has no null element preceding a non-null element.
505         incUsageModCount();
506         if (usage0 == node) {
507             movUsageFromEndToIndexZero();
508             return true;
509         }
510         if (usage1 == node) {
511             movUsageFromEndToIndexOne();
512             return true;
513         }
514         for (int i = this.extraUsagesCount - 1; i >= 0; i--) {
515             if (extraUsages[i] == node) {
516                 movUsageFromEndToExtraUsages(i);
517                 return true;
518             }
519         }
520         return false;
521     }
522 
predecessor()523     public final Node predecessor() {
524         return predecessor;
525     }
526 
modCount()527     public final int modCount() {
528         if (isModificationCountsEnabled() && graph != null) {
529             return graph.modCount(this);
530         }
531         return 0;
532     }
533 
incModCount()534     final void incModCount() {
535         if (isModificationCountsEnabled() && graph != null) {
536             graph.incModCount(this);
537         }
538     }
539 
usageModCount()540     final int usageModCount() {
541         if (isModificationCountsEnabled() && graph != null) {
542             return graph.usageModCount(this);
543         }
544         return 0;
545     }
546 
incUsageModCount()547     final void incUsageModCount() {
548         if (isModificationCountsEnabled() && graph != null) {
549             graph.incUsageModCount(this);
550         }
551     }
552 
isDeleted()553     public final boolean isDeleted() {
554         return id <= DELETED_ID_START;
555     }
556 
isAlive()557     public final boolean isAlive() {
558         return id >= ALIVE_ID_START;
559     }
560 
isUnregistered()561     public final boolean isUnregistered() {
562         return id == INITIAL_ID;
563     }
564 
565     /**
566      * Updates the usages sets of the given nodes after an input slot is changed from
567      * {@code oldInput} to {@code newInput} by removing this node from {@code oldInput}'s usages and
568      * adds this node to {@code newInput}'s usages.
569      */
updateUsages(Node oldInput, Node newInput)570     protected void updateUsages(Node oldInput, Node newInput) {
571         assert isAlive() && (newInput == null || newInput.isAlive()) : "adding " + newInput + " to " + this + " instead of " + oldInput;
572         if (oldInput != newInput) {
573             if (oldInput != null) {
574                 boolean result = removeThisFromUsages(oldInput);
575                 assert assertTrue(result, "not found in usages, old input: %s", oldInput);
576             }
577             maybeNotifyInputChanged(this);
578             if (newInput != null) {
579                 newInput.addUsage(this);
580             }
581             if (oldInput != null && oldInput.hasNoUsages()) {
582                 maybeNotifyZeroUsages(oldInput);
583             }
584         }
585     }
586 
updateUsagesInterface(NodeInterface oldInput, NodeInterface newInput)587     protected void updateUsagesInterface(NodeInterface oldInput, NodeInterface newInput) {
588         updateUsages(oldInput == null ? null : oldInput.asNode(), newInput == null ? null : newInput.asNode());
589     }
590 
591     /**
592      * Updates the predecessor of the given nodes after a successor slot is changed from
593      * oldSuccessor to newSuccessor: removes this node from oldSuccessor's predecessors and adds
594      * this node to newSuccessor's predecessors.
595      */
updatePredecessor(Node oldSuccessor, Node newSuccessor)596     protected void updatePredecessor(Node oldSuccessor, Node newSuccessor) {
597         assert isAlive() && (newSuccessor == null || newSuccessor.isAlive()) || newSuccessor == null && !isAlive() : "adding " + newSuccessor + " to " + this + " instead of " + oldSuccessor;
598         assert graph == null || !graph.isFrozen();
599         if (oldSuccessor != newSuccessor) {
600             if (oldSuccessor != null) {
601                 assert assertTrue(newSuccessor == null || oldSuccessor.predecessor == this, "wrong predecessor in old successor (%s): %s, should be %s", oldSuccessor, oldSuccessor.predecessor, this);
602                 oldSuccessor.predecessor = null;
603             }
604             if (newSuccessor != null) {
605                 assert assertTrue(newSuccessor.predecessor == null, "unexpected non-null predecessor in new successor (%s): %s, this=%s", newSuccessor, newSuccessor.predecessor, this);
606                 newSuccessor.predecessor = this;
607             }
608         }
609     }
610 
initialize(Graph newGraph)611     void initialize(Graph newGraph) {
612         assert assertTrue(id == INITIAL_ID, "unexpected id: %d", id);
613         this.graph = newGraph;
614         newGraph.register(this);
615         NodeClass<? extends Node> nc = nodeClass;
616         nc.registerAtInputsAsUsage(this);
617         nc.registerAtSuccessorsAsPredecessor(this);
618     }
619 
620     /**
621      * Information associated with this node. A single value is stored directly in the field.
622      * Multiple values are stored by creating an Object[].
623      */
624     private Object annotation;
625 
getNodeInfo(Class<T> clazz)626     private <T> T getNodeInfo(Class<T> clazz) {
627         assert clazz != Object[].class;
628         if (annotation == null) {
629             return null;
630         }
631         if (clazz.isInstance(annotation)) {
632             return clazz.cast(annotation);
633         }
634         if (annotation.getClass() == Object[].class) {
635             Object[] annotations = (Object[]) annotation;
636             for (Object ann : annotations) {
637                 if (clazz.isInstance(ann)) {
638                     return clazz.cast(ann);
639                 }
640             }
641         }
642         return null;
643     }
644 
setNodeInfo(Class<T> clazz, T value)645     private <T> void setNodeInfo(Class<T> clazz, T value) {
646         assert clazz != Object[].class;
647         if (annotation == null || clazz.isInstance(annotation)) {
648             // Replace the current value
649             this.annotation = value;
650         } else if (annotation.getClass() == Object[].class) {
651             Object[] annotations = (Object[]) annotation;
652             for (int i = 0; i < annotations.length; i++) {
653                 if (clazz.isInstance(annotations[i])) {
654                     annotations[i] = value;
655                     return;
656                 }
657             }
658             Object[] newAnnotations = Arrays.copyOf(annotations, annotations.length + 1);
659             newAnnotations[annotations.length] = value;
660             this.annotation = newAnnotations;
661         } else {
662             this.annotation = new Object[]{this.annotation, value};
663         }
664     }
665 
666     /**
667      * Gets the source position information for this node or null if it doesn't exist.
668      */
669 
getNodeSourcePosition()670     public NodeSourcePosition getNodeSourcePosition() {
671         return getNodeInfo(NodeSourcePosition.class);
672     }
673 
674     /**
675      * Set the source position to {@code sourcePosition}. Setting it to null is ignored so that it's
676      * not accidentally cleared. Use {@link #clearNodeSourcePosition()} instead.
677      */
setNodeSourcePosition(NodeSourcePosition sourcePosition)678     public void setNodeSourcePosition(NodeSourcePosition sourcePosition) {
679         if (sourcePosition == null) {
680             return;
681         }
682         setNodeInfo(NodeSourcePosition.class, sourcePosition);
683     }
684 
clearNodeSourcePosition()685     public void clearNodeSourcePosition() {
686         setNodeInfo(NodeSourcePosition.class, null);
687     }
688 
getCreationPosition()689     public NodeCreationStackTrace getCreationPosition() {
690         return getNodeInfo(NodeCreationStackTrace.class);
691     }
692 
setCreationPosition(NodeCreationStackTrace trace)693     public void setCreationPosition(NodeCreationStackTrace trace) {
694         setNodeInfo(NodeCreationStackTrace.class, trace);
695     }
696 
getInsertionPosition()697     public NodeInsertionStackTrace getInsertionPosition() {
698         return getNodeInfo(NodeInsertionStackTrace.class);
699     }
700 
setInsertionPosition(NodeInsertionStackTrace trace)701     public void setInsertionPosition(NodeInsertionStackTrace trace) {
702         setNodeInfo(NodeInsertionStackTrace.class, trace);
703     }
704 
705     /**
706      * Update the source position only if it is null.
707      */
updateNodeSourcePosition(Supplier<NodeSourcePosition> sourcePositionSupp)708     public void updateNodeSourcePosition(Supplier<NodeSourcePosition> sourcePositionSupp) {
709         if (this.getNodeSourcePosition() == null) {
710             setNodeSourcePosition(sourcePositionSupp.get());
711         }
712     }
713 
withNodeSourcePosition()714     public DebugCloseable withNodeSourcePosition() {
715         return graph.withNodeSourcePosition(this);
716     }
717 
getNodeClass()718     public final NodeClass<? extends Node> getNodeClass() {
719         return nodeClass;
720     }
721 
isAllowedUsageType(InputType type)722     public boolean isAllowedUsageType(InputType type) {
723         if (type == InputType.Value) {
724             return false;
725         }
726         return getNodeClass().getAllowedUsageTypes().contains(type);
727     }
728 
checkReplaceWith(Node other)729     private boolean checkReplaceWith(Node other) {
730         if (graph != null && graph.isFrozen()) {
731             fail("cannot modify frozen graph");
732         }
733         if (other == this) {
734             fail("cannot replace a node with itself");
735         }
736         if (isDeleted()) {
737             fail("cannot replace deleted node");
738         }
739         if (other != null && other.isDeleted()) {
740             fail("cannot replace with deleted node %s", other);
741         }
742         return true;
743     }
744 
replaceAtUsages(Node other)745     public final void replaceAtUsages(Node other) {
746         replaceAtAllUsages(other, (Node) null);
747     }
748 
replaceAtUsages(Node other, Predicate<Node> filter)749     public final void replaceAtUsages(Node other, Predicate<Node> filter) {
750         replaceAtUsages(other, filter, null);
751     }
752 
replaceAtUsagesAndDelete(Node other)753     public final void replaceAtUsagesAndDelete(Node other) {
754         replaceAtUsages(other, null, this);
755         safeDelete();
756     }
757 
replaceAtUsagesAndDelete(Node other, Predicate<Node> filter)758     public final void replaceAtUsagesAndDelete(Node other, Predicate<Node> filter) {
759         replaceAtUsages(other, filter, this);
760         safeDelete();
761     }
762 
replaceAtUsages(Node other, Predicate<Node> filter, Node toBeDeleted)763     protected void replaceAtUsages(Node other, Predicate<Node> filter, Node toBeDeleted) {
764         if (filter == null) {
765             replaceAtAllUsages(other, toBeDeleted);
766         } else {
767             replaceAtMatchingUsages(other, filter, toBeDeleted);
768         }
769     }
770 
replaceAtAllUsages(Node other, Node toBeDeleted)771     protected void replaceAtAllUsages(Node other, Node toBeDeleted) {
772         checkReplaceWith(other);
773         if (usage0 == null) {
774             return;
775         }
776         replaceAtUsage(other, toBeDeleted, usage0);
777         usage0 = null;
778 
779         if (usage1 == null) {
780             return;
781         }
782         replaceAtUsage(other, toBeDeleted, usage1);
783         usage1 = null;
784 
785         if (extraUsagesCount <= 0) {
786             return;
787         }
788         for (int i = 0; i < extraUsagesCount; i++) {
789             Node usage = extraUsages[i];
790             replaceAtUsage(other, toBeDeleted, usage);
791         }
792         this.extraUsages = NO_NODES;
793         this.extraUsagesCount = 0;
794     }
795 
replaceAtUsage(Node other, Node toBeDeleted, Node usage)796     private void replaceAtUsage(Node other, Node toBeDeleted, Node usage) {
797         boolean result = usage.getNodeClass().replaceFirstInput(usage, this, other);
798         assert assertTrue(result, "not found in inputs, usage: %s", usage);
799         /*
800          * Don't notify for nodes which are about to be deleted.
801          */
802         if (toBeDeleted == null || usage != toBeDeleted) {
803             maybeNotifyInputChanged(usage);
804         }
805         if (other != null) {
806             other.addUsage(usage);
807         }
808     }
809 
replaceAtMatchingUsages(Node other, Predicate<Node> filter, Node toBeDeleted)810     private void replaceAtMatchingUsages(Node other, Predicate<Node> filter, Node toBeDeleted) {
811         if (filter == null) {
812             fail("filter cannot be null");
813         }
814         checkReplaceWith(other);
815         int i = 0;
816         while (i < this.getUsageCount()) {
817             Node usage = this.getUsageAt(i);
818             if (filter.test(usage)) {
819                 replaceAtUsage(other, toBeDeleted, usage);
820                 this.movUsageFromEndTo(i);
821             } else {
822                 ++i;
823             }
824         }
825     }
826 
getUsageAt(int index)827     public Node getUsageAt(int index) {
828         if (index == 0) {
829             return this.usage0;
830         } else if (index == 1) {
831             return this.usage1;
832         } else {
833             return this.extraUsages[index - INLINE_USAGE_COUNT];
834         }
835     }
836 
replaceAtMatchingUsages(Node other, NodePredicate usagePredicate)837     public void replaceAtMatchingUsages(Node other, NodePredicate usagePredicate) {
838         checkReplaceWith(other);
839         replaceAtMatchingUsages(other, usagePredicate, null);
840     }
841 
replaceAtUsages(InputType type, Node other)842     public void replaceAtUsages(InputType type, Node other) {
843         checkReplaceWith(other);
844         for (Node usage : usages().snapshot()) {
845             for (Position pos : usage.inputPositions()) {
846                 if (pos.getInputType() == type && pos.get(usage) == this) {
847                     pos.set(usage, other);
848                 }
849             }
850         }
851     }
852 
maybeNotifyInputChanged(Node node)853     private void maybeNotifyInputChanged(Node node) {
854         if (graph != null) {
855             assert !graph.isFrozen();
856             NodeEventListener listener = graph.nodeEventListener;
857             if (listener != null) {
858                 listener.event(Graph.NodeEvent.INPUT_CHANGED, node);
859             }
860         }
861     }
862 
maybeNotifyZeroUsages(Node node)863     public void maybeNotifyZeroUsages(Node node) {
864         if (graph != null) {
865             assert !graph.isFrozen();
866             NodeEventListener listener = graph.nodeEventListener;
867             if (listener != null && node.isAlive()) {
868                 listener.event(Graph.NodeEvent.ZERO_USAGES, node);
869             }
870         }
871     }
872 
replaceAtPredecessor(Node other)873     public void replaceAtPredecessor(Node other) {
874         checkReplaceWith(other);
875         if (predecessor != null) {
876             if (!predecessor.getNodeClass().replaceFirstSuccessor(predecessor, this, other)) {
877                 fail("not found in successors, predecessor: %s", predecessor);
878             }
879             predecessor.updatePredecessor(this, other);
880         }
881     }
882 
replaceAndDelete(Node other)883     public void replaceAndDelete(Node other) {
884         checkReplaceWith(other);
885         if (other == null) {
886             fail("cannot replace with null");
887         }
888         if (this.hasUsages()) {
889             replaceAtUsages(other);
890         }
891         replaceAtPredecessor(other);
892         this.safeDelete();
893     }
894 
replaceFirstSuccessor(Node oldSuccessor, Node newSuccessor)895     public void replaceFirstSuccessor(Node oldSuccessor, Node newSuccessor) {
896         if (nodeClass.replaceFirstSuccessor(this, oldSuccessor, newSuccessor)) {
897             updatePredecessor(oldSuccessor, newSuccessor);
898         }
899     }
900 
replaceFirstInput(Node oldInput, Node newInput)901     public void replaceFirstInput(Node oldInput, Node newInput) {
902         if (nodeClass.replaceFirstInput(this, oldInput, newInput)) {
903             updateUsages(oldInput, newInput);
904         }
905     }
906 
clearInputs()907     public void clearInputs() {
908         assert assertFalse(isDeleted(), "cannot clear inputs of deleted node");
909         getNodeClass().unregisterAtInputsAsUsage(this);
910     }
911 
removeThisFromUsages(Node n)912     boolean removeThisFromUsages(Node n) {
913         return n.removeUsage(this);
914     }
915 
clearSuccessors()916     public void clearSuccessors() {
917         assert assertFalse(isDeleted(), "cannot clear successors of deleted node");
918         getNodeClass().unregisterAtSuccessorsAsPredecessor(this);
919     }
920 
checkDeletion()921     private boolean checkDeletion() {
922         assertTrue(isAlive(), "must be alive");
923         assertTrue(hasNoUsages(), "cannot delete node %s because of usages: %s", this, usages());
924         assertTrue(predecessor == null, "cannot delete node %s because of predecessor: %s", this, predecessor);
925         return true;
926     }
927 
928     /**
929      * Removes this node from its graph. This node must have no {@linkplain Node#usages() usages}
930      * and no {@linkplain #predecessor() predecessor}.
931      */
safeDelete()932     public void safeDelete() {
933         assert checkDeletion();
934         this.clearInputs();
935         this.clearSuccessors();
936         markDeleted();
937     }
938 
markDeleted()939     public void markDeleted() {
940         graph.unregister(this);
941         id = DELETED_ID_START - id;
942         assert isDeleted();
943     }
944 
copyWithInputs()945     public final Node copyWithInputs() {
946         return copyWithInputs(true);
947     }
948 
copyWithInputs(boolean insertIntoGraph)949     public final Node copyWithInputs(boolean insertIntoGraph) {
950         Node newNode = clone(insertIntoGraph ? graph : null, WithOnlyInputEdges);
951         if (insertIntoGraph) {
952             for (Node input : inputs()) {
953                 input.addUsage(newNode);
954             }
955         }
956         return newNode;
957     }
958 
959     /**
960      * Must be overridden by subclasses that implement {@link Simplifiable}. The implementation in
961      * {@link Node} exists to obviate the need to cast a node before invoking
962      * {@link Simplifiable#simplify(SimplifierTool)}.
963      *
964      * @param tool
965      */
simplify(SimplifierTool tool)966     public void simplify(SimplifierTool tool) {
967         throw new UnsupportedOperationException();
968     }
969 
970     /**
971      * @param newNode the result of cloning this node or {@link Unsafe#allocateInstance(Class) raw
972      *            allocating} a copy of this node
973      * @param type the type of edges to process
974      * @param edgesToCopy if {@code type} is in this set, the edges are copied otherwise they are
975      *            cleared
976      */
copyOrClearEdgesForClone(Node newNode, Edges.Type type, EnumSet<Edges.Type> edgesToCopy)977     private void copyOrClearEdgesForClone(Node newNode, Edges.Type type, EnumSet<Edges.Type> edgesToCopy) {
978         if (edgesToCopy.contains(type)) {
979             getNodeClass().getEdges(type).copy(this, newNode);
980         } else {
981             // The direct edges are already null
982             getNodeClass().getEdges(type).initializeLists(newNode, this);
983         }
984     }
985 
986     public static final EnumSet<Edges.Type> WithNoEdges = EnumSet.noneOf(Edges.Type.class);
987     public static final EnumSet<Edges.Type> WithAllEdges = EnumSet.allOf(Edges.Type.class);
988     public static final EnumSet<Edges.Type> WithOnlyInputEdges = EnumSet.of(Inputs);
989     public static final EnumSet<Edges.Type> WithOnlySucessorEdges = EnumSet.of(Successors);
990 
991     /**
992      * Makes a copy of this node in(to) a given graph.
993      *
994      * @param into the graph in which the copy will be registered (which may be this node's graph)
995      *            or null if the copy should not be registered in a graph
996      * @param edgesToCopy specifies the edges to be copied. The edges not specified in this set are
997      *            initialized to their default value (i.e., {@code null} for a direct edge, an empty
998      *            list for an edge list)
999      * @return the copy of this node
1000      */
clone(Graph into, EnumSet<Edges.Type> edgesToCopy)1001     final Node clone(Graph into, EnumSet<Edges.Type> edgesToCopy) {
1002         final NodeClass<? extends Node> nodeClassTmp = getNodeClass();
1003         boolean useIntoLeafNodeCache = false;
1004         if (into != null) {
1005             if (nodeClassTmp.valueNumberable() && nodeClassTmp.isLeafNode()) {
1006                 useIntoLeafNodeCache = true;
1007                 Node otherNode = into.findNodeInCache(this);
1008                 if (otherNode != null) {
1009                     return otherNode;
1010                 }
1011             }
1012         }
1013 
1014         Node newNode = null;
1015         try {
1016             newNode = (Node) UNSAFE.allocateInstance(getClass());
1017             newNode.nodeClass = nodeClassTmp;
1018             nodeClassTmp.getData().copy(this, newNode);
1019             copyOrClearEdgesForClone(newNode, Inputs, edgesToCopy);
1020             copyOrClearEdgesForClone(newNode, Successors, edgesToCopy);
1021         } catch (Exception e) {
1022             throw new GraalGraphError(e).addContext(this);
1023         }
1024         newNode.graph = into;
1025         newNode.id = INITIAL_ID;
1026         if (getNodeSourcePosition() != null && (into == null || into.trackNodeSourcePosition())) {
1027             newNode.setNodeSourcePosition(getNodeSourcePosition());
1028         }
1029         if (into != null) {
1030             into.register(newNode);
1031         }
1032         newNode.extraUsages = NO_NODES;
1033 
1034         if (into != null && useIntoLeafNodeCache) {
1035             into.putNodeIntoCache(newNode);
1036         }
1037         newNode.afterClone(this);
1038         return newNode;
1039     }
1040 
afterClone(@uppressWarningsR) Node other)1041     protected void afterClone(@SuppressWarnings("unused") Node other) {
1042     }
1043 
verifyInputs()1044     protected boolean verifyInputs() {
1045         for (Position pos : inputPositions()) {
1046             Node input = pos.get(this);
1047             if (input == null) {
1048                 assertTrue(pos.isInputOptional(), "non-optional input %s cannot be null in %s (fix nullness or use @OptionalInput)", pos, this);
1049             } else {
1050                 assertFalse(input.isDeleted(), "input was deleted %s", input);
1051                 assertTrue(input.isAlive(), "input is not alive yet, i.e., it was not yet added to the graph");
1052                 assertTrue(pos.getInputType() == InputType.Unchecked || input.isAllowedUsageType(pos.getInputType()), "invalid usage type %s %s", input, pos.getInputType());
1053             }
1054         }
1055         return true;
1056     }
1057 
verify()1058     public boolean verify() {
1059         assertTrue(isAlive(), "cannot verify inactive nodes (id=%d)", id);
1060         assertTrue(graph() != null, "null graph");
1061         verifyInputs();
1062         if (Options.VerifyGraalGraphEdges.getValue(getOptions())) {
1063             verifyEdges();
1064         }
1065         return true;
1066     }
1067 
verifySourcePosition()1068     public boolean verifySourcePosition() {
1069         return true;
1070     }
1071 
1072     /**
1073      * Perform expensive verification of inputs, usages, predecessors and successors.
1074      *
1075      * @return true
1076      */
verifyEdges()1077     public boolean verifyEdges() {
1078         for (Node input : inputs()) {
1079             assertTrue(input == null || input.usages().contains(this), "missing usage of %s in input %s", this, input);
1080         }
1081 
1082         for (Node successor : successors()) {
1083             assertTrue(successor.predecessor() == this, "missing predecessor in %s (actual: %s)", successor, successor.predecessor());
1084             assertTrue(successor.graph() == graph(), "mismatching graph in successor %s", successor);
1085         }
1086         for (Node usage : usages()) {
1087             assertFalse(usage.isDeleted(), "usage %s must never be deleted", usage);
1088             assertTrue(usage.inputs().contains(this), "missing input in usage %s", usage);
1089             boolean foundThis = false;
1090             for (Position pos : usage.inputPositions()) {
1091                 if (pos.get(usage) == this) {
1092                     foundThis = true;
1093                     if (pos.getInputType() != InputType.Unchecked) {
1094                         assertTrue(isAllowedUsageType(pos.getInputType()), "invalid input of type %s from %s to %s (%s)", pos.getInputType(), usage, this, pos.getName());
1095                     }
1096                 }
1097             }
1098             assertTrue(foundThis, "missing input in usage %s", usage);
1099         }
1100 
1101         if (predecessor != null) {
1102             assertFalse(predecessor.isDeleted(), "predecessor %s must never be deleted", predecessor);
1103             assertTrue(predecessor.successors().contains(this), "missing successor in predecessor %s", predecessor);
1104         }
1105         return true;
1106     }
1107 
assertTrue(boolean condition, String message, Object... args)1108     public boolean assertTrue(boolean condition, String message, Object... args) {
1109         if (condition) {
1110             return true;
1111         } else {
1112             throw fail(message, args);
1113         }
1114     }
1115 
assertFalse(boolean condition, String message, Object... args)1116     public boolean assertFalse(boolean condition, String message, Object... args) {
1117         if (condition) {
1118             throw fail(message, args);
1119         } else {
1120             return true;
1121         }
1122     }
1123 
fail(String message, Object... args)1124     protected VerificationError fail(String message, Object... args) throws GraalGraphError {
1125         throw new VerificationError(message, args).addContext(this);
1126     }
1127 
cfgPredecessors()1128     public Iterable<? extends Node> cfgPredecessors() {
1129         if (predecessor == null) {
1130             return Collections.emptySet();
1131         } else {
1132             return Collections.singleton(predecessor);
1133         }
1134     }
1135 
1136     /**
1137      * Returns an iterator that will provide all control-flow successors of this node. Normally this
1138      * will be the contents of all fields annotated with {@link Successor}, but some node classes
1139      * (like EndNode) may return different nodes.
1140      */
cfgSuccessors()1141     public Iterable<? extends Node> cfgSuccessors() {
1142         return successors();
1143     }
1144 
1145     /**
1146      * Nodes using their {@link #id} as the hash code. This works very well when nodes of the same
1147      * graph are stored in sets. It can give bad behavior when storing nodes of different graphs in
1148      * the same set.
1149      */
1150     @Override
hashCode()1151     public final int hashCode() {
1152         assert !this.isUnregistered() : "node not yet constructed";
1153         if (this.isDeleted()) {
1154             return -id + DELETED_ID_START;
1155         }
1156         return id;
1157     }
1158 
1159     /**
1160      * Do not overwrite the equality test of a node in subclasses. Equality tests must rely solely
1161      * on identity.
1162      */
1163 
1164     /**
1165      * Provides a {@link Map} of properties of this node for use in debugging (e.g., to view in the
1166      * ideal graph visualizer).
1167      */
getDebugProperties()1168     public final Map<Object, Object> getDebugProperties() {
1169         return getDebugProperties(new HashMap<>());
1170     }
1171 
1172     /**
1173      * Fills a {@link Map} with properties of this node for use in debugging (e.g., to view in the
1174      * ideal graph visualizer). Subclasses overriding this method should also fill the map using
1175      * their superclass.
1176      *
1177      * @param map
1178      */
getDebugProperties(Map<Object, Object> map)1179     public Map<Object, Object> getDebugProperties(Map<Object, Object> map) {
1180         Fields properties = getNodeClass().getData();
1181         for (int i = 0; i < properties.getCount(); i++) {
1182             map.put(properties.getName(i), properties.get(this, i));
1183         }
1184         NodeSourcePosition pos = getNodeSourcePosition();
1185         if (pos != null) {
1186             map.put("nodeSourcePosition", pos);
1187         }
1188         NodeCreationStackTrace creation = getCreationPosition();
1189         if (creation != null) {
1190             map.put("nodeCreationPosition", creation.getStrackTraceString());
1191         }
1192         NodeInsertionStackTrace insertion = getInsertionPosition();
1193         if (insertion != null) {
1194             map.put("nodeInsertionPosition", insertion.getStrackTraceString());
1195         }
1196         return map;
1197     }
1198 
1199     /**
1200      * This method is a shortcut for {@link #toString(Verbosity)} with {@link Verbosity#Short}.
1201      */
1202     @Override
toString()1203     public final String toString() {
1204         return toString(Verbosity.Short);
1205     }
1206 
1207     /**
1208      * Creates a String representation for this node with a given {@link Verbosity}.
1209      */
toString(Verbosity verbosity)1210     public String toString(Verbosity verbosity) {
1211         switch (verbosity) {
1212             case Id:
1213                 return Integer.toString(id);
1214             case Name:
1215                 return getNodeClass().shortName();
1216             case Short:
1217                 return toString(Verbosity.Id) + "|" + toString(Verbosity.Name);
1218             case Long:
1219                 return toString(Verbosity.Short);
1220             case Debugger:
1221             case All: {
1222                 StringBuilder str = new StringBuilder();
1223                 str.append(toString(Verbosity.Short)).append(" { ");
1224                 for (Map.Entry<Object, Object> entry : getDebugProperties().entrySet()) {
1225                     str.append(entry.getKey()).append("=").append(entry.getValue()).append(", ");
1226                 }
1227                 str.append(" }");
1228                 return str.toString();
1229             }
1230             default:
1231                 throw new RuntimeException("unknown verbosity: " + verbosity);
1232         }
1233     }
1234 
1235     @Deprecated
getId()1236     public int getId() {
1237         return id;
1238     }
1239 
1240     @Override
formatTo(Formatter formatter, int flags, int width, int precision)1241     public void formatTo(Formatter formatter, int flags, int width, int precision) {
1242         if ((flags & FormattableFlags.ALTERNATE) == FormattableFlags.ALTERNATE) {
1243             formatter.format("%s", toString(Verbosity.Id));
1244         } else if ((flags & FormattableFlags.UPPERCASE) == FormattableFlags.UPPERCASE) {
1245             // Use All here since Long is only slightly longer than Short.
1246             formatter.format("%s", toString(Verbosity.All));
1247         } else {
1248             formatter.format("%s", toString(Verbosity.Short));
1249         }
1250 
1251         boolean neighborsAlternate = ((flags & FormattableFlags.LEFT_JUSTIFY) == FormattableFlags.LEFT_JUSTIFY);
1252         int neighborsFlags = (neighborsAlternate ? FormattableFlags.ALTERNATE | FormattableFlags.LEFT_JUSTIFY : 0);
1253         if (width > 0) {
1254             if (this.predecessor != null) {
1255                 formatter.format(" pred={");
1256                 this.predecessor.formatTo(formatter, neighborsFlags, width - 1, 0);
1257                 formatter.format("}");
1258             }
1259 
1260             for (Position position : this.inputPositions()) {
1261                 Node input = position.get(this);
1262                 if (input != null) {
1263                     formatter.format(" ");
1264                     formatter.format(position.getName());
1265                     formatter.format("={");
1266                     input.formatTo(formatter, neighborsFlags, width - 1, 0);
1267                     formatter.format("}");
1268                 }
1269             }
1270         }
1271 
1272         if (precision > 0) {
1273             if (!hasNoUsages()) {
1274                 formatter.format(" usages={");
1275                 int z = 0;
1276                 for (Node usage : usages()) {
1277                     if (z != 0) {
1278                         formatter.format(", ");
1279                     }
1280                     usage.formatTo(formatter, neighborsFlags, 0, precision - 1);
1281                     ++z;
1282                 }
1283                 formatter.format("}");
1284             }
1285 
1286             for (Position position : this.successorPositions()) {
1287                 Node successor = position.get(this);
1288                 if (successor != null) {
1289                     formatter.format(" ");
1290                     formatter.format(position.getName());
1291                     formatter.format("={");
1292                     successor.formatTo(formatter, neighborsFlags, 0, precision - 1);
1293                     formatter.format("}");
1294                 }
1295             }
1296         }
1297     }
1298 
1299     /**
1300      * Determines if this node's {@link NodeClass#getData() data} fields are equal to the data
1301      * fields of another node of the same type. Primitive fields are compared by value and
1302      * non-primitive fields are compared by {@link Objects#equals(Object, Object)}.
1303      *
1304      * The result of this method undefined if {@code other.getClass() != this.getClass()}.
1305      *
1306      * @param other a node of exactly the same type as this node
1307      * @return true if the data fields of this object and {@code other} are equal
1308      */
valueEquals(Node other)1309     public boolean valueEquals(Node other) {
1310         return getNodeClass().dataEquals(this, other);
1311     }
1312 
1313     /**
1314      * Determines if this node is equal to the other node while ignoring differences in
1315      * {@linkplain Successor control-flow} edges.
1316      *
1317      */
dataFlowEquals(Node other)1318     public boolean dataFlowEquals(Node other) {
1319         return this == other || nodeClass == other.getNodeClass() && this.valueEquals(other) && nodeClass.equalInputs(this, other);
1320     }
1321 
pushInputs(NodeStack stack)1322     public final void pushInputs(NodeStack stack) {
1323         getNodeClass().pushInputs(this, stack);
1324     }
1325 
estimatedNodeSize()1326     public NodeSize estimatedNodeSize() {
1327         return nodeClass.size();
1328     }
1329 
estimatedNodeCycles()1330     public NodeCycles estimatedNodeCycles() {
1331         return nodeClass.cycles();
1332     }
1333 
1334 }
1335