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