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: //dedicated treatment for the &&
019: public class AND_AND_Expression extends BinaryExpression {
020:
021: int rightInitStateIndex = -1;
022: int mergedInitStateIndex = -1;
023:
024: public AND_AND_Expression(Expression left, Expression right,
025: int operator) {
026: super (left, right, operator);
027: }
028:
029: public FlowInfo analyseCode(BlockScope currentScope,
030: FlowContext flowContext, FlowInfo flowInfo) {
031:
032: Constant cst = this .left.optimizedBooleanConstant();
033: boolean isLeftOptimizedTrue = cst != Constant.NotAConstant
034: && cst.booleanValue() == true;
035: boolean isLeftOptimizedFalse = cst != Constant.NotAConstant
036: && cst.booleanValue() == false;
037:
038: if (isLeftOptimizedTrue) {
039: // TRUE && anything
040: // need to be careful of scenario:
041: // (x && y) && !z, if passing the left info to the right, it would
042: // be swapped by the !
043: FlowInfo mergedInfo = left.analyseCode(currentScope,
044: flowContext, flowInfo).unconditionalInits();
045: mergedInfo = right.analyseCode(currentScope, flowContext,
046: mergedInfo);
047: mergedInitStateIndex = currentScope.methodScope()
048: .recordInitializationStates(mergedInfo);
049: return mergedInfo;
050: }
051:
052: FlowInfo leftInfo = left.analyseCode(currentScope, flowContext,
053: flowInfo);
054: // need to be careful of scenario:
055: // (x && y) && !z, if passing the left info to the right, it would be
056: // swapped by the !
057: FlowInfo rightInfo = leftInfo.initsWhenTrue()
058: .unconditionalCopy();
059: rightInitStateIndex = currentScope.methodScope()
060: .recordInitializationStates(rightInfo);
061:
062: int previousMode = rightInfo.reachMode();
063: if (isLeftOptimizedFalse) {
064: rightInfo.setReachMode(FlowInfo.UNREACHABLE);
065: }
066: rightInfo = right.analyseCode(currentScope, flowContext,
067: rightInfo);
068: FlowInfo mergedInfo = FlowInfo.conditional(rightInfo
069: .safeInitsWhenTrue(), leftInfo.initsWhenFalse()
070: .unconditionalInits().mergedWith(
071: rightInfo.initsWhenFalse().setReachMode(
072: previousMode).unconditionalInits()));
073: // reset after trueMergedInfo got extracted
074: mergedInitStateIndex = currentScope.methodScope()
075: .recordInitializationStates(mergedInfo);
076: return mergedInfo;
077: }
078:
079: /**
080: * Code generation for a binary operation
081: */
082: public void generateCode(BlockScope currentScope,
083: CodeStream codeStream, boolean valueRequired) {
084:
085: int pc = codeStream.position;
086: if (constant != Constant.NotAConstant) {
087: // inlined value
088: if (valueRequired)
089: codeStream.generateConstant(constant,
090: implicitConversion);
091: codeStream.recordPositionsFrom(pc, this .sourceStart);
092: return;
093: }
094: Constant cst = right.constant;
095: if (cst != Constant.NotAConstant) {
096: // <expr> && true --> <expr>
097: if (cst.booleanValue() == true) {
098: this .left.generateCode(currentScope, codeStream,
099: valueRequired);
100: } else {
101: // <expr> && false --> false
102: this .left.generateCode(currentScope, codeStream, false);
103: if (valueRequired)
104: codeStream.iconst_0();
105: }
106: if (mergedInitStateIndex != -1) {
107: codeStream.removeNotDefinitelyAssignedVariables(
108: currentScope, mergedInitStateIndex);
109: }
110: codeStream.generateImplicitConversion(implicitConversion);
111: codeStream.updateLastRecordedEndPC(currentScope,
112: codeStream.position);
113: codeStream.recordPositionsFrom(pc, this .sourceStart);
114: return;
115: }
116:
117: BranchLabel falseLabel = new BranchLabel(codeStream), endLabel;
118: cst = left.optimizedBooleanConstant();
119: boolean leftIsConst = cst != Constant.NotAConstant;
120: boolean leftIsTrue = leftIsConst && cst.booleanValue() == true;
121:
122: cst = right.optimizedBooleanConstant();
123: boolean rightIsConst = cst != Constant.NotAConstant;
124: boolean rightIsTrue = rightIsConst
125: && cst.booleanValue() == true;
126:
127: generateOperands: {
128: if (leftIsConst) {
129: left.generateCode(currentScope, codeStream, false);
130: if (!leftIsTrue) {
131: break generateOperands; // no need to generate right operand
132: }
133: } else {
134: left.generateOptimizedBoolean(currentScope, codeStream,
135: null, falseLabel, true);
136: // need value, e.g. if (a == 1 && ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a!=1
137: }
138: if (rightInitStateIndex != -1) {
139: codeStream.addDefinitelyAssignedVariables(currentScope,
140: rightInitStateIndex);
141: }
142: if (rightIsConst) {
143: right.generateCode(currentScope, codeStream, false);
144: } else {
145: right.generateOptimizedBoolean(currentScope,
146: codeStream, null, falseLabel, valueRequired);
147: }
148: }
149: if (mergedInitStateIndex != -1) {
150: codeStream.removeNotDefinitelyAssignedVariables(
151: currentScope, mergedInitStateIndex);
152: }
153: /*
154: * improving code gen for such a case: boolean b = i < 0 && false since
155: * the label has never been used, we have the inlined value on the
156: * stack.
157: */
158: if (valueRequired) {
159: if (leftIsConst && !leftIsTrue) {
160: codeStream.iconst_0();
161: codeStream.updateLastRecordedEndPC(currentScope,
162: codeStream.position);
163: } else {
164: if (rightIsConst && !rightIsTrue) {
165: codeStream.iconst_0();
166: codeStream.updateLastRecordedEndPC(currentScope,
167: codeStream.position);
168: } else {
169: codeStream.iconst_1();
170: }
171: if (falseLabel.forwardReferenceCount() > 0) {
172: if ((bits & IsReturnedValue) != 0) {
173: codeStream
174: .generateImplicitConversion(this .implicitConversion);
175: codeStream.generateReturnBytecode(this );
176: falseLabel.place();
177: codeStream.iconst_0();
178: } else {
179: codeStream.goto_(endLabel = new BranchLabel(
180: codeStream));
181: codeStream.decrStackSize(1);
182: falseLabel.place();
183: codeStream.iconst_0();
184: endLabel.place();
185: }
186: } else {
187: falseLabel.place();
188: }
189: }
190: codeStream.generateImplicitConversion(implicitConversion);
191: codeStream.updateLastRecordedEndPC(currentScope,
192: codeStream.position);
193: } else {
194: falseLabel.place();
195: }
196: }
197:
198: /**
199: * Boolean operator code generation Optimized operations are: &&
200: */
201: public void generateOptimizedBoolean(BlockScope currentScope,
202: CodeStream codeStream, BranchLabel trueLabel,
203: BranchLabel falseLabel, boolean valueRequired) {
204:
205: if (constant != Constant.NotAConstant) {
206: super .generateOptimizedBoolean(currentScope, codeStream,
207: trueLabel, falseLabel, valueRequired);
208: return;
209: }
210:
211: // <expr> && true --> <expr>
212: Constant cst = right.constant;
213: if (cst != Constant.NotAConstant && cst.booleanValue() == true) {
214: int pc = codeStream.position;
215: this .left.generateOptimizedBoolean(currentScope,
216: codeStream, trueLabel, falseLabel, valueRequired);
217: if (mergedInitStateIndex != -1) {
218: codeStream.removeNotDefinitelyAssignedVariables(
219: currentScope, mergedInitStateIndex);
220: }
221: codeStream.recordPositionsFrom(pc, this .sourceStart);
222: return;
223: }
224: cst = left.optimizedBooleanConstant();
225: boolean leftIsConst = cst != Constant.NotAConstant;
226: boolean leftIsTrue = leftIsConst && cst.booleanValue() == true;
227:
228: cst = right.optimizedBooleanConstant();
229: boolean rightIsConst = cst != Constant.NotAConstant;
230: boolean rightIsTrue = rightIsConst
231: && cst.booleanValue() == true;
232:
233: // default case
234: generateOperands: {
235: if (falseLabel == null) {
236: if (trueLabel != null) {
237: // implicit falling through the FALSE case
238: BranchLabel internalFalseLabel = new BranchLabel(
239: codeStream);
240: left.generateOptimizedBoolean(currentScope,
241: codeStream, null, internalFalseLabel,
242: !leftIsConst);
243: // need value, e.g. if (a == 1 && ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a!=1
244: if (leftIsConst && !leftIsTrue) {
245: internalFalseLabel.place();
246: break generateOperands; // no need to generate right operand
247: }
248: if (rightInitStateIndex != -1) {
249: codeStream.addDefinitelyAssignedVariables(
250: currentScope, rightInitStateIndex);
251: }
252: right.generateOptimizedBoolean(currentScope,
253: codeStream, trueLabel, null, valueRequired
254: && !rightIsConst);
255: if (valueRequired && rightIsConst && rightIsTrue) {
256: codeStream.goto_(trueLabel);
257: codeStream.updateLastRecordedEndPC(
258: currentScope, codeStream.position);
259: }
260: internalFalseLabel.place();
261: }
262: } else {
263: // implicit falling through the TRUE case
264: if (trueLabel == null) {
265: left.generateOptimizedBoolean(currentScope,
266: codeStream, null, falseLabel, !leftIsConst);
267: // need value, e.g. if (a == 1 && ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a!=1
268: if (leftIsConst && !leftIsTrue) {
269: if (valueRequired)
270: codeStream.goto_(falseLabel);
271: codeStream.updateLastRecordedEndPC(
272: currentScope, codeStream.position);
273: break generateOperands; // no need to generate right operand
274: }
275: if (rightInitStateIndex != -1) {
276: codeStream.addDefinitelyAssignedVariables(
277: currentScope, rightInitStateIndex);
278: }
279: right.generateOptimizedBoolean(currentScope,
280: codeStream, null, falseLabel, valueRequired
281: && !rightIsConst);
282: if (valueRequired && rightIsConst && !rightIsTrue) {
283: codeStream.goto_(falseLabel);
284: codeStream.updateLastRecordedEndPC(
285: currentScope, codeStream.position);
286: }
287: } else {
288: // no implicit fall through TRUE/FALSE --> should never occur
289: }
290: }
291: }
292: if (mergedInitStateIndex != -1) {
293: codeStream.removeNotDefinitelyAssignedVariables(
294: currentScope, mergedInitStateIndex);
295: }
296: }
297:
298: public boolean isCompactableOperation() {
299: return false;
300: }
301:
302: public void traverse(ASTVisitor visitor, BlockScope scope) {
303: if (visitor.visit(this, scope)) {
304: left.traverse(visitor, scope);
305: right.traverse(visitor, scope);
306: }
307: visitor.endVisit(this, scope);
308: }
309: }
|