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.nodes; 24 25 import java.util.ArrayList; 26 import java.util.Iterator; 27 import java.util.List; 28 import java.util.concurrent.atomic.AtomicLong; 29 import java.util.function.Consumer; 30 31 import org.graalvm.compiler.core.common.CancellationBailoutException; 32 import org.graalvm.compiler.core.common.CompilationIdentifier; 33 import org.graalvm.compiler.core.common.GraalOptions; 34 import org.graalvm.compiler.core.common.cfg.BlockMap; 35 import org.graalvm.compiler.core.common.type.Stamp; 36 import org.graalvm.compiler.debug.DebugContext; 37 import org.graalvm.compiler.debug.JavaMethodContext; 38 import org.graalvm.compiler.graph.Graph; 39 import org.graalvm.compiler.graph.Node; 40 import org.graalvm.compiler.graph.NodeMap; 41 import org.graalvm.compiler.nodes.calc.FloatingNode; 42 import org.graalvm.compiler.nodes.cfg.Block; 43 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph; 44 import org.graalvm.compiler.nodes.java.MethodCallTargetNode; 45 import org.graalvm.compiler.nodes.spi.VirtualizableAllocation; 46 import org.graalvm.compiler.nodes.util.GraphUtil; 47 import org.graalvm.compiler.options.OptionValues; 48 import org.graalvm.util.EconomicMap; 49 import org.graalvm.util.EconomicSet; 50 import org.graalvm.util.Equivalence; 51 import org.graalvm.util.UnmodifiableEconomicMap; 52 53 import jdk.vm.ci.meta.Assumptions; 54 import jdk.vm.ci.meta.Assumptions.Assumption; 55 import jdk.vm.ci.meta.DefaultProfilingInfo; 56 import jdk.vm.ci.meta.JavaMethod; 57 import jdk.vm.ci.meta.ProfilingInfo; 58 import jdk.vm.ci.meta.ResolvedJavaField; 59 import jdk.vm.ci.meta.ResolvedJavaMethod; 60 import jdk.vm.ci.meta.SpeculationLog; 61 import jdk.vm.ci.meta.TriState; 62 import jdk.vm.ci.runtime.JVMCICompiler; 63 64 /** 65 * A graph that contains at least one distinguished node : the {@link #start() start} node. This 66 * node is the start of the control flow of the graph. 67 */ 68 public final class StructuredGraph extends Graph implements JavaMethodContext { 69 70 /** 71 * The different stages of the compilation of a {@link Graph} regarding the status of 72 * {@link GuardNode guards}, {@link DeoptimizingNode deoptimizations} and {@link FrameState 73 * framestates}. The stage of a graph progresses monotonously. 74 * 75 */ 76 public enum GuardsStage { 77 /** 78 * During this stage, there can be {@link FloatingNode floating} {@link DeoptimizingNode} 79 * such as {@link GuardNode GuardNodes}. New {@link DeoptimizingNode DeoptimizingNodes} can 80 * be introduced without constraints. {@link FrameState} nodes are associated with 81 * {@link StateSplit} nodes. 82 */ 83 FLOATING_GUARDS, 84 /** 85 * During this stage, all {@link DeoptimizingNode DeoptimizingNodes} must be 86 * {@link FixedNode fixed} but new {@link DeoptimizingNode DeoptimizingNodes} can still be 87 * introduced. {@link FrameState} nodes are still associated with {@link StateSplit} nodes. 88 */ 89 FIXED_DEOPTS, 90 /** 91 * During this stage, all {@link DeoptimizingNode DeoptimizingNodes} must be 92 * {@link FixedNode fixed}. New {@link DeoptimizingNode DeoptimizingNodes} can not be 93 * introduced any more. {@link FrameState} nodes are now associated with 94 * {@link DeoptimizingNode} nodes. 95 */ 96 AFTER_FSA; 97 98 public boolean allowsFloatingGuards() { 99 return this == FLOATING_GUARDS; 100 } 101 102 public boolean areFrameStatesAtDeopts() { 103 return this == AFTER_FSA; 104 } 105 106 public boolean areFrameStatesAtSideEffects() { 107 return !this.areFrameStatesAtDeopts(); 108 } 109 110 public boolean areDeoptsFixed() { 111 return this.ordinal() >= FIXED_DEOPTS.ordinal(); 112 } 113 } 114 115 /** 116 * Constants denoting whether or not {@link Assumption}s can be made while processing a graph. 117 */ 118 public enum AllowAssumptions { 119 YES, 120 NO; 121 public static AllowAssumptions ifTrue(boolean flag) { 122 return flag ? YES : NO; 123 } 124 125 public static AllowAssumptions ifNonNull(Assumptions assumptions) { 126 return assumptions != null ? YES : NO; 127 } 128 } 129 130 public static class ScheduleResult { 131 private final ControlFlowGraph cfg; 132 private final NodeMap<Block> nodeToBlockMap; 133 private final BlockMap<List<Node>> blockToNodesMap; 134 135 public ScheduleResult(ControlFlowGraph cfg, NodeMap<Block> nodeToBlockMap, BlockMap<List<Node>> blockToNodesMap) { 136 this.cfg = cfg; 137 this.nodeToBlockMap = nodeToBlockMap; 138 this.blockToNodesMap = blockToNodesMap; 139 } 140 141 public ControlFlowGraph getCFG() { 142 return cfg; 143 } 144 145 public NodeMap<Block> getNodeToBlockMap() { 146 return nodeToBlockMap; 147 } 148 149 public BlockMap<List<Node>> getBlockToNodesMap() { 150 return blockToNodesMap; 151 } 152 153 public List<Node> nodesFor(Block block) { 154 return blockToNodesMap.get(block); 155 } 156 } 157 158 /** 159 * Object used to create a {@link StructuredGraph}. 160 */ 161 public static class Builder { 162 private String name; 163 private final Assumptions assumptions; 164 private SpeculationLog speculationLog; 165 private ResolvedJavaMethod rootMethod; 166 private CompilationIdentifier compilationId = CompilationIdentifier.INVALID_COMPILATION_ID; 167 private int entryBCI = JVMCICompiler.INVOCATION_ENTRY_BCI; 168 private boolean useProfilingInfo = true; 169 private final OptionValues options; 170 private Cancellable cancellable = null; 171 private final DebugContext debug; 172 173 /** 174 * Creates a builder for a graph. 175 */ 176 public Builder(OptionValues options, DebugContext debug, AllowAssumptions allowAssumptions) { 177 this.options = options; 178 this.debug = debug; 179 this.assumptions = allowAssumptions == AllowAssumptions.YES ? new Assumptions() : null; 180 } 181 182 /** 183 * Creates a builder for a graph that does not support {@link Assumptions}. 184 */ 185 public Builder(OptionValues options, DebugContext debug) { 186 this.options = options; 187 this.debug = debug; 188 assumptions = null; 189 } 190 191 public String getName() { 192 return name; 193 } 194 195 public Builder name(String s) { 196 this.name = s; 197 return this; 198 } 199 200 public ResolvedJavaMethod getMethod() { 201 return rootMethod; 202 } 203 204 public Builder method(ResolvedJavaMethod method) { 205 this.rootMethod = method; 206 return this; 207 } 208 209 public DebugContext getDebug() { 210 return debug; 211 } 212 213 public SpeculationLog getSpeculationLog() { 214 return speculationLog; 215 } 216 217 public Builder speculationLog(SpeculationLog log) { 218 this.speculationLog = log; 219 return this; 220 } 221 222 public CompilationIdentifier getCompilationId() { 223 return compilationId; 224 } 225 226 public Builder compilationId(CompilationIdentifier id) { 227 this.compilationId = id; 228 return this; 229 } 230 231 public Cancellable getCancellable() { 232 return cancellable; 233 } 234 235 public Builder cancellable(Cancellable cancel) { 236 this.cancellable = cancel; 237 return this; 238 } 239 240 public int getEntryBCI() { 241 return entryBCI; 242 } 243 244 public Builder entryBCI(int bci) { 245 this.entryBCI = bci; 246 return this; 247 } 248 249 public boolean getUseProfilingInfo() { 250 return useProfilingInfo; 251 } 252 253 public Builder useProfilingInfo(boolean flag) { 254 this.useProfilingInfo = flag; 255 return this; 256 } 257 258 public StructuredGraph build() { 259 return new StructuredGraph(name, rootMethod, entryBCI, assumptions, speculationLog, useProfilingInfo, compilationId, options, debug, cancellable); 260 } 261 } 262 263 public static final long INVALID_GRAPH_ID = -1; 264 private static final AtomicLong uniqueGraphIds = new AtomicLong(); 265 266 private StartNode start; 267 private ResolvedJavaMethod rootMethod; 268 private final long graphId; 269 private final CompilationIdentifier compilationId; 270 private final int entryBCI; 271 private GuardsStage guardsStage = GuardsStage.FLOATING_GUARDS; 272 private boolean isAfterFloatingReadPhase = false; 273 private boolean isAfterFixedReadPhase = false; 274 private boolean hasValueProxies = true; 275 private boolean isAfterExpandLogic = false; 276 private final boolean useProfilingInfo; 277 private final Cancellable cancellable; 278 /** 279 * The assumptions made while constructing and transforming this graph. 280 */ 281 private final Assumptions assumptions; 282 283 private SpeculationLog speculationLog; 284 285 private ScheduleResult lastSchedule; 286 287 /** 288 * Records the methods that were used while constructing this graph, one entry for each time a 289 * specific method is used. 290 */ 291 private final List<ResolvedJavaMethod> methods = new ArrayList<>(); 292 293 /** 294 * Records the fields that were accessed while constructing this graph. 295 */ 296 297 private EconomicSet<ResolvedJavaField> fields = null; 298 299 private enum UnsafeAccessState { 300 NO_ACCESS, 301 HAS_ACCESS, 302 DISABLED 303 } 304 305 private UnsafeAccessState hasUnsafeAccess = UnsafeAccessState.NO_ACCESS; 306 307 public static final boolean USE_PROFILING_INFO = true; 308 309 public static final boolean NO_PROFILING_INFO = false; 310 311 private StructuredGraph(String name, 312 ResolvedJavaMethod method, 313 int entryBCI, 314 Assumptions assumptions, 315 SpeculationLog speculationLog, 316 boolean useProfilingInfo, 317 CompilationIdentifier compilationId, 318 OptionValues options, 319 DebugContext debug, 320 Cancellable cancellable) { 321 super(name, options, debug); 322 this.setStart(add(new StartNode())); 323 this.rootMethod = method; 324 this.graphId = uniqueGraphIds.incrementAndGet(); 325 this.compilationId = compilationId; 326 this.entryBCI = entryBCI; 327 this.assumptions = assumptions; 328 this.speculationLog = speculationLog; 329 this.useProfilingInfo = useProfilingInfo; 330 this.cancellable = cancellable; 331 } 332 333 public void setLastSchedule(ScheduleResult result) { 334 lastSchedule = result; 335 } 336 337 public ScheduleResult getLastSchedule() { 338 return lastSchedule; 339 } 340 341 public void clearLastSchedule() { 342 setLastSchedule(null); 343 } 344 345 @Override 346 public boolean maybeCompress() { 347 if (super.maybeCompress()) { 348 /* 349 * The schedule contains a NodeMap which is unusable after compression. 350 */ 351 clearLastSchedule(); 352 return true; 353 } 354 return false; 355 } 356 357 public Stamp getReturnStamp() { 358 Stamp returnStamp = null; 359 for (ReturnNode returnNode : getNodes(ReturnNode.TYPE)) { 360 ValueNode result = returnNode.result(); 361 if (result != null) { 362 if (returnStamp == null) { 363 returnStamp = result.stamp(); 364 } else { 365 returnStamp = returnStamp.meet(result.stamp()); 366 } 367 } 368 } 369 return returnStamp; 370 } 371 372 @Override 373 public String toString() { 374 StringBuilder buf = new StringBuilder(getClass().getSimpleName() + ":" + graphId); 375 String sep = "{"; 376 if (name != null) { 377 buf.append(sep); 378 buf.append(name); 379 sep = ", "; 380 } 381 if (method() != null) { 382 buf.append(sep); 383 buf.append(method()); 384 sep = ", "; 385 } 386 387 if (!sep.equals("{")) { 388 buf.append("}"); 389 } 390 return buf.toString(); 391 } 392 393 public StartNode start() { 394 return start; 395 } 396 397 /** 398 * Gets the root method from which this graph was built. 399 * 400 * @return null if this method was not built from a method or the method is not available 401 */ 402 public ResolvedJavaMethod method() { 403 return rootMethod; 404 } 405 406 public int getEntryBCI() { 407 return entryBCI; 408 } 409 410 public Cancellable getCancellable() { 411 return cancellable; 412 } 413 414 public void checkCancellation() { 415 if (cancellable != null && cancellable.isCancelled()) { 416 CancellationBailoutException.cancelCompilation(); 417 } 418 } 419 420 public boolean isOSR() { 421 return entryBCI != JVMCICompiler.INVOCATION_ENTRY_BCI; 422 } 423 424 public long graphId() { 425 return graphId; 426 } 427 428 /** 429 * @see CompilationIdentifier 430 */ 431 public CompilationIdentifier compilationId() { 432 return compilationId; 433 } 434 435 public void setStart(StartNode start) { 436 this.start = start; 437 } 438 439 /** 440 * Creates a copy of this graph. 441 * 442 * @param newName the name of the copy, used for debugging purposes (can be null) 443 * @param duplicationMapCallback consumer of the duplication map created during the copying 444 * @param debugForCopy the debug context for the graph copy. This must not be the debug for this 445 * graph if this graph can be accessed from multiple threads (e.g., it's in a cache 446 * accessed by multiple threads). 447 */ 448 @Override 449 protected Graph copy(String newName, Consumer<UnmodifiableEconomicMap<Node, Node>> duplicationMapCallback, DebugContext debugForCopy) { 450 return copy(newName, duplicationMapCallback, compilationId, debugForCopy); 451 } 452 453 private StructuredGraph copy(String newName, Consumer<UnmodifiableEconomicMap<Node, Node>> duplicationMapCallback, CompilationIdentifier newCompilationId, DebugContext debugForCopy) { 454 AllowAssumptions allowAssumptions = AllowAssumptions.ifNonNull(assumptions); 455 StructuredGraph copy = new StructuredGraph(newName, 456 method(), 457 entryBCI, 458 assumptions == null ? null : new Assumptions(), 459 speculationLog, 460 useProfilingInfo, 461 newCompilationId, 462 getOptions(), debugForCopy, null); 463 if (allowAssumptions == AllowAssumptions.YES && assumptions != null) { 464 copy.assumptions.record(assumptions); 465 } 466 copy.hasUnsafeAccess = hasUnsafeAccess; 467 copy.setGuardsStage(getGuardsStage()); 468 copy.isAfterFloatingReadPhase = isAfterFloatingReadPhase; 469 copy.hasValueProxies = hasValueProxies; 470 copy.isAfterExpandLogic = isAfterExpandLogic; 471 EconomicMap<Node, Node> replacements = EconomicMap.create(Equivalence.IDENTITY); 472 replacements.put(start, copy.start); 473 UnmodifiableEconomicMap<Node, Node> duplicates = copy.addDuplicates(getNodes(), this, this.getNodeCount(), replacements); 474 if (duplicationMapCallback != null) { 475 duplicationMapCallback.accept(duplicates); 476 } 477 return copy; 478 } 479 480 /** 481 * @param debugForCopy the debug context for the graph copy. This must not be the debug for this 482 * graph if this graph can be accessed from multiple threads (e.g., it's in a cache 483 * accessed by multiple threads). 484 */ 485 public StructuredGraph copyWithIdentifier(CompilationIdentifier newCompilationId, DebugContext debugForCopy) { 486 return copy(name, null, newCompilationId, debugForCopy); 487 } 488 489 public ParameterNode getParameter(int index) { 490 for (ParameterNode param : getNodes(ParameterNode.TYPE)) { 491 if (param.index() == index) { 492 return param; 493 } 494 } 495 return null; 496 } 497 498 public Iterable<Invoke> getInvokes() { 499 final Iterator<MethodCallTargetNode> callTargets = getNodes(MethodCallTargetNode.TYPE).iterator(); 500 return new Iterable<Invoke>() { 501 502 private Invoke next; 503 504 @Override 505 public Iterator<Invoke> iterator() { 506 return new Iterator<Invoke>() { 507 508 @Override 509 public boolean hasNext() { 510 if (next == null) { 511 while (callTargets.hasNext()) { 512 Invoke i = callTargets.next().invoke(); 513 if (i != null) { 514 next = i; 515 return true; 516 } 517 } 518 return false; 519 } else { 520 return true; 521 } 522 } 523 524 @Override 525 public Invoke next() { 526 try { 527 return next; 528 } finally { 529 next = null; 530 } 531 } 532 533 @Override 534 public void remove() { 535 throw new UnsupportedOperationException(); 536 } 537 }; 538 } 539 }; 540 } 541 542 public boolean hasLoops() { 543 return hasNode(LoopBeginNode.TYPE); 544 } 545 546 /** 547 * Unlinks a node from all its control flow neighbors and then removes it from its graph. The 548 * node must have no {@linkplain Node#usages() usages}. 549 * 550 * @param node the node to be unlinked and removed 551 */ 552 @SuppressWarnings("static-method") 553 public void removeFixed(FixedWithNextNode node) { 554 assert node != null; 555 if (node instanceof AbstractBeginNode) { 556 ((AbstractBeginNode) node).prepareDelete(); 557 } 558 assert node.hasNoUsages() : node + " " + node.usages().count() + ", " + node.usages().first(); 559 GraphUtil.unlinkFixedNode(node); 560 node.safeDelete(); 561 } 562 563 public void replaceFixed(FixedWithNextNode node, Node replacement) { 564 if (replacement instanceof FixedWithNextNode) { 565 replaceFixedWithFixed(node, (FixedWithNextNode) replacement); 566 } else { 567 assert replacement != null : "cannot replace " + node + " with null"; 568 assert replacement instanceof FloatingNode : "cannot replace " + node + " with " + replacement; 569 replaceFixedWithFloating(node, (FloatingNode) replacement); 570 } 571 } 572 573 public void replaceFixedWithFixed(FixedWithNextNode node, FixedWithNextNode replacement) { 574 assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement; 575 FixedNode next = node.next(); 576 node.setNext(null); 577 replacement.setNext(next); 578 node.replaceAndDelete(replacement); 579 if (node == start) { 580 setStart((StartNode) replacement); 581 } 582 } 583 584 @SuppressWarnings("static-method") 585 public void replaceFixedWithFloating(FixedWithNextNode node, ValueNode replacement) { 586 assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement; 587 GraphUtil.unlinkFixedNode(node); 588 node.replaceAtUsagesAndDelete(replacement); 589 } 590 591 @SuppressWarnings("static-method") 592 public void removeSplit(ControlSplitNode node, AbstractBeginNode survivingSuccessor) { 593 assert node != null; 594 assert node.hasNoUsages(); 595 assert survivingSuccessor != null; 596 node.clearSuccessors(); 597 node.replaceAtPredecessor(survivingSuccessor); 598 node.safeDelete(); 599 } 600 601 @SuppressWarnings("static-method") 602 public void removeSplitPropagate(ControlSplitNode node, AbstractBeginNode survivingSuccessor) { 603 assert node != null; 604 assert node.hasNoUsages(); 605 assert survivingSuccessor != null; 606 List<Node> snapshot = node.successors().snapshot(); 607 node.clearSuccessors(); 608 node.replaceAtPredecessor(survivingSuccessor); 609 node.safeDelete(); 610 for (Node successor : snapshot) { 611 if (successor != null && successor.isAlive()) { 612 if (successor != survivingSuccessor) { 613 GraphUtil.killCFG((FixedNode) successor); 614 } 615 } 616 } 617 } 618 619 public void replaceSplit(ControlSplitNode node, Node replacement, AbstractBeginNode survivingSuccessor) { 620 if (replacement instanceof FixedWithNextNode) { 621 replaceSplitWithFixed(node, (FixedWithNextNode) replacement, survivingSuccessor); 622 } else { 623 assert replacement != null : "cannot replace " + node + " with null"; 624 assert replacement instanceof FloatingNode : "cannot replace " + node + " with " + replacement; 625 replaceSplitWithFloating(node, (FloatingNode) replacement, survivingSuccessor); 626 } 627 } 628 629 @SuppressWarnings("static-method") 630 public void replaceSplitWithFixed(ControlSplitNode node, FixedWithNextNode replacement, AbstractBeginNode survivingSuccessor) { 631 assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement; 632 assert survivingSuccessor != null; 633 node.clearSuccessors(); 634 replacement.setNext(survivingSuccessor); 635 node.replaceAndDelete(replacement); 636 } 637 638 @SuppressWarnings("static-method") 639 public void replaceSplitWithFloating(ControlSplitNode node, FloatingNode replacement, AbstractBeginNode survivingSuccessor) { 640 assert node != null && replacement != null && node.isAlive() && replacement.isAlive() : "cannot replace " + node + " with " + replacement; 641 assert survivingSuccessor != null; 642 node.clearSuccessors(); 643 node.replaceAtPredecessor(survivingSuccessor); 644 node.replaceAtUsagesAndDelete(replacement); 645 } 646 647 @SuppressWarnings("static-method") 648 public void addAfterFixed(FixedWithNextNode node, FixedNode newNode) { 649 assert node != null && newNode != null && node.isAlive() && newNode.isAlive() : "cannot add " + newNode + " after " + node; 650 FixedNode next = node.next(); 651 node.setNext(newNode); 652 if (next != null) { 653 assert newNode instanceof FixedWithNextNode; 654 FixedWithNextNode newFixedWithNext = (FixedWithNextNode) newNode; 655 assert newFixedWithNext.next() == null; 656 newFixedWithNext.setNext(next); 657 } 658 } 659 660 @SuppressWarnings("static-method") 661 public void addBeforeFixed(FixedNode node, FixedWithNextNode newNode) { 662 assert node != null && newNode != null && node.isAlive() && newNode.isAlive() : "cannot add " + newNode + " before " + node; 663 assert node.predecessor() != null && node.predecessor() instanceof FixedWithNextNode : "cannot add " + newNode + " before " + node; 664 assert newNode.next() == null : newNode; 665 assert !(node instanceof AbstractMergeNode); 666 FixedWithNextNode pred = (FixedWithNextNode) node.predecessor(); 667 pred.setNext(newNode); 668 newNode.setNext(node); 669 } 670 671 public void reduceDegenerateLoopBegin(LoopBeginNode begin) { 672 assert begin.loopEnds().isEmpty() : "Loop begin still has backedges"; 673 if (begin.forwardEndCount() == 1) { // bypass merge and remove 674 reduceTrivialMerge(begin); 675 } else { // convert to merge 676 AbstractMergeNode merge = this.add(new MergeNode()); 677 for (EndNode end : begin.forwardEnds()) { 678 merge.addForwardEnd(end); 679 } 680 this.replaceFixedWithFixed(begin, merge); 681 } 682 } 683 684 @SuppressWarnings("static-method") 685 public void reduceTrivialMerge(AbstractMergeNode merge) { 686 assert merge.forwardEndCount() == 1; 687 assert !(merge instanceof LoopBeginNode) || ((LoopBeginNode) merge).loopEnds().isEmpty(); 688 for (PhiNode phi : merge.phis().snapshot()) { 689 assert phi.valueCount() == 1; 690 ValueNode singleValue = phi.valueAt(0); 691 if (phi.hasUsages()) { 692 phi.replaceAtUsagesAndDelete(singleValue); 693 } else { 694 phi.safeDelete(); 695 if (singleValue != null) { 696 GraphUtil.tryKillUnused(singleValue); 697 } 698 } 699 } 700 // remove loop exits 701 if (merge instanceof LoopBeginNode) { 702 ((LoopBeginNode) merge).removeExits(); 703 } 704 AbstractEndNode singleEnd = merge.forwardEndAt(0); 705 FixedNode sux = merge.next(); 706 FrameState stateAfter = merge.stateAfter(); 707 // evacuateGuards 708 merge.prepareDelete((FixedNode) singleEnd.predecessor()); 709 merge.safeDelete(); 710 if (stateAfter != null) { 711 GraphUtil.tryKillUnused(stateAfter); 712 } 713 if (sux == null) { 714 singleEnd.replaceAtPredecessor(null); 715 singleEnd.safeDelete(); 716 } else { 717 singleEnd.replaceAndDelete(sux); 718 } 719 } 720 721 public GuardsStage getGuardsStage() { 722 return guardsStage; 723 } 724 725 public void setGuardsStage(GuardsStage guardsStage) { 726 assert guardsStage.ordinal() >= this.guardsStage.ordinal(); 727 this.guardsStage = guardsStage; 728 } 729 730 public boolean isAfterFloatingReadPhase() { 731 return isAfterFloatingReadPhase; 732 } 733 734 public boolean isAfterFixedReadPhase() { 735 return isAfterFixedReadPhase; 736 } 737 738 public void setAfterFloatingReadPhase(boolean state) { 739 assert state : "cannot 'unapply' floating read phase on graph"; 740 isAfterFloatingReadPhase = state; 741 } 742 743 public void setAfterFixReadPhase(boolean state) { 744 assert state : "cannot 'unapply' fix reads phase on graph"; 745 isAfterFixedReadPhase = state; 746 } 747 748 public boolean hasValueProxies() { 749 return hasValueProxies; 750 } 751 752 public void setHasValueProxies(boolean state) { 753 assert !state : "cannot 'unapply' value proxy removal on graph"; 754 hasValueProxies = state; 755 } 756 757 public boolean isAfterExpandLogic() { 758 return isAfterExpandLogic; 759 } 760 761 public void setAfterExpandLogic() { 762 isAfterExpandLogic = true; 763 } 764 765 /** 766 * Determines if {@link ProfilingInfo} is used during construction of this graph. 767 */ 768 public boolean useProfilingInfo() { 769 return useProfilingInfo; 770 } 771 772 /** 773 * Gets the profiling info for the {@linkplain #method() root method} of this graph. 774 */ 775 public ProfilingInfo getProfilingInfo() { 776 return getProfilingInfo(method()); 777 } 778 779 /** 780 * Gets the profiling info for a given method that is or will be part of this graph, taking into 781 * account {@link #useProfilingInfo()}. 782 */ 783 public ProfilingInfo getProfilingInfo(ResolvedJavaMethod m) { 784 if (useProfilingInfo && m != null) { 785 return m.getProfilingInfo(); 786 } else { 787 return DefaultProfilingInfo.get(TriState.UNKNOWN); 788 } 789 } 790 791 /** 792 * Gets the object for recording assumptions while constructing of this graph. 793 * 794 * @return {@code null} if assumptions cannot be made for this graph 795 */ 796 public Assumptions getAssumptions() { 797 return assumptions; 798 } 799 800 /** 801 * Gets the methods that were inlined while constructing this graph. 802 */ 803 public List<ResolvedJavaMethod> getMethods() { 804 return methods; 805 } 806 807 /** 808 * Records that {@code method} was used to build this graph. 809 */ 810 public void recordMethod(ResolvedJavaMethod method) { 811 methods.add(method); 812 } 813 814 /** 815 * Updates the {@linkplain #getMethods() methods} used to build this graph with the methods used 816 * to build another graph. 817 */ 818 public void updateMethods(StructuredGraph other) { 819 assert this != other; 820 this.methods.addAll(other.methods); 821 } 822 823 /** 824 * Gets the fields that were accessed while constructing this graph. 825 */ 826 public EconomicSet<ResolvedJavaField> getFields() { 827 return fields; 828 } 829 830 /** 831 * Records that {@code field} was accessed in this graph. 832 */ 833 public void recordField(ResolvedJavaField field) { 834 assert GraalOptions.GeneratePIC.getValue(getOptions()); 835 if (this.fields == null) { 836 this.fields = EconomicSet.create(Equivalence.IDENTITY); 837 } 838 fields.add(field); 839 } 840 841 /** 842 * Updates the {@linkplain #getFields() fields} of this graph with the accessed fields of 843 * another graph. 844 */ 845 public void updateFields(StructuredGraph other) { 846 assert this != other; 847 assert GraalOptions.GeneratePIC.getValue(getOptions()); 848 if (other.fields != null) { 849 if (this.fields == null) { 850 this.fields = EconomicSet.create(Equivalence.IDENTITY); 851 } 852 this.fields.addAll(other.fields); 853 } 854 } 855 856 /** 857 * Gets the input bytecode {@linkplain ResolvedJavaMethod#getCodeSize() size} from which this 858 * graph is constructed. This ignores how many bytecodes in each constituent method are actually 859 * parsed (which may be none for methods whose IR is retrieved from a cache or less than the 860 * full amount for any given method due to profile guided branch pruning). 861 */ 862 public int getBytecodeSize() { 863 int res = 0; 864 for (ResolvedJavaMethod e : methods) { 865 res += e.getCodeSize(); 866 } 867 return res; 868 } 869 870 /** 871 * 872 * @return true if the graph contains only a {@link StartNode} and {@link ReturnNode} 873 */ 874 public boolean isTrivial() { 875 return !(start.next() instanceof ReturnNode); 876 } 877 878 @Override 879 public JavaMethod asJavaMethod() { 880 return method(); 881 } 882 883 public boolean hasUnsafeAccess() { 884 return hasUnsafeAccess == UnsafeAccessState.HAS_ACCESS; 885 } 886 887 public void markUnsafeAccess() { 888 if (hasUnsafeAccess == UnsafeAccessState.DISABLED) { 889 return; 890 } 891 hasUnsafeAccess = UnsafeAccessState.HAS_ACCESS; 892 } 893 894 public void disableUnsafeAccessTracking() { 895 hasUnsafeAccess = UnsafeAccessState.DISABLED; 896 } 897 898 public boolean isUnsafeAccessTrackingEnabled() { 899 return hasUnsafeAccess != UnsafeAccessState.DISABLED; 900 } 901 902 public SpeculationLog getSpeculationLog() { 903 return speculationLog; 904 } 905 906 public void clearAllStateAfter() { 907 for (Node node : getNodes()) { 908 if (node instanceof StateSplit) { 909 FrameState stateAfter = ((StateSplit) node).stateAfter(); 910 if (stateAfter != null) { 911 ((StateSplit) node).setStateAfter(null); 912 // 2 nodes referencing the same framestate 913 if (stateAfter.isAlive()) { 914 GraphUtil.killWithUnusedFloatingInputs(stateAfter); 915 } 916 } 917 } 918 } 919 } 920 921 public boolean hasVirtualizableAllocation() { 922 for (Node n : getNodes()) { 923 if (n instanceof VirtualizableAllocation) { 924 return true; 925 } 926 } 927 return false; 928 } 929 930 @Override 931 protected void afterRegister(Node node) { 932 assert hasValueProxies() || !(node instanceof ValueProxyNode); 933 } 934 }