removed Makefile; lifted repo/org.ibex.tool/src/ to src/
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / WhileStatement.java
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
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
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                                 // TODO (philippe) should simplify in one Loop context
114                                 condLoopContext.complainOnFinalAssignmentsInLoop(currentScope, postCondInfo);
115                                 actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits());
116                                 loopingContext.complainOnFinalAssignmentsInLoop(currentScope, actionInfo);
117                         }
118                 }
119
120                 // end of loop
121                 FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
122                                 loopingContext.initsOnBreak, 
123                                 isConditionOptimizedTrue, 
124                                 postCondInfo.initsWhenFalse(), 
125                                 isConditionOptimizedFalse,
126                                 !isConditionTrue /*while(true); unreachable(); */);
127                 mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
128                 return mergedInfo;
129         }
130
131         /**
132          * While code generation
133          *
134          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
135          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
136          */
137         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
138
139                 if ((bits & IsReachableMASK) == 0) {
140                         return;
141                 }
142                 int pc = codeStream.position;
143                 breakLabel.initialize(codeStream);
144
145                 // generate condition
146                 if (continueLabel == null) {
147                         // no need to reverse condition
148                         if (condition.constant == NotAConstant) {
149                                 condition.generateOptimizedBoolean(
150                                         currentScope,
151                                         codeStream,
152                                         null,
153                                         breakLabel,
154                                         true);
155                         }
156                 } else {
157                         continueLabel.initialize(codeStream);
158                         if (!(((condition.constant != NotAConstant)
159                                 && (condition.constant.booleanValue() == true))
160                                 || (action == null)
161                                 || action.isEmptyBlock())) {
162                                 int jumpPC = codeStream.position;
163                                 codeStream.goto_(continueLabel);
164                                 codeStream.recordPositionsFrom(jumpPC, condition.sourceStart);
165                         }
166                 }
167                 // generate the action
168                 Label actionLabel;
169                 (actionLabel = new Label(codeStream)).place();
170                 if (action != null) {
171                         // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
172                         if (condIfTrueInitStateIndex != -1) {
173                                 // insert all locals initialized inside the condition into the action generated prior to the condition
174                                 codeStream.addDefinitelyAssignedVariables(
175                                         currentScope,
176                                         condIfTrueInitStateIndex);
177                         }
178                         action.generateCode(currentScope, codeStream);
179                         // May loose some local variable initializations : affecting the local variable attributes
180                         if (preCondInitStateIndex != -1) {
181                                 codeStream.removeNotDefinitelyAssignedVariables(
182                                         currentScope,
183                                         preCondInitStateIndex);
184                         }
185
186                 }
187                 // output condition and branch back to the beginning of the repeated action
188                 if (continueLabel != null) {
189                         continueLabel.place();
190                         condition.generateOptimizedBoolean(
191                                 currentScope,
192                                 codeStream,
193                                 actionLabel,
194                                 null,
195                                 true);
196                 }
197                 breakLabel.place();
198
199                 // May loose some local variable initializations : affecting the local variable attributes
200                 if (mergedInitStateIndex != -1) {
201                         codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
202                         codeStream.addDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
203                 }
204                 codeStream.recordPositionsFrom(pc, this.sourceStart);
205         }
206
207         public void resolve(BlockScope scope) {
208
209                 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
210                 condition.implicitWidening(type, type);
211                 if (action != null)
212                         action.resolve(scope);
213         }
214
215         public StringBuffer printStatement(int tab, StringBuffer output) {
216
217                 printIndent(tab, output).append("while ("); //$NON-NLS-1$
218                 condition.printExpression(0, output).append(')');
219                 if (action == null)
220                         output.append(';');
221                 else
222                         action.printStatement(tab + 1, output); 
223                 return output;
224         }
225
226         public void traverse(
227                 ASTVisitor visitor,
228                 BlockScope blockScope) {
229
230                 if (visitor.visit(this, blockScope)) {
231                         condition.traverse(visitor, blockScope);
232                         if (action != null)
233                                 action.traverse(visitor, blockScope);
234                 }
235                 visitor.endVisit(this, blockScope);
236         }
237 }