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(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 this.replaceFixedWithFixed(begin, merge); 570 } 571 } 572 573 public void reduceTrivialMerge(AbstractMergeNode merge) { 574 assert merge.forwardEndCount() == 1; 575 assert !(merge instanceof LoopBeginNode) || ((LoopBeginNode) merge).loopEnds().isEmpty(); 576 for (PhiNode phi : merge.phis().snapshot()) { 577 assert phi.valueCount() == 1; 578 ValueNode singleValue = phi.valueAt(0); 579 phi.replaceAtUsagesAndDelete(singleValue); 580 } 581 // remove loop exits 582 if (merge instanceof LoopBeginNode) { 583 ((LoopBeginNode) merge).removeExits(); 584 } 585 AbstractEndNode singleEnd = merge.forwardEndAt(0); 586 FixedNode sux = merge.next(); 587 FrameState stateAfter = merge.stateAfter(); 588 // evacuateGuards 589 merge.prepareDelete((FixedNode) singleEnd.predecessor()); 590 merge.safeDelete(); 591 if (stateAfter != null && stateAfter.isAlive() && stateAfter.hasNoUsages()) { 592 GraphUtil.killWithUnusedFloatingInputs(stateAfter); 593 } 594 if (sux == null) { 595 singleEnd.replaceAtPredecessor(null); 596 singleEnd.safeDelete(); 597 } else { 598 singleEnd.replaceAndDelete(sux); 599 } 600 } 601 602 public GuardsStage getGuardsStage() { 603 return guardsStage; 604 } 605 606 public void setGuardsStage(GuardsStage guardsStage) { 607 assert guardsStage.ordinal() >= this.guardsStage.ordinal(); 608 this.guardsStage = guardsStage; 609 } 610 611 public boolean isAfterFloatingReadPhase() { 612 return isAfterFloatingReadPhase; 613 } 614 615 public void setAfterFloatingReadPhase(boolean state) { 616 assert state : "cannot 'unapply' floating read phase on graph"; 617 isAfterFloatingReadPhase = state; 618 } 619 620 public boolean hasValueProxies() { 621 return hasValueProxies; 622 } 623 624 public void setHasValueProxies(boolean state) { 625 assert !state : "cannot 'unapply' value proxy removal on graph"; 626 hasValueProxies = state; 627 } 628 629 /** 630 * Determines if {@link ProfilingInfo} is used during construction of this graph. 631 */ 632 public boolean useProfilingInfo() { 633 return useProfilingInfo; 634 } 635 636 /** 637 * Gets the profiling info for the {@linkplain #method() root method} of this graph. 638 */ 639 public ProfilingInfo getProfilingInfo() { 640 return getProfilingInfo(method()); 641 } 642 643 /** 644 * Gets the profiling info for a given method that is or will be part of this graph, taking into 645 * account {@link #useProfilingInfo()}. 646 */ 647 public ProfilingInfo getProfilingInfo(ResolvedJavaMethod m) { 648 if (useProfilingInfo && m != null) { 649 return m.getProfilingInfo(); 650 } else { 651 return DefaultProfilingInfo.get(TriState.UNKNOWN); 652 } 653 } 654 655 /** 656 * Gets the object for recording assumptions while constructing of this graph. 657 * 658 * @return {@code null} if assumptions cannot be made for this graph 659 */ 660 public Assumptions getAssumptions() { 661 return assumptions; 662 } 663 664 /** 665 * Gets the methods that were inlined while constructing this graph. 666 */ 667 public List<ResolvedJavaMethod> getMethods() { 668 return methods; 669 } 670 671 /** 672 * Records that {@code method} was used to build this graph. 673 */ 674 public void recordMethod(ResolvedJavaMethod method) { 675 methods.add(method); 676 } 677 678 /** 679 * Updates the {@linkplain #getMethods() methods} used to build this graph with the methods used 680 * to build another graph. 681 */ 682 public void updateMethods(StructuredGraph other) { 683 assert this != other; 684 this.methods.addAll(other.methods); 685 } 686 687 /** 688 * Gets the fields that were accessed while constructing this graph. 689 */ 690 public Set<ResolvedJavaField> getFields() { 691 return fields; 692 } 693 694 /** 695 * Records that {@code field} was accessed in this graph. 696 */ 697 public void recordField(ResolvedJavaField field) { 698 fields.add(field); 699 } 700 701 /** 702 * Updates the {@linkplain #getFields() fields} of this graph with the accessed fields of 703 * another graph. 704 */ 705 public void updateFields(StructuredGraph other) { 706 assert this != other; 707 this.fields.addAll(other.fields); 708 } 709 710 /** 711 * Gets the input bytecode {@linkplain ResolvedJavaMethod#getCodeSize() size} from which this 712 * graph is constructed. This ignores how many bytecodes in each constituent method are actually 713 * parsed (which may be none for methods whose IR is retrieved from a cache or less than the 714 * full amount for any given method due to profile guided branch pruning). 715 */ 716 public int getBytecodeSize() { 717 int res = 0; 718 for (ResolvedJavaMethod e : methods) { 719 res += e.getCodeSize(); 720 } 721 return res; 722 } 723 724 /** 725 * 726 * @return true if the graph contains only a {@link StartNode} and {@link ReturnNode} 727 */ 728 public boolean isTrivial() { 729 return !(start.next() instanceof ReturnNode); 730 } 731 732 @Override 733 public JavaMethod asJavaMethod() { 734 return method(); 735 } 736 737 public boolean hasUnsafeAccess() { 738 return hasUnsafeAccess == UnsafeAccessState.HAS_ACCESS; 739 } 740 741 public void markUnsafeAccess() { 742 if (hasUnsafeAccess == UnsafeAccessState.DISABLED) { 743 return; 744 } 745 hasUnsafeAccess = UnsafeAccessState.HAS_ACCESS; 746 } 747 748 public void disableUnsafeAccessTracking() { 749 hasUnsafeAccess = UnsafeAccessState.DISABLED; 750 } 751 752 public boolean isUnsafeAccessTrackingEnabled() { 753 return hasUnsafeAccess != UnsafeAccessState.DISABLED; 754 } 755 756 public SpeculationLog getSpeculationLog() { 757 return speculationLog; 758 } 759 760 public final void clearAllStateAfter() { 761 for (Node node : getNodes()) { 762 if (node instanceof StateSplit) { 763 FrameState stateAfter = ((StateSplit) node).stateAfter(); 764 if (stateAfter != null) { 765 ((StateSplit) node).setStateAfter(null); 766 // 2 nodes referencing the same framestate 767 if (stateAfter.isAlive()) { 768 GraphUtil.killWithUnusedFloatingInputs(stateAfter); 769 } 770 } 771 } 772 } 773 } 774 775 public final boolean hasVirtualizableAllocation() { 776 for (Node n : getNodes()) { 777 if (n instanceof VirtualizableAllocation) { 778 return true; 779 } 780 } 781 return false; 782 } 783 }