1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
13 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols.TokenName;
14 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
18 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
20 // dedicated treatment for the ||
21 public class OR_OR_Expression extends BinaryExpression {
23 int rightInitStateIndex = -1;
25 int mergedInitStateIndex = -1;
27 public OR_OR_Expression(Expression left, Expression right, int operator) {
28 super(left, right, operator);
31 public FlowInfo analyseCode(BlockScope currentScope,
32 FlowContext flowContext, FlowInfo flowInfo) {
34 Constant cst = this.left.optimizedBooleanConstant();
35 boolean isLeftOptimizedTrue = cst != NotAConstant
36 && cst.booleanValue() == true;
37 boolean isLeftOptimizedFalse = cst != NotAConstant
38 && cst.booleanValue() == false;
40 if (isLeftOptimizedFalse) {
42 // need to be careful of scenario:
43 // (x || y) || !z, if passing the left info to the right, it would
44 // be swapped by the !
45 FlowInfo mergedInfo = left.analyseCode(currentScope, flowContext,
46 flowInfo).unconditionalInits();
47 mergedInfo = right.analyseCode(currentScope, flowContext,
49 mergedInitStateIndex = currentScope.methodScope()
50 .recordInitializationStates(mergedInfo);
54 FlowInfo leftInfo = left.analyseCode(currentScope, flowContext,
57 // need to be careful of scenario:
58 // (x || y) || !z, if passing the left info to the right, it would be
60 FlowInfo rightInfo = leftInfo.initsWhenFalse().unconditionalInits()
62 rightInitStateIndex = currentScope.methodScope()
63 .recordInitializationStates(rightInfo);
65 int previousMode = rightInfo.reachMode();
66 if (isLeftOptimizedTrue) {
67 rightInfo.setReachMode(FlowInfo.UNREACHABLE);
69 rightInfo = right.analyseCode(currentScope, flowContext, rightInfo);
70 FlowInfo falseMergedInfo = rightInfo.initsWhenFalse().copy();
71 rightInfo.setReachMode(previousMode); // reset after falseMergedInfo
74 FlowInfo mergedInfo = FlowInfo
76 // merging two true initInfos for such a negative case:
77 // if ((t && (b = t)) || f) r = b; // b may not have
79 leftInfo.initsWhenTrue().copy().unconditionalInits()
81 rightInfo.initsWhenTrue().copy()
82 .unconditionalInits()),
84 mergedInitStateIndex = currentScope.methodScope()
85 .recordInitializationStates(mergedInfo);
90 * Code generation for a binary operation
93 * net.sourceforge.phpdt.internal.compiler.lookup.BlockScope
95 * net.sourceforge.phpdt.internal.compiler.codegen.CodeStream
96 * @param valueRequired
99 // public void generateCode(
100 // BlockScope currentScope,
101 // CodeStream codeStream,
102 // boolean valueRequired) {
103 // int pc = codeStream.position;
104 // Label falseLabel, endLabel;
105 // if (constant != Constant.NotAConstant) {
106 // if (valueRequired)
107 // codeStream.generateConstant(constant, implicitConversion);
108 // codeStream.recordPositionsFrom(pc, this.sourceStart);
111 // bits |= OnlyValueRequiredMASK;
112 // generateOptimizedBoolean(
116 // (falseLabel = new Label(codeStream)),
118 // /* improving code gen for such a case: boolean b = i < 0 || true;
119 // * since the label has never been used, we have the inlined value on the
121 // if (falseLabel.hasForwardReferences()) {
122 // if (valueRequired) {
123 // codeStream.iconst_1();
124 // if ((bits & ValueForReturnMASK) != 0) {
125 // codeStream.ireturn();
126 // falseLabel.place();
127 // codeStream.iconst_0();
129 // codeStream.goto_(endLabel = new Label(codeStream));
130 // codeStream.decrStackSize(1);
131 // falseLabel.place();
132 // codeStream.iconst_0();
136 // falseLabel.place();
139 // if (valueRequired) {
140 // codeStream.generateImplicitConversion(implicitConversion);
142 // codeStream.recordPositionsFrom(pc, this.sourceStart);
146 // * Boolean operator code generation
147 // * Optimized operations are: ||
149 // public void generateOptimizedBoolean(
150 // BlockScope currentScope,
151 // CodeStream codeStream,
154 // boolean valueRequired) {
155 // if (constant != Constant.NotAConstant) {
156 // super.generateOptimizedBoolean(currentScope, codeStream, trueLabel,
157 // falseLabel, valueRequired);
160 // Constant condConst;
161 // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) {
162 // if (condConst.booleanValue() == true) {
163 // // <something equivalent to true> || x
164 // left.generateOptimizedBoolean(
170 // if (valueRequired) {
171 // if ((bits & OnlyValueRequiredMASK) != 0) {
172 // codeStream.iconst_1();
174 // if (trueLabel != null) {
175 // codeStream.goto_(trueLabel);
179 // // reposition the endPC
180 // codeStream.updateLastRecordedEndPC(codeStream.position);
182 // // <something equivalent to false> || x
183 // left.generateOptimizedBoolean(
189 // if (rightInitStateIndex != -1) {
190 // codeStream.addDefinitelyAssignedVariables(currentScope,
191 // rightInitStateIndex);
193 // if ((bits & OnlyValueRequiredMASK) != 0) {
194 // right.generateCode(currentScope, codeStream, valueRequired);
196 // right.generateOptimizedBoolean(
204 // if (mergedInitStateIndex != -1) {
205 // codeStream.removeNotDefinitelyAssignedVariables(
207 // mergedInitStateIndex);
211 // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) {
212 // if (condConst.booleanValue() == true) {
213 // // x || <something equivalent to true>
214 // Label internalFalseLabel = new Label(codeStream);
215 // left.generateOptimizedBoolean(
219 // internalFalseLabel, // will be true in the end
221 // if (rightInitStateIndex != -1) {
222 // codeStream.addDefinitelyAssignedVariables(currentScope,
223 // rightInitStateIndex);
225 // internalFalseLabel.place();
226 // right.generateOptimizedBoolean(
232 // if (valueRequired) {
233 // if ((bits & OnlyValueRequiredMASK) != 0) {
234 // codeStream.iconst_1();
236 // if (trueLabel != null) {
237 // codeStream.goto_(trueLabel);
241 // // reposition the endPC
242 // codeStream.updateLastRecordedEndPC(codeStream.position);
244 // // x || <something equivalent to false>
245 // if ((bits & OnlyValueRequiredMASK) != 0) {
246 // left.generateCode(currentScope, codeStream, valueRequired);
248 // left.generateOptimizedBoolean(
255 // if (rightInitStateIndex != -1) {
256 // codeStream.addDefinitelyAssignedVariables(currentScope,
257 // rightInitStateIndex);
259 // right.generateOptimizedBoolean(
266 // if (mergedInitStateIndex != -1) {
267 // codeStream.removeNotDefinitelyAssignedVariables(
269 // mergedInitStateIndex);
274 // if (falseLabel == null) {
275 // if (trueLabel != null) {
276 // // implicit falling through the FALSE case
277 // left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null,
279 // right.generateOptimizedBoolean(
287 // // implicit falling through the TRUE case
288 // if (trueLabel == null) {
289 // Label internalTrueLabel = new Label(codeStream);
290 // left.generateOptimizedBoolean(
293 // internalTrueLabel,
296 // if (rightInitStateIndex != -1) {
297 // codeStream.addDefinitelyAssignedVariables(currentScope,
298 // rightInitStateIndex);
300 // right.generateOptimizedBoolean(
306 // internalTrueLabel.place();
308 // // no implicit fall through TRUE/FALSE --> should never occur
311 // if (mergedInitStateIndex != -1) {
312 // codeStream.removeNotDefinitelyAssignedVariables(
314 // mergedInitStateIndex);
317 public boolean isCompactableOperation() {
321 public void traverse(ASTVisitor visitor, BlockScope scope) {
322 if (visitor.visit(this, scope)) {
323 left.traverse(visitor, scope);
324 right.traverse(visitor, scope);
326 visitor.endVisit(this, scope);