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