LoopNode.java revision 1060:ca67ae7c46cb
1/*
2 * Copyright (c) 2010, 2013, 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.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.nashorn.internal.ir;
27
28import java.util.Arrays;
29import java.util.Collections;
30import java.util.List;
31import jdk.nashorn.internal.codegen.Label;
32
33/**
34 * A loop node, for example a while node, do while node or for node
35 */
36public abstract class LoopNode extends BreakableStatement {
37    /** loop continue label. */
38    protected final Label continueLabel;
39
40    /** Loop test node, null if infinite */
41    protected final JoinPredecessorExpression test;
42
43    /** Loop body */
44    protected final Block body;
45
46    /** Can control flow escape from loop, e.g. through breaks or continues to outer loops? */
47    protected final boolean controlFlowEscapes;
48
49    /**
50     * Constructor
51     *
52     * @param lineNumber         lineNumber
53     * @param token              token
54     * @param finish             finish
55     * @param body               loop body
56     * @param test               test
57     * @param controlFlowEscapes controlFlowEscapes
58     */
59    protected LoopNode(final int lineNumber, final long token, final int finish, final Block body, final JoinPredecessorExpression test, final boolean controlFlowEscapes) {
60        super(lineNumber, token, finish, new Label("while_break"));
61        this.continueLabel = new Label("while_continue");
62        this.body = body;
63        this.controlFlowEscapes = controlFlowEscapes;
64        this.test = test;
65    }
66
67    /**
68     * Constructor
69     *
70     * @param loopNode loop node
71     * @param test     new test
72     * @param body     new body
73     * @param controlFlowEscapes controlFlowEscapes
74     * @param conversion the local variable conversion carried by this loop node.
75     */
76    protected LoopNode(final LoopNode loopNode, final JoinPredecessorExpression test, final Block body,
77            final boolean controlFlowEscapes, final LocalVariableConversion conversion) {
78        super(loopNode, conversion);
79        this.continueLabel = new Label(loopNode.continueLabel);
80        this.test = test;
81        this.body = body;
82        this.controlFlowEscapes = controlFlowEscapes;
83    }
84
85    @Override
86    public abstract Node ensureUniqueLabels(final LexicalContext lc);
87
88    /**
89     * Does the control flow escape from this loop, i.e. through breaks or
90     * continues to outer loops?
91     * @return true if control flow escapes
92     */
93    public boolean controlFlowEscapes() {
94        return controlFlowEscapes;
95    }
96
97
98    @Override
99    public boolean isTerminal() {
100        if (!mustEnter()) {
101            return false;
102        }
103        //must enter but control flow may escape - then not terminal
104        if (controlFlowEscapes) {
105            return false;
106        }
107        //must enter, but body ends with return - then terminal
108        if (body.isTerminal()) {
109            return true;
110        }
111        //no breaks or returns, it is still terminal if we can never exit
112        return test == null;
113    }
114
115    /**
116     * Conservative check: does this loop have to be entered?
117     * @return true if body will execute at least once
118     */
119    public abstract boolean mustEnter();
120
121    /**
122     * Get the continue label for this while node, i.e. location to go to on continue
123     * @return continue label
124     */
125    public Label getContinueLabel() {
126        return continueLabel;
127    }
128
129    @Override
130    public List<Label> getLabels() {
131        return Collections.unmodifiableList(Arrays.asList(breakLabel, continueLabel));
132    }
133
134    @Override
135    public boolean isLoop() {
136        return true;
137    }
138
139    /**
140     * Get the body for this for node
141     * @return the body
142     */
143    public abstract Block getBody();
144
145    /**
146     * @param lc   lexical context
147     * @param body new body
148     * @return new for node if changed or existing if not
149     */
150    public abstract LoopNode setBody(final LexicalContext lc, final Block body);
151
152    /**
153     * Get the test for this for node
154     * @return the test
155     */
156    public final JoinPredecessorExpression getTest() {
157        return test;
158    }
159
160    /**
161     * Set the test for this for node
162     *
163     * @param lc lexical context
164     * @param test new test
165     * @return same or new node depending on if test was changed
166     */
167    public abstract LoopNode setTest(final LexicalContext lc, final JoinPredecessorExpression test);
168
169    /**
170     * Set the control flow escapes flag for this node.
171     * TODO  - integrate this with Lowering in a better way
172     *
173     * @param lc lexical context
174     * @param controlFlowEscapes control flow escapes value
175     * @return new loop node if changed otherwise the same
176     */
177    public abstract LoopNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes);
178}
179