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