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.phpeclipse.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.codegen.Label;
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 AND_AND_Expression extends BinaryExpression {
23 int rightInitStateIndex = -1;
24 int mergedInitStateIndex = -1;
26 public AND_AND_Expression(Expression left, Expression right, int operator) {
27 super(left, right, operator);
30 public FlowInfo analyseCode(
31 BlockScope currentScope,
32 FlowContext flowContext,
35 Constant cst = this.left.optimizedBooleanConstant();
36 boolean isLeftOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true;
37 boolean isLeftOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false;
39 if (isLeftOptimizedTrue) {
41 // need to be careful of scenario:
42 // (x && y) && !z, if passing the left info to the right, it would be swapped by the !
43 FlowInfo mergedInfo = left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
44 mergedInfo = right.analyseCode(currentScope, flowContext, mergedInfo);
45 mergedInitStateIndex =
46 currentScope.methodScope().recordInitializationStates(mergedInfo);
50 FlowInfo leftInfo = left.analyseCode(currentScope, flowContext, flowInfo);
51 // need to be careful of scenario:
52 // (x && y) && !z, if passing the left info to the right, it would be swapped by the !
53 FlowInfo rightInfo = leftInfo.initsWhenTrue().unconditionalInits().copy();
55 currentScope.methodScope().recordInitializationStates(rightInfo);
57 int previousMode = rightInfo.reachMode();
58 if (isLeftOptimizedFalse){
59 rightInfo.setReachMode(FlowInfo.UNREACHABLE);
61 rightInfo = right.analyseCode(currentScope, flowContext, rightInfo);
62 FlowInfo trueMergedInfo = rightInfo.initsWhenTrue().copy();
63 rightInfo.setReachMode(previousMode); // reset after trueMergedInfo got extracted
68 leftInfo.initsWhenFalse().copy().unconditionalInits().mergedWith(
69 rightInfo.initsWhenFalse().copy().unconditionalInits()));
70 mergedInitStateIndex =
71 currentScope.methodScope().recordInitializationStates(mergedInfo);
76 * Code generation for a binary operation
78 // public void generateCode(
79 // BlockScope currentScope,
80 // CodeStream codeStream,
81 // boolean valueRequired) {
83 // int pc = codeStream.position;
84 // Label falseLabel, endLabel;
85 // if (constant != Constant.NotAConstant) {
88 // codeStream.generateConstant(constant, implicitConversion);
89 // codeStream.recordPositionsFrom(pc, this.sourceStart);
92 // bits |= OnlyValueRequiredMASK;
93 // generateOptimizedBoolean(
97 // (falseLabel = new Label(codeStream)),
99 // /* improving code gen for such a case: boolean b = i < 0 && false
100 // * since the label has never been used, we have the inlined value on the stack. */
101 // if (falseLabel.hasForwardReferences()) {
102 // if (valueRequired) {
103 // codeStream.iconst_1();
104 // if ((bits & ValueForReturnMASK) != 0) {
105 // codeStream.ireturn();
106 // falseLabel.place();
107 // codeStream.iconst_0();
109 // codeStream.goto_(endLabel = new Label(codeStream));
110 // codeStream.decrStackSize(1);
111 // falseLabel.place();
112 // codeStream.iconst_0();
116 // falseLabel.place();
119 // if (valueRequired) {
120 // codeStream.generateImplicitConversion(implicitConversion);
122 // // reposition the endPC
123 // codeStream.updateLastRecordedEndPC(codeStream.position);
127 * Boolean operator code generation
128 * Optimized operations are: &&
130 // public void generateOptimizedBoolean(
131 // BlockScope currentScope,
132 // CodeStream codeStream,
135 // boolean valueRequired) {
137 // if (constant != Constant.NotAConstant) {
138 // super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
141 // Constant condConst;
142 // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) {
143 // if (condConst.booleanValue() == true) {
144 // // <something equivalent to true> && x
145 // left.generateOptimizedBoolean(
151 // if (rightInitStateIndex != -1) {
152 // codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
154 // if ((bits & OnlyValueRequiredMASK) != 0) {
155 // right.generateCode(currentScope, codeStream, valueRequired);
157 // right.generateOptimizedBoolean(
165 // // <something equivalent to false> && x
166 // left.generateOptimizedBoolean(
172 // if (valueRequired) {
173 // if ((bits & OnlyValueRequiredMASK) != 0) {
174 // codeStream.iconst_0();
176 // if (falseLabel != null) {
177 // // implicit falling through the TRUE case
178 // codeStream.goto_(falseLabel);
182 // // reposition the endPC
183 // codeStream.updateLastRecordedEndPC(codeStream.position);
185 // if (mergedInitStateIndex != -1) {
186 // codeStream.removeNotDefinitelyAssignedVariables(
188 // mergedInitStateIndex);
192 // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) {
193 // if (condConst.booleanValue() == true) {
194 // // x && <something equivalent to true>
195 // if ((bits & OnlyValueRequiredMASK) != 0) {
196 // left.generateCode(currentScope, codeStream, valueRequired);
198 // left.generateOptimizedBoolean(
205 // if (rightInitStateIndex != -1) {
206 // codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
208 // right.generateOptimizedBoolean(
215 // // x && <something equivalent to false>
216 // Label internalTrueLabel = new Label(codeStream);
217 // left.generateOptimizedBoolean(
220 // internalTrueLabel, // will be false in the end
223 // if (rightInitStateIndex != -1) {
224 // codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
226 // internalTrueLabel.place();
227 // right.generateOptimizedBoolean(
233 // if (valueRequired) {
234 // if ((bits & OnlyValueRequiredMASK) != 0) {
235 // codeStream.iconst_0();
237 // if (falseLabel != null) {
238 // // implicit falling through the TRUE case
239 // codeStream.goto_(falseLabel);
243 // // reposition the endPC
244 // codeStream.updateLastRecordedEndPC(codeStream.position);
246 // if (mergedInitStateIndex != -1) {
247 // codeStream.removeNotDefinitelyAssignedVariables(
249 // mergedInitStateIndex);
254 // if (falseLabel == null) {
255 // if (trueLabel != null) {
256 // // implicit falling through the FALSE case
257 // Label internalFalseLabel = new Label(codeStream);
258 // left.generateOptimizedBoolean(
262 // internalFalseLabel,
264 // if (rightInitStateIndex != -1) {
265 // codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
267 // right.generateOptimizedBoolean(
273 // internalFalseLabel.place();
276 // // implicit falling through the TRUE case
277 // if (trueLabel == null) {
278 // left.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, true);
279 // if (rightInitStateIndex != -1) {
280 // codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
282 // right.generateOptimizedBoolean(
289 // // no implicit fall through TRUE/FALSE --> should never occur
292 // if (mergedInitStateIndex != -1) {
293 // codeStream.removeNotDefinitelyAssignedVariables(
295 // mergedInitStateIndex);
299 public boolean isCompactableOperation() {
303 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
304 if (visitor.visit(this, scope)) {
305 left.traverse(visitor, scope);
306 right.traverse(visitor, scope);
308 visitor.endVisit(this, scope);