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.classfmt.ClassFileConstants;
014: import org.eclipse.jdt.internal.compiler.codegen.*;
015: import org.eclipse.jdt.internal.compiler.flow.*;
016: import org.eclipse.jdt.internal.compiler.impl.Constant;
017: import org.eclipse.jdt.internal.compiler.lookup.*;
018:
019: public class ForStatement extends Statement {
020:
021: public Statement[] initializations;
022: public Expression condition;
023: public Statement[] increments;
024: public Statement action;
025:
026: //when there is no local declaration, there is no need of a new scope
027: //scope is positioned either to a new scope, or to the "upper"scope (see resolveType)
028: public BlockScope scope;
029:
030: private BranchLabel breakLabel, continueLabel;
031:
032: // for local variables table attributes
033: int preCondInitStateIndex = -1;
034: int preIncrementsInitStateIndex = -1;
035: int condIfTrueInitStateIndex = -1;
036: int mergedInitStateIndex = -1;
037:
038: public ForStatement(Statement[] initializations,
039: Expression condition, Statement[] increments,
040: Statement action, boolean neededScope, int s, int e) {
041:
042: this .sourceStart = s;
043: this .sourceEnd = e;
044: this .initializations = initializations;
045: this .condition = condition;
046: this .increments = increments;
047: this .action = action;
048: // remember useful empty statement
049: if (action instanceof EmptyStatement)
050: action.bits |= ASTNode.IsUsefulEmptyStatement;
051: if (neededScope) {
052: this .bits |= ASTNode.NeededScope;
053: }
054: }
055:
056: public FlowInfo analyseCode(BlockScope currentScope,
057: FlowContext flowContext, FlowInfo flowInfo) {
058:
059: breakLabel = new BranchLabel();
060: continueLabel = new BranchLabel();
061:
062: // process the initializations
063: if (initializations != null) {
064: for (int i = 0, count = initializations.length; i < count; i++) {
065: flowInfo = initializations[i].analyseCode(scope,
066: flowContext, flowInfo);
067: }
068: }
069: preCondInitStateIndex = currentScope.methodScope()
070: .recordInitializationStates(flowInfo);
071:
072: Constant cst = this .condition == null ? null
073: : this .condition.constant;
074: boolean isConditionTrue = cst == null
075: || (cst != Constant.NotAConstant && cst.booleanValue() == true);
076: boolean isConditionFalse = cst != null
077: && (cst != Constant.NotAConstant && cst.booleanValue() == false);
078:
079: cst = this .condition == null ? null : this .condition
080: .optimizedBooleanConstant();
081: boolean isConditionOptimizedTrue = cst == null
082: || (cst != Constant.NotAConstant && cst.booleanValue() == true);
083: boolean isConditionOptimizedFalse = cst != null
084: && (cst != Constant.NotAConstant && cst.booleanValue() == false);
085:
086: // process the condition
087: LoopingFlowContext condLoopContext = null;
088: FlowInfo condInfo = flowInfo.nullInfoLessUnconditionalCopy();
089: if (condition != null) {
090: if (!isConditionTrue) {
091: condInfo = condition.analyseCode(scope,
092: (condLoopContext = new LoopingFlowContext(
093: flowContext, flowInfo, this , null,
094: null, scope)), condInfo);
095: }
096: }
097:
098: // process the action
099: LoopingFlowContext loopingContext;
100: UnconditionalFlowInfo actionInfo;
101: if (action == null
102: || (action.isEmptyBlock() && currentScope
103: .compilerOptions().complianceLevel <= ClassFileConstants.JDK1_3)) {
104: if (condLoopContext != null)
105: condLoopContext.complainOnDeferredFinalChecks(scope,
106: condInfo);
107: if (isConditionTrue) {
108: if (condLoopContext != null) {
109: condLoopContext.complainOnDeferredNullChecks(
110: currentScope, condInfo);
111: }
112: return FlowInfo.DEAD_END;
113: } else {
114: if (isConditionFalse) {
115: continueLabel = null; // for(;false;p());
116: }
117: actionInfo = condInfo.initsWhenTrue()
118: .unconditionalCopy();
119: loopingContext = new LoopingFlowContext(flowContext,
120: flowInfo, this , breakLabel, continueLabel,
121: scope);
122: }
123: } else {
124: loopingContext = new LoopingFlowContext(flowContext,
125: flowInfo, this , breakLabel, continueLabel, scope);
126: FlowInfo initsWhenTrue = condInfo.initsWhenTrue();
127: condIfTrueInitStateIndex = currentScope.methodScope()
128: .recordInitializationStates(initsWhenTrue);
129:
130: if (isConditionFalse) {
131: actionInfo = FlowInfo.DEAD_END;
132: } else {
133: actionInfo = initsWhenTrue.unconditionalCopy();
134: if (isConditionOptimizedFalse) {
135: actionInfo.setReachMode(FlowInfo.UNREACHABLE);
136: }
137: }
138: if (!this .action.complainIfUnreachable(actionInfo, scope,
139: false)) {
140: actionInfo = action.analyseCode(scope, loopingContext,
141: actionInfo).unconditionalInits();
142: }
143:
144: // code generation can be optimized when no need to continue in the loop
145: if ((actionInfo.tagBits
146: & loopingContext.initsOnContinue.tagBits & FlowInfo.UNREACHABLE) != 0) {
147: continueLabel = null;
148: } else {
149: if (condLoopContext != null) {
150: condLoopContext.complainOnDeferredFinalChecks(
151: scope, condInfo);
152: }
153: actionInfo = actionInfo
154: .mergedWith(loopingContext.initsOnContinue);
155: loopingContext.complainOnDeferredFinalChecks(scope,
156: actionInfo);
157: }
158: }
159: // for increments
160: FlowInfo exitBranch = flowInfo.copy();
161: // recover null inits from before condition analysis
162: LoopingFlowContext incrementContext = null;
163: if (continueLabel != null) {
164: if (increments != null) {
165: incrementContext = new LoopingFlowContext(flowContext,
166: flowInfo, this , null, null, scope);
167: FlowInfo incrementInfo = actionInfo;
168: this .preIncrementsInitStateIndex = currentScope
169: .methodScope().recordInitializationStates(
170: incrementInfo);
171: for (int i = 0, count = increments.length; i < count; i++) {
172: incrementInfo = increments[i].analyseCode(scope,
173: incrementContext, incrementInfo);
174: }
175: incrementContext
176: .complainOnDeferredFinalChecks(scope,
177: actionInfo = incrementInfo
178: .unconditionalInits());
179: }
180: exitBranch.addPotentialInitializationsFrom(actionInfo)
181: .addInitializationsFrom(condInfo.initsWhenFalse());
182: } else {
183: exitBranch
184: .addInitializationsFrom(condInfo.initsWhenFalse());
185: }
186: // nulls checks
187: if (condLoopContext != null) {
188: condLoopContext.complainOnDeferredNullChecks(currentScope,
189: actionInfo);
190: }
191: loopingContext.complainOnDeferredNullChecks(currentScope,
192: actionInfo);
193: if (incrementContext != null) {
194: incrementContext.complainOnDeferredNullChecks(currentScope,
195: actionInfo);
196: }
197:
198: //end of loop
199: FlowInfo mergedInfo = FlowInfo
200: .mergedOptimizedBranches(
201: (loopingContext.initsOnBreak.tagBits & FlowInfo.UNREACHABLE) != 0 ? loopingContext.initsOnBreak
202: : flowInfo
203: .addInitializationsFrom(loopingContext.initsOnBreak), // recover upstream null info
204: isConditionOptimizedTrue, exitBranch,
205: isConditionOptimizedFalse, !isConditionTrue /*for(;;){}while(true); unreachable(); */);
206: mergedInitStateIndex = currentScope.methodScope()
207: .recordInitializationStates(mergedInfo);
208: return mergedInfo;
209: }
210:
211: /**
212: * For statement code generation
213: *
214: * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
215: * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
216: */
217: public void generateCode(BlockScope currentScope,
218: CodeStream codeStream) {
219:
220: if ((bits & IsReachable) == 0) {
221: return;
222: }
223: int pc = codeStream.position;
224:
225: // generate the initializations
226: if (initializations != null) {
227: for (int i = 0, max = initializations.length; i < max; i++) {
228: initializations[i].generateCode(scope, codeStream);
229: }
230: }
231: Constant cst = this .condition == null ? null : this .condition
232: .optimizedBooleanConstant();
233: boolean isConditionOptimizedFalse = cst != null
234: && (cst != Constant.NotAConstant && cst.booleanValue() == false);
235: if (isConditionOptimizedFalse) {
236: condition.generateCode(scope, codeStream, false);
237: // May loose some local variable initializations : affecting the local variable attributes
238: if ((this .bits & ASTNode.NeededScope) != 0) {
239: codeStream.exitUserScope(scope);
240: }
241: if (mergedInitStateIndex != -1) {
242: codeStream.removeNotDefinitelyAssignedVariables(
243: currentScope, mergedInitStateIndex);
244: codeStream.addDefinitelyAssignedVariables(currentScope,
245: mergedInitStateIndex);
246: }
247: codeStream.recordPositionsFrom(pc, this .sourceStart);
248: return;
249: }
250:
251: // label management
252: BranchLabel actionLabel = new BranchLabel(codeStream);
253: actionLabel.tagBits |= BranchLabel.USED;
254: BranchLabel conditionLabel = new BranchLabel(codeStream);
255: breakLabel.initialize(codeStream);
256: if (this .continueLabel == null) {
257: conditionLabel.place();
258: if ((condition != null)
259: && (condition.constant == Constant.NotAConstant)) {
260: condition.generateOptimizedBoolean(scope, codeStream,
261: null, breakLabel, true);
262: }
263: } else {
264: this .continueLabel.initialize(codeStream);
265: // jump over the actionBlock
266: if ((condition != null)
267: && (condition.constant == Constant.NotAConstant)
268: && !((action == null || action.isEmptyBlock()) && (increments == null))) {
269: conditionLabel.tagBits |= BranchLabel.USED;
270: int jumpPC = codeStream.position;
271: codeStream.goto_(conditionLabel);
272: codeStream.recordPositionsFrom(jumpPC,
273: condition.sourceStart);
274: }
275: }
276:
277: // generate the loop action
278: if (action != null) {
279: // Required to fix 1PR0XVS: LFRE:WINNT - Compiler: variable table for method appears incorrect
280: if (condIfTrueInitStateIndex != -1) {
281: // insert all locals initialized inside the condition into the action generated prior to the condition
282: codeStream.addDefinitelyAssignedVariables(currentScope,
283: condIfTrueInitStateIndex);
284: }
285: actionLabel.place();
286: action.generateCode(scope, codeStream);
287: } else {
288: actionLabel.place();
289: }
290: if (this .preIncrementsInitStateIndex != -1) {
291: codeStream.removeNotDefinitelyAssignedVariables(
292: currentScope, this .preIncrementsInitStateIndex);
293: codeStream.addDefinitelyAssignedVariables(currentScope,
294: this .preIncrementsInitStateIndex);
295: }
296: // continuation point
297: if (continueLabel != null) {
298: continueLabel.place();
299: // generate the increments for next iteration
300: if (increments != null) {
301: for (int i = 0, max = increments.length; i < max; i++) {
302: increments[i].generateCode(scope, codeStream);
303: }
304: }
305: // May loose some local variable initializations : affecting the local variable attributes
306: if (preCondInitStateIndex != -1) {
307: codeStream.removeNotDefinitelyAssignedVariables(
308: currentScope, preCondInitStateIndex);
309: }
310: // generate the condition
311: conditionLabel.place();
312: if ((condition != null)
313: && (condition.constant == Constant.NotAConstant)) {
314: condition.generateOptimizedBoolean(scope, codeStream,
315: actionLabel, null, true);
316: } else {
317: codeStream.goto_(actionLabel);
318: }
319:
320: } else {
321: // May loose some local variable initializations : affecting the local variable attributes
322: if (preCondInitStateIndex != -1) {
323: codeStream.removeNotDefinitelyAssignedVariables(
324: currentScope, preCondInitStateIndex);
325: }
326: }
327:
328: // May loose some local variable initializations : affecting the local variable attributes
329: if ((this .bits & ASTNode.NeededScope) != 0) {
330: codeStream.exitUserScope(scope);
331: }
332: if (mergedInitStateIndex != -1) {
333: codeStream.removeNotDefinitelyAssignedVariables(
334: currentScope, mergedInitStateIndex);
335: codeStream.addDefinitelyAssignedVariables(currentScope,
336: mergedInitStateIndex);
337: }
338: breakLabel.place();
339: codeStream.recordPositionsFrom(pc, this .sourceStart);
340: }
341:
342: public StringBuffer printStatement(int tab, StringBuffer output) {
343:
344: printIndent(tab, output).append("for ("); //$NON-NLS-1$
345: //inits
346: if (initializations != null) {
347: for (int i = 0; i < initializations.length; i++) {
348: //nice only with expressions
349: if (i > 0)
350: output.append(", "); //$NON-NLS-1$
351: initializations[i].print(0, output);
352: }
353: }
354: output.append("; "); //$NON-NLS-1$
355: //cond
356: if (condition != null)
357: condition.printExpression(0, output);
358: output.append("; "); //$NON-NLS-1$
359: //updates
360: if (increments != null) {
361: for (int i = 0; i < increments.length; i++) {
362: if (i > 0)
363: output.append(", "); //$NON-NLS-1$
364: increments[i].print(0, output);
365: }
366: }
367: output.append(") "); //$NON-NLS-1$
368: //block
369: if (action == null)
370: output.append(';');
371: else {
372: output.append('\n');
373: action.printStatement(tab + 1, output);
374: }
375: return output;
376: }
377:
378: public void resolve(BlockScope upperScope) {
379:
380: // use the scope that will hold the init declarations
381: scope = (this .bits & ASTNode.NeededScope) != 0 ? new BlockScope(
382: upperScope)
383: : upperScope;
384: if (initializations != null)
385: for (int i = 0, length = initializations.length; i < length; i++)
386: initializations[i].resolve(scope);
387: if (condition != null) {
388: TypeBinding type = condition.resolveTypeExpecting(scope,
389: TypeBinding.BOOLEAN);
390: condition.computeConversion(scope, type, type);
391: }
392: if (increments != null)
393: for (int i = 0, length = increments.length; i < length; i++)
394: increments[i].resolve(scope);
395: if (action != null)
396: action.resolve(scope);
397: }
398:
399: public void traverse(ASTVisitor visitor, BlockScope blockScope) {
400:
401: if (visitor.visit(this , blockScope)) {
402: if (initializations != null) {
403: int initializationsLength = initializations.length;
404: for (int i = 0; i < initializationsLength; i++)
405: initializations[i].traverse(visitor, scope);
406: }
407:
408: if (condition != null)
409: condition.traverse(visitor, scope);
410:
411: if (increments != null) {
412: int incrementsLength = increments.length;
413: for (int i = 0; i < incrementsLength; i++)
414: increments[i].traverse(visitor, scope);
415: }
416:
417: if (action != null)
418: action.traverse(visitor, scope);
419: }
420: visitor.endVisit(this, blockScope);
421: }
422: }
|