001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 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.codegen.*;
015: import org.eclipse.jdt.internal.compiler.flow.*;
016: import org.eclipse.jdt.internal.compiler.lookup.*;
017:
018: public class DoStatement extends Statement {
019:
020: public Expression condition;
021: public Statement action;
022:
023: private BranchLabel breakLabel, continueLabel;
024:
025: // for local variables table attributes
026: int mergedInitStateIndex = -1;
027:
028: public DoStatement(Expression condition, Statement action,
029: int sourceStart, int sourceEnd) {
030:
031: this .sourceStart = sourceStart;
032: this .sourceEnd = sourceEnd;
033: this .condition = condition;
034: this .action = action;
035: // remember useful empty statement
036: if (action instanceof EmptyStatement)
037: action.bits |= ASTNode.IsUsefulEmptyStatement;
038: }
039:
040: public FlowInfo analyseCode(BlockScope currentScope,
041: FlowContext flowContext, FlowInfo flowInfo) {
042: this .breakLabel = new BranchLabel();
043: this .continueLabel = new BranchLabel();
044: LoopingFlowContext loopingContext = new LoopingFlowContext(
045: flowContext, flowInfo, this , this .breakLabel,
046: this .continueLabel, currentScope);
047:
048: Constant cst = this .condition.constant;
049: boolean isConditionTrue = cst != Constant.NotAConstant
050: && cst.booleanValue() == true;
051: cst = this .condition.optimizedBooleanConstant();
052: boolean isConditionOptimizedTrue = cst != Constant.NotAConstant
053: && cst.booleanValue() == true;
054: boolean isConditionOptimizedFalse = cst != Constant.NotAConstant
055: && cst.booleanValue() == false;
056:
057: int previousMode = flowInfo.reachMode();
058:
059: UnconditionalFlowInfo actionInfo = flowInfo
060: .nullInfoLessUnconditionalCopy();
061: // we need to collect the contribution to nulls of the coming paths through the
062: // loop, be they falling through normally or branched to break, continue labels
063: // or catch blocks
064: if ((this .action != null) && !this .action.isEmptyBlock()) {
065: actionInfo = this .action.analyseCode(currentScope,
066: loopingContext, actionInfo).unconditionalInits();
067:
068: // code generation can be optimized when no need to continue in the loop
069: if ((actionInfo.tagBits
070: & loopingContext.initsOnContinue.tagBits & FlowInfo.UNREACHABLE) != 0) {
071: this .continueLabel = null;
072: }
073: }
074: /* Reset reach mode, to address following scenario.
075: * final blank;
076: * do { if (true) break; else blank = 0; } while(false);
077: * blank = 1; // may be initialized already
078: */
079: actionInfo.setReachMode(previousMode);
080:
081: LoopingFlowContext condLoopContext;
082: FlowInfo condInfo = this .condition.analyseCode(currentScope,
083: (condLoopContext = new LoopingFlowContext(flowContext,
084: flowInfo, this , null, null, currentScope)),
085: (this .action == null ? actionInfo : (actionInfo
086: .mergedWith(loopingContext.initsOnContinue)))
087: .copy());
088: if (!isConditionOptimizedFalse && this .continueLabel != null) {
089: loopingContext.complainOnDeferredFinalChecks(currentScope,
090: condInfo);
091: condLoopContext.complainOnDeferredFinalChecks(currentScope,
092: condInfo);
093: loopingContext.complainOnDeferredNullChecks(currentScope,
094: flowInfo.unconditionalCopy()
095: .addPotentialNullInfoFrom(
096: condInfo.initsWhenTrue()
097: .unconditionalInits()));
098: condLoopContext.complainOnDeferredNullChecks(currentScope,
099: actionInfo.addPotentialNullInfoFrom(condInfo
100: .initsWhenTrue().unconditionalInits()));
101: }
102:
103: // end of loop
104: FlowInfo mergedInfo = FlowInfo
105: .mergedOptimizedBranches(
106: (loopingContext.initsOnBreak.tagBits & FlowInfo.UNREACHABLE) != 0 ? loopingContext.initsOnBreak
107: : flowInfo
108: .unconditionalCopy()
109: .addInitializationsFrom(
110: loopingContext.initsOnBreak),
111: // recover upstream null info
112: isConditionOptimizedTrue,
113: (condInfo.tagBits & FlowInfo.UNREACHABLE) == 0 ? flowInfo
114: .addInitializationsFrom(condInfo
115: .initsWhenFalse())
116: : condInfo,
117: // recover null inits from before condition analysis
118: false, // never consider opt false case for DO loop, since break can always occur (47776)
119: !isConditionTrue /*do{}while(true); unreachable(); */);
120: this .mergedInitStateIndex = currentScope.methodScope()
121: .recordInitializationStates(mergedInfo);
122: return mergedInfo;
123: }
124:
125: /**
126: * Do statement code generation
127: *
128: */
129: public void generateCode(BlockScope currentScope,
130: CodeStream codeStream) {
131: if ((this .bits & ASTNode.IsReachable) == 0) {
132: return;
133: }
134: int pc = codeStream.position;
135:
136: // labels management
137: BranchLabel actionLabel = new BranchLabel(codeStream);
138: if (this .action != null)
139: actionLabel.tagBits |= BranchLabel.USED;
140: actionLabel.place();
141: this .breakLabel.initialize(codeStream);
142: boolean hasContinueLabel = this .continueLabel != null;
143: if (hasContinueLabel) {
144: this .continueLabel.initialize(codeStream);
145: }
146:
147: // generate action
148: if (this .action != null) {
149: this .action.generateCode(currentScope, codeStream);
150: }
151: // continue label (135602)
152: if (hasContinueLabel) {
153: this .continueLabel.place();
154: }
155: // generate condition
156: Constant cst = this .condition.optimizedBooleanConstant();
157: boolean isConditionOptimizedFalse = cst != Constant.NotAConstant
158: && cst.booleanValue() == false;
159: if (isConditionOptimizedFalse) {
160: this .condition
161: .generateCode(currentScope, codeStream, false);
162: } else if (hasContinueLabel) {
163: this .condition.generateOptimizedBoolean(currentScope,
164: codeStream, actionLabel, null, true);
165: }
166: // May loose some local variable initializations : affecting the local variable attributes
167: if (this .mergedInitStateIndex != -1) {
168: codeStream.removeNotDefinitelyAssignedVariables(
169: currentScope, this .mergedInitStateIndex);
170: codeStream.addDefinitelyAssignedVariables(currentScope,
171: this .mergedInitStateIndex);
172: }
173: if (this .breakLabel.forwardReferenceCount() > 0) {
174: this .breakLabel.place();
175: }
176:
177: codeStream.recordPositionsFrom(pc, this .sourceStart);
178: }
179:
180: public StringBuffer printStatement(int indent, StringBuffer output) {
181: printIndent(indent, output).append("do"); //$NON-NLS-1$
182: if (this .action == null)
183: output.append(" ;\n"); //$NON-NLS-1$
184: else {
185: output.append('\n');
186: this .action.printStatement(indent + 1, output).append('\n');
187: }
188: output.append("while ("); //$NON-NLS-1$
189: return this .condition.printExpression(0, output).append(");"); //$NON-NLS-1$
190: }
191:
192: public void resolve(BlockScope scope) {
193: TypeBinding type = this .condition.resolveTypeExpecting(scope,
194: TypeBinding.BOOLEAN);
195: this .condition.computeConversion(scope, type, type);
196: if (this .action != null)
197: this .action.resolve(scope);
198: }
199:
200: public void traverse(ASTVisitor visitor, BlockScope scope) {
201: if (visitor.visit(this, scope)) {
202: if (this.action != null) {
203: this.action.traverse(visitor, scope);
204: }
205: this.condition.traverse(visitor, scope);
206: }
207: visitor.endVisit(this, scope);
208: }
209: }
|