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