1 /*
   2  * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 package org.graalvm.compiler.phases.graph;
  24 
  25 import java.util.ArrayDeque;
  26 import java.util.ArrayList;
  27 import java.util.Deque;
  28 import java.util.Map;
  29 import java.util.Set;
  30 
  31 import org.graalvm.compiler.graph.Node;
  32 import org.graalvm.compiler.graph.NodeBitMap;
  33 import org.graalvm.compiler.nodes.AbstractBeginNode;
  34 import org.graalvm.compiler.nodes.AbstractMergeNode;
  35 import org.graalvm.compiler.nodes.ControlSinkNode;
  36 import org.graalvm.compiler.nodes.ControlSplitNode;
  37 import org.graalvm.compiler.nodes.EndNode;
  38 import org.graalvm.compiler.nodes.FixedNode;
  39 import org.graalvm.compiler.nodes.FixedWithNextNode;
  40 import org.graalvm.compiler.nodes.Invoke;
  41 import org.graalvm.compiler.nodes.InvokeWithExceptionNode;
  42 import org.graalvm.compiler.nodes.LoopBeginNode;
  43 import org.graalvm.compiler.nodes.LoopEndNode;
  44 import org.graalvm.compiler.nodes.StructuredGraph;
  45 
  46 /**
  47  * A PostOrderNodeIterator iterates the fixed nodes of the graph in post order starting from a
  48  * specified fixed node.
  49  * <p>
  50  * For this iterator the CFG is defined by the classical CFG nodes ({@link ControlSplitNode},
  51  * {@link AbstractMergeNode}...) and the {@link FixedWithNextNode#next() next} pointers of
  52  * {@link FixedWithNextNode}.
  53  * <p>
  54  * While iterating it maintains a user-defined state by calling the methods available in
  55  * {@link MergeableState}.
  56  *
  57  * @param <T> the type of {@link MergeableState} handled by this PostOrderNodeIterator
  58  */
  59 public abstract class PostOrderNodeIterator<T extends MergeableState<T>> {
  60 
  61     private final NodeBitMap visitedEnds;
  62     private final Deque<AbstractBeginNode> nodeQueue;
  63     private final Map<FixedNode, T> nodeStates;
  64     private final FixedNode start;
  65 
  66     protected T state;
  67 
  68     public PostOrderNodeIterator(FixedNode start, T initialState) {
  69         StructuredGraph graph = start.graph();
  70         visitedEnds = graph.createNodeBitMap();
  71         nodeQueue = new ArrayDeque<>();
  72         nodeStates = Node.newIdentityMap();
  73         this.start = start;
  74         this.state = initialState;
  75     }
  76 
  77     public void apply() {
  78         FixedNode current = start;
  79 
  80         do {
  81             if (current instanceof InvokeWithExceptionNode) {
  82                 invoke((Invoke) current);
  83                 queueSuccessors(current, null);
  84                 current = nextQueuedNode();
  85             } else if (current instanceof LoopBeginNode) {
  86                 state.loopBegin((LoopBeginNode) current);
  87                 nodeStates.put(current, state);
  88                 state = state.clone();
  89                 loopBegin((LoopBeginNode) current);
  90                 current = ((LoopBeginNode) current).next();
  91                 assert current != null;
  92             } else if (current instanceof LoopEndNode) {
  93                 loopEnd((LoopEndNode) current);
  94                 finishLoopEnds((LoopEndNode) current);
  95                 current = nextQueuedNode();
  96             } else if (current instanceof AbstractMergeNode) {
  97                 merge((AbstractMergeNode) current);
  98                 current = ((AbstractMergeNode) current).next();
  99                 assert current != null;
 100             } else if (current instanceof FixedWithNextNode) {
 101                 FixedNode next = ((FixedWithNextNode) current).next();
 102                 assert next != null : current;
 103                 node(current);
 104                 current = next;
 105             } else if (current instanceof EndNode) {
 106                 end((EndNode) current);
 107                 queueMerge((EndNode) current);
 108                 current = nextQueuedNode();
 109             } else if (current instanceof ControlSinkNode) {
 110                 node(current);
 111                 current = nextQueuedNode();
 112             } else if (current instanceof ControlSplitNode) {
 113                 Set<Node> successors = controlSplit((ControlSplitNode) current);
 114                 queueSuccessors(current, successors);
 115                 current = nextQueuedNode();
 116             } else {
 117                 assert false : current;
 118             }
 119         } while (current != null);
 120         finished();
 121     }
 122 
 123     private void queueSuccessors(FixedNode x, Set<Node> successors) {
 124         nodeStates.put(x, state);
 125         if (successors != null) {
 126             for (Node node : successors) {
 127                 if (node != null) {
 128                     nodeStates.put((FixedNode) node.predecessor(), state);
 129                     nodeQueue.addFirst((AbstractBeginNode) node);
 130                 }
 131             }
 132         } else {
 133             for (Node node : x.successors()) {
 134                 if (node != null) {
 135                     nodeQueue.addFirst((AbstractBeginNode) node);
 136                 }
 137             }
 138         }
 139     }
 140 
 141     private FixedNode nextQueuedNode() {
 142         int maxIterations = nodeQueue.size();
 143         while (maxIterations-- > 0) {
 144             AbstractBeginNode node = nodeQueue.removeFirst();
 145             if (node instanceof AbstractMergeNode) {
 146                 AbstractMergeNode merge = (AbstractMergeNode) node;
 147                 state = nodeStates.get(merge.forwardEndAt(0)).clone();
 148                 ArrayList<T> states = new ArrayList<>(merge.forwardEndCount() - 1);
 149                 for (int i = 1; i < merge.forwardEndCount(); i++) {
 150                     T other = nodeStates.get(merge.forwardEndAt(i));
 151                     assert other != null;
 152                     states.add(other);
 153                 }
 154                 boolean ready = state.merge(merge, states);
 155                 if (ready) {
 156                     return merge;
 157                 } else {
 158                     nodeQueue.addLast(merge);
 159                 }
 160             } else {
 161                 assert node.predecessor() != null;
 162                 state = nodeStates.get(node.predecessor()).clone();
 163                 state.afterSplit(node);
 164                 return node;
 165             }
 166         }
 167         return null;
 168     }
 169 
 170     private void finishLoopEnds(LoopEndNode end) {
 171         assert !visitedEnds.isMarked(end);
 172         assert !nodeStates.containsKey(end);
 173         nodeStates.put(end, state);
 174         visitedEnds.mark(end);
 175         LoopBeginNode begin = end.loopBegin();
 176         boolean endsVisited = true;
 177         for (LoopEndNode le : begin.loopEnds()) {
 178             if (!visitedEnds.isMarked(le)) {
 179                 endsVisited = false;
 180                 break;
 181             }
 182         }
 183         if (endsVisited) {
 184             ArrayList<T> states = new ArrayList<>(begin.loopEnds().count());
 185             for (LoopEndNode le : begin.orderedLoopEnds()) {
 186                 states.add(nodeStates.get(le));
 187             }
 188             T loopBeginState = nodeStates.get(begin);
 189             if (loopBeginState != null) {
 190                 loopBeginState.loopEnds(begin, states);
 191             }
 192         }
 193     }
 194 
 195     private void queueMerge(EndNode end) {
 196         assert !visitedEnds.isMarked(end);
 197         assert !nodeStates.containsKey(end);
 198         nodeStates.put(end, state);
 199         visitedEnds.mark(end);
 200         AbstractMergeNode merge = end.merge();
 201         boolean endsVisited = true;
 202         for (int i = 0; i < merge.forwardEndCount(); i++) {
 203             if (!visitedEnds.isMarked(merge.forwardEndAt(i))) {
 204                 endsVisited = false;
 205                 break;
 206             }
 207         }
 208         if (endsVisited) {
 209             nodeQueue.add(merge);
 210         }
 211     }
 212 
 213     protected abstract void node(FixedNode node);
 214 
 215     protected void end(EndNode endNode) {
 216         node(endNode);
 217     }
 218 
 219     protected void merge(AbstractMergeNode merge) {
 220         node(merge);
 221     }
 222 
 223     protected void loopBegin(LoopBeginNode loopBegin) {
 224         node(loopBegin);
 225     }
 226 
 227     protected void loopEnd(LoopEndNode loopEnd) {
 228         node(loopEnd);
 229     }
 230 
 231     protected Set<Node> controlSplit(ControlSplitNode controlSplit) {
 232         node(controlSplit);
 233         return null;
 234     }
 235 
 236     protected void invoke(Invoke invoke) {
 237         node(invoke.asNode());
 238     }
 239 
 240     protected void finished() {
 241         // nothing to do
 242     }
 243 }