001/*
002 * Copyright (c) 2011, 2011, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.
008 *
009 * This code is distributed in the hope that it will be useful, but WITHOUT
010 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
011 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
012 * version 2 for more details (a copy is included in the LICENSE file that
013 * accompanied this code).
014 *
015 * You should have received a copy of the GNU General Public License version
016 * 2 along with this work; if not, write to the Free Software Foundation,
017 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
018 *
019 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
020 * or visit www.oracle.com if you need additional information or have any
021 * questions.
022 */
023package com.oracle.graal.phases.graph;
024
025import java.util.*;
026
027import com.oracle.graal.graph.*;
028import com.oracle.graal.nodes.*;
029
030/**
031 * A PostOrderNodeIterator iterates the fixed nodes of the graph in post order starting from a
032 * specified fixed node.
033 * <p>
034 * For this iterator the CFG is defined by the classical CFG nodes ({@link ControlSplitNode},
035 * {@link AbstractMergeNode}...) and the {@link FixedWithNextNode#next() next} pointers of
036 * {@link FixedWithNextNode}.
037 * <p>
038 * While iterating it maintains a user-defined state by calling the methods available in
039 * {@link MergeableState}.
040 *
041 * @param <T> the type of {@link MergeableState} handled by this PostOrderNodeIterator
042 */
043public abstract class PostOrderNodeIterator<T extends MergeableState<T>> {
044
045    private final NodeBitMap visitedEnds;
046    private final Deque<AbstractBeginNode> nodeQueue;
047    private final Map<FixedNode, T> nodeStates;
048    private final FixedNode start;
049
050    protected T state;
051
052    public PostOrderNodeIterator(FixedNode start, T initialState) {
053        StructuredGraph graph = start.graph();
054        visitedEnds = graph.createNodeBitMap();
055        nodeQueue = new ArrayDeque<>();
056        nodeStates = Node.newIdentityMap();
057        this.start = start;
058        this.state = initialState;
059    }
060
061    public void apply() {
062        FixedNode current = start;
063
064        do {
065            if (current instanceof InvokeWithExceptionNode) {
066                invoke((Invoke) current);
067                queueSuccessors(current, null);
068                current = nextQueuedNode();
069            } else if (current instanceof LoopBeginNode) {
070                state.loopBegin((LoopBeginNode) current);
071                nodeStates.put(current, state);
072                state = state.clone();
073                loopBegin((LoopBeginNode) current);
074                current = ((LoopBeginNode) current).next();
075                assert current != null;
076            } else if (current instanceof LoopEndNode) {
077                loopEnd((LoopEndNode) current);
078                finishLoopEnds((LoopEndNode) current);
079                current = nextQueuedNode();
080            } else if (current instanceof AbstractMergeNode) {
081                merge((AbstractMergeNode) current);
082                current = ((AbstractMergeNode) current).next();
083                assert current != null;
084            } else if (current instanceof FixedWithNextNode) {
085                FixedNode next = ((FixedWithNextNode) current).next();
086                assert next != null : current;
087                node(current);
088                current = next;
089            } else if (current instanceof EndNode) {
090                end((EndNode) current);
091                queueMerge((EndNode) current);
092                current = nextQueuedNode();
093            } else if (current instanceof ControlSinkNode) {
094                node(current);
095                current = nextQueuedNode();
096            } else if (current instanceof ControlSplitNode) {
097                Set<Node> successors = controlSplit((ControlSplitNode) current);
098                queueSuccessors(current, successors);
099                current = nextQueuedNode();
100            } else {
101                assert false : current;
102            }
103        } while (current != null);
104        finished();
105    }
106
107    private void queueSuccessors(FixedNode x, Set<Node> successors) {
108        nodeStates.put(x, state);
109        if (successors != null) {
110            for (Node node : successors) {
111                if (node != null) {
112                    nodeStates.put((FixedNode) node.predecessor(), state);
113                    nodeQueue.addFirst((AbstractBeginNode) node);
114                }
115            }
116        } else {
117            for (Node node : x.successors()) {
118                if (node != null) {
119                    nodeQueue.addFirst((AbstractBeginNode) node);
120                }
121            }
122        }
123    }
124
125    private FixedNode nextQueuedNode() {
126        int maxIterations = nodeQueue.size();
127        while (maxIterations-- > 0) {
128            AbstractBeginNode node = nodeQueue.removeFirst();
129            if (node instanceof AbstractMergeNode) {
130                AbstractMergeNode merge = (AbstractMergeNode) node;
131                state = nodeStates.get(merge.forwardEndAt(0)).clone();
132                ArrayList<T> states = new ArrayList<>(merge.forwardEndCount() - 1);
133                for (int i = 1; i < merge.forwardEndCount(); i++) {
134                    T other = nodeStates.get(merge.forwardEndAt(i));
135                    assert other != null;
136                    states.add(other);
137                }
138                boolean ready = state.merge(merge, states);
139                if (ready) {
140                    return merge;
141                } else {
142                    nodeQueue.addLast(merge);
143                }
144            } else {
145                assert node.predecessor() != null;
146                state = nodeStates.get(node.predecessor()).clone();
147                state.afterSplit(node);
148                return node;
149            }
150        }
151        return null;
152    }
153
154    private void finishLoopEnds(LoopEndNode end) {
155        assert !visitedEnds.isMarked(end);
156        assert !nodeStates.containsKey(end);
157        nodeStates.put(end, state);
158        visitedEnds.mark(end);
159        LoopBeginNode begin = end.loopBegin();
160        boolean endsVisited = true;
161        for (LoopEndNode le : begin.loopEnds()) {
162            if (!visitedEnds.isMarked(le)) {
163                endsVisited = false;
164                break;
165            }
166        }
167        if (endsVisited) {
168            ArrayList<T> states = new ArrayList<>(begin.loopEnds().count());
169            for (LoopEndNode le : begin.orderedLoopEnds()) {
170                states.add(nodeStates.get(le));
171            }
172            T loopBeginState = nodeStates.get(begin);
173            if (loopBeginState != null) {
174                loopBeginState.loopEnds(begin, states);
175            }
176        }
177    }
178
179    private void queueMerge(EndNode end) {
180        assert !visitedEnds.isMarked(end);
181        assert !nodeStates.containsKey(end);
182        nodeStates.put(end, state);
183        visitedEnds.mark(end);
184        AbstractMergeNode merge = end.merge();
185        boolean endsVisited = true;
186        for (int i = 0; i < merge.forwardEndCount(); i++) {
187            if (!visitedEnds.isMarked(merge.forwardEndAt(i))) {
188                endsVisited = false;
189                break;
190            }
191        }
192        if (endsVisited) {
193            nodeQueue.add(merge);
194        }
195    }
196
197    protected abstract void node(FixedNode node);
198
199    protected void end(EndNode endNode) {
200        node(endNode);
201    }
202
203    protected void merge(AbstractMergeNode merge) {
204        node(merge);
205    }
206
207    protected void loopBegin(LoopBeginNode loopBegin) {
208        node(loopBegin);
209    }
210
211    protected void loopEnd(LoopEndNode loopEnd) {
212        node(loopEnd);
213    }
214
215    protected Set<Node> controlSplit(ControlSplitNode controlSplit) {
216        node(controlSplit);
217        return null;
218    }
219
220    protected void invoke(Invoke invoke) {
221        node(invoke.asNode());
222    }
223
224    protected void finished() {
225        // nothing to do
226    }
227}