View Javadoc
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  
26  package jdk.nashorn.internal.ir;
27  
28  import java.util.Arrays;
29  import java.util.List;
30  import jdk.nashorn.internal.codegen.Label;
31  
32  /**
33   * A loop node, for example a while node, do while node or for node
34   */
35  public abstract class LoopNode extends BreakableStatement {
36      /** loop continue label. */
37      protected final Label continueLabel;
38  
39      /** Loop test node, null if infinite */
40      protected final Expression test;
41  
42      /** Loop body */
43      protected final Block body;
44  
45      /** Can control flow escape from loop, e.g. through breaks or continues to outer loops? */
46      protected final boolean controlFlowEscapes;
47  
48      /**
49       * Constructor
50       *
51       * @param lineNumber         lineNumber
52       * @param token              token
53       * @param finish             finish
54       * @param test               test, or null if infinite loop
55       * @param body               loop body
56       * @param controlFlowEscapes controlFlowEscapes
57       */
58      protected LoopNode(final int lineNumber, final long token, final int finish, final Expression test, final Block body, final boolean controlFlowEscapes) {
59          super(lineNumber, token, finish, new Label("while_break"));
60          this.continueLabel = new Label("while_continue");
61          this.test = test;
62          this.body = body;
63          this.controlFlowEscapes = controlFlowEscapes;
64      }
65  
66      /**
67       * Constructor
68       *
69       * @param loopNode loop node
70       * @param test     new test
71       * @param body     new body
72       * @param controlFlowEscapes controlFlowEscapes
73       */
74      protected LoopNode(final LoopNode loopNode, final Expression test, final Block body, final boolean controlFlowEscapes) {
75          super(loopNode);
76          this.continueLabel = new Label(loopNode.continueLabel);
77          this.test = test;
78          this.body = body;
79          this.controlFlowEscapes = controlFlowEscapes;
80      }
81  
82      @Override
83      public abstract Node ensureUniqueLabels(final LexicalContext lc);
84  
85      /**
86       * Does the control flow escape from this loop, i.e. through breaks or
87       * continues to outer loops?
88       * @return true if control flow escapes
89       */
90      public boolean controlFlowEscapes() {
91          return controlFlowEscapes;
92      }
93  
94  
95      @Override
96      public boolean isTerminal() {
97          if (!mustEnter()) {
98              return false;
99          }
100         //must enter but control flow may escape - then not terminal
101         if (controlFlowEscapes) {
102             return false;
103         }
104         //must enter, but body ends with return - then terminal
105         if (body.isTerminal()) {
106             return true;
107         }
108         //no breaks or returns, it is still terminal if we can never exit
109         return test == null;
110     }
111 
112     /**
113      * Conservative check: does this loop have to be entered?
114      * @return true if body will execute at least once
115      */
116     public abstract boolean mustEnter();
117 
118     /**
119      * Get the continue label for this while node, i.e. location to go to on continue
120      * @return continue label
121      */
122     public Label getContinueLabel() {
123         return continueLabel;
124     }
125 
126     @Override
127     public List<Label> getLabels() {
128         return Arrays.asList(breakLabel, continueLabel);
129     }
130 
131     @Override
132     public boolean isLoop() {
133         return true;
134     }
135 
136     /**
137      * Get the body for this for node
138      * @return the body
139      */
140     public abstract Block getBody();
141 
142     /**
143      * @param lc   lexical context
144      * @param body new body
145      * @return new for node if changed or existing if not
146      */
147     public abstract LoopNode setBody(final LexicalContext lc, final Block body);
148 
149     /**
150      * Get the test for this for node
151      * @return the test
152      */
153     public abstract Expression getTest();
154 
155     /**
156      * Set the test for this for node
157      *
158      * @param lc lexical context
159      * @param test new test
160      * @return same or new node depending on if test was changed
161      */
162     public abstract LoopNode setTest(final LexicalContext lc, final Expression test);
163 
164     /**
165      * Set the control flow escapes flag for this node.
166      * TODO  - integrate this with Lowering in a better way
167      *
168      * @param lc lexical context
169      * @param controlFlowEscapes control flow escapes value
170      * @return new loop node if changed otherwise the same
171      */
172     public abstract LoopNode setControlFlowEscapes(final LexicalContext lc, final boolean controlFlowEscapes);
173 
174 }