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 }