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