KickJava   Java API By Example, From Geeks To Geeks.

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


1 /*******************************************************************************
2  * Copyright (c) 2000, 2006 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 BinaryExpression extends OperatorExpression {
21     
22 /* Tracking helpers
23  * The following are used to elaborate realistic statistics about binary
24  * expressions. This must be neutralized in the released code.
25  * Search the keyword BE_INSTRUMENTATION to reenable.
26  * An external device must install a suitable probe so as to monitor the
27  * emission of events and publish the results.
28     public interface Probe {
29         public void ping(int depth);
30     }
31     public int depthTracker;
32     public static Probe probe;
33  */

34
35     public Expression left, right;
36     public Constant optimizedBooleanConstant;
37
38 public BinaryExpression(Expression left, Expression right, int operator) {
39     this.left = left;
40     this.right = right;
41     this.bits |= operator << ASTNode.OperatorSHIFT; // encode operator
42
this.sourceStart = left.sourceStart;
43     this.sourceEnd = right.sourceEnd;
44     // BE_INSTRUMENTATION: neutralized in the released code
45
// if (left instanceof BinaryExpression &&
46
// ((left.bits & OperatorMASK) ^ (this.bits & OperatorMASK)) == 0) {
47
// this.depthTracker = ((BinaryExpression)left).depthTracker + 1;
48
// } else {
49
// this.depthTracker = 1;
50
// }
51
}
52
53 public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext,
54         FlowInfo flowInfo) {
55     // keep implementation in sync with CombinedBinaryExpression#analyseCode
56
if (this.resolvedType.id == TypeIds.T_JavaLangString) {
57         return this.right.analyseCode(
58                             currentScope, flowContext,
59                             this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
60                         .unconditionalInits();
61     } else {
62         this.left.checkNPE(currentScope, flowContext, flowInfo);
63         flowInfo = this.left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
64         this.right.checkNPE(currentScope, flowContext, flowInfo);
65         return this.right.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits();
66     }
67 }
68
69 public void computeConstant(BlockScope scope, int leftId, int rightId) {
70     //compute the constant when valid
71
if ((this.left.constant != Constant.NotAConstant)
72         && (this.right.constant != Constant.NotAConstant)) {
73         try {
74             this.constant =
75                 Constant.computeConstantOperation(
76                     this.left.constant,
77                     leftId,
78                     (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT,
79                     this.right.constant,
80                     rightId);
81         } catch (ArithmeticException JavaDoc e) {
82             this.constant = Constant.NotAConstant;
83             // 1.2 no longer throws an exception at compile-time
84
//scope.problemReporter().compileTimeConstantThrowsArithmeticException(this);
85
}
86     } else {
87         this.constant = Constant.NotAConstant;
88         //add some work for the boolean operators & |
89
this.optimizedBooleanConstant(
90             leftId,
91             (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT,
92             rightId);
93     }
94 }
95
96 public Constant optimizedBooleanConstant() {
97     return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant;
98 }
99
100 /**
101  * Code generation for a binary operation
102  */

103 // given the current focus of CombinedBinaryExpression on strings concatenation,
104
// we do not provide a general, non-recursive implementation of generateCode,
105
// but rely upon generateOptimizedStringConcatenationCreation instead
106
public void generateCode(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
107     int pc = codeStream.position;
108     if (this.constant != Constant.NotAConstant) {
109         if (valueRequired)
110             codeStream.generateConstant(this.constant, this.implicitConversion);
111         codeStream.recordPositionsFrom(pc, this.sourceStart);
112         return;
113     }
114     switch ((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) {
115         case PLUS :
116             switch (this.bits & ASTNode.ReturnTypeIDMASK) {
117                 case T_JavaLangString :
118                     // BE_INSTRUMENTATION: neutralized in the released code
119
// if (probe != null) {
120
// probe.ping(this.depthTracker);
121
// }
122
codeStream.generateStringConcatenationAppend(currentScope, this.left, this.right);
123                     if (!valueRequired)
124                         codeStream.pop();
125                     break;
126                 case T_int :
127                     this.left.generateCode(currentScope, codeStream, valueRequired);
128                     this.right.generateCode(currentScope, codeStream, valueRequired);
129                     if (valueRequired)
130                         codeStream.iadd();
131                     break;
132                 case T_long :
133                     this.left.generateCode(currentScope, codeStream, valueRequired);
134                     this.right.generateCode(currentScope, codeStream, valueRequired);
135                     if (valueRequired)
136                         codeStream.ladd();
137                     break;
138                 case T_double :
139                     this.left.generateCode(currentScope, codeStream, valueRequired);
140                     this.right.generateCode(currentScope, codeStream, valueRequired);
141                     if (valueRequired)
142                         codeStream.dadd();
143                     break;
144                 case T_float :
145                     this.left.generateCode(currentScope, codeStream, valueRequired);
146                     this.right.generateCode(currentScope, codeStream, valueRequired);
147                     if (valueRequired)
148                         codeStream.fadd();
149                     break;
150             }
151             break;
152         case MINUS :
153             switch (this.bits & ASTNode.ReturnTypeIDMASK) {
154                 case T_int :
155                     this.left.generateCode(currentScope, codeStream, valueRequired);
156                     this.right.generateCode(currentScope, codeStream, valueRequired);
157                     if (valueRequired)
158                         codeStream.isub();
159                     break;
160                 case T_long :
161                     this.left.generateCode(currentScope, codeStream, valueRequired);
162                     this.right.generateCode(currentScope, codeStream, valueRequired);
163                     if (valueRequired)
164                         codeStream.lsub();
165                     break;
166                 case T_double :
167                     this.left.generateCode(currentScope, codeStream, valueRequired);
168                     this.right.generateCode(currentScope, codeStream, valueRequired);
169                     if (valueRequired)
170                         codeStream.dsub();
171                     break;
172                 case T_float :
173                     this.left.generateCode(currentScope, codeStream, valueRequired);
174                     this.right.generateCode(currentScope, codeStream, valueRequired);
175                     if (valueRequired)
176                         codeStream.fsub();
177                     break;
178             }
179             break;
180         case MULTIPLY :
181             switch (this.bits & ASTNode.ReturnTypeIDMASK) {
182                 case T_int :
183                     this.left.generateCode(currentScope, codeStream, valueRequired);
184                     this.right.generateCode(currentScope, codeStream, valueRequired);
185                     if (valueRequired)
186                         codeStream.imul();
187                     break;
188                 case T_long :
189                     this.left.generateCode(currentScope, codeStream, valueRequired);
190                     this.right.generateCode(currentScope, codeStream, valueRequired);
191                     if (valueRequired)
192                         codeStream.lmul();
193                     break;
194                 case T_double :
195                     this.left.generateCode(currentScope, codeStream, valueRequired);
196                     this.right.generateCode(currentScope, codeStream, valueRequired);
197                     if (valueRequired)
198                         codeStream.dmul();
199                     break;
200                 case T_float :
201                     this.left.generateCode(currentScope, codeStream, valueRequired);
202                     this.right.generateCode(currentScope, codeStream, valueRequired);
203                     if (valueRequired)
204                         codeStream.fmul();
205                     break;
206             }
207             break;
208         case DIVIDE :
209             switch (this.bits & ASTNode.ReturnTypeIDMASK) {
210                 case T_int :
211                     this.left.generateCode(currentScope, codeStream, true);
212                     this.right.generateCode(currentScope, codeStream, true);
213                     codeStream.idiv();
214                     if (!valueRequired)
215                         codeStream.pop();
216                     break;
217                 case T_long :
218                     this.left.generateCode(currentScope, codeStream, true);
219                     this.right.generateCode(currentScope, codeStream, true);
220                     codeStream.ldiv();
221                     if (!valueRequired)
222                         codeStream.pop2();
223                     break;
224                 case T_double :
225                     this.left.generateCode(currentScope, codeStream, valueRequired);
226                     this.right.generateCode(currentScope, codeStream, valueRequired);
227                     if (valueRequired)
228                         codeStream.ddiv();
229                     break;
230                 case T_float :
231                     this.left.generateCode(currentScope, codeStream, valueRequired);
232                     this.right.generateCode(currentScope, codeStream, valueRequired);
233                     if (valueRequired)
234                         codeStream.fdiv();
235                     break;
236             }
237             break;
238         case REMAINDER :
239             switch (this.bits & ASTNode.ReturnTypeIDMASK) {
240                 case T_int :
241                     this.left.generateCode(currentScope, codeStream, true);
242                     this.right.generateCode(currentScope, codeStream, true);
243                     codeStream.irem();
244                     if (!valueRequired)
245                         codeStream.pop();
246                     break;
247                 case T_long :
248                     this.left.generateCode(currentScope, codeStream, true);
249                     this.right.generateCode(currentScope, codeStream, true);
250                     codeStream.lrem();
251                     if (!valueRequired)
252                         codeStream.pop2();
253                     break;
254                 case T_double :
255                     this.left.generateCode(currentScope, codeStream, valueRequired);
256                     this.right.generateCode(currentScope, codeStream, valueRequired);
257                     if (valueRequired)
258                         codeStream.drem();
259                     break;
260                 case T_float :
261                     this.left.generateCode(currentScope, codeStream, valueRequired);
262                     this.right.generateCode(currentScope, codeStream, valueRequired);
263                     if (valueRequired)
264                         codeStream.frem();
265                     break;
266             }
267             break;
268         case AND :
269             switch (this.bits & ASTNode.ReturnTypeIDMASK) {
270                 case T_int :
271                     // 0 & x
272
if ((this.left.constant != Constant.NotAConstant)
273                         && (this.left.constant.typeID() == TypeIds.T_int)
274                         && (this.left.constant.intValue() == 0)) {
275                         this.right.generateCode(currentScope, codeStream, false);
276                         if (valueRequired)
277                             codeStream.iconst_0();
278                     } else {
279                         // x & 0
280
if ((this.right.constant != Constant.NotAConstant)
281                             && (this.right.constant.typeID() == TypeIds.T_int)
282                             && (this.right.constant.intValue() == 0)) {
283                             this.left.generateCode(currentScope, codeStream, false);
284                             if (valueRequired)
285                                 codeStream.iconst_0();
286                         } else {
287                             this.left.generateCode(currentScope, codeStream, valueRequired);
288                             this.right.generateCode(currentScope, codeStream, valueRequired);
289                             if (valueRequired)
290                                 codeStream.iand();
291                         }
292                     }
293                     break;
294                 case T_long :
295                     // 0 & x
296
if ((this.left.constant != Constant.NotAConstant)
297                         && (this.left.constant.typeID() == TypeIds.T_long)
298                         && (this.left.constant.longValue() == 0L)) {
299                         this.right.generateCode(currentScope, codeStream, false);
300                         if (valueRequired)
301                             codeStream.lconst_0();
302                     } else {
303                         // x & 0
304
if ((this.right.constant != Constant.NotAConstant)
305                             && (this.right.constant.typeID() == TypeIds.T_long)
306                             && (this.right.constant.longValue() == 0L)) {
307                             this.left.generateCode(currentScope, codeStream, false);
308                             if (valueRequired)
309                                 codeStream.lconst_0();
310                         } else {
311                             this.left.generateCode(currentScope, codeStream, valueRequired);
312                             this.right.generateCode(currentScope, codeStream, valueRequired);
313                             if (valueRequired)
314                                 codeStream.land();
315                         }
316                     }
317                     break;
318                 case T_boolean : // logical and
319
generateLogicalAnd(currentScope, codeStream, valueRequired);
320                     break;
321             }
322             break;
323         case OR :
324             switch (this.bits & ASTNode.ReturnTypeIDMASK) {
325                 case T_int :
326                     // 0 | x
327
if ((this.left.constant != Constant.NotAConstant)
328                         && (this.left.constant.typeID() == TypeIds.T_int)
329                         && (this.left.constant.intValue() == 0)) {
330                         this.right.generateCode(currentScope, codeStream, valueRequired);
331                     } else {
332                         // x | 0
333
if ((this.right.constant != Constant.NotAConstant)
334                             && (this.right.constant.typeID() == TypeIds.T_int)
335                             && (this.right.constant.intValue() == 0)) {
336                             this.left.generateCode(currentScope, codeStream, valueRequired);
337                         } else {
338                             this.left.generateCode(currentScope, codeStream, valueRequired);
339                             this.right.generateCode(currentScope, codeStream, valueRequired);
340                             if (valueRequired)
341                                 codeStream.ior();
342                         }
343                     }
344                     break;
345                 case T_long :
346                     // 0 | x
347
if ((this.left.constant != Constant.NotAConstant)
348                         && (this.left.constant.typeID() == TypeIds.T_long)
349                         && (this.left.constant.longValue() == 0L)) {
350                         this.right.generateCode(currentScope, codeStream, valueRequired);
351                     } else {
352                         // x | 0
353
if ((this.right.constant != Constant.NotAConstant)
354                             && (this.right.constant.typeID() == TypeIds.T_long)
355                             && (this.right.constant.longValue() == 0L)) {
356                             this.left.generateCode(currentScope, codeStream, valueRequired);
357                         } else {
358                             this.left.generateCode(currentScope, codeStream, valueRequired);
359                             this.right.generateCode(currentScope, codeStream, valueRequired);
360                             if (valueRequired)
361                                 codeStream.lor();
362                         }
363                     }
364                     break;
365                 case T_boolean : // logical or
366
generateLogicalOr(currentScope, codeStream, valueRequired);
367                     break;
368             }
369             break;
370         case XOR :
371             switch (this.bits & ASTNode.ReturnTypeIDMASK) {
372                 case T_int :
373                     // 0 ^ x
374
if ((this.left.constant != Constant.NotAConstant)
375                         && (this.left.constant.typeID() == TypeIds.T_int)
376                         && (this.left.constant.intValue() == 0)) {
377                         this.right.generateCode(currentScope, codeStream, valueRequired);
378                     } else {
379                         // x ^ 0
380
if ((this.right.constant != Constant.NotAConstant)
381                             && (this.right.constant.typeID() == TypeIds.T_int)
382                             && (this.right.constant.intValue() == 0)) {
383                             this.left.generateCode(currentScope, codeStream, valueRequired);
384                         } else {
385                             this.left.generateCode(currentScope, codeStream, valueRequired);
386                             this.right.generateCode(currentScope, codeStream, valueRequired);
387                             if (valueRequired)
388                                 codeStream.ixor();
389                         }
390                     }
391                     break;
392                 case T_long :
393                     // 0 ^ x
394
if ((this.left.constant != Constant.NotAConstant)
395                         && (this.left.constant.typeID() == TypeIds.T_long)
396                         && (this.left.constant.longValue() == 0L)) {
397                         this.right.generateCode(currentScope, codeStream, valueRequired);
398                     } else {
399                         // x ^ 0
400
if ((this.right.constant != Constant.NotAConstant)
401                             && (this.right.constant.typeID() == TypeIds.T_long)
402                             && (this.right.constant.longValue() == 0L)) {
403                             this.left.generateCode(currentScope, codeStream, valueRequired);
404                         } else {
405                             this.left.generateCode(currentScope, codeStream, valueRequired);
406                             this.right.generateCode(currentScope, codeStream, valueRequired);
407                             if (valueRequired)
408                                 codeStream.lxor();
409                         }
410                     }
411                     break;
412                 case T_boolean :
413                     generateLogicalXor(currentScope, codeStream, valueRequired);
414                     break;
415             }
416             break;
417         case LEFT_SHIFT :
418             switch (this.bits & ASTNode.ReturnTypeIDMASK) {
419                 case T_int :
420                     this.left.generateCode(currentScope, codeStream, valueRequired);
421                     this.right.generateCode(currentScope, codeStream, valueRequired);
422                     if (valueRequired)
423                         codeStream.ishl();
424                     break;
425                 case T_long :
426                     this.left.generateCode(currentScope, codeStream, valueRequired);
427                     this.right.generateCode(currentScope, codeStream, valueRequired);
428                     if (valueRequired)
429                         codeStream.lshl();
430             }
431             break;
432         case RIGHT_SHIFT :
433             switch (this.bits & ASTNode.ReturnTypeIDMASK) {
434                 case T_int :
435                     this.left.generateCode(currentScope, codeStream, valueRequired);
436                     this.right.generateCode(currentScope, codeStream, valueRequired);
437                     if (valueRequired)
438                         codeStream.ishr();
439                     break;
440                 case T_long :
441                     this.left.generateCode(currentScope, codeStream, valueRequired);
442                     this.right.generateCode(currentScope, codeStream, valueRequired);
443                     if (valueRequired)
444                         codeStream.lshr();
445             }
446             break;
447         case UNSIGNED_RIGHT_SHIFT :
448             switch (this.bits & ASTNode.ReturnTypeIDMASK) {
449                 case T_int :
450                     this.left.generateCode(currentScope, codeStream, valueRequired);
451                     this.right.generateCode(currentScope, codeStream, valueRequired);
452                     if (valueRequired)
453                         codeStream.iushr();
454                     break;
455                 case T_long :
456                     this.left.generateCode(currentScope, codeStream, valueRequired);
457                     this.right.generateCode(currentScope, codeStream, valueRequired);
458                     if (valueRequired)
459                         codeStream.lushr();
460             }
461             break;
462         case GREATER :
463             BranchLabel falseLabel, endLabel;
464             generateOptimizedGreaterThan(
465                 currentScope,
466                 codeStream,
467                 null,
468                 (falseLabel = new BranchLabel(codeStream)),
469                 valueRequired);
470             if (valueRequired) {
471                 codeStream.iconst_1();
472                 if ((this.bits & ASTNode.IsReturnedValue) != 0) {
473                     codeStream.generateImplicitConversion(this.implicitConversion);
474                     codeStream.generateReturnBytecode(this);
475                     falseLabel.place();
476                     codeStream.iconst_0();
477                 } else {
478                     codeStream.goto_(endLabel = new BranchLabel(codeStream));
479                     codeStream.decrStackSize(1);
480                     falseLabel.place();
481                     codeStream.iconst_0();
482                     endLabel.place();
483                 }
484             }
485             break;
486         case GREATER_EQUAL :
487             generateOptimizedGreaterThanOrEqual(
488                 currentScope,
489                 codeStream,
490                 null,
491                 (falseLabel = new BranchLabel(codeStream)),
492                 valueRequired);
493             if (valueRequired) {
494                 codeStream.iconst_1();
495                 if ((this.bits & ASTNode.IsReturnedValue) != 0) {
496                     codeStream.generateImplicitConversion(this.implicitConversion);
497                     codeStream.generateReturnBytecode(this);
498                     falseLabel.place();
499                     codeStream.iconst_0();
500                 } else {
501                     codeStream.goto_(endLabel = new BranchLabel(codeStream));
502                     codeStream.decrStackSize(1);
503                     falseLabel.place();
504                     codeStream.iconst_0();
505                     endLabel.place();
506                 }
507             }
508             break;
509         case LESS :
510             generateOptimizedLessThan(
511                 currentScope,
512                 codeStream,
513                 null,
514                 (falseLabel = new BranchLabel(codeStream)),
515                 valueRequired);
516             if (valueRequired) {
517                 codeStream.iconst_1();
518                 if ((this.bits & ASTNode.IsReturnedValue) != 0) {
519                     codeStream.generateImplicitConversion(this.implicitConversion);
520                     codeStream.generateReturnBytecode(this);
521                     falseLabel.place();
522                     codeStream.iconst_0();
523                 } else {
524                     codeStream.goto_(endLabel = new BranchLabel(codeStream));
525                     codeStream.decrStackSize(1);
526                     falseLabel.place();
527                     codeStream.iconst_0();
528                     endLabel.place();
529                 }
530             }
531             break;
532         case LESS_EQUAL :
533             generateOptimizedLessThanOrEqual(
534                 currentScope,
535                 codeStream,
536                 null,
537                 (falseLabel = new BranchLabel(codeStream)),
538                 valueRequired);
539             if (valueRequired) {
540                 codeStream.iconst_1();
541                 if ((this.bits & ASTNode.IsReturnedValue) != 0) {
542                     codeStream.generateImplicitConversion(this.implicitConversion);
543                     codeStream.generateReturnBytecode(this);
544                     falseLabel.place();
545                     codeStream.iconst_0();
546                 } else {
547                     codeStream.goto_(endLabel = new BranchLabel(codeStream));
548                     codeStream.decrStackSize(1);
549                     falseLabel.place();
550                     codeStream.iconst_0();
551                     endLabel.place();
552                 }
553             }
554     }
555     if (valueRequired) {
556         codeStream.generateImplicitConversion(this.implicitConversion);
557     }
558     codeStream.recordPositionsFrom(pc, this.sourceStart);
559 }
560
561 /**
562  * Boolean operator code generation
563  * Optimized operations are: <, <=, >, >=, &, |, ^
564  */

565 public void generateOptimizedBoolean(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
566     if ((this.constant != Constant.NotAConstant) && (this.constant.typeID() == TypeIds.T_boolean)) {
567         super.generateOptimizedBoolean(
568             currentScope,
569             codeStream,
570             trueLabel,
571             falseLabel,
572             valueRequired);
573         return;
574     }
575     switch ((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) {
576         case LESS :
577             generateOptimizedLessThan(
578                 currentScope,
579                 codeStream,
580                 trueLabel,
581                 falseLabel,
582                 valueRequired);
583             return;
584         case LESS_EQUAL :
585             generateOptimizedLessThanOrEqual(
586                 currentScope,
587                 codeStream,
588                 trueLabel,
589                 falseLabel,
590                 valueRequired);
591             return;
592         case GREATER :
593             generateOptimizedGreaterThan(
594                 currentScope,
595                 codeStream,
596                 trueLabel,
597                 falseLabel,
598                 valueRequired);
599             return;
600         case GREATER_EQUAL :
601             generateOptimizedGreaterThanOrEqual(
602                 currentScope,
603                 codeStream,
604                 trueLabel,
605                 falseLabel,
606                 valueRequired);
607             return;
608         case AND :
609             generateOptimizedLogicalAnd(
610                 currentScope,
611                 codeStream,
612                 trueLabel,
613                 falseLabel,
614                 valueRequired);
615             return;
616         case OR :
617             generateOptimizedLogicalOr(
618                 currentScope,
619                 codeStream,
620                 trueLabel,
621                 falseLabel,
622                 valueRequired);
623             return;
624         case XOR :
625             generateOptimizedLogicalXor(
626                 currentScope,
627                 codeStream,
628                 trueLabel,
629                 falseLabel,
630                 valueRequired);
631             return;
632     }
633     super.generateOptimizedBoolean(
634         currentScope,
635         codeStream,
636         trueLabel,
637         falseLabel,
638         valueRequired);
639 }
640
641 /**
642  * Boolean generation for >
643  */

644 public void generateOptimizedGreaterThan(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
645     int promotedTypeID = (this.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
646     // both sides got promoted in the same way
647
if (promotedTypeID == TypeIds.T_int) {
648         // 0 > x
649
if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.intValue() == 0)) {
650             this.right.generateCode(currentScope, codeStream, valueRequired);
651             if (valueRequired) {
652                 if (falseLabel == null) {
653                     if (trueLabel != null) {
654                         // implicitly falling through the FALSE case
655
codeStream.iflt(trueLabel);
656                     }
657                 } else {
658                     if (trueLabel == null) {
659                         // implicitly falling through the TRUE case
660
codeStream.ifge(falseLabel);
661                     } else {
662                         // no implicit fall through TRUE/FALSE --> should never occur
663
}
664                 }
665             }
666             // reposition the endPC
667
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
668             return;
669         }
670         // x > 0
671
if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.intValue() == 0)) {
672             this.left.generateCode(currentScope, codeStream, valueRequired);
673             if (valueRequired) {
674                 if (falseLabel == null) {
675                     if (trueLabel != null) {
676                         // implicitly falling through the FALSE case
677
codeStream.ifgt(trueLabel);
678                     }
679                 } else {
680                     if (trueLabel == null) {
681                         // implicitly falling through the TRUE case
682
codeStream.ifle(falseLabel);
683                     } else {
684                         // no implicit fall through TRUE/FALSE --> should never occur
685
}
686                 }
687             }
688             // reposition the endPC
689
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
690             return;
691         }
692     }
693     // default comparison
694
this.left.generateCode(currentScope, codeStream, valueRequired);
695     this.right.generateCode(currentScope, codeStream, valueRequired);
696     if (valueRequired) {
697         if (falseLabel == null) {
698             if (trueLabel != null) {
699                 // implicit falling through the FALSE case
700
switch (promotedTypeID) {
701                     case T_int :
702                         codeStream.if_icmpgt(trueLabel);
703                         break;
704                     case T_float :
705                         codeStream.fcmpl();
706                         codeStream.ifgt(trueLabel);
707                         break;
708                     case T_long :
709                         codeStream.lcmp();
710                         codeStream.ifgt(trueLabel);
711                         break;
712                     case T_double :
713                         codeStream.dcmpl();
714                         codeStream.ifgt(trueLabel);
715                 }
716                 // reposition the endPC
717
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
718                 return;
719             }
720         } else {
721             if (trueLabel == null) {
722                 // implicit falling through the TRUE case
723
switch (promotedTypeID) {
724                     case T_int :
725                         codeStream.if_icmple(falseLabel);
726                         break;
727                     case T_float :
728                         codeStream.fcmpl();
729                         codeStream.ifle(falseLabel);
730                         break;
731                     case T_long :
732                         codeStream.lcmp();
733                         codeStream.ifle(falseLabel);
734                         break;
735                     case T_double :
736                         codeStream.dcmpl();
737                         codeStream.ifle(falseLabel);
738                 }
739                 // reposition the endPC
740
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
741                 return;
742             } else {
743                 // no implicit fall through TRUE/FALSE --> should never occur
744
}
745         }
746     }
747 }
748
749 /**
750  * Boolean generation for >=
751  */

752 public void generateOptimizedGreaterThanOrEqual(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
753     int promotedTypeID = (this.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
754     // both sides got promoted in the same way
755
if (promotedTypeID == TypeIds.T_int) {
756         // 0 >= x
757
if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.intValue() == 0)) {
758             this.right.generateCode(currentScope, codeStream, valueRequired);
759             if (valueRequired) {
760                 if (falseLabel == null) {
761                     if (trueLabel != null) {
762                         // implicitly falling through the FALSE case
763
codeStream.ifle(trueLabel);
764                     }
765                 } else {
766                     if (trueLabel == null) {
767                         // implicitly falling through the TRUE case
768
codeStream.ifgt(falseLabel);
769                     } else {
770                         // no implicit fall through TRUE/FALSE --> should never occur
771
}
772                 }
773             }
774             // reposition the endPC
775
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
776             return;
777         }
778         // x >= 0
779
if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.intValue() == 0)) {
780             this.left.generateCode(currentScope, codeStream, valueRequired);
781             if (valueRequired) {
782                 if (falseLabel == null) {
783                     if (trueLabel != null) {
784                         // implicitly falling through the FALSE case
785
codeStream.ifge(trueLabel);
786                     }
787                 } else {
788                     if (trueLabel == null) {
789                         // implicitly falling through the TRUE case
790
codeStream.iflt(falseLabel);
791                     } else {
792                         // no implicit fall through TRUE/FALSE --> should never occur
793
}
794                 }
795             }
796             // reposition the endPC
797
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
798             return;
799         }
800     }
801     // default comparison
802
this.left.generateCode(currentScope, codeStream, valueRequired);
803     this.right.generateCode(currentScope, codeStream, valueRequired);
804     if (valueRequired) {
805         if (falseLabel == null) {
806             if (trueLabel != null) {
807                 // implicit falling through the FALSE case
808
switch (promotedTypeID) {
809                     case T_int :
810                         codeStream.if_icmpge(trueLabel);
811                         break;
812                     case T_float :
813                         codeStream.fcmpl();
814                         codeStream.ifge(trueLabel);
815                         break;
816                     case T_long :
817                         codeStream.lcmp();
818                         codeStream.ifge(trueLabel);
819                         break;
820                     case T_double :
821                         codeStream.dcmpl();
822                         codeStream.ifge(trueLabel);
823                 }
824                 // reposition the endPC
825
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
826                 return;
827             }
828         } else {
829             if (trueLabel == null) {
830                 // implicit falling through the TRUE case
831
switch (promotedTypeID) {
832                     case T_int :
833                         codeStream.if_icmplt(falseLabel);
834                         break;
835                     case T_float :
836                         codeStream.fcmpl();
837                         codeStream.iflt(falseLabel);
838                         break;
839                     case T_long :
840                         codeStream.lcmp();
841                         codeStream.iflt(falseLabel);
842                         break;
843                     case T_double :
844                         codeStream.dcmpl();
845                         codeStream.iflt(falseLabel);
846                 }
847                 // reposition the endPC
848
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
849                 return;
850             } else {
851                 // no implicit fall through TRUE/FALSE --> should never occur
852
}
853         }
854     }
855 }
856
857 /**
858  * Boolean generation for <
859  */

860 public void generateOptimizedLessThan(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
861     int promotedTypeID = (this.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
862     // both sides got promoted in the same way
863
if (promotedTypeID == TypeIds.T_int) {
864         // 0 < x
865
if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.intValue() == 0)) {
866             this.right.generateCode(currentScope, codeStream, valueRequired);
867             if (valueRequired) {
868                 if (falseLabel == null) {
869                     if (trueLabel != null) {
870                         // implicitly falling through the FALSE case
871
codeStream.ifgt(trueLabel);
872                     }
873                 } else {
874                     if (trueLabel == null) {
875                         // implicitly falling through the TRUE case
876
codeStream.ifle(falseLabel);
877                     } else {
878                         // no implicit fall through TRUE/FALSE --> should never occur
879
}
880                 }
881             }
882             codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
883             return;
884         }
885         // x < 0
886
if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.intValue() == 0)) {
887             this.left.generateCode(currentScope, codeStream, valueRequired);
888             if (valueRequired) {
889                 if (falseLabel == null) {
890                     if (trueLabel != null) {
891                         // implicitly falling through the FALSE case
892
codeStream.iflt(trueLabel);
893                     }
894                 } else {
895                     if (trueLabel == null) {
896                         // implicitly falling through the TRUE case
897
codeStream.ifge(falseLabel);
898                     } else {
899                         // no implicit fall through TRUE/FALSE --> should never occur
900
}
901                 }
902             }
903             codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
904             return;
905         }
906     }
907     // default comparison
908
this.left.generateCode(currentScope, codeStream, valueRequired);
909     this.right.generateCode(currentScope, codeStream, valueRequired);
910     if (valueRequired) {
911         if (falseLabel == null) {
912             if (trueLabel != null) {
913                 // implicit falling through the FALSE case
914
switch (promotedTypeID) {
915                     case T_int :
916                         codeStream.if_icmplt(trueLabel);
917                         break;
918                     case T_float :
919                         codeStream.fcmpg();
920                         codeStream.iflt(trueLabel);
921                         break;
922                     case T_long :
923                         codeStream.lcmp();
924                         codeStream.iflt(trueLabel);
925                         break;
926                     case T_double :
927                         codeStream.dcmpg();
928                         codeStream.iflt(trueLabel);
929                 }
930                 codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
931                 return;
932             }
933         } else {
934             if (trueLabel == null) {
935                 // implicit falling through the TRUE case
936
switch (promotedTypeID) {
937                     case T_int :
938                         codeStream.if_icmpge(falseLabel);
939                         break;
940                     case T_float :
941                         codeStream.fcmpg();
942                         codeStream.ifge(falseLabel);
943                         break;
944                     case T_long :
945                         codeStream.lcmp();
946                         codeStream.ifge(falseLabel);
947                         break;
948                     case T_double :
949                         codeStream.dcmpg();
950                         codeStream.ifge(falseLabel);
951                 }
952                 codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
953                 return;
954             } else {
955                 // no implicit fall through TRUE/FALSE --> should never occur
956
}
957         }
958     }
959 }
960
961 /**
962  * Boolean generation for <=
963  */

964 public void generateOptimizedLessThanOrEqual(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
965     int promotedTypeID = (this.left.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4;
966     // both sides got promoted in the same way
967
if (promotedTypeID == TypeIds.T_int) {
968         // 0 <= x
969
if ((this.left.constant != Constant.NotAConstant) && (this.left.constant.intValue() == 0)) {
970             this.right.generateCode(currentScope, codeStream, valueRequired);
971             if (valueRequired) {
972                 if (falseLabel == null) {
973                     if (trueLabel != null) {
974                         // implicitly falling through the FALSE case
975
codeStream.ifge(trueLabel);
976                     }
977                 } else {
978                     if (trueLabel == null) {
979                         // implicitly falling through the TRUE case
980
codeStream.iflt(falseLabel);
981                     } else {
982                         // no implicit fall through TRUE/FALSE --> should never occur
983
}
984                 }
985             }
986             // reposition the endPC
987
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
988             return;
989         }
990         // x <= 0
991
if ((this.right.constant != Constant.NotAConstant) && (this.right.constant.intValue() == 0)) {
992             this.left.generateCode(currentScope, codeStream, valueRequired);
993             if (valueRequired) {
994                 if (falseLabel == null) {
995                     if (trueLabel != null) {
996                         // implicitly falling through the FALSE case
997
codeStream.ifle(trueLabel);
998                     }
999                 } else {
1000                    if (trueLabel == null) {
1001                        // implicitly falling through the TRUE case
1002
codeStream.ifgt(falseLabel);
1003                    } else {
1004                        // no implicit fall through TRUE/FALSE --> should never occur
1005
}
1006                }
1007            }
1008            // reposition the endPC
1009
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1010            return;
1011        }
1012    }
1013    // default comparison
1014
this.left.generateCode(currentScope, codeStream, valueRequired);
1015    this.right.generateCode(currentScope, codeStream, valueRequired);
1016    if (valueRequired) {
1017        if (falseLabel == null) {
1018            if (trueLabel != null) {
1019                // implicit falling through the FALSE case
1020
switch (promotedTypeID) {
1021                    case T_int :
1022                        codeStream.if_icmple(trueLabel);
1023                        break;
1024                    case T_float :
1025                        codeStream.fcmpg();
1026                        codeStream.ifle(trueLabel);
1027                        break;
1028                    case T_long :
1029                        codeStream.lcmp();
1030                        codeStream.ifle(trueLabel);
1031                        break;
1032                    case T_double :
1033                        codeStream.dcmpg();
1034                        codeStream.ifle(trueLabel);
1035                }
1036                // reposition the endPC
1037
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1038                return;
1039            }
1040        } else {
1041            if (trueLabel == null) {
1042                // implicit falling through the TRUE case
1043
switch (promotedTypeID) {
1044                    case T_int :
1045                        codeStream.if_icmpgt(falseLabel);
1046                        break;
1047                    case T_float :
1048                        codeStream.fcmpg();
1049                        codeStream.ifgt(falseLabel);
1050                        break;
1051                    case T_long :
1052                        codeStream.lcmp();
1053                        codeStream.ifgt(falseLabel);
1054                        break;
1055                    case T_double :
1056                        codeStream.dcmpg();
1057                        codeStream.ifgt(falseLabel);
1058                }
1059                // reposition the endPC
1060
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1061                return;
1062            } else {
1063                // no implicit fall through TRUE/FALSE --> should never occur
1064
}
1065        }
1066    }
1067}
1068
1069/**
1070 * Boolean generation for &
1071 */

1072public void generateLogicalAnd(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
1073    Constant condConst;
1074    if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) {
1075        if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
1076            if (condConst.booleanValue() == true) {
1077                // <something equivalent to true> & x
1078
this.left.generateCode(currentScope, codeStream, false);
1079                this.right.generateCode(currentScope, codeStream, valueRequired);
1080            } else {
1081                // <something equivalent to false> & x
1082
this.left.generateCode(currentScope, codeStream, false);
1083                this.right.generateCode(currentScope, codeStream, false);
1084                if (valueRequired) {
1085                    codeStream.iconst_0();
1086                }
1087                // reposition the endPC
1088
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1089            }
1090            return;
1091        }
1092        if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
1093            if (condConst.booleanValue() == true) {
1094                // x & <something equivalent to true>
1095
this.left.generateCode(currentScope, codeStream, valueRequired);
1096                this.right.generateCode(currentScope, codeStream, false);
1097            } else {
1098                // x & <something equivalent to false>
1099
this.left.generateCode(currentScope, codeStream, false);
1100                this.right.generateCode(currentScope, codeStream, false);
1101                if (valueRequired) {
1102                    codeStream.iconst_0();
1103                }
1104                // reposition the endPC
1105
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1106            }
1107            return;
1108        }
1109    }
1110    // default case
1111
this.left.generateCode(currentScope, codeStream, valueRequired);
1112    this.right.generateCode(currentScope, codeStream, valueRequired);
1113    if (valueRequired) {
1114        codeStream.iand();
1115    }
1116    // reposition the endPC
1117
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1118}
1119
1120/**
1121 * Boolean generation for |
1122 */

1123public void generateLogicalOr(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
1124    Constant condConst;
1125    if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) {
1126        if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
1127            if (condConst.booleanValue() == true) {
1128                // <something equivalent to true> | x
1129
this.left.generateCode(currentScope, codeStream, false);
1130                this.right.generateCode(currentScope, codeStream, false);
1131                if (valueRequired) {
1132                    codeStream.iconst_1();
1133                }
1134                // reposition the endPC
1135
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1136            } else {
1137                // <something equivalent to false> | x
1138
this.left.generateCode(currentScope, codeStream, false);
1139                this.right.generateCode(currentScope, codeStream, valueRequired);
1140            }
1141            return;
1142        }
1143        if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
1144            if (condConst.booleanValue() == true) {
1145                // x | <something equivalent to true>
1146
this.left.generateCode(currentScope, codeStream, false);
1147                this.right.generateCode(currentScope, codeStream, false);
1148                if (valueRequired) {
1149                    codeStream.iconst_1();
1150                }
1151                // reposition the endPC
1152
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1153            } else {
1154                // x | <something equivalent to false>
1155
this.left.generateCode(currentScope, codeStream, valueRequired);
1156                this.right.generateCode(currentScope, codeStream, false);
1157            }
1158            return;
1159        }
1160    }
1161    // default case
1162
this.left.generateCode(currentScope, codeStream, valueRequired);
1163    this.right.generateCode(currentScope, codeStream, valueRequired);
1164    if (valueRequired) {
1165        codeStream.ior();
1166    }
1167    // reposition the endPC
1168
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1169}
1170
1171/**
1172 * Boolean generation for ^
1173 */

1174public void generateLogicalXor(BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {
1175    Constant condConst;
1176    if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) {
1177        if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
1178            if (condConst.booleanValue() == true) {
1179                // <something equivalent to true> ^ x
1180
this.left.generateCode(currentScope, codeStream, false);
1181                if (valueRequired) {
1182                    codeStream.iconst_1();
1183                }
1184                this.right.generateCode(currentScope, codeStream, valueRequired);
1185                if (valueRequired) {
1186                    codeStream.ixor(); // negate
1187
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1188                }
1189            } else {
1190                // <something equivalent to false> ^ x
1191
this.left.generateCode(currentScope, codeStream, false);
1192                this.right.generateCode(currentScope, codeStream, valueRequired);
1193            }
1194            return;
1195        }
1196        if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
1197            if (condConst.booleanValue() == true) {
1198                // x ^ <something equivalent to true>
1199
this.left.generateCode(currentScope, codeStream, valueRequired);
1200                this.right.generateCode(currentScope, codeStream, false);
1201                if (valueRequired) {
1202                    codeStream.iconst_1();
1203                    codeStream.ixor(); // negate
1204
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1205                }
1206            } else {
1207                // x ^ <something equivalent to false>
1208
this.left.generateCode(currentScope, codeStream, valueRequired);
1209                this.right.generateCode(currentScope, codeStream, false);
1210            }
1211            return;
1212        }
1213    }
1214    // default case
1215
this.left.generateCode(currentScope, codeStream, valueRequired);
1216    this.right.generateCode(currentScope, codeStream, valueRequired);
1217    if (valueRequired) {
1218        codeStream.ixor();
1219    }
1220    // reposition the endPC
1221
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1222}
1223
1224/**
1225 * Boolean generation for &
1226 */

1227public void generateOptimizedLogicalAnd(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
1228    Constant condConst;
1229    if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) {
1230        if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
1231            if (condConst.booleanValue() == true) {
1232                // <something equivalent to true> & x
1233
this.left.generateOptimizedBoolean(
1234                    currentScope,
1235                    codeStream,
1236                    trueLabel,
1237                    falseLabel,
1238                    false);
1239                this.right.generateOptimizedBoolean(
1240                    currentScope,
1241                    codeStream,
1242                    trueLabel,
1243                    falseLabel,
1244                    valueRequired);
1245            } else {
1246                // <something equivalent to false> & x
1247
this.left.generateOptimizedBoolean(
1248                    currentScope,
1249                    codeStream,
1250                    trueLabel,
1251                    falseLabel,
1252                    false);
1253                this.right.generateOptimizedBoolean(
1254                    currentScope,
1255                    codeStream,
1256                    trueLabel,
1257                    falseLabel,
1258                    false);
1259                if (valueRequired) {
1260                    if (falseLabel != null) {
1261                        // implicit falling through the TRUE case
1262
codeStream.goto_(falseLabel);
1263                    }
1264                }
1265                // reposition the endPC
1266
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1267            }
1268            return;
1269        }
1270        if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
1271            if (condConst.booleanValue() == true) {
1272                // x & <something equivalent to true>
1273
this.left.generateOptimizedBoolean(
1274                    currentScope,
1275                    codeStream,
1276                    trueLabel,
1277                    falseLabel,
1278                    valueRequired);
1279                this.right.generateOptimizedBoolean(
1280                    currentScope,
1281                    codeStream,
1282                    trueLabel,
1283                    falseLabel,
1284                    false);
1285            } else {
1286                // x & <something equivalent to false>
1287
BranchLabel internalTrueLabel = new BranchLabel(codeStream);
1288                this.left.generateOptimizedBoolean(
1289                    currentScope,
1290                    codeStream,
1291                    internalTrueLabel,
1292                    falseLabel,
1293                    false);
1294                internalTrueLabel.place();
1295                this.right.generateOptimizedBoolean(
1296                    currentScope,
1297                    codeStream,
1298                    trueLabel,
1299                    falseLabel,
1300                    false);
1301                if (valueRequired) {
1302                    if (falseLabel != null) {
1303                        // implicit falling through the TRUE case
1304
codeStream.goto_(falseLabel);
1305                    }
1306                }
1307                // reposition the endPC
1308
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1309            }
1310            return;
1311        }
1312    }
1313    // default case
1314
this.left.generateCode(currentScope, codeStream, valueRequired);
1315    this.right.generateCode(currentScope, codeStream, valueRequired);
1316    if (valueRequired) {
1317        codeStream.iand();
1318        if (falseLabel == null) {
1319            if (trueLabel != null) {
1320                // implicit falling through the FALSE case
1321
codeStream.ifne(trueLabel);
1322            }
1323        } else {
1324            // implicit falling through the TRUE case
1325
if (trueLabel == null) {
1326                codeStream.ifeq(falseLabel);
1327            } else {
1328                // no implicit fall through TRUE/FALSE --> should never occur
1329
}
1330        }
1331    }
1332    // reposition the endPC
1333
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1334}
1335
1336/**
1337 * Boolean generation for |
1338 */

1339public void generateOptimizedLogicalOr(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
1340    Constant condConst;
1341    if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) {
1342        if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
1343            if (condConst.booleanValue() == true) {
1344                // <something equivalent to true> | x
1345
this.left.generateOptimizedBoolean(
1346                    currentScope,
1347                    codeStream,
1348                    trueLabel,
1349                    falseLabel,
1350                    false);
1351                BranchLabel internalFalseLabel = new BranchLabel(codeStream);
1352                this.right.generateOptimizedBoolean(
1353                    currentScope,
1354                    codeStream,
1355                    trueLabel,
1356                    internalFalseLabel,
1357                    false);
1358                internalFalseLabel.place();
1359                if (valueRequired) {
1360                    if (trueLabel != null) {
1361                        codeStream.goto_(trueLabel);
1362                    }
1363                }
1364                // reposition the endPC
1365
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1366            } else {
1367                // <something equivalent to false> | x
1368
this.left.generateOptimizedBoolean(
1369                    currentScope,
1370                    codeStream,
1371                    trueLabel,
1372                    falseLabel,
1373                    false);
1374                this.right.generateOptimizedBoolean(
1375                    currentScope,
1376                    codeStream,
1377                    trueLabel,
1378                    falseLabel,
1379                    valueRequired);
1380            }
1381            return;
1382        }
1383        if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
1384            if (condConst.booleanValue() == true) {
1385                // x | <something equivalent to true>
1386
BranchLabel internalFalseLabel = new BranchLabel(codeStream);
1387                this.left.generateOptimizedBoolean(
1388                    currentScope,
1389                    codeStream,
1390                    trueLabel,
1391                    internalFalseLabel,
1392                    false);
1393                internalFalseLabel.place();
1394                this.right.generateOptimizedBoolean(
1395                    currentScope,
1396                    codeStream,
1397                    trueLabel,
1398                    falseLabel,
1399                    false);
1400                if (valueRequired) {
1401                    if (trueLabel != null) {
1402                        codeStream.goto_(trueLabel);
1403                    }
1404                }
1405                // reposition the endPC
1406
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1407            } else {
1408                // x | <something equivalent to false>
1409
this.left.generateOptimizedBoolean(
1410                    currentScope,
1411                    codeStream,
1412                    trueLabel,
1413                    falseLabel,
1414                    valueRequired);
1415                this.right.generateOptimizedBoolean(
1416                    currentScope,
1417                    codeStream,
1418                    trueLabel,
1419                    falseLabel,
1420                    false);
1421            }
1422            return;
1423        }
1424    }
1425    // default case
1426
this.left.generateCode(currentScope, codeStream, valueRequired);
1427    this.right.generateCode(currentScope, codeStream, valueRequired);
1428    if (valueRequired) {
1429        codeStream.ior();
1430        if (falseLabel == null) {
1431            if (trueLabel != null) {
1432                // implicit falling through the FALSE case
1433
codeStream.ifne(trueLabel);
1434            }
1435        } else {
1436            // implicit falling through the TRUE case
1437
if (trueLabel == null) {
1438                codeStream.ifeq(falseLabel);
1439            } else {
1440                // no implicit fall through TRUE/FALSE --> should never occur
1441
}
1442        }
1443    }
1444    // reposition the endPC
1445
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1446}
1447
1448/**
1449 * Boolean generation for ^
1450 */

1451public void generateOptimizedLogicalXor(BlockScope currentScope, CodeStream codeStream, BranchLabel trueLabel, BranchLabel falseLabel, boolean valueRequired) {
1452    Constant condConst;
1453    if ((this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK) == TypeIds.T_boolean) {
1454        if ((condConst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
1455            if (condConst.booleanValue() == true) {
1456                // <something equivalent to true> ^ x
1457
this.left.generateOptimizedBoolean(
1458                    currentScope,
1459                    codeStream,
1460                    trueLabel,
1461                    falseLabel,
1462                    false);
1463                this.right.generateOptimizedBoolean(
1464                    currentScope,
1465                    codeStream,
1466                    falseLabel, // negating
1467
trueLabel,
1468                    valueRequired);
1469            } else {
1470                // <something equivalent to false> ^ x
1471
this.left.generateOptimizedBoolean(
1472                    currentScope,
1473                    codeStream,
1474                    trueLabel,
1475                    falseLabel,
1476                    false);
1477                this.right.generateOptimizedBoolean(
1478                    currentScope,
1479                    codeStream,
1480                    trueLabel,
1481                    falseLabel,
1482                    valueRequired);
1483            }
1484            return;
1485        }
1486        if ((condConst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
1487            if (condConst.booleanValue() == true) {
1488                // x ^ <something equivalent to true>
1489
this.left.generateOptimizedBoolean(
1490                    currentScope,
1491                    codeStream,
1492                    falseLabel, // negating
1493
trueLabel,
1494                    valueRequired);
1495                this.right.generateOptimizedBoolean(
1496                    currentScope,
1497                    codeStream,
1498                    trueLabel,
1499                    falseLabel,
1500                    false);
1501            } else {
1502                // x ^ <something equivalent to false>
1503
this.left.generateOptimizedBoolean(
1504                    currentScope,
1505                    codeStream,
1506                    trueLabel,
1507                    falseLabel,
1508                    valueRequired);
1509                this.right.generateOptimizedBoolean(
1510                    currentScope,
1511                    codeStream,
1512                    trueLabel,
1513                    falseLabel,
1514                    false);
1515            }
1516            return;
1517        }
1518    }
1519    // default case
1520
this.left.generateCode(currentScope, codeStream, valueRequired);
1521    this.right.generateCode(currentScope, codeStream, valueRequired);
1522    if (valueRequired) {
1523        codeStream.ixor();
1524        if (falseLabel == null) {
1525            if (trueLabel != null) {
1526                // implicit falling through the FALSE case
1527
codeStream.ifne(trueLabel);
1528            }
1529        } else {
1530            // implicit falling through the TRUE case
1531
if (trueLabel == null) {
1532                codeStream.ifeq(falseLabel);
1533            } else {
1534                // no implicit fall through TRUE/FALSE --> should never occur
1535
}
1536        }
1537    }
1538    // reposition the endPC
1539
codeStream.updateLastRecordedEndPC(currentScope, codeStream.position);
1540}
1541
1542public void generateOptimizedStringConcatenation(BlockScope blockScope, CodeStream codeStream, int typeID) {
1543    // keep implementation in sync with CombinedBinaryExpression
1544
// #generateOptimizedStringConcatenation
1545
/* In the case trying to make a string concatenation, there is no need to create a new
1546     * string buffer, thus use a lower-level API for code generation involving only the
1547     * appending of arguments to the existing StringBuffer
1548     */

1549
1550    if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS)
1551        && ((this.bits & ASTNode.ReturnTypeIDMASK) == TypeIds.T_JavaLangString)) {
1552        if (this.constant != Constant.NotAConstant) {
1553            codeStream.generateConstant(this.constant, this.implicitConversion);
1554            codeStream.invokeStringConcatenationAppendForType(this.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
1555        } else {
1556            int pc = codeStream.position;
1557            this.left.generateOptimizedStringConcatenation(
1558                blockScope,
1559                codeStream,
1560                this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
1561            codeStream.recordPositionsFrom(pc, this.left.sourceStart);
1562            pc = codeStream.position;
1563            this.right.generateOptimizedStringConcatenation(
1564                blockScope,
1565                codeStream,
1566                this.right.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
1567            codeStream.recordPositionsFrom(pc, this.right.sourceStart);
1568        }
1569    } else {
1570        super.generateOptimizedStringConcatenation(blockScope, codeStream, typeID);
1571    }
1572}
1573
1574public void generateOptimizedStringConcatenationCreation(BlockScope blockScope, CodeStream codeStream, int typeID) {
1575    // keep implementation in sync with CombinedBinaryExpression
1576
// #generateOptimizedStringConcatenationCreation
1577
/* In the case trying to make a string concatenation, there is no need to create a new
1578     * string buffer, thus use a lower-level API for code generation involving only the
1579     * appending of arguments to the existing StringBuffer
1580     */

1581    if ((((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS)
1582        && ((this.bits & ASTNode.ReturnTypeIDMASK) == TypeIds.T_JavaLangString)) {
1583        if (this.constant != Constant.NotAConstant) {
1584            codeStream.newStringContatenation(); // new: java.lang.StringBuffer
1585
codeStream.dup();
1586            codeStream.ldc(this.constant.stringValue());
1587            codeStream.invokeStringConcatenationStringConstructor();
1588            // invokespecial: java.lang.StringBuffer.<init>(Ljava.lang.String;)V
1589
} else {
1590            int pc = codeStream.position;
1591            this.left.generateOptimizedStringConcatenationCreation(
1592                blockScope,
1593                codeStream,
1594                this.left.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
1595            codeStream.recordPositionsFrom(pc, this.left.sourceStart);
1596            pc = codeStream.position;
1597            this.right.generateOptimizedStringConcatenation(
1598                blockScope,
1599                codeStream,
1600                this.right.implicitConversion & TypeIds.COMPILE_TYPE_MASK);
1601            codeStream.recordPositionsFrom(pc, this.right.sourceStart);
1602        }
1603    } else {
1604        super.generateOptimizedStringConcatenationCreation(blockScope, codeStream, typeID);
1605    }
1606}
1607
1608public boolean isCompactableOperation() {
1609    return true;
1610}
1611
1612/**
1613 * Separates into a reusable method the subpart of {@link
1614 * #resolveType(BlockScope)} that needs to be executed while climbing up the
1615 * chain of expressions of this' leftmost branch. For use by {@link
1616 * CombinedBinaryExpression#resolveType(BlockScope)}.
1617 * @param scope the scope within which the resolution occurs
1618 */

1619void nonRecursiveResolveTypeUpwards(BlockScope scope) {
1620    // keep implementation in sync with BinaryExpression#resolveType
1621
boolean leftIsCast, rightIsCast;
1622    TypeBinding leftType = this.left.resolvedType;
1623    
1624    if ((rightIsCast = this.right instanceof CastExpression) == true) {
1625        this.right.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
1626
}
1627    TypeBinding rightType = this.right.resolveType(scope);
1628
1629    // use the id of the type to navigate into the table
1630
if (leftType == null || rightType == null) {
1631        this.constant = Constant.NotAConstant;
1632        return;
1633    }
1634
1635    int leftTypeID = leftType.id;
1636    int rightTypeID = rightType.id;
1637
1638    // autoboxing support
1639
boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
1640    if (use15specifics) {
1641        if (!leftType.isBaseType() && rightTypeID != TypeIds.T_JavaLangString && rightTypeID != TypeIds.T_null) {
1642            leftTypeID = scope.environment().computeBoxingType(leftType).id;
1643        }
1644        if (!rightType.isBaseType() && leftTypeID != TypeIds.T_JavaLangString && leftTypeID != TypeIds.T_null) {
1645            rightTypeID = scope.environment().computeBoxingType(rightType).id;
1646        }
1647    }
1648    if (leftTypeID > 15
1649        || rightTypeID > 15) { // must convert String + Object || Object + String
1650
if (leftTypeID == TypeIds.T_JavaLangString) {
1651            rightTypeID = TypeIds.T_JavaLangObject;
1652        } else if (rightTypeID == TypeIds.T_JavaLangString) {
1653            leftTypeID = TypeIds.T_JavaLangObject;
1654        } else {
1655            this.constant = Constant.NotAConstant;
1656            scope.problemReporter().invalidOperator(this, leftType, rightType);
1657            return;
1658        }
1659    }
1660    if (((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS) {
1661        if (leftTypeID == TypeIds.T_JavaLangString) {
1662            this.left.computeConversion(scope, leftType, leftType);
1663            if (rightType.isArrayType() && ((ArrayBinding) rightType).elementsType() == TypeBinding.CHAR) {
1664                scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.right);
1665            }
1666        }
1667        if (rightTypeID == TypeIds.T_JavaLangString) {
1668            this.right.computeConversion(scope, rightType, rightType);
1669            if (leftType.isArrayType() && ((ArrayBinding) leftType).elementsType() == TypeBinding.CHAR) {
1670                scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.left);
1671            }
1672        }
1673    }
1674
1675    // the code is an int
1676
// (cast) left Op (cast) right --> result
1677
// 0000 0000 0000 0000 0000
1678
// <<16 <<12 <<8 <<4 <<0
1679

1680    // Don't test for result = 0. If it is zero, some more work is done.
1681
// On the one hand when it is not zero (correct code) we avoid doing the test
1682
int operator = (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT;
1683    int operatorSignature = OperatorExpression.OperatorSignatures[operator][(leftTypeID << 4) + rightTypeID];
1684
1685    this.left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), leftType);
1686    this.right.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 8) & 0x0000F), rightType);
1687    this.bits |= operatorSignature & 0xF;
1688    switch (operatorSignature & 0xF) { // record the current ReturnTypeID
1689
// only switch on possible result type.....
1690
case T_boolean :
1691            this.resolvedType = TypeBinding.BOOLEAN;
1692            break;
1693        case T_byte :
1694            this.resolvedType = TypeBinding.BYTE;
1695            break;
1696        case T_char :
1697            this.resolvedType = TypeBinding.CHAR;
1698            break;
1699        case T_double :
1700            this.resolvedType = TypeBinding.DOUBLE;
1701            break;
1702        case T_float :
1703            this.resolvedType = TypeBinding.FLOAT;
1704            break;
1705        case T_int :
1706            this.resolvedType = TypeBinding.INT;
1707            break;
1708        case T_long :
1709            this.resolvedType = TypeBinding.LONG;
1710            break;
1711        case T_JavaLangString :
1712            this.resolvedType = scope.getJavaLangString();
1713            break;
1714        default : //error........
1715
this.constant = Constant.NotAConstant;
1716            scope.problemReporter().invalidOperator(this, leftType, rightType);
1717            return;
1718    }
1719
1720    // check need for operand cast
1721
if ((leftIsCast = (this.left instanceof CastExpression)) == true ||
1722            rightIsCast) {
1723        CastExpression.checkNeedForArgumentCasts(scope, operator, operatorSignature, this.left, leftTypeID, leftIsCast, this.right, rightTypeID, rightIsCast);
1724    }
1725    // compute the constant when valid
1726
computeConstant(scope, leftTypeID, rightTypeID);
1727}
1728
1729public void optimizedBooleanConstant(int leftId, int operator, int rightId) {
1730    switch (operator) {
1731        case AND :
1732            if ((leftId != TypeIds.T_boolean) || (rightId != TypeIds.T_boolean))
1733                return;
1734        case AND_AND :
1735            Constant cst;
1736            if ((cst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
1737                if (cst.booleanValue() == false) { // left is equivalent to false
1738
this.optimizedBooleanConstant = cst; // constant(false)
1739
return;
1740                } else { //left is equivalent to true
1741
if ((cst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
1742                        this.optimizedBooleanConstant = cst;
1743                        // the conditional result is equivalent to the right conditional value
1744
}
1745                    return;
1746                }
1747            }
1748            if ((cst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
1749                if (cst.booleanValue() == false) { // right is equivalent to false
1750
this.optimizedBooleanConstant = cst; // constant(false)
1751
}
1752            }
1753            return;
1754        case OR :
1755            if ((leftId != TypeIds.T_boolean) || (rightId != TypeIds.T_boolean))
1756                return;
1757        case OR_OR :
1758            if ((cst = this.left.optimizedBooleanConstant()) != Constant.NotAConstant) {
1759                if (cst.booleanValue() == true) { // left is equivalent to true
1760
this.optimizedBooleanConstant = cst; // constant(true)
1761
return;
1762                } else { //left is equivalent to false
1763
if ((cst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
1764                        this.optimizedBooleanConstant = cst;
1765                    }
1766                    return;
1767                }
1768            }
1769            if ((cst = this.right.optimizedBooleanConstant()) != Constant.NotAConstant) {
1770                if (cst.booleanValue() == true) { // right is equivalent to true
1771
this.optimizedBooleanConstant = cst; // constant(true)
1772
}
1773            }
1774    }
1775}
1776
1777public StringBuffer JavaDoc printExpressionNoParenthesis(int indent, StringBuffer JavaDoc output) {
1778    // keep implementation in sync with
1779
// CombinedBinaryExpression#printExpressionNoParenthesis
1780
this.left.printExpression(indent, output).append(' ').append(operatorToString()).append(' ');
1781    return this.right.printExpression(0, output);
1782}
1783
1784public TypeBinding resolveType(BlockScope scope) {
1785    // keep implementation in sync with CombinedBinaryExpression#resolveType
1786
// and nonRecursiveResolveTypeUpwards
1787
boolean leftIsCast, rightIsCast;
1788    if ((leftIsCast = this.left instanceof CastExpression) == true) this.left.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
1789
TypeBinding leftType = this.left.resolveType(scope);
1790
1791    if ((rightIsCast = this.right instanceof CastExpression) == true) this.right.bits |= ASTNode.DisableUnnecessaryCastCheck; // will check later on
1792
TypeBinding rightType = this.right.resolveType(scope);
1793
1794    // use the id of the type to navigate into the table
1795
if (leftType == null || rightType == null) {
1796        this.constant = Constant.NotAConstant;
1797        return null;
1798    }
1799
1800    int leftTypeID = leftType.id;
1801    int rightTypeID = rightType.id;
1802
1803    // autoboxing support
1804
boolean use15specifics = scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5;
1805    if (use15specifics) {
1806        if (!leftType.isBaseType() && rightTypeID != TypeIds.T_JavaLangString && rightTypeID != TypeIds.T_null) {
1807            leftTypeID = scope.environment().computeBoxingType(leftType).id;
1808        }
1809        if (!rightType.isBaseType() && leftTypeID != TypeIds.T_JavaLangString && leftTypeID != TypeIds.T_null) {
1810            rightTypeID = scope.environment().computeBoxingType(rightType).id;
1811        }
1812    }
1813    if (leftTypeID > 15
1814        || rightTypeID > 15) { // must convert String + Object || Object + String
1815
if (leftTypeID == TypeIds.T_JavaLangString) {
1816            rightTypeID = TypeIds.T_JavaLangObject;
1817        } else if (rightTypeID == TypeIds.T_JavaLangString) {
1818            leftTypeID = TypeIds.T_JavaLangObject;
1819        } else {
1820            this.constant = Constant.NotAConstant;
1821            scope.problemReporter().invalidOperator(this, leftType, rightType);
1822            return null;
1823        }
1824    }
1825    if (((this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT) == OperatorIds.PLUS) {
1826        if (leftTypeID == TypeIds.T_JavaLangString) {
1827            this.left.computeConversion(scope, leftType, leftType);
1828            if (rightType.isArrayType() && ((ArrayBinding) rightType).elementsType() == TypeBinding.CHAR) {
1829                scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.right);
1830            }
1831        }
1832        if (rightTypeID == TypeIds.T_JavaLangString) {
1833            this.right.computeConversion(scope, rightType, rightType);
1834            if (leftType.isArrayType() && ((ArrayBinding) leftType).elementsType() == TypeBinding.CHAR) {
1835                scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(this.left);
1836            }
1837        }
1838    }
1839
1840    // the code is an int
1841
// (cast) left Op (cast) right --> result
1842
// 0000 0000 0000 0000 0000
1843
// <<16 <<12 <<8 <<4 <<0
1844

1845    // Don't test for result = 0. If it is zero, some more work is done.
1846
// On the one hand when it is not zero (correct code) we avoid doing the test
1847
int operator = (this.bits & ASTNode.OperatorMASK) >> ASTNode.OperatorSHIFT;
1848    int operatorSignature = OperatorExpression.OperatorSignatures[operator][(leftTypeID << 4) + rightTypeID];
1849
1850    this.left.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 16) & 0x0000F), leftType);
1851    this.right.computeConversion(scope, TypeBinding.wellKnownType(scope, (operatorSignature >>> 8) & 0x0000F), rightType);
1852    this.bits |= operatorSignature & 0xF;
1853    switch (operatorSignature & 0xF) { // record the current ReturnTypeID
1854
// only switch on possible result type.....
1855
case T_boolean :
1856            this.resolvedType = TypeBinding.BOOLEAN;
1857            break;
1858        case T_byte :
1859            this.resolvedType = TypeBinding.BYTE;
1860            break;
1861        case T_char :
1862            this.resolvedType = TypeBinding.CHAR;
1863            break;
1864        case T_double :
1865            this.resolvedType = TypeBinding.DOUBLE;
1866            break;
1867        case T_float :
1868            this.resolvedType = TypeBinding.FLOAT;
1869            break;
1870        case T_int :
1871            this.resolvedType = TypeBinding.INT;
1872            break;
1873        case T_long :
1874            this.resolvedType = TypeBinding.LONG;
1875            break;
1876        case T_JavaLangString :
1877            this.resolvedType = scope.getJavaLangString();
1878            break;
1879        default : //error........
1880
this.constant = Constant.NotAConstant;
1881            scope.problemReporter().invalidOperator(this, leftType, rightType);
1882            return null;
1883    }
1884
1885    // check need for operand cast
1886
if (leftIsCast || rightIsCast) {
1887        CastExpression.checkNeedForArgumentCasts(scope, operator, operatorSignature, this.left, leftTypeID, leftIsCast, this.right, rightTypeID, rightIsCast);
1888    }
1889    // compute the constant when valid
1890
computeConstant(scope, leftTypeID, rightTypeID);
1891    return this.resolvedType;
1892}
1893
1894public void traverse(ASTVisitor visitor, BlockScope scope) {
1895    if (visitor.visit(this, scope)) {
1896        this.left.traverse(visitor, scope);
1897        this.right.traverse(visitor, scope);
1898    }
1899    visitor.endVisit(this, scope);
1900}
1901}
1902
Popular Tags