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
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
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.*;
20 public class WhileStatement extends Statement {
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;
29 public WhileStatement(Expression condition, Statement action, int s, int e) {
31 this.condition = condition;
33 // remember useful empty statement
34 if (action instanceof EmptyStatement) action.bits |= IsUsefulEmptyStatementMASK;
39 public FlowInfo analyseCode(
40 BlockScope currentScope,
41 FlowContext flowContext,
44 breakLabel = new Label();
45 continueLabel = new Label();
47 Constant cst = this.condition.constant;
48 boolean isConditionTrue = cst != NotAConstant && cst.booleanValue() == true;
49 boolean isConditionFalse = cst != NotAConstant && cst.booleanValue() == false;
51 cst = this.condition.optimizedBooleanConstant();
52 boolean isConditionOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true;
53 boolean isConditionOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false;
55 preCondInitStateIndex =
56 currentScope.methodScope().recordInitializationStates(flowInfo);
57 LoopingFlowContext condLoopContext;
58 FlowInfo condInfo = flowInfo.copy().unconditionalInits().discardNullRelatedInitializations();
59 condInfo = this.condition.analyseCode(
62 new LoopingFlowContext(flowContext, this, null, null, currentScope)),
65 LoopingFlowContext loopingContext;
69 || (action.isEmptyBlock() && currentScope.environment().options.complianceLevel <= ClassFileConstants.JDK1_3)) {
70 condLoopContext.complainOnDeferredChecks(currentScope, condInfo);
71 if (isConditionTrue) {
72 return FlowInfo.DEAD_END;
74 FlowInfo mergedInfo = condInfo.initsWhenFalse().unconditionalInits();
75 if (isConditionOptimizedTrue){
76 mergedInfo.setReachMode(FlowInfo.UNREACHABLE);
78 mergedInitStateIndex =
79 currentScope.methodScope().recordInitializationStates(mergedInfo);
83 // in case the condition was inlined to false, record the fact that there is no way to reach any
84 // statement inside the looping action
86 new LoopingFlowContext(
92 if (isConditionFalse) {
93 actionInfo = FlowInfo.DEAD_END;
95 actionInfo = condInfo.initsWhenTrue().copy();
96 if (isConditionOptimizedFalse){
97 actionInfo.setReachMode(FlowInfo.UNREACHABLE);
101 // for computing local var attributes
102 condIfTrueInitStateIndex =
103 currentScope.methodScope().recordInitializationStates(
104 condInfo.initsWhenTrue());
106 if (!this.action.complainIfUnreachable(actionInfo, currentScope, false)) {
107 actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo);
110 // code generation can be optimized when no need to continue in the loop
111 exitBranch = condInfo.initsWhenFalse();
112 exitBranch.addInitializationsFrom(flowInfo); // recover null inits from before condition analysis
113 if (!actionInfo.isReachable() && !loopingContext.initsOnContinue.isReachable()) {
114 continueLabel = null;
116 condLoopContext.complainOnDeferredChecks(currentScope, condInfo);
117 actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits());
118 loopingContext.complainOnDeferredChecks(currentScope, actionInfo);
119 exitBranch.addPotentialInitializationsFrom(actionInfo.unconditionalInits());
124 FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
125 loopingContext.initsOnBreak,
126 isConditionOptimizedTrue,
128 isConditionOptimizedFalse,
129 !isConditionTrue /*while(true); unreachable(); */);
130 mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
135 * While code generation
137 * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
138 * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
140 public void generateCode(BlockScope currentScope, CodeStream codeStream) {
142 if ((bits & IsReachableMASK) == 0) {
145 int pc = codeStream.position;
146 breakLabel.initialize(codeStream);
148 // generate condition
149 if (continueLabel == null) {
150 // no need to reverse condition
151 if (condition.constant == NotAConstant) {
152 condition.generateOptimizedBoolean(
160 continueLabel.initialize(codeStream);
161 if (!(((condition.constant != NotAConstant)
162 && (condition.constant.booleanValue() == true))
164 || action.isEmptyBlock())) {
165 int jumpPC = codeStream.position;
166 codeStream.goto_(continueLabel);
167 codeStream.recordPositionsFrom(jumpPC, condition.sourceStart);
170 // generate the action
172 (actionLabel = new Label(codeStream)).place();
173 if (action != null) {
174 // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
175 if (condIfTrueInitStateIndex != -1) {
176 // insert all locals initialized inside the condition into the action generated prior to the condition
177 codeStream.addDefinitelyAssignedVariables(
179 condIfTrueInitStateIndex);
181 action.generateCode(currentScope, codeStream);
182 // May loose some local variable initializations : affecting the local variable attributes
183 if (preCondInitStateIndex != -1) {
184 codeStream.removeNotDefinitelyAssignedVariables(currentScope, preCondInitStateIndex);
188 // output condition and branch back to the beginning of the repeated action
189 if (continueLabel != null) {
190 continueLabel.place();
191 condition.generateOptimizedBoolean(
200 // May loose some local variable initializations : affecting the local variable attributes
201 if (mergedInitStateIndex != -1) {
202 codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
203 codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
205 codeStream.recordPositionsFrom(pc, this.sourceStart);
208 public void resolve(BlockScope scope) {
210 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
211 condition.computeConversion(scope, type, type);
213 action.resolve(scope);
216 public StringBuffer printStatement(int tab, StringBuffer output) {
218 printIndent(tab, output).append("while ("); //$NON-NLS-1$
219 condition.printExpression(0, output).append(')');
223 action.printStatement(tab + 1, output);
227 public void traverse(
229 BlockScope blockScope) {
231 if (visitor.visit(this, blockScope)) {
232 condition.traverse(visitor, blockScope);
234 action.traverse(visitor, blockScope);
236 visitor.endVisit(this, blockScope);