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 OR_OR_Expression extends BinaryExpression {
020:
021: int rightInitStateIndex = -1;
022: int mergedInitStateIndex = -1;
023:
024: public OR_OR_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 (isLeftOptimizedFalse) {
039: // FALSE || anything
040: // need to be careful of scenario:
041: // (x || y) || !z, if passing the left info to the right, it would be swapped by the !
042: FlowInfo mergedInfo = left.analyseCode(currentScope,
043: flowContext, flowInfo).unconditionalInits();
044: mergedInfo = right.analyseCode(currentScope, flowContext,
045: mergedInfo);
046: mergedInitStateIndex = currentScope.methodScope()
047: .recordInitializationStates(mergedInfo);
048: return mergedInfo;
049: }
050:
051: FlowInfo leftInfo = left.analyseCode(currentScope, flowContext,
052: flowInfo);
053:
054: // need to be careful of scenario:
055: // (x || y) || !z, if passing the left info to the right, it would be swapped by the !
056: FlowInfo rightInfo = leftInfo.initsWhenFalse()
057: .unconditionalCopy();
058: rightInitStateIndex = currentScope.methodScope()
059: .recordInitializationStates(rightInfo);
060:
061: int previousMode = rightInfo.reachMode();
062: if (isLeftOptimizedTrue) {
063: rightInfo.setReachMode(FlowInfo.UNREACHABLE);
064: }
065: rightInfo = right.analyseCode(currentScope, flowContext,
066: rightInfo);
067: FlowInfo mergedInfo = FlowInfo.conditional(
068: // merging two true initInfos for such a negative case: if ((t && (b = t)) || f) r = b; // b may not have been initialized
069: leftInfo.initsWhenTrue().unconditionalInits()
070: .mergedWith(
071: rightInfo.safeInitsWhenTrue()
072: .setReachMode(previousMode)
073: .unconditionalInits()),
074: rightInfo.initsWhenFalse());
075: mergedInitStateIndex = currentScope.methodScope()
076: .recordInitializationStates(mergedInfo);
077: return mergedInfo;
078: }
079:
080: /**
081: * Code generation for a binary operation
082: */
083: public void generateCode(BlockScope currentScope,
084: CodeStream codeStream, boolean valueRequired) {
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 --> true
097: if (cst.booleanValue() == true) {
098: this .left.generateCode(currentScope, codeStream, false);
099: if (valueRequired)
100: codeStream.iconst_1();
101: } else {
102: // <expr>|| false --> <expr>
103: this .left.generateCode(currentScope, codeStream,
104: valueRequired);
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 trueLabel = 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: trueLabel, null, 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, trueLabel, null, 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 || true 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_1();
161: codeStream.updateLastRecordedEndPC(currentScope,
162: codeStream.position);
163: } else {
164: if (rightIsConst && rightIsTrue) {
165: codeStream.iconst_1();
166: codeStream.updateLastRecordedEndPC(currentScope,
167: codeStream.position);
168: } else {
169: codeStream.iconst_0();
170: }
171: if (trueLabel.forwardReferenceCount() > 0) {
172: if ((bits & IsReturnedValue) != 0) {
173: codeStream
174: .generateImplicitConversion(this .implicitConversion);
175: codeStream.generateReturnBytecode(this );
176: trueLabel.place();
177: codeStream.iconst_1();
178: } else {
179: codeStream.goto_(endLabel = new BranchLabel(
180: codeStream));
181: codeStream.decrStackSize(1);
182: trueLabel.place();
183: codeStream.iconst_1();
184: endLabel.place();
185: }
186: } else {
187: trueLabel.place();
188: }
189: }
190: codeStream.generateImplicitConversion(implicitConversion);
191: codeStream.updateLastRecordedEndPC(currentScope,
192: codeStream.position);
193: } else {
194: trueLabel.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: if (constant != Constant.NotAConstant) {
205: super .generateOptimizedBoolean(currentScope, codeStream,
206: trueLabel, falseLabel, valueRequired);
207: return;
208: }
209:
210: // <expr> || false --> <expr>
211: Constant cst = right.constant;
212: if (cst != Constant.NotAConstant && cst.booleanValue() == false) {
213: int pc = codeStream.position;
214: this .left.generateOptimizedBoolean(currentScope,
215: codeStream, trueLabel, falseLabel, valueRequired);
216: if (mergedInitStateIndex != -1) {
217: codeStream.removeNotDefinitelyAssignedVariables(
218: currentScope, mergedInitStateIndex);
219: }
220: codeStream.recordPositionsFrom(pc, this .sourceStart);
221: return;
222: }
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: left.generateOptimizedBoolean(currentScope,
239: codeStream, trueLabel, null, !leftIsConst);
240: // need value, e.g. if (a == 1 || ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a==1
241: if (leftIsTrue) {
242: if (valueRequired)
243: codeStream.goto_(trueLabel);
244: codeStream.updateLastRecordedEndPC(
245: currentScope, codeStream.position);
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 && rightIsTrue) {
256: codeStream.goto_(trueLabel);
257: codeStream.updateLastRecordedEndPC(
258: currentScope, codeStream.position);
259: }
260: }
261: } else {
262: // implicit falling through the TRUE case
263: if (trueLabel == null) {
264: BranchLabel internalTrueLabel = new BranchLabel(
265: codeStream);
266: left.generateOptimizedBoolean(currentScope,
267: codeStream, internalTrueLabel, null,
268: !leftIsConst);
269: // need value, e.g. if (a == 1 || ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a==1
270: if (leftIsTrue) {
271: internalTrueLabel.place();
272: break generateOperands; // no need to generate right operand
273: }
274: if (rightInitStateIndex != -1) {
275: codeStream.addDefinitelyAssignedVariables(
276: currentScope, rightInitStateIndex);
277: }
278: right.generateOptimizedBoolean(currentScope,
279: codeStream, null, falseLabel, valueRequired
280: && !rightIsConst);
281: if (valueRequired && rightIsConst && !rightIsTrue) {
282: codeStream.goto_(falseLabel);
283: codeStream.updateLastRecordedEndPC(
284: currentScope, codeStream.position);
285: }
286: internalTrueLabel.place();
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: }
|