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