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