1 /******************************************************************************* 2 * Copyright (c) 2000, 2004 IBM Corporation and others. 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Common Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/cpl-v10.html 7 * 8 * Contributors: 9 * IBM Corporation - initial API and implementation 10 *******************************************************************************/ 11 package org.eclipse.jdt.internal.compiler.ast; 12 13 import org.eclipse.jdt.internal.compiler.ASTVisitor; 14 import org.eclipse.jdt.internal.compiler.impl.*; 15 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants; 16 import org.eclipse.jdt.internal.compiler.codegen.*; 17 import org.eclipse.jdt.internal.compiler.flow.*; 18 import org.eclipse.jdt.internal.compiler.lookup.*; 19 20 public class WhileStatement extends Statement { 21 22 public Expression condition; 23 public Statement action; 24 private Label breakLabel, continueLabel; 25 int preCondInitStateIndex = -1; 26 int condIfTrueInitStateIndex = -1; 27 int mergedInitStateIndex = -1; 28 WhileStatement(Expression condition, Statement action, int s, int e)29 public WhileStatement(Expression condition, Statement action, int s, int e) { 30 31 this.condition = condition; 32 this.action = action; 33 // remember useful empty statement 34 if (action instanceof EmptyStatement) action.bits |= IsUsefulEmptyStatementMASK; 35 sourceStart = s; 36 sourceEnd = e; 37 } 38 analyseCode( BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo)39 public FlowInfo analyseCode( 40 BlockScope currentScope, 41 FlowContext flowContext, 42 FlowInfo flowInfo) { 43 44 breakLabel = new Label(); 45 continueLabel = new Label(); 46 47 Constant cst = this.condition.constant; 48 boolean isConditionTrue = cst != NotAConstant && cst.booleanValue() == true; 49 boolean isConditionFalse = cst != NotAConstant && cst.booleanValue() == false; 50 51 cst = this.condition.optimizedBooleanConstant(); 52 boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true; 53 boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false; 54 55 preCondInitStateIndex = 56 currentScope.methodScope().recordInitializationStates(flowInfo); 57 LoopingFlowContext condLoopContext; 58 FlowInfo postCondInfo = 59 this.condition.analyseCode( 60 currentScope, 61 (condLoopContext = 62 new LoopingFlowContext(flowContext, this, null, null, currentScope)), 63 flowInfo); 64 65 LoopingFlowContext loopingContext; 66 FlowInfo actionInfo; 67 if (action == null 68 || (action.isEmptyBlock() && currentScope.environment().options.complianceLevel <= ClassFileConstants.JDK1_3)) { 69 condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo); 70 if (isConditionTrue) { 71 return FlowInfo.DEAD_END; 72 } else { 73 FlowInfo mergedInfo = postCondInfo.initsWhenFalse().unconditionalInits(); 74 if (isConditionOptimizedTrue){ 75 mergedInfo.setReachMode(FlowInfo.UNREACHABLE); 76 } 77 mergedInitStateIndex = 78 currentScope.methodScope().recordInitializationStates(mergedInfo); 79 return mergedInfo; 80 } 81 } else { 82 // in case the condition was inlined to false, record the fact that there is no way to reach any 83 // statement inside the looping action 84 loopingContext = 85 new LoopingFlowContext( 86 flowContext, 87 this, 88 breakLabel, 89 continueLabel, 90 currentScope); 91 if (isConditionFalse) { 92 actionInfo = FlowInfo.DEAD_END; 93 } else { 94 actionInfo = postCondInfo.initsWhenTrue().copy(); 95 if (isConditionOptimizedFalse){ 96 actionInfo.setReachMode(FlowInfo.UNREACHABLE); 97 } 98 } 99 100 // for computing local var attributes 101 condIfTrueInitStateIndex = 102 currentScope.methodScope().recordInitializationStates( 103 postCondInfo.initsWhenTrue()); 104 105 if (!this.action.complainIfUnreachable(actionInfo, currentScope, false)) { 106 actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo); 107 } 108 109 // code generation can be optimized when no need to continue in the loop 110 if (!actionInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) { 111 continueLabel = null; 112 } else { 113 condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo); 114 actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits()); 115 loopingContext.complainOnFinalAssignmentsInLoop(currentScope, actionInfo); 116 } 117 } 118 119 // end of loop 120 FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches( 121 loopingContext.initsOnBreak, 122 isConditionOptimizedTrue, 123 postCondInfo.initsWhenFalse(), 124 isConditionOptimizedFalse, 125 !isConditionTrue /*while(true); unreachable(); */); 126 mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo); 127 return mergedInfo; 128 } 129 130 /** 131 * While code generation 132 * 133 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope 134 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream 135 */ generateCode(BlockScope currentScope, CodeStream codeStream)136 public void generateCode(BlockScope currentScope, CodeStream codeStream) { 137 138 if ((bits & IsReachableMASK) == 0) { 139 return; 140 } 141 int pc = codeStream.position; 142 breakLabel.initialize(codeStream); 143 144 // generate condition 145 if (continueLabel == null) { 146 // no need to reverse condition 147 if (condition.constant == NotAConstant) { 148 condition.generateOptimizedBoolean( 149 currentScope, 150 codeStream, 151 null, 152 breakLabel, 153 true); 154 } 155 } else { 156 continueLabel.initialize(codeStream); 157 if (!(((condition.constant != NotAConstant) 158 && (condition.constant.booleanValue() == true)) 159 || (action == null) 160 || action.isEmptyBlock())) { 161 int jumpPC = codeStream.position; 162 codeStream.goto_(continueLabel); 163 codeStream.recordPositionsFrom(jumpPC, condition.sourceStart); 164 } 165 } 166 // generate the action 167 Label actionLabel; 168 (actionLabel = new Label(codeStream)).place(); 169 if (action != null) { 170 // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect 171 if (condIfTrueInitStateIndex != -1) { 172 // insert all locals initialized inside the condition into the action generated prior to the condition 173 codeStream.addDefinitelyAssignedVariables( 174 currentScope, 175 condIfTrueInitStateIndex); 176 } 177 action.generateCode(currentScope, codeStream); 178 // May loose some local variable initializations : affecting the local variable attributes 179 if (preCondInitStateIndex != -1) { 180 codeStream.removeNotDefinitelyAssignedVariables(currentScope, preCondInitStateIndex); 181 } 182 183 } 184 // output condition and branch back to the beginning of the repeated action 185 if (continueLabel != null) { 186 continueLabel.place(); 187 condition.generateOptimizedBoolean( 188 currentScope, 189 codeStream, 190 actionLabel, 191 null, 192 true); 193 } 194 breakLabel.place(); 195 196 // May loose some local variable initializations : affecting the local variable attributes 197 if (mergedInitStateIndex != -1) { 198 codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); 199 codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex); 200 } 201 codeStream.recordPositionsFrom(pc, this.sourceStart); 202 } 203 resolve(BlockScope scope)204 public void resolve(BlockScope scope) { 205 206 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding); 207 condition.computeConversion(scope, type, type); 208 if (action != null) 209 action.resolve(scope); 210 } 211 printStatement(int tab, StringBuffer output)212 public StringBuffer printStatement(int tab, StringBuffer output) { 213 214 printIndent(tab, output).append("while ("); //$NON-NLS-1$ 215 condition.printExpression(0, output).append(')'); 216 if (action == null) 217 output.append(';'); 218 else 219 action.printStatement(tab + 1, output); 220 return output; 221 } 222 traverse( ASTVisitor visitor, BlockScope blockScope)223 public void traverse( 224 ASTVisitor visitor, 225 BlockScope blockScope) { 226 227 if (visitor.visit(this, blockScope)) { 228 condition.traverse(visitor, blockScope); 229 if (action != null) 230 action.traverse(visitor, blockScope); 231 } 232 visitor.endVisit(this, blockScope); 233 } 234 } 235