1/*
2 * Copyright (c) 2015, 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 static org.graalvm.compiler.debug.GraalError.shouldNotReachHere;
26import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
27import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
28
29import java.util.ArrayDeque;
30import java.util.ArrayList;
31import java.util.Arrays;
32import java.util.BitSet;
33import java.util.Deque;
34import java.util.HashMap;
35import java.util.Iterator;
36import java.util.List;
37import java.util.Map;
38import java.util.SortedMap;
39import java.util.TreeMap;
40
41import org.graalvm.compiler.common.PermanentBailoutException;
42import org.graalvm.compiler.core.common.Fields;
43import org.graalvm.compiler.core.common.util.TypeReader;
44import org.graalvm.compiler.core.common.util.UnsafeArrayTypeReader;
45import org.graalvm.compiler.debug.Debug;
46import org.graalvm.compiler.debug.GraalError;
47import org.graalvm.compiler.graph.Edges;
48import org.graalvm.compiler.graph.Graph;
49import org.graalvm.compiler.graph.Node;
50import org.graalvm.compiler.graph.NodeBitMap;
51import org.graalvm.compiler.graph.NodeClass;
52import org.graalvm.compiler.graph.NodeInputList;
53import org.graalvm.compiler.graph.NodeList;
54import org.graalvm.compiler.graph.NodeSourcePosition;
55import org.graalvm.compiler.graph.NodeSuccessorList;
56import org.graalvm.compiler.graph.spi.Canonicalizable;
57import org.graalvm.compiler.graph.spi.CanonicalizerTool;
58import org.graalvm.compiler.nodeinfo.InputType;
59import org.graalvm.compiler.nodeinfo.NodeInfo;
60import org.graalvm.compiler.nodes.GraphDecoder.MethodScope;
61import org.graalvm.compiler.nodes.GraphDecoder.ProxyPlaceholder;
62import org.graalvm.compiler.nodes.calc.FloatingNode;
63import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
64import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin.LoopExplosionKind;
65
66import jdk.vm.ci.code.Architecture;
67import jdk.vm.ci.meta.DeoptimizationAction;
68import jdk.vm.ci.meta.DeoptimizationReason;
69import jdk.vm.ci.meta.JavaConstant;
70import jdk.vm.ci.meta.JavaKind;
71import jdk.vm.ci.meta.PrimitiveConstant;
72import jdk.vm.ci.meta.ResolvedJavaType;
73
74/**
75 * Decoder for {@link EncodedGraph encoded graphs} produced by {@link GraphEncoder}. Support for
76 * loop explosion during decoding is built into this class, because it requires many interactions
77 * with the decoding process. Subclasses can provide canonicalization and simplification of nodes
78 * during decoding, as well as method inlining during decoding.
79 */
80public class GraphDecoder {
81
82    /** Decoding state maintained for each encoded graph. */
83    protected class MethodScope {
84        /** The loop that contains the call. Only non-null during method inlining. */
85        public final LoopScope callerLoopScope;
86        /** The target graph where decoded nodes are added to. */
87        public final StructuredGraph graph;
88        /**
89         * Mark for nodes that were present before the decoding of this method started. Note that
90         * nodes that were decoded after the mark can still be part of an outer method, since
91         * floating nodes of outer methods are decoded lazily.
92         */
93        public final Graph.Mark methodStartMark;
94        /** The encode graph that is decoded. */
95        public final EncodedGraph encodedGraph;
96        /** Access to the encoded graph. */
97        public final TypeReader reader;
98        /** The kind of loop explosion to be performed during decoding. */
99        public final LoopExplosionKind loopExplosion;
100        /** A list of tasks to run before the method scope is closed. */
101        public final List<Runnable> cleanupTasks;
102
103        /** All return nodes encountered during decoding. */
104        public final List<ReturnNode> returnNodes;
105        /** The exception unwind node encountered during decoding, or null. */
106        public final List<UnwindNode> unwindNodes;
107
108        /** All merges created during loop explosion. */
109        public final NodeBitMap loopExplosionMerges;
110        /**
111         * The start of explosion, and the merge point for when irreducible loops are detected. Only
112         * used when {@link MethodScope#loopExplosion} is {@link LoopExplosionKind#MERGE_EXPLODE}.
113         */
114        public MergeNode loopExplosionHead;
115
116        protected MethodScope(LoopScope callerLoopScope, StructuredGraph graph, EncodedGraph encodedGraph, LoopExplosionKind loopExplosion) {
117            this.callerLoopScope = callerLoopScope;
118            this.graph = graph;
119            this.methodStartMark = graph.getMark();
120            this.encodedGraph = encodedGraph;
121            this.loopExplosion = loopExplosion;
122            this.cleanupTasks = new ArrayList<>();
123            this.returnNodes = new ArrayList<>();
124            this.unwindNodes = new ArrayList<>();
125
126            if (encodedGraph != null) {
127                reader = UnsafeArrayTypeReader.create(encodedGraph.getEncoding(), encodedGraph.getStartOffset(), architecture.supportsUnalignedMemoryAccess());
128                if (encodedGraph.nodeStartOffsets == null) {
129                    int nodeCount = reader.getUVInt();
130                    long[] nodeStartOffsets = new long[nodeCount];
131                    for (int i = 0; i < nodeCount; i++) {
132                        nodeStartOffsets[i] = encodedGraph.getStartOffset() - reader.getUV();
133                    }
134                    encodedGraph.nodeStartOffsets = nodeStartOffsets;
135                }
136            } else {
137                reader = null;
138            }
139
140            if (loopExplosion != LoopExplosionKind.NONE) {
141                loopExplosionMerges = new NodeBitMap(graph);
142            } else {
143                loopExplosionMerges = null;
144            }
145        }
146    }
147
148    /** Decoding state maintained for each loop in the encoded graph. */
149    protected static class LoopScope {
150        public final MethodScope methodScope;
151        public final LoopScope outer;
152        public final int loopDepth;
153        public final int loopIteration;
154        /**
155         * Upcoming loop iterations during loop explosions that have not been processed yet. Only
156         * used when {@link MethodScope#loopExplosion} is not {@link LoopExplosionKind#NONE}.
157         */
158        public Deque<LoopScope> nextIterations;
159        /**
160         * Information about already processed loop iterations for state merging during loop
161         * explosion. Only used when {@link MethodScope#loopExplosion} is
162         * {@link LoopExplosionKind#MERGE_EXPLODE}.
163         */
164        public final Map<LoopExplosionState, LoopExplosionState> iterationStates;
165        public final int loopBeginOrderId;
166        /**
167         * The worklist of fixed nodes to process. Since we already the correct processing order
168         * from the orderId, we just set the orderId bit in the bitset when a node is ready for
169         * processing. The lowest set bit is the next node to process.
170         */
171        public final BitSet nodesToProcess;
172        /** Nodes that have been created, indexed by the orderId. */
173        public final Node[] createdNodes;
174        /**
175         * Nodes that have been created in outer loop scopes and existed before starting to process
176         * this loop, indexed by the orderId.
177         */
178        public final Node[] initialCreatedNodes;
179
180        protected LoopScope(MethodScope methodScope) {
181            this.methodScope = methodScope;
182            this.outer = null;
183            this.nextIterations = methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN ? new ArrayDeque<>() : null;
184            this.loopDepth = 0;
185            this.loopIteration = 0;
186            this.iterationStates = null;
187            this.loopBeginOrderId = -1;
188
189            int nodeCount = methodScope.encodedGraph.nodeStartOffsets.length;
190            this.nodesToProcess = new BitSet(nodeCount);
191            this.initialCreatedNodes = new Node[nodeCount];
192            this.createdNodes = new Node[nodeCount];
193        }
194
195        protected LoopScope(MethodScope methodScope, LoopScope outer, int loopDepth, int loopIteration, int loopBeginOrderId, Node[] initialCreatedNodes, Node[] createdNodes,
196                        Deque<LoopScope> nextIterations, Map<LoopExplosionState, LoopExplosionState> iterationStates) {
197            this.methodScope = methodScope;
198            this.outer = outer;
199            this.loopDepth = loopDepth;
200            this.loopIteration = loopIteration;
201            this.nextIterations = nextIterations;
202            this.iterationStates = iterationStates;
203            this.loopBeginOrderId = loopBeginOrderId;
204            this.nodesToProcess = new BitSet(initialCreatedNodes.length);
205            this.initialCreatedNodes = initialCreatedNodes;
206            this.createdNodes = Arrays.copyOf(createdNodes, createdNodes.length);
207        }
208
209        @Override
210        public String toString() {
211            return loopDepth + "," + loopIteration + (loopBeginOrderId == -1 ? "" : "#" + loopBeginOrderId);
212        }
213    }
214
215    protected static class LoopExplosionState {
216        public final FrameState state;
217        public final MergeNode merge;
218        public final int hashCode;
219
220        protected LoopExplosionState(FrameState state, MergeNode merge) {
221            this.state = state;
222            this.merge = merge;
223
224            int h = 0;
225            for (ValueNode value : state.values()) {
226                if (value == null) {
227                    h = h * 31 + 1234;
228                } else {
229                    h = h * 31 + ProxyPlaceholder.unwrap(value).hashCode();
230                }
231            }
232            this.hashCode = h;
233        }
234
235        @Override
236        public boolean equals(Object obj) {
237            if (!(obj instanceof LoopExplosionState)) {
238                return false;
239            }
240
241            FrameState otherState = ((LoopExplosionState) obj).state;
242            FrameState thisState = state;
243            assert thisState.outerFrameState() == otherState.outerFrameState();
244
245            Iterator<ValueNode> thisIter = thisState.values().iterator();
246            Iterator<ValueNode> otherIter = otherState.values().iterator();
247            while (thisIter.hasNext() && otherIter.hasNext()) {
248                ValueNode thisValue = ProxyPlaceholder.unwrap(thisIter.next());
249                ValueNode otherValue = ProxyPlaceholder.unwrap(otherIter.next());
250                if (thisValue != otherValue) {
251                    return false;
252                }
253            }
254            return thisIter.hasNext() == otherIter.hasNext();
255        }
256
257        @Override
258        public int hashCode() {
259            return hashCode;
260        }
261    }
262
263    /**
264     * Additional information encoded for {@link Invoke} nodes to allow method inlining without
265     * decoding the frame state and successors beforehand.
266     */
267    protected static class InvokeData {
268        public final Invoke invoke;
269        public final ResolvedJavaType contextType;
270        public final int invokeOrderId;
271        public final int callTargetOrderId;
272        public final int stateAfterOrderId;
273        public final int nextOrderId;
274
275        public final int nextNextOrderId;
276        public final int exceptionOrderId;
277        public final int exceptionStateOrderId;
278        public final int exceptionNextOrderId;
279        public JavaConstant constantReceiver;
280
281        protected InvokeData(Invoke invoke, ResolvedJavaType contextType, int invokeOrderId, int callTargetOrderId, int stateAfterOrderId, int nextOrderId, int nextNextOrderId, int exceptionOrderId,
282                        int exceptionStateOrderId, int exceptionNextOrderId) {
283            this.invoke = invoke;
284            this.contextType = contextType;
285            this.invokeOrderId = invokeOrderId;
286            this.callTargetOrderId = callTargetOrderId;
287            this.stateAfterOrderId = stateAfterOrderId;
288            this.nextOrderId = nextOrderId;
289            this.nextNextOrderId = nextNextOrderId;
290            this.exceptionOrderId = exceptionOrderId;
291            this.exceptionStateOrderId = exceptionStateOrderId;
292            this.exceptionNextOrderId = exceptionNextOrderId;
293        }
294    }
295
296    /**
297     * A node that is created during {@link LoopExplosionKind#MERGE_EXPLODE loop explosion} that can
298     * later be replaced by a ProxyNode if {@link LoopDetector loop detection} finds out that the
299     * value is defined in the loop, but used outside the loop.
300     */
301    @NodeInfo(cycles = CYCLES_IGNORED, size = SIZE_IGNORED)
302    protected static final class ProxyPlaceholder extends FloatingNode implements Canonicalizable {
303        public static final NodeClass<ProxyPlaceholder> TYPE = NodeClass.create(ProxyPlaceholder.class);
304
305        @Input ValueNode value;
306        @Input(InputType.Unchecked) Node proxyPoint;
307
308        public ProxyPlaceholder(ValueNode value, MergeNode proxyPoint) {
309            super(TYPE, value.stamp());
310            this.value = value;
311            this.proxyPoint = proxyPoint;
312        }
313
314        void setValue(ValueNode value) {
315            updateUsages(this.value, value);
316            this.value = value;
317        }
318
319        @Override
320        public Node canonical(CanonicalizerTool tool) {
321            if (tool.allUsagesAvailable()) {
322                /* The node is always unnecessary after graph decoding. */
323                return value;
324            } else {
325                return this;
326            }
327        }
328
329        public static ValueNode unwrap(ValueNode value) {
330            ValueNode result = value;
331            while (result instanceof ProxyPlaceholder) {
332                result = ((ProxyPlaceholder) result).value;
333            }
334            return result;
335        }
336    }
337
338    protected final Architecture architecture;
339
340    public GraphDecoder(Architecture architecture) {
341        this.architecture = architecture;
342    }
343
344    @SuppressWarnings("try")
345    public final void decode(StructuredGraph graph, EncodedGraph encodedGraph) {
346        try (Debug.Scope scope = Debug.scope("GraphDecoder", graph)) {
347            MethodScope methodScope = new MethodScope(null, graph, encodedGraph, LoopExplosionKind.NONE);
348            decode(createInitialLoopScope(methodScope, null));
349            cleanupGraph(methodScope);
350            assert methodScope.graph.verify();
351        } catch (Throwable ex) {
352            Debug.handle(ex);
353        }
354    }
355
356    protected final LoopScope createInitialLoopScope(MethodScope methodScope, FixedWithNextNode startNode) {
357        LoopScope loopScope = new LoopScope(methodScope);
358        FixedNode firstNode;
359        if (startNode != null) {
360            /*
361             * The start node of a graph can be referenced as the guard for a GuardedNode. We
362             * register the previous block node, so that such guards are correctly anchored when
363             * doing inlining during graph decoding.
364             */
365            registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, AbstractBeginNode.prevBegin(startNode), false, false);
366
367            firstNode = makeStubNode(methodScope, loopScope, GraphEncoder.FIRST_NODE_ORDER_ID);
368            startNode.setNext(firstNode);
369            loopScope.nodesToProcess.set(GraphEncoder.FIRST_NODE_ORDER_ID);
370        } else {
371            firstNode = methodScope.graph.start();
372            registerNode(loopScope, GraphEncoder.START_NODE_ORDER_ID, firstNode, false, false);
373            loopScope.nodesToProcess.set(GraphEncoder.START_NODE_ORDER_ID);
374        }
375
376        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
377            methodScope.cleanupTasks.add(new LoopDetector(methodScope, startNode));
378        }
379        return loopScope;
380    }
381
382    protected final void decode(LoopScope initialLoopScope) {
383        LoopScope loopScope = initialLoopScope;
384        /* Process inlined methods. */
385        while (loopScope != null) {
386            MethodScope methodScope = loopScope.methodScope;
387
388            /* Process loops of method. */
389            while (loopScope != null) {
390
391                /* Process nodes of loop. */
392                while (!loopScope.nodesToProcess.isEmpty()) {
393                    loopScope = processNextNode(methodScope, loopScope);
394                    methodScope = loopScope.methodScope;
395                    /*
396                     * We can have entered a new loop, and we can have entered a new inlined method.
397                     */
398                }
399
400                /* Finished with a loop. */
401                if (loopScope.nextIterations != null && !loopScope.nextIterations.isEmpty()) {
402                    /* Loop explosion: process the loop iteration. */
403                    assert loopScope.nextIterations.peekFirst().loopIteration == loopScope.loopIteration + 1;
404                    loopScope = loopScope.nextIterations.removeFirst();
405                } else {
406                    propagateCreatedNodes(loopScope);
407                    loopScope = loopScope.outer;
408                }
409            }
410
411            /*
412             * Finished with an inlined method. Perform all registered end-of-method cleanup tasks
413             * and continue with loop that contained the call.
414             */
415            for (Runnable task : methodScope.cleanupTasks) {
416                task.run();
417            }
418            loopScope = methodScope.callerLoopScope;
419        }
420    }
421
422    private static void propagateCreatedNodes(LoopScope loopScope) {
423        if (loopScope.outer == null) {
424            return;
425        }
426
427        /* Register nodes that were created while decoding the loop to the outside scope. */
428        for (int i = 0; i < loopScope.createdNodes.length; i++) {
429            if (loopScope.outer.createdNodes[i] == null) {
430                loopScope.outer.createdNodes[i] = loopScope.createdNodes[i];
431            }
432        }
433    }
434
435    protected LoopScope processNextNode(MethodScope methodScope, LoopScope loopScope) {
436        int nodeOrderId = loopScope.nodesToProcess.nextSetBit(0);
437        loopScope.nodesToProcess.clear(nodeOrderId);
438
439        FixedNode node = (FixedNode) lookupNode(loopScope, nodeOrderId);
440        if (node.isDeleted()) {
441            return loopScope;
442        }
443
444        if ((node instanceof MergeNode ||
445                        (node instanceof LoopBeginNode && (methodScope.loopExplosion == LoopExplosionKind.FULL_UNROLL || methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE ||
446                                        methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN))) &&
447                        ((AbstractMergeNode) node).forwardEndCount() == 1) {
448            AbstractMergeNode merge = (AbstractMergeNode) node;
449            EndNode singleEnd = merge.forwardEndAt(0);
450
451            /* Nodes that would use this merge as the guard need to use the previous block. */
452            registerNode(loopScope, nodeOrderId, AbstractBeginNode.prevBegin(singleEnd), true, false);
453
454            FixedNode next = makeStubNode(methodScope, loopScope, nodeOrderId + GraphEncoder.BEGIN_NEXT_ORDER_ID_OFFSET);
455            singleEnd.replaceAtPredecessor(next);
456
457            merge.safeDelete();
458            singleEnd.safeDelete();
459            return loopScope;
460        }
461
462        LoopScope successorAddScope = loopScope;
463        boolean updatePredecessors = true;
464        if (node instanceof LoopExitNode) {
465            if (methodScope.loopExplosion == LoopExplosionKind.FULL_EXPLODE_UNTIL_RETURN || (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE && loopScope.loopDepth > 1)) {
466                /*
467                 * We do not want to merge loop exits of inner loops. Instead, we want to keep
468                 * exploding the outer loop separately for every loop exit and then merge the outer
469                 * loop. Therefore, we create a new LoopScope of the outer loop for every loop exit
470                 * of the inner loop.
471                 */
472                LoopScope outerScope = loopScope.outer;
473                int nextIterationNumber = outerScope.nextIterations.isEmpty() ? outerScope.loopIteration + 1 : outerScope.nextIterations.getLast().loopIteration + 1;
474                successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId, outerScope.initialCreatedNodes,
475                                loopScope.initialCreatedNodes, outerScope.nextIterations, outerScope.iterationStates);
476                checkLoopExplosionIteration(methodScope, successorAddScope);
477
478                /*
479                 * Nodes that are still unprocessed in the outer scope might be merge nodes that are
480                 * also reachable from the new exploded scope. Clearing them ensures that we do not
481                 * merge, but instead keep exploding.
482                 */
483                for (int id = outerScope.nodesToProcess.nextSetBit(0); id >= 0; id = outerScope.nodesToProcess.nextSetBit(id + 1)) {
484                    successorAddScope.createdNodes[id] = null;
485                }
486
487                outerScope.nextIterations.addLast(successorAddScope);
488            } else {
489                successorAddScope = loopScope.outer;
490            }
491            updatePredecessors = methodScope.loopExplosion == LoopExplosionKind.NONE;
492        }
493
494        methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]);
495        int typeId = methodScope.reader.getUVInt();
496        assert node.getNodeClass() == methodScope.encodedGraph.getNodeClasses()[typeId];
497        readProperties(methodScope, node);
498        makeSuccessorStubs(methodScope, successorAddScope, node, updatePredecessors);
499        makeInputNodes(methodScope, loopScope, node, true);
500
501        LoopScope resultScope = loopScope;
502        if (node instanceof LoopBeginNode) {
503            if (methodScope.loopExplosion != LoopExplosionKind.NONE) {
504                handleLoopExplosionBegin(methodScope, loopScope, (LoopBeginNode) node);
505            }
506
507        } else if (node instanceof LoopExitNode) {
508            if (methodScope.loopExplosion != LoopExplosionKind.NONE) {
509                handleLoopExplosionProxyNodes(methodScope, loopScope, successorAddScope, (LoopExitNode) node, nodeOrderId);
510            } else {
511                handleProxyNodes(methodScope, loopScope, (LoopExitNode) node);
512            }
513
514        } else if (node instanceof MergeNode) {
515            handleMergeNode(((MergeNode) node));
516
517        } else if (node instanceof AbstractEndNode) {
518            LoopScope phiInputScope = loopScope;
519            LoopScope phiNodeScope = loopScope;
520
521            if (methodScope.loopExplosion != LoopExplosionKind.NONE && node instanceof LoopEndNode) {
522                node = handleLoopExplosionEnd(methodScope, loopScope, (LoopEndNode) node);
523                phiNodeScope = loopScope.nextIterations.getLast();
524            }
525
526            int mergeOrderId = readOrderId(methodScope);
527            AbstractMergeNode merge = (AbstractMergeNode) lookupNode(phiNodeScope, mergeOrderId);
528            if (merge == null) {
529                merge = (AbstractMergeNode) makeStubNode(methodScope, phiNodeScope, mergeOrderId);
530
531                if (merge instanceof LoopBeginNode) {
532                    assert phiNodeScope == phiInputScope && phiNodeScope == loopScope;
533                    resultScope = new LoopScope(methodScope, loopScope, loopScope.loopDepth + 1, 0, mergeOrderId,
534                                    Arrays.copyOf(loopScope.createdNodes, loopScope.createdNodes.length), loopScope.createdNodes, //
535                                    methodScope.loopExplosion != LoopExplosionKind.NONE ? new ArrayDeque<>() : null, //
536                                    methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE ? new HashMap<>() : null);
537                    phiInputScope = resultScope;
538                    phiNodeScope = resultScope;
539
540                    registerNode(loopScope, mergeOrderId, null, true, true);
541                    loopScope.nodesToProcess.clear(mergeOrderId);
542                    resultScope.nodesToProcess.set(mergeOrderId);
543                }
544            }
545
546            handlePhiFunctions(methodScope, phiInputScope, phiNodeScope, (AbstractEndNode) node, merge);
547
548        } else if (node instanceof Invoke) {
549            InvokeData invokeData = readInvokeData(methodScope, nodeOrderId, (Invoke) node);
550            resultScope = handleInvoke(methodScope, loopScope, invokeData);
551
552        } else if (node instanceof ReturnNode) {
553            methodScope.returnNodes.add((ReturnNode) node);
554        } else if (node instanceof UnwindNode) {
555            methodScope.unwindNodes.add((UnwindNode) node);
556
557        } else {
558            handleFixedNode(methodScope, loopScope, nodeOrderId, node);
559        }
560
561        return resultScope;
562    }
563
564    private InvokeData readInvokeData(MethodScope methodScope, int invokeOrderId, Invoke invoke) {
565        ResolvedJavaType contextType = (ResolvedJavaType) readObject(methodScope);
566        int callTargetOrderId = readOrderId(methodScope);
567        int stateAfterOrderId = readOrderId(methodScope);
568        int nextOrderId = readOrderId(methodScope);
569
570        if (invoke instanceof InvokeWithExceptionNode) {
571            int nextNextOrderId = readOrderId(methodScope);
572            int exceptionOrderId = readOrderId(methodScope);
573            int exceptionStateOrderId = readOrderId(methodScope);
574            int exceptionNextOrderId = readOrderId(methodScope);
575            return new InvokeData(invoke, contextType, invokeOrderId, callTargetOrderId, stateAfterOrderId, nextOrderId, nextNextOrderId, exceptionOrderId, exceptionStateOrderId,
576                            exceptionNextOrderId);
577        } else {
578            return new InvokeData(invoke, contextType, invokeOrderId, callTargetOrderId, stateAfterOrderId, nextOrderId, -1, -1, -1, -1);
579        }
580    }
581
582    /**
583     * {@link Invoke} nodes do not have the {@link CallTargetNode}, {@link FrameState}, and
584     * successors encoded. Instead, this information is provided separately to allow method inlining
585     * without decoding and adding them to the graph upfront. For non-inlined methods, this method
586     * restores the normal state. Subclasses can override it to perform method inlining.
587     *
588     * The return value is the loop scope where decoding should continue. When method inlining
589     * should be performed, the returned loop scope must be a new loop scope for the inlined method.
590     * Without inlining, the original loop scope must be returned.
591     */
592    protected LoopScope handleInvoke(MethodScope methodScope, LoopScope loopScope, InvokeData invokeData) {
593        assert invokeData.invoke.callTarget() == null : "callTarget edge is ignored during decoding of Invoke";
594        CallTargetNode callTarget = (CallTargetNode) ensureNodeCreated(methodScope, loopScope, invokeData.callTargetOrderId);
595        if (invokeData.invoke instanceof InvokeWithExceptionNode) {
596            ((InvokeWithExceptionNode) invokeData.invoke).setCallTarget(callTarget);
597        } else {
598            ((InvokeNode) invokeData.invoke).setCallTarget(callTarget);
599        }
600
601        assert invokeData.invoke.stateAfter() == null && invokeData.invoke.stateDuring() == null : "FrameState edges are ignored during decoding of Invoke";
602        invokeData.invoke.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, invokeData.stateAfterOrderId));
603
604        invokeData.invoke.setNext(makeStubNode(methodScope, loopScope, invokeData.nextOrderId));
605        if (invokeData.invoke instanceof InvokeWithExceptionNode) {
606            ((InvokeWithExceptionNode) invokeData.invoke).setExceptionEdge((AbstractBeginNode) makeStubNode(methodScope, loopScope, invokeData.exceptionOrderId));
607        }
608        return loopScope;
609    }
610
611    /**
612     * Hook for subclasses to perform simplifications for a non-loop-header control flow merge.
613     *
614     * @param merge The control flow merge.
615     */
616    protected void handleMergeNode(MergeNode merge) {
617    }
618
619    protected void handleLoopExplosionBegin(MethodScope methodScope, LoopScope loopScope, LoopBeginNode loopBegin) {
620        checkLoopExplosionIteration(methodScope, loopScope);
621
622        List<EndNode> predecessors = loopBegin.forwardEnds().snapshot();
623        FixedNode successor = loopBegin.next();
624        FrameState frameState = loopBegin.stateAfter();
625
626        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
627            LoopExplosionState queryState = new LoopExplosionState(frameState, null);
628            LoopExplosionState existingState = loopScope.iterationStates.get(queryState);
629            if (existingState != null) {
630                loopBegin.replaceAtUsagesAndDelete(existingState.merge);
631                successor.safeDelete();
632                for (EndNode predecessor : predecessors) {
633                    existingState.merge.addForwardEnd(predecessor);
634                }
635                return;
636            }
637        }
638
639        MergeNode merge = methodScope.graph.add(new MergeNode());
640        methodScope.loopExplosionMerges.markAndGrow(merge);
641
642        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
643            if (loopScope.iterationStates.size() == 0 && loopScope.loopDepth == 1) {
644                if (methodScope.loopExplosionHead != null) {
645                    throw new PermanentBailoutException("Graal implementation restriction: Method with %s loop explosion must not have more than one top-level loop", LoopExplosionKind.MERGE_EXPLODE);
646                }
647                methodScope.loopExplosionHead = merge;
648            }
649
650            List<ValueNode> newFrameStateValues = new ArrayList<>();
651            for (ValueNode frameStateValue : frameState.values) {
652                if (frameStateValue == null || frameStateValue.isConstant() || !methodScope.graph.isNew(methodScope.methodStartMark, frameStateValue)) {
653                    newFrameStateValues.add(frameStateValue);
654
655                } else {
656                    ProxyPlaceholder newFrameStateValue = methodScope.graph.unique(new ProxyPlaceholder(frameStateValue, merge));
657                    newFrameStateValues.add(newFrameStateValue);
658
659                    /*
660                     * We do not have the orderID of the value anymore, so we need to search through
661                     * the complete list of nodes to find a match.
662                     */
663                    for (int i = 0; i < loopScope.createdNodes.length; i++) {
664                        if (loopScope.createdNodes[i] == frameStateValue) {
665                            loopScope.createdNodes[i] = newFrameStateValue;
666                        }
667                        if (loopScope.initialCreatedNodes[i] == frameStateValue) {
668                            loopScope.initialCreatedNodes[i] = newFrameStateValue;
669                        }
670                    }
671                }
672            }
673
674            FrameState newFrameState = methodScope.graph.add(new FrameState(frameState.outerFrameState(), frameState.getCode(), frameState.bci, newFrameStateValues, frameState.localsSize(),
675                            frameState.stackSize(), frameState.rethrowException(), frameState.duringCall(), frameState.monitorIds(), frameState.virtualObjectMappings()));
676
677            frameState.replaceAtUsages(newFrameState);
678            frameState.safeDelete();
679            frameState = newFrameState;
680        }
681
682        loopBegin.replaceAtUsagesAndDelete(merge);
683        merge.setStateAfter(frameState);
684        merge.setNext(successor);
685        for (EndNode predecessor : predecessors) {
686            merge.addForwardEnd(predecessor);
687        }
688
689        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE) {
690            LoopExplosionState explosionState = new LoopExplosionState(frameState, merge);
691            loopScope.iterationStates.put(explosionState, explosionState);
692        }
693    }
694
695    /**
696     * Hook for subclasses.
697     *
698     * @param methodScope The current method.
699     * @param loopScope The current loop.
700     */
701    protected void checkLoopExplosionIteration(MethodScope methodScope, LoopScope loopScope) {
702        throw shouldNotReachHere("when subclass uses loop explosion, it needs to implement this method");
703    }
704
705    protected FixedNode handleLoopExplosionEnd(MethodScope methodScope, LoopScope loopScope, LoopEndNode loopEnd) {
706        EndNode replacementNode = methodScope.graph.add(new EndNode());
707        loopEnd.replaceAtPredecessor(replacementNode);
708        loopEnd.safeDelete();
709
710        assert methodScope.loopExplosion != LoopExplosionKind.NONE;
711        if (methodScope.loopExplosion != LoopExplosionKind.FULL_UNROLL || loopScope.nextIterations.isEmpty()) {
712            int nextIterationNumber = loopScope.nextIterations.isEmpty() ? loopScope.loopIteration + 1 : loopScope.nextIterations.getLast().loopIteration + 1;
713            LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId, loopScope.initialCreatedNodes,
714                            loopScope.initialCreatedNodes, loopScope.nextIterations, loopScope.iterationStates);
715            checkLoopExplosionIteration(methodScope, nextIterationScope);
716            loopScope.nextIterations.addLast(nextIterationScope);
717            registerNode(nextIterationScope, loopScope.loopBeginOrderId, null, true, true);
718            makeStubNode(methodScope, nextIterationScope, loopScope.loopBeginOrderId);
719        }
720        return replacementNode;
721    }
722
723    /**
724     * Hook for subclasses.
725     *
726     * @param methodScope The current method.
727     * @param loopScope The current loop.
728     * @param nodeOrderId The orderId of the node.
729     * @param node The node to be simplified.
730     */
731    protected void handleFixedNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId, FixedNode node) {
732    }
733
734    protected void handleProxyNodes(MethodScope methodScope, LoopScope loopScope, LoopExitNode loopExit) {
735        assert loopExit.stateAfter() == null;
736        int stateAfterOrderId = readOrderId(methodScope);
737        loopExit.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, stateAfterOrderId));
738
739        int numProxies = methodScope.reader.getUVInt();
740        for (int i = 0; i < numProxies; i++) {
741            int proxyOrderId = readOrderId(methodScope);
742            ProxyNode proxy = (ProxyNode) ensureNodeCreated(methodScope, loopScope, proxyOrderId);
743            /*
744             * The ProxyNode transports a value from the loop to the outer scope. We therefore
745             * register it in the outer scope.
746             */
747            registerNode(loopScope.outer, proxyOrderId, proxy, false, false);
748        }
749    }
750
751    protected void handleLoopExplosionProxyNodes(MethodScope methodScope, LoopScope loopScope, LoopScope outerScope, LoopExitNode loopExit, int loopExitOrderId) {
752        assert loopExit.stateAfter() == null;
753        int stateAfterOrderId = readOrderId(methodScope);
754
755        BeginNode begin = methodScope.graph.add(new BeginNode());
756
757        FixedNode loopExitSuccessor = loopExit.next();
758        loopExit.replaceAtPredecessor(begin);
759
760        MergeNode loopExitPlaceholder = null;
761        if (methodScope.loopExplosion == LoopExplosionKind.MERGE_EXPLODE && loopScope.loopDepth == 1) {
762            /*
763             * This exit might end up as a loop exit of a loop detected after partial evaluation. We
764             * need to be able to create a FrameState and the necessary proxy nodes in this case.
765             */
766            loopExitPlaceholder = methodScope.graph.add(new MergeNode());
767            methodScope.loopExplosionMerges.markAndGrow(loopExitPlaceholder);
768
769            EndNode end = methodScope.graph.add(new EndNode());
770            begin.setNext(end);
771            loopExitPlaceholder.addForwardEnd(end);
772
773            begin = methodScope.graph.add(new BeginNode());
774            loopExitPlaceholder.setNext(begin);
775        }
776
777        /*
778         * In the original graph, the loop exit is not a merge node. Multiple exploded loop
779         * iterations now take the same loop exit, so we have to introduce a new merge node to
780         * handle the merge.
781         */
782        MergeNode merge = null;
783        Node existingExit = lookupNode(outerScope, loopExitOrderId);
784        if (existingExit == null) {
785            /* First loop iteration that exits. No merge necessary yet. */
786            registerNode(outerScope, loopExitOrderId, begin, false, false);
787            begin.setNext(loopExitSuccessor);
788
789        } else if (existingExit instanceof BeginNode) {
790            /* Second loop iteration that exits. Create the merge. */
791            merge = methodScope.graph.add(new MergeNode());
792            registerNode(outerScope, loopExitOrderId, merge, true, false);
793            /* Add the first iteration. */
794            EndNode firstEnd = methodScope.graph.add(new EndNode());
795            ((BeginNode) existingExit).setNext(firstEnd);
796            merge.addForwardEnd(firstEnd);
797            merge.setNext(loopExitSuccessor);
798
799        } else {
800            /* Subsequent loop iteration. Merge already created. */
801            merge = (MergeNode) existingExit;
802        }
803
804        if (merge != null) {
805            EndNode end = methodScope.graph.add(new EndNode());
806            begin.setNext(end);
807            merge.addForwardEnd(end);
808        }
809
810        /*
811         * Possibly create phi nodes for the original proxy nodes that flow out of the loop. Note
812         * that we definitely do not need a proxy node itself anymore, since the loop was exploded
813         * and is no longer present.
814         */
815        int numProxies = methodScope.reader.getUVInt();
816        boolean phiCreated = false;
817        for (int i = 0; i < numProxies; i++) {
818            int proxyOrderId = readOrderId(methodScope);
819            ProxyNode proxy = (ProxyNode) ensureNodeCreated(methodScope, loopScope, proxyOrderId);
820            ValueNode phiInput = proxy.value();
821
822            if (loopExitPlaceholder != null) {
823                if (!phiInput.isConstant()) {
824                    phiInput = methodScope.graph.unique(new ProxyPlaceholder(phiInput, loopExitPlaceholder));
825                }
826                registerNode(loopScope, proxyOrderId, phiInput, true, false);
827            }
828
829            ValueNode replacement;
830            ValueNode existing = (ValueNode) outerScope.createdNodes[proxyOrderId];
831            if (existing == null || existing == phiInput) {
832                /*
833                 * We are at the first loop exit, or the proxy carries the same value for all exits.
834                 * We do not need a phi node yet.
835                 */
836                registerNode(outerScope, proxyOrderId, phiInput, true, false);
837                replacement = phiInput;
838
839            } else if (!merge.isPhiAtMerge(existing)) {
840                /* Now we have two different values, so we need to create a phi node. */
841                PhiNode phi = methodScope.graph.addWithoutUnique(new ValuePhiNode(proxy.stamp(), merge));
842                /* Add the inputs from all previous exits. */
843                for (int j = 0; j < merge.phiPredecessorCount() - 1; j++) {
844                    phi.addInput(existing);
845                }
846                /* Add the input from this exit. */
847                phi.addInput(phiInput);
848                registerNode(outerScope, proxyOrderId, phi, true, false);
849                replacement = phi;
850                phiCreated = true;
851
852            } else {
853                /* Phi node has been created before, so just add the new input. */
854                PhiNode phi = (PhiNode) existing;
855                phi.addInput(phiInput);
856                replacement = phi;
857            }
858
859            proxy.replaceAtUsagesAndDelete(replacement);
860        }
861
862        if (loopExitPlaceholder != null) {
863            registerNode(loopScope, stateAfterOrderId, null, true, true);
864            loopExitPlaceholder.setStateAfter((FrameState) ensureNodeCreated(methodScope, loopScope, stateAfterOrderId));
865        }
866
867        if (merge != null && (merge.stateAfter() == null || phiCreated)) {
868            FrameState oldStateAfter = merge.stateAfter();
869            registerNode(outerScope, stateAfterOrderId, null, true, true);
870            merge.setStateAfter((FrameState) ensureNodeCreated(methodScope, outerScope, stateAfterOrderId));
871            if (oldStateAfter != null) {
872                oldStateAfter.safeDelete();
873            }
874        }
875        loopExit.safeDelete();
876        assert loopExitSuccessor.predecessor() == null;
877        if (merge != null) {
878            merge.getNodeClass().getSuccessorEdges().update(merge, null, loopExitSuccessor);
879        } else {
880            begin.getNodeClass().getSuccessorEdges().update(begin, null, loopExitSuccessor);
881        }
882    }
883
884    protected void handlePhiFunctions(MethodScope methodScope, LoopScope phiInputScope, LoopScope phiNodeScope, AbstractEndNode end, AbstractMergeNode merge) {
885
886        if (end instanceof LoopEndNode) {
887            /*
888             * Fix the loop end index and the number of loop ends. When we do canonicalization
889             * during decoding, we can end up with fewer ends than the encoded graph had. And the
890             * order of loop ends can be different.
891             */
892            int numEnds = ((LoopBeginNode) merge).loopEnds().count();
893            ((LoopBeginNode) merge).nextEndIndex = numEnds;
894            ((LoopEndNode) end).endIndex = numEnds - 1;
895
896        } else {
897            if (merge.ends == null) {
898                merge.ends = new NodeInputList<>(merge);
899            }
900            merge.addForwardEnd((EndNode) end);
901        }
902
903        /*
904         * We create most phi functions lazily. Canonicalization and simplification during decoding
905         * can lead to dead branches that are not decoded, so we might not need all phi functions
906         * that the original graph contained. Since we process all predecessors before actually
907         * processing the merge node, we have the final phi function when processing the merge node.
908         * The only exception are loop headers of non-exploded loops: since backward branches are
909         * not processed yet when processing the loop body, we need to create all phi functions
910         * upfront.
911         */
912        boolean lazyPhi = allowLazyPhis() && (!(merge instanceof LoopBeginNode) || methodScope.loopExplosion != LoopExplosionKind.NONE);
913        int numPhis = methodScope.reader.getUVInt();
914        for (int i = 0; i < numPhis; i++) {
915            int phiInputOrderId = readOrderId(methodScope);
916            int phiNodeOrderId = readOrderId(methodScope);
917
918            ValueNode phiInput = (ValueNode) ensureNodeCreated(methodScope, phiInputScope, phiInputOrderId);
919
920            ValueNode existing = (ValueNode) lookupNode(phiNodeScope, phiNodeOrderId);
921            if (lazyPhi && (existing == null || existing == phiInput)) {
922                /* Phi function not yet necessary. */
923                registerNode(phiNodeScope, phiNodeOrderId, phiInput, true, false);
924
925            } else if (!merge.isPhiAtMerge(existing)) {
926                /*
927                 * Phi function is necessary. Create it and fill it with existing inputs as well as
928                 * the new input.
929                 */
930                registerNode(phiNodeScope, phiNodeOrderId, null, true, true);
931                PhiNode phi = (PhiNode) ensureNodeCreated(methodScope, phiNodeScope, phiNodeOrderId);
932
933                phi.setMerge(merge);
934                for (int j = 0; j < merge.phiPredecessorCount() - 1; j++) {
935                    phi.addInput(existing);
936                }
937                phi.addInput(phiInput);
938
939            } else {
940                /* Phi node has been created before, so just add the new input. */
941                PhiNode phi = (PhiNode) existing;
942                phi.addInput(phiInput);
943            }
944        }
945    }
946
947    protected boolean allowLazyPhis() {
948        /* We need to exactly reproduce the encoded graph, including unnecessary phi functions. */
949        return false;
950    }
951
952    protected Node instantiateNode(MethodScope methodScope, int nodeOrderId) {
953        methodScope.reader.setByteIndex(methodScope.encodedGraph.nodeStartOffsets[nodeOrderId]);
954        NodeClass<?> nodeClass = methodScope.encodedGraph.getNodeClasses()[methodScope.reader.getUVInt()];
955        return nodeClass.allocateInstance();
956    }
957
958    protected void readProperties(MethodScope methodScope, Node node) {
959        node.setNodeSourcePosition((NodeSourcePosition) readObject(methodScope));
960        Fields fields = node.getNodeClass().getData();
961        for (int pos = 0; pos < fields.getCount(); pos++) {
962            if (fields.getType(pos).isPrimitive()) {
963                long primitive = methodScope.reader.getSV();
964                fields.setRawPrimitive(node, pos, primitive);
965            } else {
966                Object value = readObject(methodScope);
967                fields.set(node, pos, value);
968            }
969        }
970    }
971
972    /**
973     * Process the input edges of a node. Input nodes that have not yet been created must be
974     * non-fixed nodes (because fixed nodes are processed in reverse postorder. Such non-fixed nodes
975     * are created on demand (recursively since they can themselves reference not yet created
976     * nodes).
977     */
978    protected void makeInputNodes(MethodScope methodScope, LoopScope loopScope, Node node, boolean updateUsages) {
979        Edges edges = node.getNodeClass().getEdges(Edges.Type.Inputs);
980        for (int index = 0; index < edges.getDirectCount(); index++) {
981            if (skipEdge(node, edges, index, true, true)) {
982                continue;
983            }
984            int orderId = readOrderId(methodScope);
985            Node value = ensureNodeCreated(methodScope, loopScope, orderId);
986            edges.initializeNode(node, index, value);
987            if (updateUsages && value != null && !value.isDeleted()) {
988                edges.update(node, null, value);
989
990            }
991        }
992        for (int index = edges.getDirectCount(); index < edges.getCount(); index++) {
993            if (skipEdge(node, edges, index, false, true)) {
994                continue;
995            }
996            int size = methodScope.reader.getSVInt();
997            if (size != -1) {
998                NodeList<Node> nodeList = new NodeInputList<>(node, size);
999                edges.initializeList(node, index, nodeList);
1000                for (int idx = 0; idx < size; idx++) {
1001                    int orderId = readOrderId(methodScope);
1002                    Node value = ensureNodeCreated(methodScope, loopScope, orderId);
1003                    nodeList.initialize(idx, value);
1004                    if (updateUsages && value != null && !value.isDeleted()) {
1005                        edges.update(node, null, value);
1006                    }
1007                }
1008            }
1009        }
1010    }
1011
1012    protected Node ensureNodeCreated(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) {
1013        if (nodeOrderId == GraphEncoder.NULL_ORDER_ID) {
1014            return null;
1015        }
1016        Node node = lookupNode(loopScope, nodeOrderId);
1017        if (node != null) {
1018            return node;
1019        }
1020
1021        node = decodeFloatingNode(methodScope, loopScope, nodeOrderId);
1022
1023        if (node instanceof ProxyNode || node instanceof PhiNode) {
1024            /*
1025             * We need these nodes as they were in the original graph, without any canonicalization
1026             * or value numbering.
1027             */
1028            node = methodScope.graph.addWithoutUnique(node);
1029        } else {
1030            /* Allow subclasses to canonicalize and intercept nodes. */
1031            node = handleFloatingNodeBeforeAdd(methodScope, loopScope, node);
1032            if (!node.isAlive()) {
1033                node = addFloatingNode(methodScope, node);
1034            }
1035            node = handleFloatingNodeAfterAdd(methodScope, loopScope, node);
1036        }
1037        registerNode(loopScope, nodeOrderId, node, false, false);
1038        return node;
1039    }
1040
1041    protected Node addFloatingNode(MethodScope methodScope, Node node) {
1042        /*
1043         * We want to exactly reproduce the encoded graph. Even though nodes should be unique in the
1044         * encoded graph, this is not always guaranteed.
1045         */
1046        return methodScope.graph.addWithoutUnique(node);
1047    }
1048
1049    /**
1050     * Decodes a non-fixed node, but does not do any post-processing and does not register it.
1051     */
1052    protected Node decodeFloatingNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) {
1053        long readerByteIndex = methodScope.reader.getByteIndex();
1054        Node node = instantiateNode(methodScope, nodeOrderId);
1055        if (node instanceof FixedNode) {
1056            /*
1057             * This is a severe error that will lead to a corrupted graph, so it is better not to
1058             * continue decoding at all.
1059             */
1060            throw shouldNotReachHere("Not a floating node: " + node.getClass().getName());
1061        }
1062
1063        /* Read the properties of the node. */
1064        readProperties(methodScope, node);
1065        /* There must not be any successors to read, since it is a non-fixed node. */
1066        assert node.getNodeClass().getEdges(Edges.Type.Successors).getCount() == 0;
1067        /* Read the inputs of the node, possibly creating them recursively. */
1068        makeInputNodes(methodScope, loopScope, node, false);
1069        methodScope.reader.setByteIndex(readerByteIndex);
1070        return node;
1071    }
1072
1073    /**
1074     * Hook for subclasses to process a non-fixed node before it is added to the graph.
1075     *
1076     * @param methodScope The current method.
1077     * @param loopScope The current loop.
1078     * @param node The node to be canonicalized.
1079     * @return The replacement for the node, or the node itself.
1080     */
1081    protected Node handleFloatingNodeBeforeAdd(MethodScope methodScope, LoopScope loopScope, Node node) {
1082        return node;
1083    }
1084
1085    /**
1086     * Hook for subclasses to process a non-fixed node after it is added to the graph.
1087     *
1088     * If this method replaces a node with another node, it must update its source position if the
1089     * original node has the source position set.
1090     *
1091     * @param methodScope The current method.
1092     * @param loopScope The current loop.
1093     * @param node The node to be canonicalized.
1094     * @return The replacement for the node, or the node itself.
1095     */
1096    protected Node handleFloatingNodeAfterAdd(MethodScope methodScope, LoopScope loopScope, Node node) {
1097        return node;
1098    }
1099
1100    /**
1101     * Process successor edges of a node. We create the successor nodes so that we can fill the
1102     * successor list, but no properties or edges are loaded yet. That is done when the successor is
1103     * on top of the worklist in {@link #processNextNode}.
1104     */
1105    protected void makeSuccessorStubs(MethodScope methodScope, LoopScope loopScope, Node node, boolean updatePredecessors) {
1106        Edges edges = node.getNodeClass().getEdges(Edges.Type.Successors);
1107        for (int index = 0; index < edges.getDirectCount(); index++) {
1108            if (skipEdge(node, edges, index, true, true)) {
1109                continue;
1110            }
1111            int orderId = readOrderId(methodScope);
1112            Node value = makeStubNode(methodScope, loopScope, orderId);
1113            edges.initializeNode(node, index, value);
1114            if (updatePredecessors && value != null) {
1115                edges.update(node, null, value);
1116            }
1117        }
1118        for (int index = edges.getDirectCount(); index < edges.getCount(); index++) {
1119            if (skipEdge(node, edges, index, false, true)) {
1120                continue;
1121            }
1122            int size = methodScope.reader.getSVInt();
1123            if (size != -1) {
1124                NodeList<Node> nodeList = new NodeSuccessorList<>(node, size);
1125                edges.initializeList(node, index, nodeList);
1126                for (int idx = 0; idx < size; idx++) {
1127                    int orderId = readOrderId(methodScope);
1128                    Node value = makeStubNode(methodScope, loopScope, orderId);
1129                    nodeList.initialize(idx, value);
1130                    if (updatePredecessors && value != null) {
1131                        edges.update(node, null, value);
1132                    }
1133                }
1134            }
1135        }
1136    }
1137
1138    protected FixedNode makeStubNode(MethodScope methodScope, LoopScope loopScope, int nodeOrderId) {
1139        if (nodeOrderId == GraphEncoder.NULL_ORDER_ID) {
1140            return null;
1141        }
1142        FixedNode node = (FixedNode) lookupNode(loopScope, nodeOrderId);
1143        if (node != null) {
1144            return node;
1145        }
1146
1147        long readerByteIndex = methodScope.reader.getByteIndex();
1148        node = (FixedNode) methodScope.graph.add(instantiateNode(methodScope, nodeOrderId));
1149        /* Properties and edges are not filled yet, the node remains uninitialized. */
1150        methodScope.reader.setByteIndex(readerByteIndex);
1151
1152        registerNode(loopScope, nodeOrderId, node, false, false);
1153        loopScope.nodesToProcess.set(nodeOrderId);
1154        return node;
1155    }
1156
1157    /**
1158     * Returns false for {@link Edges} that are not necessary in the encoded graph because they are
1159     * reconstructed using other sources of information.
1160     */
1161    protected static boolean skipEdge(Node node, Edges edges, int index, boolean direct, boolean decode) {
1162        if (node instanceof PhiNode) {
1163            /* The inputs of phi functions are filled manually when the end nodes are processed. */
1164            assert edges.type() == Edges.Type.Inputs;
1165            if (direct) {
1166                assert index == edges.getDirectCount() - 1 : "PhiNode has one direct input (the MergeNode)";
1167            } else {
1168                assert index == edges.getCount() - 1 : "PhiNode has one variable size input (the values)";
1169                if (decode) {
1170                    /* The values must not be null, so initialize with an empty list. */
1171                    edges.initializeList(node, index, new NodeInputList<>(node));
1172                }
1173            }
1174            return true;
1175
1176        } else if (node instanceof AbstractMergeNode && edges.type() == Edges.Type.Inputs && !direct) {
1177            /* The ends of merge nodes are filled manually when the ends are processed. */
1178            assert index == edges.getCount() - 1 : "MergeNode has one variable size input (the ends)";
1179            assert Edges.getNodeList(node, edges.getOffsets(), index) != null : "Input list must have been already created";
1180            return true;
1181
1182        } else if (node instanceof LoopExitNode && edges.type() == Edges.Type.Inputs && edges.getType(index) == FrameState.class) {
1183            /* The stateAfter of the loop exit is filled manually. */
1184            return true;
1185
1186        } else if (node instanceof Invoke) {
1187            assert node instanceof InvokeNode || node instanceof InvokeWithExceptionNode : "The only two Invoke node classes. Got " + node.getClass();
1188            assert direct : "Invoke and InvokeWithException only have direct successor and input edges";
1189            if (edges.type() == Edges.Type.Successors) {
1190                assert edges.getCount() == (node instanceof InvokeWithExceptionNode ? 2 : 1) : "InvokeNode has one successor (next); InvokeWithExceptionNode has two successors (next, exceptionEdge)";
1191                return true;
1192            } else {
1193                assert edges.type() == Edges.Type.Inputs;
1194                if (edges.getType(index) == CallTargetNode.class) {
1195                    return true;
1196                } else if (edges.getType(index) == FrameState.class) {
1197                    assert edges.get(node, index) == null || edges.get(node, index) == ((Invoke) node).stateAfter() : "Only stateAfter can be a FrameState during encoding";
1198                    return true;
1199                }
1200            }
1201        }
1202        return false;
1203    }
1204
1205    protected Node lookupNode(LoopScope loopScope, int nodeOrderId) {
1206        return loopScope.createdNodes[nodeOrderId];
1207    }
1208
1209    protected void registerNode(LoopScope loopScope, int nodeOrderId, Node node, boolean allowOverwrite, boolean allowNull) {
1210        assert node == null || node.isAlive();
1211        assert allowNull || node != null;
1212        assert allowOverwrite || lookupNode(loopScope, nodeOrderId) == null;
1213        loopScope.createdNodes[nodeOrderId] = node;
1214    }
1215
1216    protected int readOrderId(MethodScope methodScope) {
1217        return methodScope.reader.getUVInt();
1218    }
1219
1220    protected Object readObject(MethodScope methodScope) {
1221        return methodScope.encodedGraph.getObjects()[methodScope.reader.getUVInt()];
1222    }
1223
1224    /**
1225     * Removes unnecessary nodes from the graph after decoding.
1226     *
1227     * @param methodScope The current method.
1228     */
1229    protected void cleanupGraph(MethodScope methodScope) {
1230        assert verifyEdges(methodScope);
1231    }
1232
1233    protected boolean verifyEdges(MethodScope methodScope) {
1234        for (Node node : methodScope.graph.getNodes()) {
1235            assert node.isAlive();
1236            for (Node i : node.inputs()) {
1237                assert i.isAlive();
1238                assert i.usages().contains(node);
1239            }
1240            for (Node s : node.successors()) {
1241                assert s.isAlive();
1242                assert s.predecessor() == node;
1243            }
1244
1245            for (Node usage : node.usages()) {
1246                assert usage.isAlive();
1247                assert usage.inputs().contains(node) : node + " / " + usage + " / " + usage.inputs().count();
1248            }
1249            if (node.predecessor() != null) {
1250                assert node.predecessor().isAlive();
1251                assert node.predecessor().successors().contains(node);
1252            }
1253        }
1254        return true;
1255    }
1256}
1257
1258class LoopDetector implements Runnable {
1259
1260    /**
1261     * Information about loops before the actual loop nodes are inserted.
1262     */
1263    static class Loop {
1264        /**
1265         * The header, i.e., the target of backward branches.
1266         */
1267        MergeNode header;
1268        /**
1269         * The ends, i.e., the source of backward branches. The {@link EndNode#successors successor}
1270         * is the {@link #header loop header}.
1271         */
1272        List<EndNode> ends = new ArrayList<>();
1273        /**
1274         * Exits of the loop. The successor is a {@link MergeNode} marked in
1275         * {@link MethodScope#loopExplosionMerges}.
1276         */
1277        List<AbstractEndNode> exits = new ArrayList<>();
1278        /**
1279         * Set to true when the loop is irreducible, i.e., has multiple entries. See
1280         * {@link #handleIrreducibleLoop} for details on the handling.
1281         */
1282        boolean irreducible;
1283    }
1284
1285    private final MethodScope methodScope;
1286    private final FixedNode startInstruction;
1287
1288    private Loop irreducibleLoopHandler;
1289    private IntegerSwitchNode irreducibleLoopSwitch;
1290
1291    protected LoopDetector(MethodScope methodScope, FixedNode startInstruction) {
1292        this.methodScope = methodScope;
1293        this.startInstruction = startInstruction;
1294    }
1295
1296    @Override
1297    public void run() {
1298        Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "Before loop detection");
1299
1300        List<Loop> orderedLoops = findLoops();
1301        assert orderedLoops.get(orderedLoops.size() - 1) == irreducibleLoopHandler : "outermost loop must be the last element in the list";
1302
1303        for (Loop loop : orderedLoops) {
1304            if (loop.ends.isEmpty()) {
1305                assert loop == irreducibleLoopHandler;
1306                continue;
1307            }
1308
1309            /*
1310             * The algorithm to find loop exits requires that inner loops have already been
1311             * processed. Therefore, we need to iterate the loops in order (inner loops before outer
1312             * loops), and we cannot find the exits for all loops before we start inserting nodes.
1313             */
1314            findLoopExits(loop);
1315
1316            if (loop.irreducible) {
1317                handleIrreducibleLoop(loop);
1318            } else {
1319                insertLoopNodes(loop);
1320            }
1321            Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "After handling of loop %s", loop.header);
1322        }
1323
1324        logIrreducibleLoops();
1325        Debug.dump(Debug.VERBOSE_LOG_LEVEL, methodScope.graph, "After loop detection");
1326    }
1327
1328    private List<Loop> findLoops() {
1329        /* Mapping from the loop header node to additional loop information. */
1330        Map<MergeNode, Loop> unorderedLoops = new HashMap<>();
1331        /* Loops in reverse order of, i.e., inner loops before outer loops. */
1332        List<Loop> orderedLoops = new ArrayList<>();
1333
1334        /*
1335         * Ensure we have an outermost loop that we can use to eliminate irreducible loops. This
1336         * loop can remain empty (no ends), in which case it is ignored.
1337         */
1338        irreducibleLoopHandler = findOrCreateLoop(unorderedLoops, methodScope.loopExplosionHead);
1339
1340        NodeBitMap visited = methodScope.graph.createNodeBitMap();
1341        NodeBitMap active = methodScope.graph.createNodeBitMap();
1342        Deque<Node> stack = new ArrayDeque<>();
1343        visited.mark(startInstruction);
1344        stack.push(startInstruction);
1345
1346        while (!stack.isEmpty()) {
1347            Node current = stack.peek();
1348            assert visited.isMarked(current);
1349
1350            if (active.isMarked(current)) {
1351                /* We are back-tracking, i.e., all successor nodes have been processed. */
1352                stack.pop();
1353                active.clear(current);
1354
1355                Loop loop = unorderedLoops.get(current);
1356                if (loop != null) {
1357                    /*
1358                     * Since nodes are popped in reverse order that they were pushed, we add inner
1359                     * loops before outer loops here.
1360                     */
1361                    assert !orderedLoops.contains(loop);
1362                    orderedLoops.add(loop);
1363                }
1364
1365            } else {
1366                /*
1367                 * Process the node. Note that we do not remove the node from the stack, i.e., we
1368                 * will peek it again. But the next time the node is marked as active, so we do not
1369                 * execute this code again.
1370                 */
1371                active.mark(current);
1372                for (Node successor : current.cfgSuccessors()) {
1373                    if (active.isMarked(successor)) {
1374                        /* Detected a cycle, i.e., a backward branch of a loop. */
1375                        Loop loop = findOrCreateLoop(unorderedLoops, (MergeNode) successor);
1376                        assert !loop.ends.contains(current);
1377                        loop.ends.add((EndNode) current);
1378
1379                    } else if (visited.isMarked(successor)) {
1380                        /* Forward merge into a branch we are already exploring. */
1381
1382                    } else {
1383                        /* Forward branch to a node we have not seen yet. */
1384                        visited.mark(successor);
1385                        stack.push(successor);
1386                    }
1387                }
1388            }
1389        }
1390        return orderedLoops;
1391    }
1392
1393    private Loop findOrCreateLoop(Map<MergeNode, Loop> unorderedLoops, MergeNode loopHeader) {
1394        assert methodScope.loopExplosionMerges.isMarkedAndGrow(loopHeader) : loopHeader;
1395        Loop loop = unorderedLoops.get(loopHeader);
1396        if (loop == null) {
1397            loop = new Loop();
1398            loop.header = loopHeader;
1399            unorderedLoops.put(loopHeader, loop);
1400        }
1401        return loop;
1402    }
1403
1404    private void findLoopExits(Loop loop) {
1405        /*
1406         * Backward marking of loop nodes: Starting with the known loop ends, we mark all nodes that
1407         * are reachable until we hit the loop begin. All successors of loop nodes that are not
1408         * marked as loop nodes themselves are exits of the loop. We mark all successors, and then
1409         * subtract the loop nodes, to find the exits.
1410         */
1411
1412        NodeBitMap possibleExits = methodScope.graph.createNodeBitMap();
1413        NodeBitMap visited = methodScope.graph.createNodeBitMap();
1414        Deque<Node> stack = new ArrayDeque<>();
1415        for (EndNode loopEnd : loop.ends) {
1416            stack.push(loopEnd);
1417            visited.mark(loopEnd);
1418        }
1419
1420        while (!stack.isEmpty()) {
1421            Node current = stack.pop();
1422            if (current == loop.header) {
1423                continue;
1424            }
1425            if (!methodScope.graph.isNew(methodScope.methodStartMark, current)) {
1426                /*
1427                 * The current node is before the method that contains the exploded loop. The loop
1428                 * must have a second entry point, i.e., it is an irreducible loop.
1429                 */
1430                loop.irreducible = true;
1431                return;
1432            }
1433
1434            for (Node predecessor : current.cfgPredecessors()) {
1435                if (predecessor instanceof LoopExitNode) {
1436                    /*
1437                     * Inner loop. We do not need to mark every node of it, instead we just continue
1438                     * marking at the loop header.
1439                     */
1440                    LoopBeginNode innerLoopBegin = ((LoopExitNode) predecessor).loopBegin();
1441                    if (!visited.isMarked(innerLoopBegin)) {
1442                        stack.push(innerLoopBegin);
1443                        visited.mark(innerLoopBegin);
1444
1445                        /*
1446                         * All loop exits of the inner loop possibly need a LoopExit of our loop.
1447                         * Because we are processing inner loops first, we are guaranteed to already
1448                         * have all exits of the inner loop.
1449                         */
1450                        for (LoopExitNode exit : innerLoopBegin.loopExits()) {
1451                            possibleExits.mark(exit);
1452                        }
1453                    }
1454
1455                } else if (!visited.isMarked(predecessor)) {
1456                    stack.push(predecessor);
1457                    visited.mark(predecessor);
1458
1459                    if (predecessor instanceof ControlSplitNode) {
1460                        for (Node succ : predecessor.cfgSuccessors()) {
1461                            /*
1462                             * We would not need to mark the current node, and would not need to
1463                             * mark visited nodes. But it is easier to just mark everything, since
1464                             * we subtract all visited nodes in the end anyway. Note that at this
1465                             * point we do not have the complete visited information, so we would
1466                             * always mark too many possible exits.
1467                             */
1468                            possibleExits.mark(succ);
1469                        }
1470                    }
1471                }
1472            }
1473        }
1474
1475        /* All visited nodes are not exits of our loop. */
1476        possibleExits.subtract(visited);
1477
1478        /*
1479         * Now we know all the actual loop exits. Ideally, we would insert LoopExit nodes for them.
1480         * However, a LoopExit needs a valid FrameState that captures the state at the point where
1481         * we exit the loop. During graph decoding, we create a FrameState for every exploded loop
1482         * iteration. We need to do a forward marking until we hit the next such point. This puts
1483         * some nodes into the loop that are actually not part of the loop.
1484         *
1485         * In some cases, we did not create a FrameState during graph decoding: when there was no
1486         * LoopExit in the original loop that we exploded. This happens for code paths that lead
1487         * immediately to a DeoptimizeNode.
1488         *
1489         * Both cases mimic the behavior of the BytecodeParser, which also puts more nodes than
1490         * necessary into a loop because it computes loop information based on bytecodes, before the
1491         * actual parsing.
1492         */
1493
1494        for (Node succ : possibleExits) {
1495            stack.push(succ);
1496            visited.mark(succ);
1497            assert !methodScope.loopExplosionMerges.isMarkedAndGrow(succ);
1498        }
1499
1500        while (!stack.isEmpty()) {
1501            Node current = stack.pop();
1502            assert visited.isMarked(current);
1503            assert current instanceof ControlSinkNode || current instanceof LoopEndNode || current.cfgSuccessors().iterator().hasNext() : "Must not reach a node that has not been decoded yet";
1504
1505            for (Node successor : current.cfgSuccessors()) {
1506                if (visited.isMarked(successor)) {
1507                    /* Already processed this successor. */
1508
1509                } else if (methodScope.loopExplosionMerges.isMarkedAndGrow(successor)) {
1510                    /*
1511                     * We have a FrameState for the successor. The LoopExit will be inserted between
1512                     * the current node and the successor node. Since the successor node is a
1513                     * MergeNode, the current node mus be a AbstractEndNode with only that MergeNode
1514                     * as the successor.
1515                     */
1516                    assert successor instanceof MergeNode;
1517                    assert !loop.exits.contains(current);
1518                    loop.exits.add((AbstractEndNode) current);
1519
1520                } else {
1521                    /* Node we have not seen yet. */
1522                    visited.mark(successor);
1523                    stack.push(successor);
1524                }
1525            }
1526        }
1527    }
1528
1529    private void insertLoopNodes(Loop loop) {
1530        MergeNode merge = loop.header;
1531        FrameState stateAfter = merge.stateAfter().duplicate();
1532        FixedNode afterMerge = merge.next();
1533        merge.setNext(null);
1534        EndNode preLoopEnd = methodScope.graph.add(new EndNode());
1535        LoopBeginNode loopBegin = methodScope.graph.add(new LoopBeginNode());
1536
1537        merge.setNext(preLoopEnd);
1538        /* Add the single non-loop predecessor of the loop header. */
1539        loopBegin.addForwardEnd(preLoopEnd);
1540        loopBegin.setNext(afterMerge);
1541        loopBegin.setStateAfter(stateAfter);
1542
1543        /*
1544         * Phi functions of the original merge need to be split: inputs that come from forward edges
1545         * remain with the original phi function; inputs that come from backward edges are added to
1546         * new phi functions.
1547         */
1548        List<PhiNode> mergePhis = merge.phis().snapshot();
1549        List<PhiNode> loopBeginPhis = new ArrayList<>(mergePhis.size());
1550        for (int i = 0; i < mergePhis.size(); i++) {
1551            PhiNode mergePhi = mergePhis.get(i);
1552            PhiNode loopBeginPhi = methodScope.graph.addWithoutUnique(new ValuePhiNode(mergePhi.stamp(), loopBegin));
1553            mergePhi.replaceAtUsages(loopBeginPhi);
1554            /*
1555             * The first input of the new phi function is the original phi function, for the one
1556             * forward edge of the LoopBeginNode.
1557             */
1558            loopBeginPhi.addInput(mergePhi);
1559            loopBeginPhis.add(loopBeginPhi);
1560        }
1561
1562        for (EndNode endNode : loop.ends) {
1563            for (int i = 0; i < mergePhis.size(); i++) {
1564                PhiNode mergePhi = mergePhis.get(i);
1565                PhiNode loopBeginPhi = loopBeginPhis.get(i);
1566                loopBeginPhi.addInput(mergePhi.valueAt(endNode));
1567            }
1568
1569            merge.removeEnd(endNode);
1570            LoopEndNode loopEnd = methodScope.graph.add(new LoopEndNode(loopBegin));
1571            endNode.replaceAndDelete(loopEnd);
1572        }
1573
1574        /*
1575         * Insert the LoopExit nodes (the easy part) and compute the FrameState for the new exits
1576         * (the difficult part).
1577         */
1578        for (AbstractEndNode exit : loop.exits) {
1579            AbstractMergeNode loopExplosionMerge = exit.merge();
1580            assert methodScope.loopExplosionMerges.isMarkedAndGrow(loopExplosionMerge);
1581
1582            LoopExitNode loopExit = methodScope.graph.add(new LoopExitNode(loopBegin));
1583            exit.replaceAtPredecessor(loopExit);
1584            loopExit.setNext(exit);
1585            assignLoopExitState(loopExit, loopExplosionMerge, exit);
1586        }
1587    }
1588
1589    /**
1590     * During graph decoding, we create a FrameState for every exploded loop iteration. This is
1591     * mostly the state that we want, we only need to tweak it a little bit: we need to insert the
1592     * appropriate ProxyNodes for all values that are created inside the loop and that flow out of
1593     * the loop.
1594     */
1595    private void assignLoopExitState(LoopExitNode loopExit, AbstractMergeNode loopExplosionMerge, AbstractEndNode loopExplosionEnd) {
1596        FrameState oldState = loopExplosionMerge.stateAfter();
1597
1598        /* Collect all nodes that are in the FrameState at the LoopBegin. */
1599        NodeBitMap loopBeginValues = new NodeBitMap(methodScope.graph);
1600        for (FrameState state = loopExit.loopBegin().stateAfter(); state != null; state = state.outerFrameState()) {
1601            for (ValueNode value : state.values()) {
1602                if (value != null && !value.isConstant() && !loopExit.loopBegin().isPhiAtMerge(value)) {
1603                    loopBeginValues.mark(ProxyPlaceholder.unwrap(value));
1604                }
1605            }
1606        }
1607
1608        List<ValueNode> newValues = new ArrayList<>(oldState.values().size());
1609        for (ValueNode v : oldState.values()) {
1610            ValueNode value = v;
1611            ValueNode realValue = ProxyPlaceholder.unwrap(value);
1612
1613            /*
1614             * The LoopExit is inserted before the existing merge, i.e., separately for every branch
1615             * that leads to the merge. So for phi functions of the merge, we need to take the input
1616             * that corresponds to our branch.
1617             */
1618            if (realValue instanceof PhiNode && loopExplosionMerge.isPhiAtMerge(realValue)) {
1619                value = ((PhiNode) realValue).valueAt(loopExplosionEnd);
1620                realValue = ProxyPlaceholder.unwrap(value);
1621            }
1622
1623            if (realValue == null || realValue.isConstant() || loopBeginValues.contains(realValue) || !methodScope.graph.isNew(methodScope.methodStartMark, realValue)) {
1624                newValues.add(realValue);
1625            } else {
1626                /*
1627                 * The node is not in the FrameState of the LoopBegin, i.e., it is a value computed
1628                 * inside the loop.
1629                 */
1630                GraalError.guarantee(value instanceof ProxyPlaceholder && ((ProxyPlaceholder) value).proxyPoint == loopExplosionMerge,
1631                                "Value flowing out of loop, but we are not prepared to insert a ProxyNode");
1632
1633                ProxyPlaceholder proxyPlaceholder = (ProxyPlaceholder) value;
1634                ValueProxyNode proxy = ProxyNode.forValue(proxyPlaceholder.value, loopExit, methodScope.graph);
1635                proxyPlaceholder.setValue(proxy);
1636                newValues.add(proxy);
1637            }
1638        }
1639
1640        FrameState newState = new FrameState(oldState.outerFrameState(), oldState.getCode(), oldState.bci, newValues, oldState.localsSize(), oldState.stackSize(), oldState.rethrowException(),
1641                        oldState.duringCall(), oldState.monitorIds(), oldState.virtualObjectMappings());
1642
1643        assert loopExit.stateAfter() == null;
1644        loopExit.setStateAfter(methodScope.graph.add(newState));
1645    }
1646
1647    /**
1648     * Graal does not support irreducible loops (loops with more than one entry point). There are
1649     * two ways to make them reducible: 1) duplicate nodes (peel a loop iteration starting at the
1650     * second entry point until we reach the first entry point), or 2) insert a big outer loop
1651     * covering the whole method and build a state machine for the different loop entry points.
1652     * Since node duplication can lead to an exponential explosion of nodes in the worst case, we
1653     * use the second approach.
1654     *
1655     * We already did some preparations to insert a big outer loop:
1656     * {@link MethodScope#loopExplosionHead} is the loop header for the outer loop, and we ensured
1657     * that we have a {@link Loop} data object for it in {@link #irreducibleLoopHandler}.
1658     *
1659     * Now we need to insert the state machine. We have several implementation restrictions to make
1660     * that efficient:
1661     * <ul>
1662     * <li>There must be only one loop variable, i.e., one value that is different in the
1663     * {@link FrameState} of the different loop headers.</li>
1664     * <li>The loop variable must use the primitive {@code int} type, because Graal only has a
1665     * {@link IntegerSwitchNode switch node} for {@code int}.</li>
1666     * <li>The values of the loop variable that are merged are {@link PrimitiveConstant compile time
1667     * constants}.</li>
1668     * </ul>
1669     */
1670    private void handleIrreducibleLoop(Loop loop) {
1671        assert loop != irreducibleLoopHandler;
1672
1673        FrameState loopState = loop.header.stateAfter();
1674        FrameState explosionHeadState = irreducibleLoopHandler.header.stateAfter();
1675        assert loopState.outerFrameState() == explosionHeadState.outerFrameState();
1676        NodeInputList<ValueNode> loopValues = loopState.values();
1677        NodeInputList<ValueNode> explosionHeadValues = explosionHeadState.values();
1678        assert loopValues.size() == explosionHeadValues.size();
1679
1680        /*
1681         * Find the loop variable, and the value of the loop variable for our loop and the outermost
1682         * loop. There must be exactly one loop variable.
1683         */
1684        int loopVariableIndex = -1;
1685        ValueNode loopValue = null;
1686        ValueNode explosionHeadValue = null;
1687        for (int i = 0; i < loopValues.size(); i++) {
1688            ValueNode curLoopValue = loopValues.get(i);
1689            ValueNode curExplosionHeadValue = explosionHeadValues.get(i);
1690
1691            if (curLoopValue != curExplosionHeadValue) {
1692                if (loopVariableIndex != -1) {
1693                    throw bailout("must have only one variable that is changed in loop. " + loopValue + " != " + explosionHeadValue + " and " + curLoopValue + " != " + curExplosionHeadValue);
1694                }
1695
1696                loopVariableIndex = i;
1697                loopValue = curLoopValue;
1698                explosionHeadValue = curExplosionHeadValue;
1699            }
1700        }
1701        assert loopVariableIndex != -1;
1702
1703        ValuePhiNode loopVariablePhi;
1704        SortedMap<Integer, AbstractBeginNode> dispatchTable = new TreeMap<>();
1705        AbstractBeginNode unreachableDefaultSuccessor;
1706        if (irreducibleLoopSwitch == null) {
1707            /*
1708             * This is the first irreducible loop. We need to build the initial state machine
1709             * (dispatch for the loop header of the outermost loop).
1710             */
1711            assert !irreducibleLoopHandler.header.isPhiAtMerge(explosionHeadValue);
1712            assert irreducibleLoopHandler.header.phis().isEmpty();
1713
1714            /* The new phi function for the loop variable. */
1715            loopVariablePhi = methodScope.graph.addWithoutUnique(new ValuePhiNode(explosionHeadValue.stamp().unrestricted(), irreducibleLoopHandler.header));
1716            for (int i = 0; i < irreducibleLoopHandler.header.phiPredecessorCount(); i++) {
1717                loopVariablePhi.addInput(explosionHeadValue);
1718            }
1719
1720            /*
1721             * Build the new FrameState for the loop header. There is only once change in comparison
1722             * to the old FrameState: the loop variable is replaced with the phi function.
1723             */
1724            FrameState oldFrameState = explosionHeadState;
1725            List<ValueNode> newFrameStateValues = new ArrayList<>();
1726            for (int i = 0; i < explosionHeadValues.size(); i++) {
1727                if (i == loopVariableIndex) {
1728                    newFrameStateValues.add(loopVariablePhi);
1729                } else {
1730                    newFrameStateValues.add(explosionHeadValues.get(i));
1731                }
1732            }
1733            FrameState newFrameState = methodScope.graph.add(
1734                            new FrameState(oldFrameState.outerFrameState(), oldFrameState.getCode(), oldFrameState.bci, newFrameStateValues, oldFrameState.localsSize(),
1735                                            oldFrameState.stackSize(), oldFrameState.rethrowException(), oldFrameState.duringCall(), oldFrameState.monitorIds(),
1736                                            oldFrameState.virtualObjectMappings()));
1737            oldFrameState.replaceAtUsages(newFrameState);
1738
1739            /*
1740             * Disconnect the outermost loop header from its loop body, so that we can later on
1741             * insert the switch node. Collect dispatch information for the outermost loop.
1742             */
1743            FixedNode handlerNext = irreducibleLoopHandler.header.next();
1744            irreducibleLoopHandler.header.setNext(null);
1745            BeginNode handlerBegin = methodScope.graph.add(new BeginNode());
1746            handlerBegin.setNext(handlerNext);
1747            dispatchTable.put(asInt(explosionHeadValue), handlerBegin);
1748
1749            /*
1750             * We know that there will always be a matching key in the switch. But Graal always
1751             * wants a default successor, so we build a dummy block that just deoptimizes.
1752             */
1753            unreachableDefaultSuccessor = methodScope.graph.add(new BeginNode());
1754            DeoptimizeNode deopt = methodScope.graph.add(new DeoptimizeNode(DeoptimizationAction.InvalidateRecompile, DeoptimizationReason.UnreachedCode));
1755            unreachableDefaultSuccessor.setNext(deopt);
1756
1757        } else {
1758            /*
1759             * This is the second or a subsequent irreducible loop, i.e., we already inserted a
1760             * switch node before. We re-create the dispatch state machine of that switch, so that
1761             * we can extend it with one more branch.
1762             */
1763            assert irreducibleLoopHandler.header.isPhiAtMerge(explosionHeadValue);
1764            assert irreducibleLoopHandler.header.phis().count() == 1 && irreducibleLoopHandler.header.phis().first() == explosionHeadValue;
1765            assert irreducibleLoopSwitch.value() == explosionHeadValue;
1766
1767            /* We can modify the phi function used by the old switch node. */
1768            loopVariablePhi = (ValuePhiNode) explosionHeadValue;
1769
1770            /*
1771             * We cannot modify the old switch node. Insert all information from the old switch node
1772             * into our temporary data structures for the new, larger, switch node.
1773             */
1774            for (int i = 0; i < irreducibleLoopSwitch.keyCount(); i++) {
1775                int key = irreducibleLoopSwitch.keyAt(i).asInt();
1776                dispatchTable.put(key, irreducibleLoopSwitch.successorAtKey(key));
1777            }
1778            unreachableDefaultSuccessor = irreducibleLoopSwitch.defaultSuccessor();
1779
1780            /* Unlink and delete the old switch node, we do not need it anymore. */
1781            assert irreducibleLoopHandler.header.next() == irreducibleLoopSwitch;
1782            irreducibleLoopHandler.header.setNext(null);
1783            irreducibleLoopSwitch.clearSuccessors();
1784            irreducibleLoopSwitch.safeDelete();
1785        }
1786
1787        /* Insert our loop into the dispatch state machine. */
1788        assert loop.header.phis().isEmpty();
1789        BeginNode dispatchBegin = methodScope.graph.add(new BeginNode());
1790        EndNode dispatchEnd = methodScope.graph.add(new EndNode());
1791        dispatchBegin.setNext(dispatchEnd);
1792        loop.header.addForwardEnd(dispatchEnd);
1793        int intLoopValue = asInt(loopValue);
1794        assert !dispatchTable.containsKey(intLoopValue);
1795        dispatchTable.put(intLoopValue, dispatchBegin);
1796
1797        /* Disconnect the ends of our loop and re-connect them to the outermost loop header. */
1798        for (EndNode end : loop.ends) {
1799            loop.header.removeEnd(end);
1800            irreducibleLoopHandler.ends.add(end);
1801            irreducibleLoopHandler.header.addForwardEnd(end);
1802            loopVariablePhi.addInput(loopValue);
1803        }
1804
1805        /* Build and insert the switch node. */
1806        irreducibleLoopSwitch = methodScope.graph.add(createSwitch(loopVariablePhi, dispatchTable, unreachableDefaultSuccessor));
1807        irreducibleLoopHandler.header.setNext(irreducibleLoopSwitch);
1808    }
1809
1810    private static int asInt(ValueNode node) {
1811        if (!node.isConstant() || node.asJavaConstant().getJavaKind() != JavaKind.Int) {
1812            throw bailout("must have a loop variable of type int. " + node);
1813        }
1814        return node.asJavaConstant().asInt();
1815    }
1816
1817    private static RuntimeException bailout(String msg) {
1818        throw new PermanentBailoutException("Graal implementation restriction: Method with %s loop explosion %s", LoopExplosionKind.MERGE_EXPLODE, msg);
1819    }
1820
1821    private static IntegerSwitchNode createSwitch(ValuePhiNode switchedValue, SortedMap<Integer, AbstractBeginNode> dispatchTable, AbstractBeginNode defaultSuccessor) {
1822        int numKeys = dispatchTable.size();
1823        int numSuccessors = numKeys + 1;
1824
1825        AbstractBeginNode[] switchSuccessors = new AbstractBeginNode[numSuccessors];
1826        int[] switchKeys = new int[numKeys];
1827        double[] switchKeyProbabilities = new double[numSuccessors];
1828        int[] switchKeySuccessors = new int[numSuccessors];
1829
1830        int idx = 0;
1831        for (Map.Entry<Integer, AbstractBeginNode> entry : dispatchTable.entrySet()) {
1832            switchSuccessors[idx] = entry.getValue();
1833            switchKeys[idx] = entry.getKey();
1834            switchKeyProbabilities[idx] = 1d / numKeys;
1835            switchKeySuccessors[idx] = idx;
1836            idx++;
1837        }
1838        switchSuccessors[idx] = defaultSuccessor;
1839        /* We know the default branch is never going to be executed. */
1840        switchKeyProbabilities[idx] = 0;
1841        switchKeySuccessors[idx] = idx;
1842
1843        return new IntegerSwitchNode(switchedValue, switchSuccessors, switchKeys, switchKeyProbabilities, switchKeySuccessors);
1844    }
1845
1846    /**
1847     * Print information about irreducible loops, when enabled with -Dgraal.Log=IrreducibleLoops.
1848     */
1849    @SuppressWarnings("try")
1850    private void logIrreducibleLoops() {
1851        try (Debug.Scope s = Debug.scope("IrreducibleLoops")) {
1852            if (Debug.isLogEnabled(Debug.BASIC_LOG_LEVEL) && irreducibleLoopSwitch != null) {
1853                StringBuilder msg = new StringBuilder("Inserted state machine to remove irreducible loops. Dispatching to the following states: ");
1854                String sep = "";
1855                for (int i = 0; i < irreducibleLoopSwitch.keyCount(); i++) {
1856                    msg.append(sep).append(irreducibleLoopSwitch.keyAt(i).asInt());
1857                    sep = ", ";
1858                }
1859                Debug.log(Debug.BASIC_LOG_LEVEL, "%s", msg);
1860            }
1861        }
1862    }
1863}
1864