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