KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > internal > compiler > ast > EqualExpression


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-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.classfmt.ClassFileConstants;
16 import org.eclipse.jdt.internal.compiler.codegen.*;
17 import org.eclipse.jdt.internal.compiler.flow.*;
18 import org.eclipse.jdt.internal.compiler.lookup.*;
19
20 public class EqualExpression extends BinaryExpression {
21
22     public EqualExpression(Expression left, Expression right,int operator) {
23         super(left,right,operator);
24     }
25     private void checkNullComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse) {
26         
27         LocalVariableBinding local = this.left.localVariableBinding();
28         if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
29             checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, right.nullStatus(flowInfo), this.left);
30         }
31         local = this.right.localVariableBinding();
32         if (local != null && (local.type.tagBits & TagBits.IsBaseType) == 0) {
33             checkVariableComparison(scope, flowContext, flowInfo, initsWhenTrue, initsWhenFalse, local, left.nullStatus(flowInfo), this.right);
34         }
35     }
36     private void checkVariableComparison(BlockScope scope, FlowContext flowContext, FlowInfo flowInfo, FlowInfo initsWhenTrue, FlowInfo initsWhenFalse, LocalVariableBinding local, int nullStatus, Expression reference) {
37         switch (nullStatus) {
38             case FlowInfo.NULL :
39                 if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
40                     flowContext.recordUsingNullReference(scope, local, reference,
41                             FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo);
42                     initsWhenTrue.markAsComparedEqualToNull(local); // from thereon it is set
43
initsWhenFalse.markAsComparedEqualToNonNull(local); // from thereon it is set
44
} else {
45                     flowContext.recordUsingNullReference(scope, local, reference,
46                             FlowContext.CAN_ONLY_NULL_NON_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo);
47                     initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set
48
initsWhenFalse.markAsComparedEqualToNull(local); // from thereon it is set
49
}
50                 break;
51             case FlowInfo.NON_NULL :
52                 if (((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
53                     flowContext.recordUsingNullReference(scope, local, reference,
54                             FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NON_NULL, flowInfo);
55                     initsWhenTrue.markAsComparedEqualToNonNull(local); // from thereon it is set
56
} else {
57                     flowContext.recordUsingNullReference(scope, local, reference,
58                             FlowContext.CAN_ONLY_NULL | FlowContext.IN_COMPARISON_NULL, flowInfo);
59                 }
60                 break;
61         }
62         // we do not impact enclosing try context because this kind of protection
63
// does not preclude the variable from being null in an enclosing scope
64
}
65     
66     public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) {
67         FlowInfo result;
68         if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
69             if ((left.constant != Constant.NotAConstant) && (left.constant.typeID() == T_boolean)) {
70                 if (left.constant.booleanValue()) { // true == anything
71
// this is equivalent to the right argument inits
72
result = right.analyseCode(currentScope, flowContext, flowInfo);
73                 } else { // false == anything
74
// this is equivalent to the right argument inits negated
75
result = right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
76                 }
77             }
78             else if ((right.constant != Constant.NotAConstant) && (right.constant.typeID() == T_boolean)) {
79                 if (right.constant.booleanValue()) { // anything == true
80
// this is equivalent to the left argument inits
81
result = left.analyseCode(currentScope, flowContext, flowInfo);
82                 } else { // anything == false
83
// this is equivalent to the right argument inits negated
84
result = left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
85                 }
86             }
87             else {
88                 result = right.analyseCode(
89                     currentScope, flowContext,
90                     left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).unconditionalInits();
91             }
92         } else { //NOT_EQUAL :
93
if ((left.constant != Constant.NotAConstant) && (left.constant.typeID() == T_boolean)) {
94                 if (!left.constant.booleanValue()) { // false != anything
95
// this is equivalent to the right argument inits
96
result = right.analyseCode(currentScope, flowContext, flowInfo);
97                 } else { // true != anything
98
// this is equivalent to the right argument inits negated
99
result = right.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
100                 }
101             }
102             else if ((right.constant != Constant.NotAConstant) && (right.constant.typeID() == T_boolean)) {
103                 if (!right.constant.booleanValue()) { // anything != false
104
// this is equivalent to the right argument inits
105
result = left.analyseCode(currentScope, flowContext, flowInfo);
106                 } else { // anything != true
107
// this is equivalent to the right argument inits negated
108
result = left.analyseCode(currentScope, flowContext, flowInfo).asNegatedCondition();
109                 }
110             }
111             else {
112                 result = right.analyseCode(
113                     currentScope, flowContext,
114                     left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits()).
115                     /* unneeded since we flatten it: asNegatedCondition(). */
116                     unconditionalInits();
117             }
118         }
119         if (result instanceof UnconditionalFlowInfo &&
120                 (result.tagBits & FlowInfo.UNREACHABLE) == 0) { // the flow info is flat
121
result = FlowInfo.conditional(result.copy(), result.copy());
122             // TODO (maxime) check, reintroduced copy
123
}
124       checkNullComparison(currentScope, flowContext, result, result.initsWhenTrue(), result.initsWhenFalse());
125       return result;
126     }
127     
128     public final void computeConstant(TypeBinding leftType, TypeBinding rightType) {
129         if ((this.left.constant != Constant.NotAConstant) && (this.right.constant != Constant.NotAConstant)) {
130             this.constant =
131                 Constant.computeConstantOperationEQUAL_EQUAL(
132                     left.constant,
133                     leftType.id,
134                     right.constant,
135                     rightType.id);
136             if (((this.bits & OperatorMASK) >> OperatorSHIFT) == NOT_EQUAL)
137                 constant = BooleanConstant.fromValue(!constant.booleanValue());
138         } else {
139             this.constant = Constant.NotAConstant;
140             // no optimization for null == null
141
}
142     }
143     /**
144      * Normal == or != code generation.
145      *
146      * @param currentScope org.eclipse.jdt.internal.compiler.lookup.BlockScope
147      * @param codeStream org.eclipse.jdt.internal.compiler.codegen.CodeStream
148      * @param valueRequired boolean
149      */

150     public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
151     
152         int pc = codeStream.position;
153         if (constant != Constant.NotAConstant) {
154             if (valueRequired)
155                 codeStream.generateConstant(constant, implicitConversion);
156             codeStream.recordPositionsFrom(pc, this.sourceStart);
157             return;
158         }
159         
160         if ((left.implicitConversion & COMPILE_TYPE_MASK) /*compile-time*/ == T_boolean) {
161             generateBooleanEqual(currentScope, codeStream, valueRequired);
162         } else {
163             generateNonBooleanEqual(currentScope, codeStream, valueRequired);
164         }
165         if (valueRequired) {
166             codeStream.generateImplicitConversion(implicitConversion);
167         }
168         codeStream.recordPositionsFrom(pc, this.sourceStart);
169     }
170     /**
171      * Boolean operator code generation
172      * Optimized operations are: == and !=
173      */

174     public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
175     
176         if (constant != Constant.NotAConstant) {
177             super.generateOptimizedBoolean(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
178             return;
179         }
180         if (((bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL) {
181             if ((left.implicitConversion & COMPILE_TYPE_MASK) /*compile-time*/ == T_boolean) {
182                 generateOptimizedBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
183             } else {
184                 generateOptimizedNonBooleanEqual(currentScope, codeStream, trueLabel, falseLabel, valueRequired);
185             }
186         } else {
187             if ((left.implicitConversion & COMPILE_TYPE_MASK) /*compile-time*/ == T_boolean) {
188                 generateOptimizedBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired);
189             } else {
190                 generateOptimizedNonBooleanEqual(currentScope, codeStream, falseLabel, trueLabel, valueRequired);
191             }
192         }
193     }
194
195     /**
196      * Boolean generation for == with boolean operands
197      *
198      * Note this code does not optimize conditional constants !!!!
199      */

200     public void generateBooleanEqual(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
201     
202         // optimized cases: <something equivalent to true> == x, <something equivalent to false> == x,
203
// optimized cases: <something equivalent to false> != x, <something equivalent to true> != x,
204
boolean isEqualOperator = ((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL;
205         Constant cst = left.optimizedBooleanConstant();
206         if (cst != Constant.NotAConstant) {
207             Constant rightCst = right.optimizedBooleanConstant();
208             if (rightCst != Constant.NotAConstant) {
209                 // <something equivalent to true> == <something equivalent to true>, <something equivalent to false> != <something equivalent to true>
210
// <something equivalent to true> == <something equivalent to false>, <something equivalent to false> != <something equivalent to false>
211
left.generateCode(currentScope, codeStream, false);
212                 right.generateCode(currentScope, codeStream, false);
213                 if (valueRequired) {
214                     boolean leftBool = cst.booleanValue();
215                     boolean rightBool = rightCst.booleanValue();
216                     if (isEqualOperator) {
217                         if (leftBool == rightBool) {
218                             codeStream.iconst_1();
219                         } else {
220                             codeStream.iconst_0();
221                         }
222                     } else {
223                         if (leftBool != rightBool) {
224                             codeStream.iconst_1();
225                         } else {
226                             codeStream.iconst_0();
227                         }
228                     }
229                 }
230             } else if (cst.booleanValue() == isEqualOperator) {
231                 // <something equivalent to true> == x, <something equivalent to false> != x
232
left.generateCode(currentScope, codeStream, false);
233                 right.generateCode(currentScope, codeStream, valueRequired);
234             } else {
235                 // <something equivalent to false> == x, <something equivalent to true> != x
236
if (valueRequired) {
237                     BranchLabel falseLabel = new BranchLabel(codeStream);
238                     left.generateCode(currentScope, codeStream, false);
239                     right.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, valueRequired);
240                     // comparison is TRUE
241
codeStream.iconst_0();
242                     if ((bits & IsReturnedValue) != 0){
243                         codeStream.generateImplicitConversion(this.implicitConversion);
244                         codeStream.generateReturnBytecode(this);
245                         // comparison is FALSE
246
falseLabel.place();
247                         codeStream.iconst_1();
248                     } else {
249                         BranchLabel endLabel = new BranchLabel(codeStream);
250                         codeStream.goto_(endLabel);
251                         codeStream.decrStackSize(1);
252                         // comparison is FALSE
253
falseLabel.place();
254                         codeStream.iconst_1();
255                         endLabel.place();
256                     }
257                 } else {
258                     left.generateCode(currentScope, codeStream, false);
259                     right.generateCode(currentScope, codeStream, false);
260                 }
261 // left.generateCode(currentScope, codeStream, false);
262
// right.generateCode(currentScope, codeStream, valueRequired);
263
// if (valueRequired) {
264
// codeStream.iconst_1();
265
// codeStream.ixor(); // negate
266
// }
267
}
268             return;
269         }
270         cst = right.optimizedBooleanConstant();
271         if (cst != Constant.NotAConstant) {
272             if (cst.booleanValue() == isEqualOperator) {
273                 // x == <something equivalent to true>, x != <something equivalent to false>
274
left.generateCode(currentScope, codeStream, valueRequired);
275                 right.generateCode(currentScope, codeStream, false);
276             } else {
277                 // x == <something equivalent to false>, x != <something equivalent to true>
278
if (valueRequired) {
279                     BranchLabel falseLabel = new BranchLabel(codeStream);
280                     left.generateOptimizedBoolean(currentScope, codeStream, null, falseLabel, valueRequired);
281                     right.generateCode(currentScope, codeStream, false);
282                     // comparison is TRUE
283
codeStream.iconst_0();
284                     if ((bits & IsReturnedValue) != 0){
285                         codeStream.generateImplicitConversion(this.implicitConversion);
286                         codeStream.generateReturnBytecode(this);
287                         // comparison is FALSE
288
falseLabel.place();
289                         codeStream.iconst_1();
290                     } else {
291                         BranchLabel endLabel = new BranchLabel(codeStream);
292                         codeStream.goto_(endLabel);
293                         codeStream.decrStackSize(1);
294                         // comparison is FALSE
295
falseLabel.place();
296                         codeStream.iconst_1();
297                         endLabel.place();
298                     }
299                 } else {
300                     left.generateCode(currentScope, codeStream, false);
301                     right.generateCode(currentScope, codeStream, false);
302                 }
303 // left.generateCode(currentScope, codeStream, valueRequired);
304
// right.generateCode(currentScope, codeStream, false);
305
// if (valueRequired) {
306
// codeStream.iconst_1();
307
// codeStream.ixor(); // negate
308
// }
309
}
310             return;
311         }
312         // default case
313
left.generateCode(currentScope, codeStream, valueRequired);
314         right.generateCode(currentScope, codeStream, valueRequired);
315
316         if (valueRequired) {
317             if (isEqualOperator) {
318                 BranchLabel falseLabel;
319                 codeStream.if_icmpne(falseLabel = new BranchLabel(codeStream));
320                 // comparison is TRUE
321
codeStream.iconst_1();
322                 if ((bits & IsReturnedValue) != 0){
323                     codeStream.generateImplicitConversion(this.implicitConversion);
324                     codeStream.generateReturnBytecode(this);
325                     // comparison is FALSE
326
falseLabel.place();
327                     codeStream.iconst_0();
328                 } else {
329                     BranchLabel endLabel = new BranchLabel(codeStream);
330                     codeStream.goto_(endLabel);
331                     codeStream.decrStackSize(1);
332                     // comparison is FALSE
333
falseLabel.place();
334                     codeStream.iconst_0();
335                     endLabel.place();
336                 }
337             } else {
338                 codeStream.ixor();
339             }
340         }
341     }
342     
343     /**
344      * Boolean generation for == with boolean operands
345      *
346      * Note this code does not optimize conditional constants !!!!
347      */

348     public void generateOptimizedBooleanEqual(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
349     
350         // optimized cases: true == x, false == x
351
if (left.constant != Constant.NotAConstant) {
352             boolean inline = left.constant.booleanValue();
353             right.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired);
354             return;
355         } // optimized cases: x == true, x == false
356
if (right.constant != Constant.NotAConstant) {
357             boolean inline = right.constant.booleanValue();
358             left.generateOptimizedBoolean(currentScope, codeStream, (inline ? trueLabel : falseLabel), (inline ? falseLabel : trueLabel), valueRequired);
359             return;
360         }
361         // default case
362
left.generateCode(currentScope, codeStream, valueRequired);
363         right.generateCode(currentScope, codeStream, valueRequired);
364         if (valueRequired) {
365             if (falseLabel == null) {
366                 if (trueLabel != null) {
367                     // implicit falling through the FALSE case
368
codeStream.if_icmpeq(trueLabel);
369                 }
370             } else {
371                 // implicit falling through the TRUE case
372
if (trueLabel == null) {
373                     codeStream.if_icmpne(falseLabel);
374                 } else {
375                     // no implicit fall through TRUE/FALSE --> should never occur
376
}
377             }
378         }
379         // reposition the endPC
380
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
381     }
382     /**
383      * Boolean generation for == with non-boolean operands
384      *
385      */

386     public void generateNonBooleanEqual(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
387     
388         boolean isEqualOperator = ((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL;
389         if (((left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_int) {
390             Constant cst;
391             if ((cst = left.constant) != Constant.NotAConstant && cst.intValue() == 0) {
392                 // optimized case: 0 == x, 0 != x
393
right.generateCode(currentScope, codeStream, valueRequired);
394                 if (valueRequired) {
395                     BranchLabel falseLabel = new BranchLabel(codeStream);
396                     if (isEqualOperator) {
397                         codeStream.ifne(falseLabel);
398                     } else {
399                         codeStream.ifeq(falseLabel);
400                     }
401                     // comparison is TRUE
402
codeStream.iconst_1();
403                     if ((bits & IsReturnedValue) != 0){
404                         codeStream.generateImplicitConversion(this.implicitConversion);
405                         codeStream.generateReturnBytecode(this);
406                         // comparison is FALSE
407
falseLabel.place();
408                         codeStream.iconst_0();
409                     } else {
410                         BranchLabel endLabel = new BranchLabel(codeStream);
411                         codeStream.goto_(endLabel);
412                         codeStream.decrStackSize(1);
413                         // comparison is FALSE
414
falseLabel.place();
415                         codeStream.iconst_0();
416                         endLabel.place();
417                     }
418                 }
419                 return;
420             }
421             if ((cst = right.constant) != Constant.NotAConstant && cst.intValue() == 0) {
422                 // optimized case: x == 0, x != 0
423
left.generateCode(currentScope, codeStream, valueRequired);
424                 if (valueRequired) {
425                     BranchLabel falseLabel = new BranchLabel(codeStream);
426                     if (isEqualOperator) {
427                         codeStream.ifne(falseLabel);
428                     } else {
429                         codeStream.ifeq(falseLabel);
430                     }
431                     // comparison is TRUE
432
codeStream.iconst_1();
433                     if ((bits & IsReturnedValue) != 0){
434                         codeStream.generateImplicitConversion(this.implicitConversion);
435                         codeStream.generateReturnBytecode(this);
436                         // comparison is FALSE
437
falseLabel.place();
438                         codeStream.iconst_0();
439                     } else {
440                         BranchLabel endLabel = new BranchLabel(codeStream);
441                         codeStream.goto_(endLabel);
442                         codeStream.decrStackSize(1);
443                         // comparison is FALSE
444
falseLabel.place();
445                         codeStream.iconst_0();
446                         endLabel.place();
447                     }
448                 }
449                 return;
450             }
451         }
452
453         // null cases
454
if (right instanceof NullLiteral) {
455             if (left instanceof NullLiteral) {
456                 // null == null, null != null
457
if (valueRequired) {
458                     if (isEqualOperator) {
459                         codeStream.iconst_1();
460                     } else {
461                         codeStream.iconst_0();
462                     }
463                 }
464             } else {
465                 // x == null, x != null
466
left.generateCode(currentScope, codeStream, valueRequired);
467                 if (valueRequired) {
468                     BranchLabel falseLabel = new BranchLabel(codeStream);
469                     if (isEqualOperator) {
470                         codeStream.ifnonnull(falseLabel);
471                     } else {
472                         codeStream.ifnull(falseLabel);
473                     }
474                     // comparison is TRUE
475
codeStream.iconst_1();
476                     if ((bits & IsReturnedValue) != 0){
477                         codeStream.generateImplicitConversion(this.implicitConversion);
478                         codeStream.generateReturnBytecode(this);
479                         // comparison is FALSE
480
falseLabel.place();
481                         codeStream.iconst_0();
482                     } else {
483                         BranchLabel endLabel = new BranchLabel(codeStream);
484                         codeStream.goto_(endLabel);
485                         codeStream.decrStackSize(1);
486                         // comparison is FALSE
487
falseLabel.place();
488                         codeStream.iconst_0();
489                         endLabel.place();
490                     }
491                 }
492             }
493             return;
494         } else if (left instanceof NullLiteral) {
495             // null = x, null != x
496
right.generateCode(currentScope, codeStream, valueRequired);
497             if (valueRequired) {
498                 BranchLabel falseLabel = new BranchLabel(codeStream);
499                 if (isEqualOperator) {
500                     codeStream.ifnonnull(falseLabel);
501                 } else {
502                     codeStream.ifnull(falseLabel);
503                 }
504                 // comparison is TRUE
505
codeStream.iconst_1();
506                 if ((bits & IsReturnedValue) != 0){
507                     codeStream.generateImplicitConversion(this.implicitConversion);
508                     codeStream.generateReturnBytecode(this);
509                     // comparison is FALSE
510
falseLabel.place();
511                     codeStream.iconst_0();
512                 } else {
513                     BranchLabel endLabel = new BranchLabel(codeStream);
514                     codeStream.goto_(endLabel);
515                     codeStream.decrStackSize(1);
516                     // comparison is FALSE
517
falseLabel.place();
518                     codeStream.iconst_0();
519                     endLabel.place();
520                 }
521             }
522             return;
523         }
524     
525         // default case
526
left.generateCode(currentScope, codeStream, valueRequired);
527         right.generateCode(currentScope, codeStream, valueRequired);
528         if (valueRequired) {
529             BranchLabel falseLabel = new BranchLabel(codeStream);
530             if (isEqualOperator) {
531                 switch ((left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { // operand runtime type
532
case T_int :
533                         codeStream.if_icmpne(falseLabel);
534                         break;
535                     case T_float :
536                         codeStream.fcmpl();
537                         codeStream.ifne(falseLabel);
538                         break;
539                     case T_long :
540                         codeStream.lcmp();
541                         codeStream.ifne(falseLabel);
542                         break;
543                     case T_double :
544                         codeStream.dcmpl();
545                         codeStream.ifne(falseLabel);
546                         break;
547                     default :
548                         codeStream.if_acmpne(falseLabel);
549                 }
550             } else {
551                 switch ((left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { // operand runtime type
552
case T_int :
553                         codeStream.if_icmpeq(falseLabel);
554                         break;
555                     case T_float :
556                         codeStream.fcmpl();
557                         codeStream.ifeq(falseLabel);
558                         break;
559                     case T_long :
560                         codeStream.lcmp();
561                         codeStream.ifeq(falseLabel);
562                         break;
563                     case T_double :
564                         codeStream.dcmpl();
565                         codeStream.ifeq(falseLabel);
566                         break;
567                     default :
568                         codeStream.if_acmpeq(falseLabel);
569                 }
570             }
571             // comparison is TRUE
572
codeStream.iconst_1();
573             if ((bits & IsReturnedValue) != 0){
574                 codeStream.generateImplicitConversion(this.implicitConversion);
575                 codeStream.generateReturnBytecode(this);
576                 // comparison is FALSE
577
falseLabel.place();
578                 codeStream.iconst_0();
579             } else {
580                 BranchLabel endLabel = new BranchLabel(codeStream);
581                 codeStream.goto_(endLabel);
582                 codeStream.decrStackSize(1);
583                 // comparison is FALSE
584
falseLabel.place();
585                 codeStream.iconst_0();
586                 endLabel.place();
587             }
588         }
589     }
590     
591     /**
592      * Boolean generation for == with non-boolean operands
593      *
594      */

595     public void generateOptimizedNonBooleanEqual(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
596     
597         int pc = codeStream.position;
598         Constant inline;
599         if ((inline = right.constant) != Constant.NotAConstant) {
600             // optimized case: x == 0
601
if ((((left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_int) && (inline.intValue() == 0)) {
602                 left.generateCode(currentScope, codeStream, valueRequired);
603                 if (valueRequired) {
604                     if (falseLabel == null) {
605                         if (trueLabel != null) {
606                             // implicit falling through the FALSE case
607
codeStream.ifeq(trueLabel);
608                         }
609                     } else {
610                         // implicit falling through the TRUE case
611
if (trueLabel == null) {
612                             codeStream.ifne(falseLabel);
613                         } else {
614                             // no implicit fall through TRUE/FALSE --> should never occur
615
}
616                     }
617                 }
618                 codeStream.recordPositionsFrom(pc, this.sourceStart);
619                 return;
620             }
621         }
622         if ((inline = left.constant) != Constant.NotAConstant) {
623             // optimized case: 0 == x
624
if ((((left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_int)
625                 && (inline.intValue() == 0)) {
626                 right.generateCode(currentScope, codeStream, valueRequired);
627                 if (valueRequired) {
628                     if (falseLabel == null) {
629                         if (trueLabel != null) {
630                             // implicit falling through the FALSE case
631
codeStream.ifeq(trueLabel);
632                         }
633                     } else {
634                         // implicit falling through the TRUE case
635
if (trueLabel == null) {
636                             codeStream.ifne(falseLabel);
637                         } else {
638                             // no implicit fall through TRUE/FALSE --> should never occur
639
}
640                     }
641                 }
642                 codeStream.recordPositionsFrom(pc, this.sourceStart);
643                 return;
644             }
645         }
646         // null cases
647
// optimized case: x == null
648
if (right instanceof NullLiteral) {
649             if (left instanceof NullLiteral) {
650                 // null == null
651
if (valueRequired) {
652                     if (falseLabel == null) {
653                         // implicit falling through the FALSE case
654
if (trueLabel != null) {
655                             codeStream.goto_(trueLabel);
656                         }
657                     }
658                 }
659             } else {
660                 left.generateCode(currentScope, codeStream, valueRequired);
661                 if (valueRequired) {
662                     if (falseLabel == null) {
663                         if (trueLabel != null) {
664                             // implicit falling through the FALSE case
665
codeStream.ifnull(trueLabel);
666                         }
667                     } else {
668                         // implicit falling through the TRUE case
669
if (trueLabel == null) {
670                             codeStream.ifnonnull(falseLabel);
671                         } else {
672                             // no implicit fall through TRUE/FALSE --> should never occur
673
}
674                     }
675                 }
676             }
677             codeStream.recordPositionsFrom(pc, this.sourceStart);
678             return;
679         } else if (left instanceof NullLiteral) { // optimized case: null == x
680
right.generateCode(currentScope, codeStream, valueRequired);
681             if (valueRequired) {
682                 if (falseLabel == null) {
683                     if (trueLabel != null) {
684                         // implicit falling through the FALSE case
685
codeStream.ifnull(trueLabel);
686                     }
687                 } else {
688                     // implicit falling through the TRUE case
689
if (trueLabel == null) {
690                         codeStream.ifnonnull(falseLabel);
691                     } else {
692                         // no implicit fall through TRUE/FALSE --> should never occur
693
}
694                 }
695             }
696             codeStream.recordPositionsFrom(pc, this.sourceStart);
697             return;
698         }
699     
700         // default case
701
left.generateCode(currentScope, codeStream, valueRequired);
702         right.generateCode(currentScope, codeStream, valueRequired);
703         if (valueRequired) {
704             if (falseLabel == null) {
705                 if (trueLabel != null) {
706                     // implicit falling through the FALSE case
707
switch ((left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { // operand runtime type
708
case T_int :
709                             codeStream.if_icmpeq(trueLabel);
710                             break;
711                         case T_float :
712                             codeStream.fcmpl();
713                             codeStream.ifeq(trueLabel);
714                             break;
715                         case T_long :
716                             codeStream.lcmp();
717                             codeStream.ifeq(trueLabel);
718                             break;
719                         case T_double :
720                             codeStream.dcmpl();
721                             codeStream.ifeq(trueLabel);
722                             break;
723                         default :
724                             codeStream.if_acmpeq(trueLabel);
725                     }
726                 }
727             } else {
728                 // implicit falling through the TRUE case
729
if (trueLabel == null) {
730                     switch ((left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) { // operand runtime type
731
case T_int :
732                             codeStream.if_icmpne(falseLabel);
733                             break;
734                         case T_float :
735                             codeStream.fcmpl();
736                             codeStream.ifne(falseLabel);
737                             break;
738                         case T_long :
739                             codeStream.lcmp();
740                             codeStream.ifne(falseLabel);
741                             break;
742                         case T_double :
743                             codeStream.dcmpl();
744                             codeStream.ifne(falseLabel);
745                             break;
746                         default :
747                             codeStream.if_acmpne(falseLabel);
748                     }
749                 } else {
750                     // no implicit fall through TRUE/FALSE --> should never occur
751
}
752             }
753         }
754         codeStream.recordPositionsFrom(pc, this.sourceStart);
755     }
756     public boolean isCompactableOperation() {
757         return false;
758     }
759     public TypeBinding resolveType(BlockScope scope) {
760     
761             boolean leftIsCast, rightIsCast;
762             if ((leftIsCast = left instanceof CastExpression) == true) left.bits |= DisableUnnecessaryCastCheck; // will check later on
763
TypeBinding originalLeftType = left.resolveType(scope);
764     
765             if ((rightIsCast = right instanceof CastExpression) == true) right.bits |= DisableUnnecessaryCastCheck; // will check later on
766
TypeBinding originalRightType = right.resolveType(scope);
767     
768         // always return BooleanBinding
769
if (originalLeftType == null || originalRightType == null){
770             constant = Constant.NotAConstant;
771             return null;
772         }
773     
774         // autoboxing support
775
boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
776         TypeBinding leftType = originalLeftType, rightType = originalRightType;
777         if (use15specifics) {
778             if (leftType != TypeBinding.NULL && leftType.isBaseType()) {
779                 if (!rightType.isBaseType()) {
780                     rightType = scope.environment().computeBoxingType(rightType);
781                 }
782             } else {
783                 if (rightType != TypeBinding.NULL && rightType.isBaseType()) {
784                     leftType = scope.environment().computeBoxingType(leftType);
785                 }
786             }
787         }
788         // both base type
789
if (leftType.isBaseType() && rightType.isBaseType()) {
790             int leftTypeID = leftType.id;
791             int rightTypeID = rightType.id;
792     
793             // the code is an int
794
// (cast) left == (cast) right --> result
795
// 0000 0000 0000 0000 0000
796
// <<16 <<12 <<8 <<4 <<0
797
int operatorSignature = OperatorSignatures[EQUAL_EQUAL][ (leftTypeID << 4) + rightTypeID];
798             left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), originalLeftType);
799             right.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 8) & 0x0000F), originalRightType);
800             bits |= operatorSignature & 0xF;
801             if ((operatorSignature & 0x0000F) == T_undefined) {
802                 constant = Constant.NotAConstant;
803                 scope.problemReporter().invalidOperator(this, leftType, rightType);
804                 return null;
805             }
806             // check need for operand cast
807
if (leftIsCast || rightIsCast) {
808                 CastExpression.checkNeedForArgumentCasts(scope, EQUAL_EQUAL, operatorSignature, left, leftType.id, leftIsCast, right, rightType.id, rightIsCast);
809             }
810             computeConstant(leftType, rightType);
811             return this.resolvedType = TypeBinding.BOOLEAN;
812         }
813     
814         // Object references
815
// spec 15.20.3
816
if ((!leftType.isBaseType() || leftType == TypeBinding.NULL) // cannot compare: Object == (int)0
817
&& (!rightType.isBaseType() || rightType == TypeBinding.NULL)
818                 && (this.checkCastTypesCompatibility(scope, leftType, rightType, null)
819                         || this.checkCastTypesCompatibility(scope, rightType, leftType, null))) {
820
821             // (special case for String)
822
if ((rightType.id == T_JavaLangString) && (leftType.id == T_JavaLangString)) {
823                 computeConstant(leftType, rightType);
824             } else {
825                 constant = Constant.NotAConstant;
826             }
827             TypeBinding objectType = scope.getJavaLangObject();
828             left.computeConversion(scope, objectType, leftType);
829             right.computeConversion(scope, objectType, rightType);
830             // check need for operand cast
831
boolean unnecessaryLeftCast = (left.bits & UnnecessaryCast) != 0;
832             boolean unnecessaryRightCast = (right.bits & UnnecessaryCast) != 0;
833             if (unnecessaryLeftCast || unnecessaryRightCast) {
834                 TypeBinding alternateLeftType = unnecessaryLeftCast ? ((CastExpression)left).expression.resolvedType : leftType;
835                 TypeBinding alternateRightType = unnecessaryRightCast ? ((CastExpression)right).expression.resolvedType : rightType;
836                 if (this.checkCastTypesCompatibility(scope, alternateLeftType, alternateRightType, null)
837                         || this.checkCastTypesCompatibility(scope, alternateRightType, alternateLeftType, null)) {
838                     if (unnecessaryLeftCast) scope.problemReporter().unnecessaryCast((CastExpression)left);
839                     if (unnecessaryRightCast) scope.problemReporter().unnecessaryCast((CastExpression)right);
840                 }
841             }
842             return this.resolvedType = TypeBinding.BOOLEAN;
843         }
844         constant = Constant.NotAConstant;
845         scope.problemReporter().notCompatibleTypesError(this, leftType, rightType);
846         return null;
847     }
848     public void traverse(ASTVisitor visitor, BlockScope scope) {
849         if (visitor.visit(this, scope)) {
850             left.traverse(visitor, scope);
851             right.traverse(visitor, scope);
852         }
853         visitor.endVisit(this, scope);
854     }
855 }
856
Popular Tags