001/*
002 * Copyright (c) 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.nodes;
024
025import java.util.*;
026
027import com.oracle.graal.compiler.common.type.*;
028import com.oracle.graal.graph.*;
029import com.oracle.graal.graph.iterators.*;
030import com.oracle.graal.graph.spi.*;
031import com.oracle.graal.nodeinfo.*;
032import com.oracle.graal.nodes.extended.*;
033import com.oracle.graal.nodes.spi.*;
034
035@NodeInfo(allowedUsageTypes = {InputType.Guard, InputType.Anchor})
036public abstract class AbstractBeginNode extends FixedWithNextNode implements LIRLowerable, Simplifiable, GuardingNode, AnchoringNode, IterableNodeType {
037
038    public static final NodeClass<AbstractBeginNode> TYPE = NodeClass.create(AbstractBeginNode.class);
039
040    protected AbstractBeginNode(NodeClass<? extends AbstractBeginNode> c) {
041        this(c, StampFactory.forVoid());
042    }
043
044    protected AbstractBeginNode(NodeClass<? extends AbstractBeginNode> c, Stamp stamp) {
045        super(c, stamp);
046    }
047
048    @Override
049    public void simplify(SimplifierTool tool) {
050        FixedNode prev = (FixedNode) this.predecessor();
051        if (prev == null) {
052            // This is the start node.
053        } else if (prev instanceof ControlSplitNode) {
054            // This begin node is necessary.
055        } else {
056            // This begin node can be removed and all guards moved up to the preceding begin node.
057            prepareDelete();
058            tool.addToWorkList(next());
059            graph().removeFixed(this);
060        }
061    }
062
063    public static AbstractBeginNode prevBegin(FixedNode from) {
064        Node next = from;
065        while (next != null) {
066            if (next instanceof AbstractBeginNode) {
067                AbstractBeginNode begin = (AbstractBeginNode) next;
068                return begin;
069            }
070            next = next.predecessor();
071        }
072        return null;
073    }
074
075    private void evacuateGuards(FixedNode evacuateFrom) {
076        if (!hasNoUsages()) {
077            AbstractBeginNode prevBegin = prevBegin(evacuateFrom);
078            assert prevBegin != null;
079            for (Node anchored : anchored().snapshot()) {
080                anchored.replaceFirstInput(this, prevBegin);
081            }
082        }
083    }
084
085    public void prepareDelete() {
086        prepareDelete((FixedNode) predecessor());
087    }
088
089    public void prepareDelete(FixedNode evacuateFrom) {
090        removeProxies();
091        evacuateGuards(evacuateFrom);
092    }
093
094    public void removeProxies() {
095        if (this.hasUsages()) {
096            outer: while (true) {
097                for (ProxyNode vpn : proxies().snapshot()) {
098                    ValueNode value = vpn.value();
099                    vpn.replaceAtUsages(value);
100                    vpn.safeDelete();
101                    if (value == this) {
102                        // Guard proxy could have this input as value.
103                        continue outer;
104                    }
105                }
106                break;
107            }
108        }
109    }
110
111    @Override
112    public boolean verify() {
113        assertTrue(predecessor() != null || this == graph().start() || this instanceof AbstractMergeNode, "begin nodes must be connected");
114        return super.verify();
115    }
116
117    @Override
118    public void generate(NodeLIRBuilderTool gen) {
119        // nop
120    }
121
122    public NodeIterable<GuardNode> guards() {
123        return usages().filter(GuardNode.class);
124    }
125
126    public NodeIterable<Node> anchored() {
127        return usages().filter(n -> {
128            if (n instanceof ProxyNode) {
129                ProxyNode proxyNode = (ProxyNode) n;
130                return proxyNode.proxyPoint() != this;
131            }
132            return true;
133        });
134    }
135
136    @SuppressWarnings({"unchecked", "rawtypes"})
137    public NodeIterable<ProxyNode> proxies() {
138        return (NodeIterable) usages().filter(n -> {
139            if (n instanceof ProxyNode) {
140                ProxyNode proxyNode = (ProxyNode) n;
141                return proxyNode.proxyPoint() == this;
142            }
143            return false;
144        });
145    }
146
147    public NodeIterable<FixedNode> getBlockNodes() {
148        return new NodeIterable<FixedNode>() {
149
150            @Override
151            public Iterator<FixedNode> iterator() {
152                return new BlockNodeIterator(AbstractBeginNode.this);
153            }
154        };
155    }
156
157    private class BlockNodeIterator implements Iterator<FixedNode> {
158
159        private FixedNode current;
160
161        public BlockNodeIterator(FixedNode next) {
162            this.current = next;
163        }
164
165        @Override
166        public boolean hasNext() {
167            return current != null;
168        }
169
170        @Override
171        public FixedNode next() {
172            FixedNode ret = current;
173            if (ret == null) {
174                throw new NoSuchElementException();
175            }
176            if (!(current instanceof FixedWithNextNode) || (current instanceof AbstractBeginNode && current != AbstractBeginNode.this)) {
177                current = null;
178            } else {
179                current = ((FixedWithNextNode) current).next();
180            }
181            return ret;
182        }
183
184        @Override
185        public void remove() {
186            throw new UnsupportedOperationException();
187        }
188    }
189}