1 /*
2  * Copyright (c) 2012, 2020, 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 
24 
25 package org.graalvm.compiler.nodes;
26 
27 import static org.graalvm.compiler.nodeinfo.InputType.Association;
28 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
29 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
30 
31 import org.graalvm.compiler.graph.IterableNodeType;
32 import org.graalvm.compiler.graph.Node;
33 import org.graalvm.compiler.graph.NodeClass;
34 import org.graalvm.compiler.graph.iterators.NodeIterable;
35 import org.graalvm.compiler.graph.spi.Simplifiable;
36 import org.graalvm.compiler.graph.spi.SimplifierTool;
37 import org.graalvm.compiler.nodeinfo.NodeInfo;
38 import org.graalvm.compiler.nodes.StructuredGraph.FrameStateVerificationFeature;
39 import org.graalvm.compiler.nodes.util.GraphUtil;
40 
41 @NodeInfo(allowedUsageTypes = {Association}, cycles = CYCLES_0, size = SIZE_0)
42 public final class LoopExitNode extends BeginStateSplitNode implements IterableNodeType, Simplifiable {
43 
44     public static final NodeClass<LoopExitNode> TYPE = NodeClass.create(LoopExitNode.class);
45 
46     /*
47      * The declared type of the field cannot be LoopBeginNode, because loop explosion during partial
48      * evaluation can temporarily assign a non-loop begin. This node will then be deleted shortly
49      * after - but we still must not have type system violations for that short amount of time.
50      */
51     @Input(Association) AbstractBeginNode loopBegin;
52 
LoopExitNode(LoopBeginNode loop)53     public LoopExitNode(LoopBeginNode loop) {
54         super(TYPE);
55         assert loop != null;
56         loopBegin = loop;
57     }
58 
loopBegin()59     public LoopBeginNode loopBegin() {
60         return (LoopBeginNode) loopBegin;
61     }
62 
63     @Override
anchored()64     public NodeIterable<Node> anchored() {
65         return super.anchored().filter(n -> {
66             if (n instanceof ProxyNode) {
67                 ProxyNode proxyNode = (ProxyNode) n;
68                 return proxyNode.proxyPoint() != this;
69             }
70             return true;
71         });
72     }
73 
74     @Override
75     public void prepareDelete(FixedNode evacuateFrom) {
76         removeProxies();
77         super.prepareDelete(evacuateFrom);
78     }
79 
80     public void removeProxies() {
81         if (this.hasUsages()) {
82             outer: while (true) {
83                 for (ProxyNode vpn : proxies().snapshot()) {
84                     ValueNode value = vpn.value();
85                     vpn.replaceAtUsagesAndDelete(value);
86                     if (value == this) {
87                         // Guard proxy could have this input as value.
88                         continue outer;
89                     }
90                 }
91                 break;
92             }
93         }
94     }
95 
96     @SuppressWarnings({"unchecked", "rawtypes"})
97     public NodeIterable<ProxyNode> proxies() {
98         return (NodeIterable) usages().filter(n -> {
99             if (n instanceof ProxyNode) {
100                 ProxyNode proxyNode = (ProxyNode) n;
101                 return proxyNode.proxyPoint() == this;
102             }
103             return false;
104         });
105     }
106 
107     public void removeExit() {
108         this.removeProxies();
109         FrameState loopStateAfter = this.stateAfter();
110         graph().replaceFixedWithFixed(this, graph().add(new BeginNode()));
111         if (loopStateAfter != null) {
112             GraphUtil.tryKillUnused(loopStateAfter);
113         }
114     }
115 
116     @Override
117     public void simplify(SimplifierTool tool) {
118         Node prev = this.predecessor();
119         while (tool.allUsagesAvailable() && prev instanceof BeginNode && prev.hasNoUsages()) {
120             AbstractBeginNode begin = (AbstractBeginNode) prev;
121             this.setNodeSourcePosition(begin.getNodeSourcePosition());
122             prev = prev.predecessor();
123             graph().removeFixed(begin);
124         }
125     }
126 
127     @Override
128     public boolean verify() {
129         /*
130          * State verification for loop exits is special in that loop exits with exception handling
131          * BCIs must not survive until code generation, thus they are cleared shortly before frame
132          * state assignment, thus we only verify them until their removal
133          */
134         assert !this.graph().getFrameStateVerification().implies(FrameStateVerificationFeature.LOOP_EXITS) || this.stateAfter != null : "Loop exit must have a state until FSA " + this;
135         return super.verify();
136     }
137 }
138