Makefile fixup
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / AND_AND_Expression.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2004 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
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  *******************************************************************************/
11 package org.eclipse.jdt.internal.compiler.ast;
12
13 import org.eclipse.jdt.internal.compiler.ASTVisitor;
14 import org.eclipse.jdt.internal.compiler.impl.*;
15 import org.eclipse.jdt.internal.compiler.codegen.*;
16 import org.eclipse.jdt.internal.compiler.flow.*;
17 import org.eclipse.jdt.internal.compiler.lookup.*;
18
19 //dedicated treatment for the &&
20 public class AND_AND_Expression extends BinaryExpression {
21
22         int rightInitStateIndex = -1;
23         int mergedInitStateIndex = -1;
24
25         public AND_AND_Expression(Expression left, Expression right, int operator) {
26                 super(left, right, operator);
27         }
28
29         public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
30
31                 Constant cst = this.left.optimizedBooleanConstant();
32                 boolean isLeftOptimizedTrue = cst != NotAConstant && cst.booleanValue() == true;
33                 boolean isLeftOptimizedFalse = cst != NotAConstant && cst.booleanValue() == false;
34
35                 if (isLeftOptimizedTrue) {
36                         // TRUE && anything
37                         // need to be careful of scenario:
38                         //  (x && y) && !z, if passing the left info to the right, it would
39                         // be swapped by the !
40                         FlowInfo mergedInfo = left.analyseCode(currentScope, flowContext, flowInfo)
41                                         .unconditionalInits();
42                         mergedInfo = right.analyseCode(currentScope, flowContext, mergedInfo);
43                         mergedInitStateIndex = currentScope.methodScope()
44                                         .recordInitializationStates(mergedInfo);
45                         return mergedInfo;
46                 }
47
48                 FlowInfo leftInfo = left.analyseCode(currentScope, flowContext, flowInfo);
49                 // need to be careful of scenario:
50                 //  (x && y) && !z, if passing the left info to the right, it would be
51                 // swapped by the !
52                 FlowInfo rightInfo = leftInfo.initsWhenTrue().unconditionalInits().copy();
53                 rightInitStateIndex = currentScope.methodScope().recordInitializationStates(rightInfo);
54
55                 int previousMode = rightInfo.reachMode();
56                 if (isLeftOptimizedFalse) {
57                         rightInfo.setReachMode(FlowInfo.UNREACHABLE);
58                 }
59                 rightInfo = right.analyseCode(currentScope, flowContext, rightInfo);
60                 FlowInfo trueMergedInfo = rightInfo.initsWhenTrue().copy();
61                 rightInfo.setReachMode(previousMode); // reset after trueMergedInfo got extracted
62                 FlowInfo mergedInfo = FlowInfo.conditional(
63                                 trueMergedInfo, 
64                                 leftInfo.initsWhenFalse().copy().unconditionalInits().mergedWith(
65                                                 rightInfo.initsWhenFalse().copy().unconditionalInits()));
66                 mergedInitStateIndex = currentScope.methodScope().recordInitializationStates(mergedInfo);
67                 return mergedInfo;
68         }
69
70         /**
71          * Code generation for a binary operation
72          */
73         public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
74
75                 int pc = codeStream.position;
76                 if (constant != Constant.NotAConstant) {
77                         // inlined value
78                         if (valueRequired)
79                                 codeStream.generateConstant(constant, implicitConversion);
80                         codeStream.recordPositionsFrom(pc, this.sourceStart);
81                         return;
82                 }
83                 Constant cst = right.constant;
84                 if (cst != NotAConstant) {
85                         // <expr> && true --> <expr>
86                         if (cst.booleanValue() == true) {
87                                 this.left.generateCode(currentScope, codeStream, valueRequired);
88                         } else {
89                                 // <expr> && false --> false
90                                 this.left.generateCode(currentScope, codeStream, false);
91                                 if (valueRequired) codeStream.iconst_0();
92                         }
93                         if (mergedInitStateIndex != -1) {
94                                 codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
95                         }                       
96                         codeStream.generateImplicitConversion(implicitConversion);
97                         codeStream.updateLastRecordedEndPC(codeStream.position);
98                         codeStream.recordPositionsFrom(pc, this.sourceStart);
99                         return;
100                 }
101                 
102                 Label falseLabel = new Label(codeStream), endLabel;
103                 cst = left.optimizedBooleanConstant();
104                 boolean leftIsConst = cst != NotAConstant;
105                 boolean leftIsTrue = leftIsConst && cst.booleanValue() == true;
106
107                 cst = right.optimizedBooleanConstant();
108                 boolean rightIsConst = cst != NotAConstant;
109                 boolean rightIsTrue = rightIsConst && cst.booleanValue() == true;
110
111                 generateOperands : {
112                         if (leftIsConst) {
113                                 left.generateCode(currentScope, codeStream, false);
114                                 if (!leftIsTrue) {
115                                         break generateOperands; // no need to generate right operand
116                                 }
117                         } else {
118                                 left.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, true); 
119                                 // need value, e.g. if (a == 1 && ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a!=1 
120                         }
121                         if (rightInitStateIndex != -1) {
122                                 codeStream.addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
123                         }
124                         if (rightIsConst) {
125                                 right.generateCode(currentScope, codeStream, false);
126                         } else {
127                                 right.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, valueRequired);
128                         }
129                 }
130                 if (mergedInitStateIndex != -1) {
131                         codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
132                 }
133                 /*
134                  * improving code gen for such a case: boolean b = i < 0 && false since
135                  * the label has never been used, we have the inlined value on the
136                  * stack.
137                  */
138                 if (valueRequired) {
139                         if (leftIsConst && !leftIsTrue) {
140                                 codeStream.iconst_0();
141                                 codeStream.updateLastRecordedEndPC(codeStream.position);
142                         } else {
143                                 if (rightIsConst && !rightIsTrue) {
144                                         codeStream.iconst_0();
145                                         codeStream.updateLastRecordedEndPC(codeStream.position);
146                                 } else {
147                                         codeStream.iconst_1();
148                                 }
149                                 if (falseLabel.hasForwardReferences()) {
150                                         if ((bits & ValueForReturnMASK) != 0) {
151                                                 codeStream.ireturn();
152                                                 falseLabel.place();
153                                                 codeStream.iconst_0();
154                                         } else {
155                                                 codeStream.goto_(endLabel = new Label(codeStream));
156                                                 codeStream.decrStackSize(1);
157                                                 falseLabel.place();
158                                                 codeStream.iconst_0();
159                                                 endLabel.place();
160                                         }
161                                 } else {
162                                         falseLabel.place();
163                                 }
164                         }
165                         codeStream.generateImplicitConversion(implicitConversion);
166                         codeStream.updateLastRecordedEndPC(codeStream.position);
167                 } else {
168                         falseLabel.place();
169                 }
170         }
171
172         /**
173          * Boolean operator code generation Optimized operations are: &&
174          */
175         public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream,
176                         Label trueLabel, Label falseLabel, boolean valueRequired) {
177
178                 if (constant != Constant.NotAConstant) {
179                         super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel,
180                                         valueRequired);
181                         return;
182                 }
183
184                 // <expr> && true --> <expr>
185                 Constant cst = right.constant;
186                 if (cst != NotAConstant && cst.booleanValue() == true) {
187                         int pc = codeStream.position;
188                         this.left.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
189                         if (mergedInitStateIndex != -1) {
190                                 codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
191                         }                       
192                         codeStream.recordPositionsFrom(pc, this.sourceStart);
193                         return;
194                 }
195                 cst = left.optimizedBooleanConstant();
196                 boolean leftIsConst = cst != NotAConstant;
197                 boolean leftIsTrue = leftIsConst && cst.booleanValue() == true;
198
199                 cst = right.optimizedBooleanConstant();
200                 boolean rightIsConst = cst != NotAConstant;
201                 boolean rightIsTrue = rightIsConst && cst.booleanValue() == true;
202
203                 // default case
204                 generateOperands : {
205                         if (falseLabel == null) {
206                                 if (trueLabel != null) {
207                                         // implicit falling through the FALSE case
208                                         Label internalFalseLabel = new Label(codeStream);
209                                         left.generateOptimizedBoolean(currentScope, codeStream, null,
210                                                         internalFalseLabel, !leftIsConst); 
211                                         // need value, e.g. if (a == 1 && ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a!=1
212                                         if (leftIsConst && !leftIsTrue) {
213                                                 internalFalseLabel.place();
214                                                 break generateOperands; // no need to generate right operand
215                                         }
216                                         if (rightInitStateIndex != -1) {
217                                                 codeStream
218                                                                 .addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
219                                         }
220                                         right.generateOptimizedBoolean(currentScope, codeStream, trueLabel, null,
221                                                         valueRequired && !rightIsConst);
222                                         if (valueRequired && rightIsConst && rightIsTrue) {
223                                                 codeStream.goto_(trueLabel);
224                                                 codeStream.updateLastRecordedEndPC(codeStream.position);
225                                         }
226                                         internalFalseLabel.place();
227                                 }
228                         } else {
229                                 // implicit falling through the TRUE case
230                                 if (trueLabel == null) {
231                                         left.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, !leftIsConst); 
232                                         // need value, e.g. if (a == 1 && ((b = 2) > 0)) {} -> shouldn't initialize 'b' if a!=1
233                                         if (leftIsConst && !leftIsTrue) {
234                                                 codeStream.goto_(falseLabel);
235                                                 codeStream.updateLastRecordedEndPC(codeStream.position);
236                                                 break generateOperands; // no need to generate right operand
237                                         }
238                                         if (rightInitStateIndex != -1) {
239                                                 codeStream
240                                                                 .addDefinitelyAssignedVariables(currentScope, rightInitStateIndex);
241                                         }
242                                         right.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel,
243                                                         valueRequired && !rightIsConst);
244                                         if (valueRequired && rightIsConst && !rightIsTrue) {
245                                                 codeStream.goto_(falseLabel);
246                                                 codeStream.updateLastRecordedEndPC(codeStream.position);
247                                         }
248                                 } else {
249                                         // no implicit fall through TRUE/FALSE --> should never occur
250                                 }
251                         }
252                 }
253                 if (mergedInitStateIndex != -1) {
254                         codeStream.removeNotDefinitelyAssignedVariables(currentScope, mergedInitStateIndex);
255                 }
256         }
257
258         public boolean isCompactableOperation() {
259                 return false;
260         }
261
262         public void traverse(ASTVisitor visitor, BlockScope scope) {
263                 if (visitor.visit(this, scope)) {
264                         left.traverse(visitor, scope);
265                         right.traverse(visitor, scope);
266                 }
267                 visitor.endVisit(this, scope);
268         }
269 }