1 /*
   2  * Copyright (c) 2011, 2012, 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.Iterator;
  29 import java.util.List;
  30 import java.util.Map;
  31 
  32 import org.graalvm.compiler.graph.Node;
  33 import org.graalvm.compiler.nodes.AbstractBeginNode;
  34 import org.graalvm.compiler.nodes.AbstractEndNode;
  35 import org.graalvm.compiler.nodes.AbstractMergeNode;
  36 import org.graalvm.compiler.nodes.EndNode;
  37 import org.graalvm.compiler.nodes.FixedNode;
  38 import org.graalvm.compiler.nodes.FixedWithNextNode;
  39 import org.graalvm.compiler.nodes.LoopBeginNode;
  40 import org.graalvm.compiler.nodes.LoopEndNode;
  41 import org.graalvm.compiler.nodes.LoopExitNode;
  42 
  43 public final class ReentrantNodeIterator {
  44 
  45     public static class LoopInfo<StateT> {
  46 
  47         public final Map<LoopEndNode, StateT> endStates;
  48         public final Map<LoopExitNode, StateT> exitStates;
  49 
  50         public LoopInfo(int endCount, int exitCount) {
  51             endStates = Node.newIdentityMap(endCount);
  52             exitStates = Node.newIdentityMap(exitCount);
  53         }
  54     }
  55 
  56     public abstract static class NodeIteratorClosure<StateT> {
  57 
  58         protected abstract StateT processNode(FixedNode node, StateT currentState);
  59 
  60         protected abstract StateT merge(AbstractMergeNode merge, List<StateT> states);
  61 
  62         protected abstract StateT afterSplit(AbstractBeginNode node, StateT oldState);
  63 
  64         protected abstract Map<LoopExitNode, StateT> processLoop(LoopBeginNode loop, StateT initialState);
  65 
  66         /**
  67          * Determine whether iteration should continue in the current state.
  68          *
  69          * @param currentState
  70          */
  71         protected boolean continueIteration(StateT currentState) {
  72             return true;
  73         }
  74     }
  75 
  76     private ReentrantNodeIterator() {
  77         // no instances allowed
  78     }
  79 
  80     public static <StateT> LoopInfo<StateT> processLoop(NodeIteratorClosure<StateT> closure, LoopBeginNode loop, StateT initialState) {
  81         Map<FixedNode, StateT> blockEndStates = apply(closure, loop, initialState, loop);
  82 
  83         LoopInfo<StateT> info = new LoopInfo<>(loop.loopEnds().count(), loop.loopExits().count());
  84         for (LoopEndNode end : loop.loopEnds()) {
  85             if (blockEndStates.containsKey(end)) {
  86                 info.endStates.put(end, blockEndStates.get(end));
  87             }
  88         }
  89         for (LoopExitNode exit : loop.loopExits()) {
  90             if (blockEndStates.containsKey(exit)) {
  91                 info.exitStates.put(exit, blockEndStates.get(exit));
  92             }
  93         }
  94         return info;
  95     }
  96 
  97     public static <StateT> void apply(NodeIteratorClosure<StateT> closure, FixedNode start, StateT initialState) {
  98         apply(closure, start, initialState, null);
  99     }
 100 
 101     private static <StateT> Map<FixedNode, StateT> apply(NodeIteratorClosure<StateT> closure, FixedNode start, StateT initialState, LoopBeginNode boundary) {
 102         assert start != null;
 103         Deque<AbstractBeginNode> nodeQueue = new ArrayDeque<>();
 104         Map<FixedNode, StateT> blockEndStates = Node.newIdentityMap();
 105 
 106         StateT state = initialState;
 107         FixedNode current = start;
 108         do {
 109             while (current instanceof FixedWithNextNode) {
 110                 if (boundary != null && current instanceof LoopExitNode && ((LoopExitNode) current).loopBegin() == boundary) {
 111                     blockEndStates.put(current, state);
 112                     current = null;
 113                 } else {
 114                     FixedNode next = ((FixedWithNextNode) current).next();
 115                     state = closure.processNode(current, state);
 116                     current = closure.continueIteration(state) ? next : null;
 117                 }
 118             }
 119 
 120             if (current != null) {
 121                 state = closure.processNode(current, state);
 122 
 123                 if (closure.continueIteration(state)) {
 124                     Iterator<Node> successors = current.successors().iterator();
 125                     if (!successors.hasNext()) {
 126                         if (current instanceof LoopEndNode) {
 127                             blockEndStates.put(current, state);
 128                         } else if (current instanceof EndNode) {
 129                             // add the end node and see if the merge is ready for processing
 130                             AbstractMergeNode merge = ((EndNode) current).merge();
 131                             if (merge instanceof LoopBeginNode) {
 132                                 Map<LoopExitNode, StateT> loopExitState = closure.processLoop((LoopBeginNode) merge, state);
 133                                 for (Map.Entry<LoopExitNode, StateT> entry : loopExitState.entrySet()) {
 134                                     blockEndStates.put(entry.getKey(), entry.getValue());
 135                                     nodeQueue.add(entry.getKey());
 136                                 }
 137                             } else {
 138                                 boolean endsVisited = true;
 139                                 for (AbstractEndNode forwardEnd : merge.forwardEnds()) {
 140                                     if (forwardEnd != current && !blockEndStates.containsKey(forwardEnd)) {
 141                                         endsVisited = false;
 142                                         break;
 143                                     }
 144                                 }
 145                                 if (endsVisited) {
 146                                     ArrayList<StateT> states = new ArrayList<>(merge.forwardEndCount());
 147                                     for (int i = 0; i < merge.forwardEndCount(); i++) {
 148                                         AbstractEndNode forwardEnd = merge.forwardEndAt(i);
 149                                         assert forwardEnd == current || blockEndStates.containsKey(forwardEnd);
 150                                         StateT other = forwardEnd == current ? state : blockEndStates.remove(forwardEnd);
 151                                         states.add(other);
 152                                     }
 153                                     state = closure.merge(merge, states);
 154                                     current = closure.continueIteration(state) ? merge : null;
 155                                     continue;
 156                                 } else {
 157                                     assert !blockEndStates.containsKey(current);
 158                                     blockEndStates.put(current, state);
 159                                 }
 160                             }
 161                         }
 162                     } else {
 163                         FixedNode firstSuccessor = (FixedNode) successors.next();
 164                         if (!successors.hasNext()) {
 165                             current = firstSuccessor;
 166                             continue;
 167                         } else {
 168                             do {
 169                                 AbstractBeginNode successor = (AbstractBeginNode) successors.next();
 170                                 StateT successorState = closure.afterSplit(successor, state);
 171                                 if (closure.continueIteration(successorState)) {
 172                                     blockEndStates.put(successor, successorState);
 173                                     nodeQueue.add(successor);
 174                                 }
 175                             } while (successors.hasNext());
 176 
 177                             state = closure.afterSplit((AbstractBeginNode) firstSuccessor, state);
 178                             current = closure.continueIteration(state) ? firstSuccessor : null;
 179                             continue;
 180                         }
 181                     }
 182                 }
 183             }
 184 
 185             // get next queued block
 186             if (nodeQueue.isEmpty()) {
 187                 return blockEndStates;
 188             } else {
 189                 current = nodeQueue.removeFirst();
 190                 assert blockEndStates.containsKey(current);
 191                 state = blockEndStates.remove(current);
 192                 assert !(current instanceof AbstractMergeNode) && current instanceof AbstractBeginNode;
 193             }
 194         } while (true);
 195     }
 196 }