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