001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.internal.compiler.ast;
011:
012: import org.eclipse.jdt.internal.compiler.ASTVisitor;
013: import org.eclipse.jdt.internal.compiler.impl.*;
014: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
015: import org.eclipse.jdt.internal.compiler.codegen.*;
016: import org.eclipse.jdt.internal.compiler.flow.*;
017: import org.eclipse.jdt.internal.compiler.lookup.*;
018:
019: public class WhileStatement extends Statement {
020:
021: public Expression condition;
022: public Statement action;
023: private BranchLabel breakLabel, continueLabel;
024: int preCondInitStateIndex = -1;
025: int condIfTrueInitStateIndex = -1;
026: int mergedInitStateIndex = -1;
027:
028: public WhileStatement(Expression condition, Statement action,
029: int s, int e) {
030:
031: this .condition = condition;
032: this .action = action;
033: // remember useful empty statement
034: if (action instanceof EmptyStatement)
035: action.bits |= IsUsefulEmptyStatement;
036: sourceStart = s;
037: sourceEnd = e;
038: }
039:
040: public FlowInfo analyseCode(BlockScope currentScope,
041: FlowContext flowContext, FlowInfo flowInfo) {
042:
043: breakLabel = new BranchLabel();
044: continueLabel = new BranchLabel();
045:
046: Constant cst = this .condition.constant;
047: boolean isConditionTrue = cst != Constant.NotAConstant
048: && cst.booleanValue() == true;
049: boolean isConditionFalse = cst != Constant.NotAConstant
050: && cst.booleanValue() == false;
051:
052: cst = this .condition.optimizedBooleanConstant();
053: boolean isConditionOptimizedTrue = cst != Constant.NotAConstant
054: && cst.booleanValue() == true;
055: boolean isConditionOptimizedFalse = cst != Constant.NotAConstant
056: && cst.booleanValue() == false;
057:
058: preCondInitStateIndex = currentScope.methodScope()
059: .recordInitializationStates(flowInfo);
060: LoopingFlowContext condLoopContext;
061: FlowInfo condInfo = flowInfo.nullInfoLessUnconditionalCopy();
062: // we need to collect the contribution to nulls of the coming paths through the
063: // loop, be they falling through normally or branched to break, continue labels
064: // or catch blocks
065: condInfo = this .condition.analyseCode(currentScope,
066: (condLoopContext = new LoopingFlowContext(flowContext,
067: flowInfo, this , null, null, currentScope)),
068: condInfo);
069:
070: LoopingFlowContext loopingContext;
071: FlowInfo actionInfo;
072: FlowInfo exitBranch;
073: if (action == null
074: || (action.isEmptyBlock() && currentScope
075: .compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3)) {
076: condLoopContext.complainOnDeferredFinalChecks(currentScope,
077: condInfo);
078: condLoopContext.complainOnDeferredNullChecks(currentScope,
079: condInfo.unconditionalInits());
080: if (isConditionTrue) {
081: return FlowInfo.DEAD_END;
082: } else {
083: FlowInfo mergedInfo = flowInfo.copy()
084: .addInitializationsFrom(
085: condInfo.initsWhenFalse());
086: if (isConditionOptimizedTrue) {
087: mergedInfo.setReachMode(FlowInfo.UNREACHABLE);
088: }
089: mergedInitStateIndex = currentScope.methodScope()
090: .recordInitializationStates(mergedInfo);
091: return mergedInfo;
092: }
093: } else {
094: // in case the condition was inlined to false, record the fact that there is no way to reach any
095: // statement inside the looping action
096: loopingContext = new LoopingFlowContext(flowContext,
097: flowInfo, this , breakLabel, continueLabel,
098: currentScope);
099: if (isConditionFalse) {
100: actionInfo = FlowInfo.DEAD_END;
101: } else {
102: actionInfo = condInfo.initsWhenTrue().copy();
103: if (isConditionOptimizedFalse) {
104: actionInfo.setReachMode(FlowInfo.UNREACHABLE);
105: }
106: }
107:
108: // for computing local var attributes
109: condIfTrueInitStateIndex = currentScope.methodScope()
110: .recordInitializationStates(
111: condInfo.initsWhenTrue());
112:
113: if (!this .action.complainIfUnreachable(actionInfo,
114: currentScope, false)) {
115: actionInfo = this .action.analyseCode(currentScope,
116: loopingContext, actionInfo);
117: }
118:
119: // code generation can be optimized when no need to continue in the loop
120: exitBranch = flowInfo.copy();
121: // need to start over from flowInfo so as to get null inits
122:
123: if ((actionInfo.tagBits
124: & loopingContext.initsOnContinue.tagBits & FlowInfo.UNREACHABLE) != 0) {
125: continueLabel = null;
126: exitBranch.addInitializationsFrom(condInfo
127: .initsWhenFalse());
128: } else {
129: condLoopContext.complainOnDeferredFinalChecks(
130: currentScope, condInfo);
131: actionInfo = actionInfo
132: .mergedWith(loopingContext.initsOnContinue
133: .unconditionalInits());
134: condLoopContext.complainOnDeferredNullChecks(
135: currentScope, actionInfo);
136: loopingContext.complainOnDeferredFinalChecks(
137: currentScope, actionInfo);
138: loopingContext.complainOnDeferredNullChecks(
139: currentScope, actionInfo);
140: exitBranch.addPotentialInitializationsFrom(
141: actionInfo.unconditionalInits())
142: .addInitializationsFrom(
143: condInfo.initsWhenFalse());
144: }
145: }
146:
147: // end of loop
148: FlowInfo mergedInfo = FlowInfo
149: .mergedOptimizedBranches(
150: (loopingContext.initsOnBreak.tagBits & FlowInfo.UNREACHABLE) != 0 ? loopingContext.initsOnBreak
151: : flowInfo
152: .addInitializationsFrom(loopingContext.initsOnBreak), // recover upstream null info
153: isConditionOptimizedTrue, exitBranch,
154: isConditionOptimizedFalse, !isConditionTrue /*while(true); unreachable(); */);
155: mergedInitStateIndex = currentScope.methodScope()
156: .recordInitializationStates(mergedInfo);
157: return mergedInfo;
158: }
159:
160: /**
161: * While code generation
162: *
163: * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
164: * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
165: */
166: public void generateCode(BlockScope currentScope,
167: CodeStream codeStream) {
168:
169: if ((bits & IsReachable) == 0) {
170: return;
171: }
172: int pc = codeStream.position;
173: Constant cst = this .condition.optimizedBooleanConstant();
174: boolean isConditionOptimizedFalse = cst != Constant.NotAConstant
175: && cst.booleanValue() == false;
176: if (isConditionOptimizedFalse) {
177: condition.generateCode(currentScope, codeStream, false);
178: // May loose some local variable initializations : affecting the local variable attributes
179: if (mergedInitStateIndex != -1) {
180: codeStream.removeNotDefinitelyAssignedVariables(
181: currentScope, mergedInitStateIndex);
182: codeStream.addDefinitelyAssignedVariables(currentScope,
183: mergedInitStateIndex);
184: }
185: codeStream.recordPositionsFrom(pc, this .sourceStart);
186: return;
187: }
188:
189: breakLabel.initialize(codeStream);
190:
191: // generate condition
192: if (continueLabel == null) {
193: // no need to reverse condition
194: if (condition.constant == Constant.NotAConstant) {
195: condition.generateOptimizedBoolean(currentScope,
196: codeStream, null, breakLabel, true);
197: }
198: } else {
199: continueLabel.initialize(codeStream);
200: if (!(((condition.constant != Constant.NotAConstant) && (condition.constant
201: .booleanValue() == true))
202: || (action == null) || action.isEmptyBlock())) {
203: int jumpPC = codeStream.position;
204: codeStream.goto_(continueLabel);
205: codeStream.recordPositionsFrom(jumpPC,
206: condition.sourceStart);
207: }
208: }
209: // generate the action
210: BranchLabel actionLabel = new BranchLabel(codeStream);
211: if (action != null) {
212: actionLabel.tagBits |= BranchLabel.USED;
213: // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
214: if (condIfTrueInitStateIndex != -1) {
215: // insert all locals initialized inside the condition into the action generated prior to the condition
216: codeStream.addDefinitelyAssignedVariables(currentScope,
217: condIfTrueInitStateIndex);
218: }
219: actionLabel.place();
220: action.generateCode(currentScope, codeStream);
221: // May loose some local variable initializations : affecting the local variable attributes
222: if (preCondInitStateIndex != -1) {
223: codeStream.removeNotDefinitelyAssignedVariables(
224: currentScope, preCondInitStateIndex);
225: }
226: } else {
227: actionLabel.place();
228: }
229: // output condition and branch back to the beginning of the repeated action
230: if (continueLabel != null) {
231: continueLabel.place();
232: condition.generateOptimizedBoolean(currentScope,
233: codeStream, actionLabel, null, true);
234: }
235:
236: // May loose some local variable initializations : affecting the local variable attributes
237: if (mergedInitStateIndex != -1) {
238: codeStream.removeNotDefinitelyAssignedVariables(
239: currentScope, mergedInitStateIndex);
240: codeStream.addDefinitelyAssignedVariables(currentScope,
241: mergedInitStateIndex);
242: }
243: breakLabel.place();
244: codeStream.recordPositionsFrom(pc, this .sourceStart);
245: }
246:
247: public void resolve(BlockScope scope) {
248:
249: TypeBinding type = condition.resolveTypeExpecting(scope,
250: TypeBinding.BOOLEAN);
251: condition.computeConversion(scope, type, type);
252: if (action != null)
253: action.resolve(scope);
254: }
255:
256: public StringBuffer printStatement(int tab, StringBuffer output) {
257:
258: printIndent(tab, output).append("while ("); //$NON-NLS-1$
259: condition.printExpression(0, output).append(')');
260: if (action == null)
261: output.append(';');
262: else
263: action.printStatement(tab + 1, output);
264: return output;
265: }
266:
267: public void traverse(ASTVisitor visitor, BlockScope blockScope) {
268:
269: if (visitor.visit(this, blockScope)) {
270: condition.traverse(visitor, blockScope);
271: if (action != null)
272: action.traverse(visitor, blockScope);
273: }
274: visitor.endVisit(this, blockScope);
275: }
276: }
|