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