added -J option to preserve unmodified files in preexisting jarfile
[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 condInfo = flowInfo.copy().unconditionalInits().discardNullRelatedInitializations();
59                 condInfo = this.condition.analyseCode(
60                                 currentScope,
61                                 (condLoopContext =
62                                         new LoopingFlowContext(flowContext, this, null, null, currentScope)),
63                                 condInfo);
64
65                 LoopingFlowContext loopingContext;
66                 FlowInfo actionInfo;
67                 FlowInfo exitBranch;
68                 if (action == null 
69                         || (action.isEmptyBlock() && currentScope.environment().options.complianceLevel <= ClassFileConstants.JDK1_3)) {
70                         condLoopContext.complainOnDeferredChecks(currentScope, condInfo);
71                         if (isConditionTrue) {
72                                 return FlowInfo.DEAD_END;
73                         } else {
74                                 FlowInfo mergedInfo = condInfo.initsWhenFalse().unconditionalInits();
75                                 if (isConditionOptimizedTrue){
76                                         mergedInfo.setReachMode(FlowInfo.UNREACHABLE);
77                                 }
78                                 mergedInitStateIndex =
79                                         currentScope.methodScope().recordInitializationStates(mergedInfo);
80                                 return mergedInfo;
81                         }
82                 } else {
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
85                         loopingContext =
86                                 new LoopingFlowContext(
87                                         flowContext,
88                                         this,
89                                         breakLabel,
90                                         continueLabel,
91                                         currentScope);
92                         if (isConditionFalse) {
93                                 actionInfo = FlowInfo.DEAD_END;
94                         } else {
95                                 actionInfo = condInfo.initsWhenTrue().copy();
96                                 if (isConditionOptimizedFalse){
97                                         actionInfo.setReachMode(FlowInfo.UNREACHABLE);
98                                 }
99                         }
100
101                         // for computing local var attributes
102                         condIfTrueInitStateIndex =
103                                 currentScope.methodScope().recordInitializationStates(
104                                         condInfo.initsWhenTrue());
105
106                         if (!this.action.complainIfUnreachable(actionInfo, currentScope, false)) {
107                                 actionInfo = this.action.analyseCode(currentScope, loopingContext, actionInfo);
108                         }
109
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;
115                         } else {
116                                 condLoopContext.complainOnDeferredChecks(currentScope, condInfo);
117                                 actionInfo = actionInfo.mergedWith(loopingContext.initsOnContinue.unconditionalInits());
118                                 loopingContext.complainOnDeferredChecks(currentScope, actionInfo);
119                                 exitBranch.addPotentialInitializationsFrom(actionInfo.unconditionalInits());
120                         }
121                 }
122
123                 // end of loop
124                 FlowInfo mergedInfo = FlowInfo.mergedOptimizedBranches(
125                                 loopingContext.initsOnBreak, 
126                                 isConditionOptimizedTrue, 
127                                 exitBranch,
128                                 isConditionOptimizedFalse,
129                                 !isConditionTrue /*while(true); unreachable(); */);
130                 mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
131                 return mergedInfo;
132         }
133
134         /**
135          * While code generation
136          *
137          * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
138          * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
139          */
140         public void generateCode(BlockScope currentScope, CodeStream codeStream) {
141
142                 if ((bits & IsReachableMASK) == 0) {
143                         return;
144                 }
145                 int pc = codeStream.position;
146                 breakLabel.initialize(codeStream);
147
148                 // generate condition
149                 if (continueLabel == null) {
150                         // no need to reverse condition
151                         if (condition.constant == NotAConstant) {
152                                 condition.generateOptimizedBoolean(
153                                         currentScope,
154                                         codeStream,
155                                         null,
156                                         breakLabel,
157                                         true);
158                         }
159                 } else {
160                         continueLabel.initialize(codeStream);
161                         if (!(((condition.constant != NotAConstant)
162                                 && (condition.constant.booleanValue() == true))
163                                 || (action == null)
164                                 || action.isEmptyBlock())) {
165                                 int jumpPC = codeStream.position;
166                                 codeStream.goto_(continueLabel);
167                                 codeStream.recordPositionsFrom(jumpPC, condition.sourceStart);
168                         }
169                 }
170                 // generate the action
171                 Label actionLabel;
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(
178                                         currentScope,
179                                         condIfTrueInitStateIndex);
180                         }
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);
185                         }
186
187                 }
188                 // output condition and branch back to the beginning of the repeated action
189                 if (continueLabel != null) {
190                         continueLabel.place();
191                         condition.generateOptimizedBoolean(
192                                 currentScope,
193                                 codeStream,
194                                 actionLabel,
195                                 null,
196                                 true);
197                 }
198                 breakLabel.place();
199
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);
204                 }
205                 codeStream.recordPositionsFrom(pc, this.sourceStart);
206         }
207
208         public void resolve(BlockScope scope) {
209
210                 TypeBinding type = condition.resolveTypeExpecting(scope, BooleanBinding);
211                 condition.computeConversion(scope, type, type);
212                 if (action != null)
213                         action.resolve(scope);
214         }
215
216         public StringBuffer printStatement(int tab, StringBuffer output) {
217
218                 printIndent(tab, output).append("while ("); //$NON-NLS-1$
219                 condition.printExpression(0, output).append(')');
220                 if (action == null)
221                         output.append(';');
222                 else
223                         action.printStatement(tab + 1, output); 
224                 return output;
225         }
226
227         public void traverse(
228                 ASTVisitor visitor,
229                 BlockScope blockScope) {
230
231                 if (visitor.visit(this, blockScope)) {
232                         condition.traverse(visitor, blockScope);
233                         if (action != null)
234                                 action.traverse(visitor, blockScope);
235                 }
236                 visitor.endVisit(this, blockScope);
237         }
238 }