misc changes
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / ast / BinaryExpression.java
1 /*******************************************************************************
2  * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
3  * All rights reserved. This program and the accompanying materials 
4  * are made available under the terms of the Common Public License v0.5 
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v05.html
7  * 
8  * Contributors:
9  *     IBM Corporation - initial API and implementation
10  ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
12
13 import net.sourceforge.phpdt.internal.compiler.IAbstractSyntaxTreeVisitor;
14 import net.sourceforge.phpdt.internal.compiler.impl.*;
15 import net.sourceforge.phpdt.internal.compiler.codegen.*;
16 import net.sourceforge.phpdt.internal.compiler.flow.*;
17 import net.sourceforge.phpdt.internal.compiler.lookup.*;
18
19 public class BinaryExpression extends OperatorExpression {
20
21         public Expression left, right;
22         public Constant optimizedBooleanConstant;
23
24         public BinaryExpression(Expression left, Expression right, int operator) {
25
26                 this.left = left;
27                 this.right = right;
28                 this.bits |= operator << OperatorSHIFT; // encode operator
29                 this.sourceStart = left.sourceStart;
30                 this.sourceEnd = right.sourceEnd;
31         }
32
33         public FlowInfo analyseCode(
34                 BlockScope currentScope,
35                 FlowContext flowContext,
36                 FlowInfo flowInfo) {
37
38                 return right
39                         .analyseCode(
40                                 currentScope,
41                                 flowContext,
42                                 left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
43                         .unconditionalInits();
44         }
45
46         public void computeConstant(BlockScope scope, int leftId, int rightId) {
47
48                 //compute the constant when valid
49                 if ((left.constant != Constant.NotAConstant)
50                         && (right.constant != Constant.NotAConstant)) {
51                         try {
52                                 constant =
53                                         Constant.computeConstantOperation(
54                                                 left.constant,
55                                                 leftId,
56                                                 (bits & OperatorMASK) >> OperatorSHIFT,
57                                                 right.constant,
58                                                 rightId);
59                         } catch (ArithmeticException e) {
60                                 constant = Constant.NotAConstant;
61                                 // 1.2 no longer throws an exception at compile-time
62                                 //scope.problemReporter().compileTimeConstantThrowsArithmeticException(this);
63                         }
64                 } else {
65                         constant = Constant.NotAConstant;
66                         //add some work for the boolean operators & |  
67                         optimizedBooleanConstant(
68                                 leftId,
69                                 (bits & OperatorMASK) >> OperatorSHIFT,
70                                 rightId);
71                 }
72         }
73
74         public Constant conditionalConstant() {
75
76                 return optimizedBooleanConstant == null ? constant : optimizedBooleanConstant;
77         }
78
79         /**
80          * Code generation for a binary operation
81          */
82         public void generateCode(
83                 BlockScope currentScope,
84                 CodeStream codeStream,
85                 boolean valueRequired) {
86
87                 int pc = codeStream.position;
88                 Label falseLabel, endLabel;
89                 if (constant != Constant.NotAConstant) {
90                         if (valueRequired)
91                                 codeStream.generateConstant(constant, implicitConversion);
92                         codeStream.recordPositionsFrom(pc, this.sourceStart);
93                         return;
94                 }
95                 bits |= OnlyValueRequiredMASK;
96                 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
97                         case PLUS :
98                                 switch (bits & ReturnTypeIDMASK) {
99                                         case T_String :
100                                                 codeStream.generateStringAppend(currentScope, left, right);
101                                                 if (!valueRequired)
102                                                         codeStream.pop();
103                                                 break;
104                                         case T_int :
105                                                 left.generateCode(currentScope, codeStream, valueRequired);
106                                                 right.generateCode(currentScope, codeStream, valueRequired);
107                                                 if (valueRequired)
108                                                         codeStream.iadd();
109                                                 break;
110                                         case T_long :
111                                                 left.generateCode(currentScope, codeStream, valueRequired);
112                                                 right.generateCode(currentScope, codeStream, valueRequired);
113                                                 if (valueRequired)
114                                                         codeStream.ladd();
115                                                 break;
116                                         case T_double :
117                                                 left.generateCode(currentScope, codeStream, valueRequired);
118                                                 right.generateCode(currentScope, codeStream, valueRequired);
119                                                 if (valueRequired)
120                                                         codeStream.dadd();
121                                                 break;
122                                         case T_float :
123                                                 left.generateCode(currentScope, codeStream, valueRequired);
124                                                 right.generateCode(currentScope, codeStream, valueRequired);
125                                                 if (valueRequired)
126                                                         codeStream.fadd();
127                                                 break;
128                                 }
129                                 break;
130                         case MINUS :
131                                 switch (bits & ReturnTypeIDMASK) {
132                                         case T_int :
133                                                 left.generateCode(currentScope, codeStream, valueRequired);
134                                                 right.generateCode(currentScope, codeStream, valueRequired);
135                                                 if (valueRequired)
136                                                         codeStream.isub();
137                                                 break;
138                                         case T_long :
139                                                 left.generateCode(currentScope, codeStream, valueRequired);
140                                                 right.generateCode(currentScope, codeStream, valueRequired);
141                                                 if (valueRequired)
142                                                         codeStream.lsub();
143                                                 break;
144                                         case T_double :
145                                                 left.generateCode(currentScope, codeStream, valueRequired);
146                                                 right.generateCode(currentScope, codeStream, valueRequired);
147                                                 if (valueRequired)
148                                                         codeStream.dsub();
149                                                 break;
150                                         case T_float :
151                                                 left.generateCode(currentScope, codeStream, valueRequired);
152                                                 right.generateCode(currentScope, codeStream, valueRequired);
153                                                 if (valueRequired)
154                                                         codeStream.fsub();
155                                                 break;
156                                 }
157                                 break;
158                         case MULTIPLY :
159                                 switch (bits & ReturnTypeIDMASK) {
160                                         case T_int :
161                                                 left.generateCode(currentScope, codeStream, valueRequired);
162                                                 right.generateCode(currentScope, codeStream, valueRequired);
163                                                 if (valueRequired)
164                                                         codeStream.imul();
165                                                 break;
166                                         case T_long :
167                                                 left.generateCode(currentScope, codeStream, valueRequired);
168                                                 right.generateCode(currentScope, codeStream, valueRequired);
169                                                 if (valueRequired)
170                                                         codeStream.lmul();
171                                                 break;
172                                         case T_double :
173                                                 left.generateCode(currentScope, codeStream, valueRequired);
174                                                 right.generateCode(currentScope, codeStream, valueRequired);
175                                                 if (valueRequired)
176                                                         codeStream.dmul();
177                                                 break;
178                                         case T_float :
179                                                 left.generateCode(currentScope, codeStream, valueRequired);
180                                                 right.generateCode(currentScope, codeStream, valueRequired);
181                                                 if (valueRequired)
182                                                         codeStream.fmul();
183                                                 break;
184                                 }
185                                 break;
186                         case DIVIDE :
187                                 switch (bits & ReturnTypeIDMASK) {
188                                         case T_int :
189                                                 left.generateCode(currentScope, codeStream, true);
190                                                 right.generateCode(currentScope, codeStream, true);
191                                                 codeStream.idiv();
192                                                 if (!valueRequired)
193                                                         codeStream.pop();
194                                                 break;
195                                         case T_long :
196                                                 left.generateCode(currentScope, codeStream, true);
197                                                 right.generateCode(currentScope, codeStream, true);
198                                                 codeStream.ldiv();
199                                                 if (!valueRequired)
200                                                         codeStream.pop2();
201                                                 break;
202                                         case T_double :
203                                                 left.generateCode(currentScope, codeStream, valueRequired);
204                                                 right.generateCode(currentScope, codeStream, valueRequired);
205                                                 if (valueRequired)
206                                                         codeStream.ddiv();
207                                                 break;
208                                         case T_float :
209                                                 left.generateCode(currentScope, codeStream, valueRequired);
210                                                 right.generateCode(currentScope, codeStream, valueRequired);
211                                                 if (valueRequired)
212                                                         codeStream.fdiv();
213                                                 break;
214                                 }
215                                 break;
216                         case REMAINDER :
217                                 switch (bits & ReturnTypeIDMASK) {
218                                         case T_int :
219                                                 left.generateCode(currentScope, codeStream, true);
220                                                 right.generateCode(currentScope, codeStream, true);
221                                                 codeStream.irem();
222                                                 if (!valueRequired)
223                                                         codeStream.pop();
224                                                 break;
225                                         case T_long :
226                                                 left.generateCode(currentScope, codeStream, true);
227                                                 right.generateCode(currentScope, codeStream, true);
228                                                 codeStream.lrem();
229                                                 if (!valueRequired)
230                                                         codeStream.pop2();
231                                                 break;
232                                         case T_double :
233                                                 left.generateCode(currentScope, codeStream, valueRequired);
234                                                 right.generateCode(currentScope, codeStream, valueRequired);
235                                                 if (valueRequired)
236                                                         codeStream.drem();
237                                                 break;
238                                         case T_float :
239                                                 left.generateCode(currentScope, codeStream, valueRequired);
240                                                 right.generateCode(currentScope, codeStream, valueRequired);
241                                                 if (valueRequired)
242                                                         codeStream.frem();
243                                                 break;
244                                 }
245                                 break;
246                         case AND :
247                                 switch (bits & ReturnTypeIDMASK) {
248                                         case T_int :
249                                                 // 0 & x
250                                                 if ((left.constant != Constant.NotAConstant)
251                                                         && (left.constant.typeID() == T_int)
252                                                         && (left.constant.intValue() == 0)) {
253                                                         right.generateCode(currentScope, codeStream, false);
254                                                         if (valueRequired)
255                                                                 codeStream.iconst_0();
256                                                 } else {
257                                                         // x & 0
258                                                         if ((right.constant != Constant.NotAConstant)
259                                                                 && (right.constant.typeID() == T_int)
260                                                                 && (right.constant.intValue() == 0)) {
261                                                                 left.generateCode(currentScope, codeStream, false);
262                                                                 if (valueRequired)
263                                                                         codeStream.iconst_0();
264                                                         } else {
265                                                                 left.generateCode(currentScope, codeStream, valueRequired);
266                                                                 right.generateCode(currentScope, codeStream, valueRequired);
267                                                                 if (valueRequired)
268                                                                         codeStream.iand();
269                                                         }
270                                                 }
271                                                 break;
272                                         case T_long :
273                                                 // 0 & x
274                                                 if ((left.constant != Constant.NotAConstant)
275                                                         && (left.constant.typeID() == T_long)
276                                                         && (left.constant.longValue() == 0L)) {
277                                                         right.generateCode(currentScope, codeStream, false);
278                                                         if (valueRequired)
279                                                                 codeStream.lconst_0();
280                                                 } else {
281                                                         // x & 0
282                                                         if ((right.constant != Constant.NotAConstant)
283                                                                 && (right.constant.typeID() == T_long)
284                                                                 && (right.constant.longValue() == 0L)) {
285                                                                 left.generateCode(currentScope, codeStream, false);
286                                                                 if (valueRequired)
287                                                                         codeStream.lconst_0();
288                                                         } else {
289                                                                 left.generateCode(currentScope, codeStream, valueRequired);
290                                                                 right.generateCode(currentScope, codeStream, valueRequired);
291                                                                 if (valueRequired)
292                                                                         codeStream.land();
293                                                         }
294                                                 }
295                                                 break;
296                                         case T_boolean : // logical and
297                                                 generateOptimizedLogicalAnd(
298                                                         currentScope,
299                                                         codeStream,
300                                                         null,
301                                                         (falseLabel = new Label(codeStream)),
302                                                         valueRequired);
303                                                 /* improving code gen for such a case: boolean b = i < 0 && false;
304                                                  * since the label has never been used, we have the inlined value on the stack. */
305                                                 if (falseLabel.hasForwardReferences()) {
306                                                         if (valueRequired) {
307                                                                 codeStream.iconst_1();
308                                                                 if ((bits & ValueForReturnMASK) != 0) {
309                                                                         codeStream.ireturn();
310                                                                         falseLabel.place();
311                                                                         codeStream.iconst_0();
312                                                                 } else {
313                                                                         codeStream.goto_(endLabel = new Label(codeStream));
314                                                                         codeStream.decrStackSize(1);
315                                                                         falseLabel.place();
316                                                                         codeStream.iconst_0();
317                                                                         endLabel.place();
318                                                                 }
319                                                         } else {
320                                                                 falseLabel.place();
321                                                         }
322                                                 }
323                                 }
324                                 break;
325                         case OR :
326                                 switch (bits & ReturnTypeIDMASK) {
327                                         case T_int :
328                                                 // 0 | x
329                                                 if ((left.constant != Constant.NotAConstant)
330                                                         && (left.constant.typeID() == T_int)
331                                                         && (left.constant.intValue() == 0)) {
332                                                         right.generateCode(currentScope, codeStream, valueRequired);
333                                                 } else {
334                                                         // x | 0
335                                                         if ((right.constant != Constant.NotAConstant)
336                                                                 && (right.constant.typeID() == T_int)
337                                                                 && (right.constant.intValue() == 0)) {
338                                                                 left.generateCode(currentScope, codeStream, valueRequired);
339                                                         } else {
340                                                                 left.generateCode(currentScope, codeStream, valueRequired);
341                                                                 right.generateCode(currentScope, codeStream, valueRequired);
342                                                                 if (valueRequired)
343                                                                         codeStream.ior();
344                                                         }
345                                                 }
346                                                 break;
347                                         case T_long :
348                                                 // 0 | x
349                                                 if ((left.constant != Constant.NotAConstant)
350                                                         && (left.constant.typeID() == T_long)
351                                                         && (left.constant.longValue() == 0L)) {
352                                                         right.generateCode(currentScope, codeStream, valueRequired);
353                                                 } else {
354                                                         // x | 0
355                                                         if ((right.constant != Constant.NotAConstant)
356                                                                 && (right.constant.typeID() == T_long)
357                                                                 && (right.constant.longValue() == 0L)) {
358                                                                 left.generateCode(currentScope, codeStream, valueRequired);
359                                                         } else {
360                                                                 left.generateCode(currentScope, codeStream, valueRequired);
361                                                                 right.generateCode(currentScope, codeStream, valueRequired);
362                                                                 if (valueRequired)
363                                                                         codeStream.lor();
364                                                         }
365                                                 }
366                                                 break;
367                                         case T_boolean : // logical or
368                                                 generateOptimizedLogicalOr(
369                                                         currentScope,
370                                                         codeStream,
371                                                         null,
372                                                         (falseLabel = new Label(codeStream)),
373                                                         valueRequired);
374                                                 /* improving code gen for such a case: boolean b = i < 0 || true;
375                                                  * since the label has never been used, we have the inlined value on the stack. */
376                                                 if (falseLabel.hasForwardReferences()) {
377                                                         if (valueRequired) {
378                                                                 codeStream.iconst_1();
379                                                                 if ((bits & ValueForReturnMASK) != 0) {
380                                                                         codeStream.ireturn();
381                                                                         falseLabel.place();
382                                                                         codeStream.iconst_0();
383                                                                 } else {
384                                                                         codeStream.goto_(endLabel = new Label(codeStream));
385                                                                         codeStream.decrStackSize(1);
386                                                                         falseLabel.place();
387                                                                         codeStream.iconst_0();
388                                                                         endLabel.place();
389                                                                 }
390                                                         } else {
391                                                                 falseLabel.place();
392                                                         }
393                                                 }
394                                 }
395                                 break;
396                         case XOR :
397                                 switch (bits & ReturnTypeIDMASK) {
398                                         case T_int :
399                                                 // 0 ^ x
400                                                 if ((left.constant != Constant.NotAConstant)
401                                                         && (left.constant.typeID() == T_int)
402                                                         && (left.constant.intValue() == 0)) {
403                                                         right.generateCode(currentScope, codeStream, valueRequired);
404                                                 } else {
405                                                         // x ^ 0
406                                                         if ((right.constant != Constant.NotAConstant)
407                                                                 && (right.constant.typeID() == T_int)
408                                                                 && (right.constant.intValue() == 0)) {
409                                                                 left.generateCode(currentScope, codeStream, valueRequired);
410                                                         } else {
411                                                                 left.generateCode(currentScope, codeStream, valueRequired);
412                                                                 right.generateCode(currentScope, codeStream, valueRequired);
413                                                                 if (valueRequired)
414                                                                         codeStream.ixor();
415                                                         }
416                                                 }
417                                                 break;
418                                         case T_long :
419                                                 // 0 ^ x
420                                                 if ((left.constant != Constant.NotAConstant)
421                                                         && (left.constant.typeID() == T_long)
422                                                         && (left.constant.longValue() == 0L)) {
423                                                         right.generateCode(currentScope, codeStream, valueRequired);
424                                                 } else {
425                                                         // x ^ 0
426                                                         if ((right.constant != Constant.NotAConstant)
427                                                                 && (right.constant.typeID() == T_long)
428                                                                 && (right.constant.longValue() == 0L)) {
429                                                                 left.generateCode(currentScope, codeStream, valueRequired);
430                                                         } else {
431                                                                 left.generateCode(currentScope, codeStream, valueRequired);
432                                                                 right.generateCode(currentScope, codeStream, valueRequired);
433                                                                 if (valueRequired)
434                                                                         codeStream.lxor();
435                                                         }
436                                                 }
437                                                 break;
438                                         case T_boolean :
439                                                 generateOptimizedLogicalXor(
440                                                         currentScope,
441                                                         codeStream,
442                                                         null,
443                                                         (falseLabel = new Label(codeStream)),
444                                                         valueRequired);
445                                                 /* improving code gen for such a case: boolean b = i < 0 ^ bool;
446                                                  * since the label has never been used, we have the inlined value on the stack. */
447                                                 if (falseLabel.hasForwardReferences()) {
448                                                         if (valueRequired) {
449                                                                 codeStream.iconst_1();
450                                                                 if ((bits & ValueForReturnMASK) != 0) {
451                                                                         codeStream.ireturn();
452                                                                         falseLabel.place();
453                                                                         codeStream.iconst_0();
454                                                                 } else {
455                                                                         codeStream.goto_(endLabel = new Label(codeStream));
456                                                                         codeStream.decrStackSize(1);
457                                                                         falseLabel.place();
458                                                                         codeStream.iconst_0();
459                                                                         endLabel.place();
460                                                                 }
461                                                         } else {
462                                                                 falseLabel.place();
463                                                         }
464                                                 }
465                                 }
466                                 break;
467                         case LEFT_SHIFT :
468                                 switch (bits & ReturnTypeIDMASK) {
469                                         case T_int :
470                                                 left.generateCode(currentScope, codeStream, valueRequired);
471                                                 right.generateCode(currentScope, codeStream, valueRequired);
472                                                 if (valueRequired)
473                                                         codeStream.ishl();
474                                                 break;
475                                         case T_long :
476                                                 left.generateCode(currentScope, codeStream, valueRequired);
477                                                 right.generateCode(currentScope, codeStream, valueRequired);
478                                                 if (valueRequired)
479                                                         codeStream.lshl();
480                                 }
481                                 break;
482                         case RIGHT_SHIFT :
483                                 switch (bits & ReturnTypeIDMASK) {
484                                         case T_int :
485                                                 left.generateCode(currentScope, codeStream, valueRequired);
486                                                 right.generateCode(currentScope, codeStream, valueRequired);
487                                                 if (valueRequired)
488                                                         codeStream.ishr();
489                                                 break;
490                                         case T_long :
491                                                 left.generateCode(currentScope, codeStream, valueRequired);
492                                                 right.generateCode(currentScope, codeStream, valueRequired);
493                                                 if (valueRequired)
494                                                         codeStream.lshr();
495                                 }
496                                 break;
497                         case UNSIGNED_RIGHT_SHIFT :
498                                 switch (bits & ReturnTypeIDMASK) {
499                                         case T_int :
500                                                 left.generateCode(currentScope, codeStream, valueRequired);
501                                                 right.generateCode(currentScope, codeStream, valueRequired);
502                                                 if (valueRequired)
503                                                         codeStream.iushr();
504                                                 break;
505                                         case T_long :
506                                                 left.generateCode(currentScope, codeStream, valueRequired);
507                                                 right.generateCode(currentScope, codeStream, valueRequired);
508                                                 if (valueRequired)
509                                                         codeStream.lushr();
510                                 }
511                                 break;
512                         case GREATER :
513                                 generateOptimizedGreaterThan(
514                                         currentScope,
515                                         codeStream,
516                                         null,
517                                         (falseLabel = new Label(codeStream)),
518                                         valueRequired);
519                                 if (valueRequired) {
520                                         codeStream.iconst_1();
521                                         if ((bits & ValueForReturnMASK) != 0) {
522                                                 codeStream.ireturn();
523                                                 falseLabel.place();
524                                                 codeStream.iconst_0();
525                                         } else {
526                                                 codeStream.goto_(endLabel = new Label(codeStream));
527                                                 codeStream.decrStackSize(1);
528                                                 falseLabel.place();
529                                                 codeStream.iconst_0();
530                                                 endLabel.place();
531                                         }
532                                 }
533                                 break;
534                         case GREATER_EQUAL :
535                                 generateOptimizedGreaterThanOrEqual(
536                                         currentScope,
537                                         codeStream,
538                                         null,
539                                         (falseLabel = new Label(codeStream)),
540                                         valueRequired);
541                                 if (valueRequired) {
542                                         codeStream.iconst_1();
543                                         if ((bits & ValueForReturnMASK) != 0) {
544                                                 codeStream.ireturn();
545                                                 falseLabel.place();
546                                                 codeStream.iconst_0();
547                                         } else {
548                                                 codeStream.goto_(endLabel = new Label(codeStream));
549                                                 codeStream.decrStackSize(1);
550                                                 falseLabel.place();
551                                                 codeStream.iconst_0();
552                                                 endLabel.place();
553                                         }
554                                 }
555                                 break;
556                         case LESS :
557                                 generateOptimizedLessThan(
558                                         currentScope,
559                                         codeStream,
560                                         null,
561                                         (falseLabel = new Label(codeStream)),
562                                         valueRequired);
563                                 if (valueRequired) {
564                                         codeStream.iconst_1();
565                                         if ((bits & ValueForReturnMASK) != 0) {
566                                                 codeStream.ireturn();
567                                                 falseLabel.place();
568                                                 codeStream.iconst_0();
569                                         } else {
570                                                 codeStream.goto_(endLabel = new Label(codeStream));
571                                                 codeStream.decrStackSize(1);
572                                                 falseLabel.place();
573                                                 codeStream.iconst_0();
574                                                 endLabel.place();
575                                         }
576                                 }
577                                 break;
578                         case LESS_EQUAL :
579                                 generateOptimizedLessThanOrEqual(
580                                         currentScope,
581                                         codeStream,
582                                         null,
583                                         (falseLabel = new Label(codeStream)),
584                                         valueRequired);
585                                 if (valueRequired) {
586                                         codeStream.iconst_1();
587                                         if ((bits & ValueForReturnMASK) != 0) {
588                                                 codeStream.ireturn();
589                                                 falseLabel.place();
590                                                 codeStream.iconst_0();
591                                         } else {
592                                                 codeStream.goto_(endLabel = new Label(codeStream));
593                                                 codeStream.decrStackSize(1);
594                                                 falseLabel.place();
595                                                 codeStream.iconst_0();
596                                                 endLabel.place();
597                                         }
598                                 }
599                 }
600                 if (valueRequired) {
601                         codeStream.generateImplicitConversion(implicitConversion);
602                 }
603                 codeStream.recordPositionsFrom(pc, this.sourceStart);
604         }
605
606         /**
607          * Boolean operator code generation
608          *      Optimized operations are: <, <=, >, >=, &, |, ^
609          */
610         public void generateOptimizedBoolean(
611                 BlockScope currentScope,
612                 CodeStream codeStream,
613                 Label trueLabel,
614                 Label falseLabel,
615                 boolean valueRequired) {
616
617                 if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
618                         super.generateOptimizedBoolean(
619                                 currentScope,
620                                 codeStream,
621                                 trueLabel,
622                                 falseLabel,
623                                 valueRequired);
624                         return;
625                 }
626                 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
627                         case LESS :
628                                 generateOptimizedLessThan(
629                                         currentScope,
630                                         codeStream,
631                                         trueLabel,
632                                         falseLabel,
633                                         valueRequired);
634                                 return;
635                         case LESS_EQUAL :
636                                 generateOptimizedLessThanOrEqual(
637                                         currentScope,
638                                         codeStream,
639                                         trueLabel,
640                                         falseLabel,
641                                         valueRequired);
642                                 return;
643                         case GREATER :
644                                 generateOptimizedGreaterThan(
645                                         currentScope,
646                                         codeStream,
647                                         trueLabel,
648                                         falseLabel,
649                                         valueRequired);
650                                 return;
651                         case GREATER_EQUAL :
652                                 generateOptimizedGreaterThanOrEqual(
653                                         currentScope,
654                                         codeStream,
655                                         trueLabel,
656                                         falseLabel,
657                                         valueRequired);
658                                 return;
659                         case AND :
660                                 generateOptimizedLogicalAnd(
661                                         currentScope,
662                                         codeStream,
663                                         trueLabel,
664                                         falseLabel,
665                                         valueRequired);
666                                 return;
667                         case OR :
668                                 generateOptimizedLogicalOr(
669                                         currentScope,
670                                         codeStream,
671                                         trueLabel,
672                                         falseLabel,
673                                         valueRequired);
674                                 return;
675                         case XOR :
676                                 generateOptimizedLogicalXor(
677                                         currentScope,
678                                         codeStream,
679                                         trueLabel,
680                                         falseLabel,
681                                         valueRequired);
682                                 return;
683                 }
684                 super.generateOptimizedBoolean(
685                         currentScope,
686                         codeStream,
687                         trueLabel,
688                         falseLabel,
689                         valueRequired);
690         }
691
692         /**
693          * Boolean generation for >
694          */
695         public void generateOptimizedGreaterThan(
696                 BlockScope currentScope,
697                 CodeStream codeStream,
698                 Label trueLabel,
699                 Label falseLabel,
700                 boolean valueRequired) {
701
702                 int pc = codeStream.position;
703                 int promotedTypeID = left.implicitConversion >> 4;
704                 // both sides got promoted in the same way
705                 if (promotedTypeID == T_int) {
706                         // 0 > x
707                         if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
708                                 right.generateCode(currentScope, codeStream, valueRequired);
709                                 if (valueRequired) {
710                                         if (falseLabel == null) {
711                                                 if (trueLabel != null) {
712                                                         // implicitly falling through the FALSE case
713                                                         codeStream.iflt(trueLabel);
714                                                 }
715                                         } else {
716                                                 if (trueLabel == null) {
717                                                         // implicitly falling through the TRUE case
718                                                         codeStream.ifge(falseLabel);
719                                                 } else {
720                                                         // no implicit fall through TRUE/FALSE --> should never occur
721                                                 }
722                                         }
723                                 }
724                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
725                                 return;
726                         }
727                         // x > 0
728                         if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
729                                 left.generateCode(currentScope, codeStream, valueRequired);
730                                 if (valueRequired) {
731                                         if (falseLabel == null) {
732                                                 if (trueLabel != null) {
733                                                         // implicitly falling through the FALSE case
734                                                         codeStream.ifgt(trueLabel);
735                                                 }
736                                         } else {
737                                                 if (trueLabel == null) {
738                                                         // implicitly falling through the TRUE case
739                                                         codeStream.ifle(falseLabel);
740                                                 } else {
741                                                         // no implicit fall through TRUE/FALSE --> should never occur
742                                                 }
743                                         }
744                                 }
745                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
746                                 return;
747                         }
748                 }
749                 // default comparison
750                 left.generateCode(currentScope, codeStream, valueRequired);
751                 right.generateCode(currentScope, codeStream, valueRequired);
752                 if (valueRequired) {
753                         if (falseLabel == null) {
754                                 if (trueLabel != null) {
755                                         // implicit falling through the FALSE case
756                                         switch (promotedTypeID) {
757                                                 case T_int :
758                                                         codeStream.if_icmpgt(trueLabel);
759                                                         break;
760                                                 case T_float :
761                                                         codeStream.fcmpl();
762                                                         codeStream.ifgt(trueLabel);
763                                                         break;
764                                                 case T_long :
765                                                         codeStream.lcmp();
766                                                         codeStream.ifgt(trueLabel);
767                                                         break;
768                                                 case T_double :
769                                                         codeStream.dcmpl();
770                                                         codeStream.ifgt(trueLabel);
771                                         }
772                                         codeStream.recordPositionsFrom(pc, this.sourceStart);
773                                         return;
774                                 }
775                         } else {
776                                 if (trueLabel == null) {
777                                         // implicit falling through the TRUE case
778                                         switch (promotedTypeID) {
779                                                 case T_int :
780                                                         codeStream.if_icmple(falseLabel);
781                                                         break;
782                                                 case T_float :
783                                                         codeStream.fcmpl();
784                                                         codeStream.ifle(falseLabel);
785                                                         break;
786                                                 case T_long :
787                                                         codeStream.lcmp();
788                                                         codeStream.ifle(falseLabel);
789                                                         break;
790                                                 case T_double :
791                                                         codeStream.dcmpl();
792                                                         codeStream.ifle(falseLabel);
793                                         }
794                                         codeStream.recordPositionsFrom(pc, this.sourceStart);
795                                         return;
796                                 } else {
797                                         // no implicit fall through TRUE/FALSE --> should never occur
798                                 }
799                         }
800                 }
801         }
802
803         /**
804          * Boolean generation for >=
805          */
806         public void generateOptimizedGreaterThanOrEqual(
807                 BlockScope currentScope,
808                 CodeStream codeStream,
809                 Label trueLabel,
810                 Label falseLabel,
811                 boolean valueRequired) {
812
813                 int pc = codeStream.position;
814                 int promotedTypeID = left.implicitConversion >> 4;
815                 // both sides got promoted in the same way
816                 if (promotedTypeID == T_int) {
817                         // 0 >= x
818                         if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
819                                 right.generateCode(currentScope, codeStream, valueRequired);
820                                 if (valueRequired) {
821                                         if (falseLabel == null) {
822                                                 if (trueLabel != null) {
823                                                         // implicitly falling through the FALSE case
824                                                         codeStream.ifle(trueLabel);
825                                                 }
826                                         } else {
827                                                 if (trueLabel == null) {
828                                                         // implicitly falling through the TRUE case
829                                                         codeStream.ifgt(falseLabel);
830                                                 } else {
831                                                         // no implicit fall through TRUE/FALSE --> should never occur
832                                                 }
833                                         }
834                                 }
835                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
836                                 return;
837                         }
838                         // x >= 0
839                         if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
840                                 left.generateCode(currentScope, codeStream, valueRequired);
841                                 if (valueRequired) {
842                                         if (falseLabel == null) {
843                                                 if (trueLabel != null) {
844                                                         // implicitly falling through the FALSE case
845                                                         codeStream.ifge(trueLabel);
846                                                 }
847                                         } else {
848                                                 if (trueLabel == null) {
849                                                         // implicitly falling through the TRUE case
850                                                         codeStream.iflt(falseLabel);
851                                                 } else {
852                                                         // no implicit fall through TRUE/FALSE --> should never occur
853                                                 }
854                                         }
855                                 }
856                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
857                                 return;
858                         }
859                 }
860                 // default comparison
861                 left.generateCode(currentScope, codeStream, valueRequired);
862                 right.generateCode(currentScope, codeStream, valueRequired);
863                 if (valueRequired) {
864                         if (falseLabel == null) {
865                                 if (trueLabel != null) {
866                                         // implicit falling through the FALSE case
867                                         switch (promotedTypeID) {
868                                                 case T_int :
869                                                         codeStream.if_icmpge(trueLabel);
870                                                         break;
871                                                 case T_float :
872                                                         codeStream.fcmpl();
873                                                         codeStream.ifge(trueLabel);
874                                                         break;
875                                                 case T_long :
876                                                         codeStream.lcmp();
877                                                         codeStream.ifge(trueLabel);
878                                                         break;
879                                                 case T_double :
880                                                         codeStream.dcmpl();
881                                                         codeStream.ifge(trueLabel);
882                                         }
883                                         codeStream.recordPositionsFrom(pc, this.sourceStart);
884                                         return;
885                                 }
886                         } else {
887                                 if (trueLabel == null) {
888                                         // implicit falling through the TRUE case
889                                         switch (promotedTypeID) {
890                                                 case T_int :
891                                                         codeStream.if_icmplt(falseLabel);
892                                                         break;
893                                                 case T_float :
894                                                         codeStream.fcmpl();
895                                                         codeStream.iflt(falseLabel);
896                                                         break;
897                                                 case T_long :
898                                                         codeStream.lcmp();
899                                                         codeStream.iflt(falseLabel);
900                                                         break;
901                                                 case T_double :
902                                                         codeStream.dcmpl();
903                                                         codeStream.iflt(falseLabel);
904                                         }
905                                         codeStream.recordPositionsFrom(pc, this.sourceStart);
906                                         return;
907                                 } else {
908                                         // no implicit fall through TRUE/FALSE --> should never occur
909                                 }
910                         }
911                 }
912         }
913
914         /**
915          * Boolean generation for <
916          */
917         public void generateOptimizedLessThan(
918                 BlockScope currentScope,
919                 CodeStream codeStream,
920                 Label trueLabel,
921                 Label falseLabel,
922                 boolean valueRequired) {
923
924                 int pc = codeStream.position;
925                 int promotedTypeID = left.implicitConversion >> 4;
926                 // both sides got promoted in the same way
927                 if (promotedTypeID == T_int) {
928                         // 0 < x
929                         if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
930                                 right.generateCode(currentScope, codeStream, valueRequired);
931                                 if (valueRequired) {
932                                         if (falseLabel == null) {
933                                                 if (trueLabel != null) {
934                                                         // implicitly falling through the FALSE case
935                                                         codeStream.ifgt(trueLabel);
936                                                 }
937                                         } else {
938                                                 if (trueLabel == null) {
939                                                         // implicitly falling through the TRUE case
940                                                         codeStream.ifle(falseLabel);
941                                                 } else {
942                                                         // no implicit fall through TRUE/FALSE --> should never occur
943                                                 }
944                                         }
945                                 }
946                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
947                                 return;
948                         }
949                         // x < 0
950                         if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
951                                 left.generateCode(currentScope, codeStream, valueRequired);
952                                 if (valueRequired) {
953                                         if (falseLabel == null) {
954                                                 if (trueLabel != null) {
955                                                         // implicitly falling through the FALSE case
956                                                         codeStream.iflt(trueLabel);
957                                                 }
958                                         } else {
959                                                 if (trueLabel == null) {
960                                                         // implicitly falling through the TRUE case
961                                                         codeStream.ifge(falseLabel);
962                                                 } else {
963                                                         // no implicit fall through TRUE/FALSE --> should never occur
964                                                 }
965                                         }
966                                 }
967                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
968                                 return;
969                         }
970                 }
971                 // default comparison
972                 left.generateCode(currentScope, codeStream, valueRequired);
973                 right.generateCode(currentScope, codeStream, valueRequired);
974                 if (valueRequired) {
975                         if (falseLabel == null) {
976                                 if (trueLabel != null) {
977                                         // implicit falling through the FALSE case
978                                         switch (promotedTypeID) {
979                                                 case T_int :
980                                                         codeStream.if_icmplt(trueLabel);
981                                                         break;
982                                                 case T_float :
983                                                         codeStream.fcmpg();
984                                                         codeStream.iflt(trueLabel);
985                                                         break;
986                                                 case T_long :
987                                                         codeStream.lcmp();
988                                                         codeStream.iflt(trueLabel);
989                                                         break;
990                                                 case T_double :
991                                                         codeStream.dcmpg();
992                                                         codeStream.iflt(trueLabel);
993                                         }
994                                         codeStream.recordPositionsFrom(pc, this.sourceStart);
995                                         return;
996                                 }
997                         } else {
998                                 if (trueLabel == null) {
999                                         // implicit falling through the TRUE case
1000                                         switch (promotedTypeID) {
1001                                                 case T_int :
1002                                                         codeStream.if_icmpge(falseLabel);
1003                                                         break;
1004                                                 case T_float :
1005                                                         codeStream.fcmpg();
1006                                                         codeStream.ifge(falseLabel);
1007                                                         break;
1008                                                 case T_long :
1009                                                         codeStream.lcmp();
1010                                                         codeStream.ifge(falseLabel);
1011                                                         break;
1012                                                 case T_double :
1013                                                         codeStream.dcmpg();
1014                                                         codeStream.ifge(falseLabel);
1015                                         }
1016                                         codeStream.recordPositionsFrom(pc, this.sourceStart);
1017                                         return;
1018                                 } else {
1019                                         // no implicit fall through TRUE/FALSE --> should never occur
1020                                 }
1021                         }
1022                 }
1023         }
1024         
1025         /**
1026          * Boolean generation for <=
1027          */
1028         public void generateOptimizedLessThanOrEqual(
1029                 BlockScope currentScope,
1030                 CodeStream codeStream,
1031                 Label trueLabel,
1032                 Label falseLabel,
1033                 boolean valueRequired) {
1034
1035                 int pc = codeStream.position;
1036                 int promotedTypeID = left.implicitConversion >> 4;
1037                 // both sides got promoted in the same way
1038                 if (promotedTypeID == T_int) {
1039                         // 0 <= x
1040                         if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
1041                                 right.generateCode(currentScope, codeStream, valueRequired);
1042                                 if (valueRequired) {
1043                                         if (falseLabel == null) {
1044                                                 if (trueLabel != null) {
1045                                                         // implicitly falling through the FALSE case
1046                                                         codeStream.ifge(trueLabel);
1047                                                 }
1048                                         } else {
1049                                                 if (trueLabel == null) {
1050                                                         // implicitly falling through the TRUE case
1051                                                         codeStream.iflt(falseLabel);
1052                                                 } else {
1053                                                         // no implicit fall through TRUE/FALSE --> should never occur
1054                                                 }
1055                                         }
1056                                 }
1057                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
1058                                 return;
1059                         }
1060                         // x <= 0
1061                         if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
1062                                 left.generateCode(currentScope, codeStream, valueRequired);
1063                                 if (valueRequired) {
1064                                         if (falseLabel == null) {
1065                                                 if (trueLabel != null) {
1066                                                         // implicitly falling through the FALSE case
1067                                                         codeStream.ifle(trueLabel);
1068                                                 }
1069                                         } else {
1070                                                 if (trueLabel == null) {
1071                                                         // implicitly falling through the TRUE case
1072                                                         codeStream.ifgt(falseLabel);
1073                                                 } else {
1074                                                         // no implicit fall through TRUE/FALSE --> should never occur
1075                                                 }
1076                                         }
1077                                 }
1078                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
1079                                 return;
1080                         }
1081                 }
1082                 // default comparison
1083                 left.generateCode(currentScope, codeStream, valueRequired);
1084                 right.generateCode(currentScope, codeStream, valueRequired);
1085                 if (valueRequired) {
1086                         if (falseLabel == null) {
1087                                 if (trueLabel != null) {
1088                                         // implicit falling through the FALSE case
1089                                         switch (promotedTypeID) {
1090                                                 case T_int :
1091                                                         codeStream.if_icmple(trueLabel);
1092                                                         break;
1093                                                 case T_float :
1094                                                         codeStream.fcmpg();
1095                                                         codeStream.ifle(trueLabel);
1096                                                         break;
1097                                                 case T_long :
1098                                                         codeStream.lcmp();
1099                                                         codeStream.ifle(trueLabel);
1100                                                         break;
1101                                                 case T_double :
1102                                                         codeStream.dcmpg();
1103                                                         codeStream.ifle(trueLabel);
1104                                         }
1105                                         codeStream.recordPositionsFrom(pc, this.sourceStart);
1106                                         return;
1107                                 }
1108                         } else {
1109                                 if (trueLabel == null) {
1110                                         // implicit falling through the TRUE case
1111                                         switch (promotedTypeID) {
1112                                                 case T_int :
1113                                                         codeStream.if_icmpgt(falseLabel);
1114                                                         break;
1115                                                 case T_float :
1116                                                         codeStream.fcmpg();
1117                                                         codeStream.ifgt(falseLabel);
1118                                                         break;
1119                                                 case T_long :
1120                                                         codeStream.lcmp();
1121                                                         codeStream.ifgt(falseLabel);
1122                                                         break;
1123                                                 case T_double :
1124                                                         codeStream.dcmpg();
1125                                                         codeStream.ifgt(falseLabel);
1126                                         }
1127                                         codeStream.recordPositionsFrom(pc, this.sourceStart);
1128                                         return;
1129                                 } else {
1130                                         // no implicit fall through TRUE/FALSE --> should never occur
1131                                 }
1132                         }
1133                 }
1134         }
1135         
1136         /**
1137          * Boolean generation for &
1138          */
1139         public void generateOptimizedLogicalAnd(
1140                 BlockScope currentScope,
1141                 CodeStream codeStream,
1142                 Label trueLabel,
1143                 Label falseLabel,
1144                 boolean valueRequired) {
1145                         
1146                 int pc = codeStream.position;
1147                 Constant condConst;
1148                 if ((left.implicitConversion & 0xF) == T_boolean) {
1149                         if ((condConst = left.conditionalConstant()) != NotAConstant) {
1150                                 if (condConst.booleanValue() == true) {
1151                                         // <something equivalent to true> & x
1152                                         left.generateOptimizedBoolean(
1153                                                 currentScope,
1154                                                 codeStream,
1155                                                 trueLabel,
1156                                                 falseLabel,
1157                                                 false);
1158                                         if ((bits & OnlyValueRequiredMASK) != 0) {
1159                                                 right.generateCode(currentScope, codeStream, valueRequired);
1160                                         } else {
1161                                                 right.generateOptimizedBoolean(
1162                                                         currentScope,
1163                                                         codeStream,
1164                                                         trueLabel,
1165                                                         falseLabel,
1166                                                         valueRequired);
1167                                         }
1168                                 } else {
1169                                         // <something equivalent to false> & x
1170                                         left.generateOptimizedBoolean(
1171                                                 currentScope,
1172                                                 codeStream,
1173                                                 trueLabel,
1174                                                 falseLabel,
1175                                                 false);
1176                                         right.generateOptimizedBoolean(
1177                                                 currentScope,
1178                                                 codeStream,
1179                                                 trueLabel,
1180                                                 falseLabel,
1181                                                 false);
1182                                         if (valueRequired) {
1183                                                 if ((bits & OnlyValueRequiredMASK) != 0) {
1184                                                         codeStream.iconst_0();
1185                                                 } else {
1186                                                         if (falseLabel != null) {
1187                                                                 // implicit falling through the TRUE case
1188                                                                 codeStream.goto_(falseLabel);
1189                                                         }
1190                                                 }
1191                                         }
1192                                 }
1193                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
1194                                 return;
1195                         }
1196                         if ((condConst = right.conditionalConstant()) != NotAConstant) {
1197                                 if (condConst.booleanValue() == true) {
1198                                         // x & <something equivalent to true>
1199                                         if ((bits & OnlyValueRequiredMASK) != 0) {
1200                                                 left.generateCode(currentScope, codeStream, valueRequired);
1201                                         } else {
1202                                                 left.generateOptimizedBoolean(
1203                                                         currentScope,
1204                                                         codeStream,
1205                                                         trueLabel,
1206                                                         falseLabel,
1207                                                         valueRequired);
1208                                         }
1209                                         right.generateOptimizedBoolean(
1210                                                 currentScope,
1211                                                 codeStream,
1212                                                 trueLabel,
1213                                                 falseLabel,
1214                                                 false);
1215                                 } else {
1216                                         // x & <something equivalent to false>
1217                                         left.generateOptimizedBoolean(
1218                                                 currentScope,
1219                                                 codeStream,
1220                                                 trueLabel,
1221                                                 falseLabel,
1222                                                 false);
1223                                         right.generateOptimizedBoolean(
1224                                                 currentScope,
1225                                                 codeStream,
1226                                                 trueLabel,
1227                                                 falseLabel,
1228                                                 false);
1229                                         if (valueRequired) {
1230                                                 if ((bits & OnlyValueRequiredMASK) != 0) {
1231                                                         codeStream.iconst_0();
1232                                                 } else {
1233                                                         if (falseLabel != null) {
1234                                                                 // implicit falling through the TRUE case
1235                                                                 codeStream.goto_(falseLabel);
1236                                                         }
1237                                                 }
1238                                         }
1239                                 }
1240                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
1241                                 return;
1242                         }
1243                 }
1244                 // default case
1245                 left.generateCode(currentScope, codeStream, valueRequired);
1246                 right.generateCode(currentScope, codeStream, valueRequired);
1247                 if (valueRequired) {
1248                         codeStream.iand();
1249                         if ((bits & OnlyValueRequiredMASK) == 0) {
1250                                 if (falseLabel == null) {
1251                                         if (trueLabel != null) {
1252                                                 // implicit falling through the FALSE case
1253                                                 codeStream.ifne(trueLabel);
1254                                         }
1255                                 } else {
1256                                         // implicit falling through the TRUE case
1257                                         if (trueLabel == null) {
1258                                                 codeStream.ifeq(falseLabel);
1259                                         } else {
1260                                                 // no implicit fall through TRUE/FALSE --> should never occur
1261                                         }
1262                                 }
1263                         }
1264                 }
1265                 codeStream.recordPositionsFrom(pc, this.sourceStart);
1266         }
1267         
1268         /**
1269          * Boolean generation for |
1270          */
1271         public void generateOptimizedLogicalOr(
1272                 BlockScope currentScope,
1273                 CodeStream codeStream,
1274                 Label trueLabel,
1275                 Label falseLabel,
1276                 boolean valueRequired) {
1277                         
1278                 int pc = codeStream.position;
1279                 Constant condConst;
1280                 if ((left.implicitConversion & 0xF) == T_boolean) {
1281                         if ((condConst = left.conditionalConstant()) != NotAConstant) {
1282                                 if (condConst.booleanValue() == true) {
1283                                         // <something equivalent to true> | x
1284                                         left.generateOptimizedBoolean(
1285                                                 currentScope,
1286                                                 codeStream,
1287                                                 trueLabel,
1288                                                 falseLabel,
1289                                                 false);
1290                                         right.generateOptimizedBoolean(
1291                                                 currentScope,
1292                                                 codeStream,
1293                                                 trueLabel,
1294                                                 falseLabel,
1295                                                 false);
1296                                         if (valueRequired) {
1297                                                 if ((bits & OnlyValueRequiredMASK) != 0) {
1298                                                         codeStream.iconst_1();
1299                                                 } else {
1300                                                         if (trueLabel != null) {
1301                                                                 codeStream.goto_(trueLabel);
1302                                                         }
1303                                                 }
1304                                         }
1305                                 } else {
1306                                         // <something equivalent to false> | x
1307                                         left.generateOptimizedBoolean(
1308                                                 currentScope,
1309                                                 codeStream,
1310                                                 trueLabel,
1311                                                 falseLabel,
1312                                                 false);
1313                                         if ((bits & OnlyValueRequiredMASK) != 0) {
1314                                                 right.generateCode(currentScope, codeStream, valueRequired);
1315                                         } else {
1316                                                 right.generateOptimizedBoolean(
1317                                                         currentScope,
1318                                                         codeStream,
1319                                                         trueLabel,
1320                                                         falseLabel,
1321                                                         valueRequired);
1322                                         }
1323                                 }
1324                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
1325                                 return;
1326                         }
1327                         if ((condConst = right.conditionalConstant()) != NotAConstant) {
1328                                 if (condConst.booleanValue() == true) {
1329                                         // x | <something equivalent to true>
1330                                         left.generateOptimizedBoolean(
1331                                                 currentScope,
1332                                                 codeStream,
1333                                                 trueLabel,
1334                                                 falseLabel,
1335                                                 false);
1336                                         right.generateOptimizedBoolean(
1337                                                 currentScope,
1338                                                 codeStream,
1339                                                 trueLabel,
1340                                                 falseLabel,
1341                                                 false);
1342                                         if (valueRequired) {
1343                                                 if ((bits & OnlyValueRequiredMASK) != 0) {
1344                                                         codeStream.iconst_1();
1345                                                 } else {
1346                                                         if (trueLabel != null) {
1347                                                                 codeStream.goto_(trueLabel);
1348                                                         }
1349                                                 }
1350                                         }
1351                                 } else {
1352                                         // x | <something equivalent to false>
1353                                         if ((bits & OnlyValueRequiredMASK) != 0) {
1354                                                 left.generateCode(currentScope, codeStream, valueRequired);
1355                                         } else {
1356                                                 left.generateOptimizedBoolean(
1357                                                         currentScope,
1358                                                         codeStream,
1359                                                         trueLabel,
1360                                                         falseLabel,
1361                                                         valueRequired);
1362                                         }
1363                                         right.generateOptimizedBoolean(
1364                                                 currentScope,
1365                                                 codeStream,
1366                                                 trueLabel,
1367                                                 falseLabel,
1368                                                 false);
1369                                 }
1370                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
1371                                 return;
1372                         }
1373                 }
1374                 // default case
1375                 left.generateCode(currentScope, codeStream, valueRequired);
1376                 right.generateCode(currentScope, codeStream, valueRequired);
1377                 if (valueRequired) {
1378                         codeStream.ior();
1379                         if ((bits & OnlyValueRequiredMASK) == 0) {
1380                                 if (falseLabel == null) {
1381                                         if (trueLabel != null) {
1382                                                 // implicit falling through the FALSE case
1383                                                 codeStream.ifne(trueLabel);
1384                                         }
1385                                 } else {
1386                                         // implicit falling through the TRUE case
1387                                         if (trueLabel == null) {
1388                                                 codeStream.ifeq(falseLabel);
1389                                         } else {
1390                                                 // no implicit fall through TRUE/FALSE --> should never occur
1391                                         }
1392                                 }
1393                         }
1394                 }
1395                 codeStream.recordPositionsFrom(pc, this.sourceStart);
1396         }
1397         
1398         /**
1399          * Boolean generation for ^
1400          */
1401         public void generateOptimizedLogicalXor(
1402                 BlockScope currentScope,
1403                 CodeStream codeStream,
1404                 Label trueLabel,
1405                 Label falseLabel,
1406                 boolean valueRequired) {
1407                         
1408                 int pc = codeStream.position;
1409                 Constant condConst;
1410                 if ((left.implicitConversion & 0xF) == T_boolean) {
1411                         if ((condConst = left.conditionalConstant()) != NotAConstant) {
1412                                 if (condConst.booleanValue() == true) {
1413                                         // <something equivalent to true> ^ x
1414                                         left.generateOptimizedBoolean(
1415                                                 currentScope,
1416                                                 codeStream,
1417                                                 trueLabel,
1418                                                 falseLabel,
1419                                                 false);
1420                                         right.generateOptimizedBoolean(
1421                                                 currentScope,
1422                                                 codeStream,
1423                                                 falseLabel,
1424                                                 trueLabel,
1425                                                 valueRequired);
1426                                 } else {
1427                                         // <something equivalent to false> ^ x
1428                                         left.generateOptimizedBoolean(
1429                                                 currentScope,
1430                                                 codeStream,
1431                                                 trueLabel,
1432                                                 falseLabel,
1433                                                 false);
1434                                         if ((bits & OnlyValueRequiredMASK) != 0) {
1435                                                 right.generateCode(currentScope, codeStream, valueRequired);
1436                                         } else {
1437                                                 right.generateOptimizedBoolean(
1438                                                         currentScope,
1439                                                         codeStream,
1440                                                         trueLabel,
1441                                                         falseLabel,
1442                                                         valueRequired);
1443                                         }
1444                                 }
1445                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
1446                                 return;
1447                         }
1448                         if ((condConst = right.conditionalConstant()) != NotAConstant) {
1449                                 if (condConst.booleanValue() == true) {
1450                                         // x ^ <something equivalent to true>
1451                                         left.generateOptimizedBoolean(
1452                                                 currentScope,
1453                                                 codeStream,
1454                                                 falseLabel,
1455                                                 trueLabel,
1456                                                 valueRequired);
1457                                         right.generateOptimizedBoolean(
1458                                                 currentScope,
1459                                                 codeStream,
1460                                                 trueLabel,
1461                                                 falseLabel,
1462                                                 false);
1463                                 } else {
1464                                         // x ^ <something equivalent to false>
1465                                         if ((bits & OnlyValueRequiredMASK) != 0) {
1466                                                 left.generateCode(currentScope, codeStream, valueRequired);
1467                                         } else {
1468                                                 left.generateOptimizedBoolean(
1469                                                         currentScope,
1470                                                         codeStream,
1471                                                         trueLabel,
1472                                                         falseLabel,
1473                                                         valueRequired);
1474                                         }
1475                                         right.generateOptimizedBoolean(
1476                                                 currentScope,
1477                                                 codeStream,
1478                                                 trueLabel,
1479                                                 falseLabel,
1480                                                 false);
1481                                 }
1482                                 codeStream.recordPositionsFrom(pc, this.sourceStart);
1483                                 return;
1484                         }
1485                 }
1486                 // default case
1487                 left.generateCode(currentScope, codeStream, valueRequired);
1488                 right.generateCode(currentScope, codeStream, valueRequired);
1489                 if (valueRequired) {
1490                         codeStream.ixor();
1491                         if ((bits & OnlyValueRequiredMASK) == 0) {
1492                                 if (falseLabel == null) {
1493                                         if (trueLabel != null) {
1494                                                 // implicit falling through the FALSE case
1495                                                 codeStream.ifne(trueLabel);
1496                                         }
1497                                 } else {
1498                                         // implicit falling through the TRUE case
1499                                         if (trueLabel == null) {
1500                                                 codeStream.ifeq(falseLabel);
1501                                         } else {
1502                                                 // no implicit fall through TRUE/FALSE --> should never occur
1503                                         }
1504                                 }
1505                         }
1506                 }
1507                 codeStream.recordPositionsFrom(pc, this.sourceStart);
1508         }
1509         
1510         public void generateOptimizedStringBuffer(
1511                 BlockScope blockScope,
1512                 CodeStream codeStream,
1513                 int typeID) {
1514                         
1515                 /* In the case trying to make a string concatenation, there is no need to create a new
1516                  * string buffer, thus use a lower-level API for code generation involving only the
1517                  * appending of arguments to the existing StringBuffer
1518                  */
1519
1520                 if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS)
1521                         && ((bits & ReturnTypeIDMASK) == T_String)) {
1522                         if (constant != NotAConstant) {
1523                                 codeStream.generateConstant(constant, implicitConversion);
1524                                 codeStream.invokeStringBufferAppendForType(implicitConversion & 0xF);
1525                         } else {
1526                                 int pc = codeStream.position;
1527                                 left.generateOptimizedStringBuffer(
1528                                         blockScope,
1529                                         codeStream,
1530                                         left.implicitConversion & 0xF);
1531                                 codeStream.recordPositionsFrom(pc, left.sourceStart);
1532                                 pc = codeStream.position;
1533                                 right.generateOptimizedStringBuffer(
1534                                         blockScope,
1535                                         codeStream,
1536                                         right.implicitConversion & 0xF);
1537                                 codeStream.recordPositionsFrom(pc, right.sourceStart);
1538                         }
1539                 } else {
1540                         super.generateOptimizedStringBuffer(blockScope, codeStream, typeID);
1541                 }
1542         }
1543         
1544         public void generateOptimizedStringBufferCreation(
1545                 BlockScope blockScope,
1546                 CodeStream codeStream,
1547                 int typeID) {
1548                         
1549                 /* In the case trying to make a string concatenation, there is no need to create a new
1550                  * string buffer, thus use a lower-level API for code generation involving only the 
1551                  * appending of arguments to the existing StringBuffer
1552                  */
1553
1554                 if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS)
1555                         && ((bits & ReturnTypeIDMASK) == T_String)) {
1556                         if (constant != NotAConstant) {
1557                                 codeStream.newStringBuffer(); // new: java.lang.StringBuffer
1558                                 codeStream.dup();
1559                                 codeStream.ldc(constant.stringValue());
1560                                 codeStream.invokeStringBufferStringConstructor();
1561                                 // invokespecial: java.lang.StringBuffer.<init>(Ljava.lang.String;)V
1562                         } else {
1563                                 int pc = codeStream.position;
1564                                 left.generateOptimizedStringBufferCreation(
1565                                         blockScope,
1566                                         codeStream,
1567                                         left.implicitConversion & 0xF);
1568                                 codeStream.recordPositionsFrom(pc, left.sourceStart);
1569                                 pc = codeStream.position;
1570                                 right.generateOptimizedStringBuffer(
1571                                         blockScope,
1572                                         codeStream,
1573                                         right.implicitConversion & 0xF);
1574                                 codeStream.recordPositionsFrom(pc, right.sourceStart);
1575                         }
1576                 } else {
1577                         super.generateOptimizedStringBufferCreation(blockScope, codeStream, typeID);
1578                 }
1579         }
1580         
1581         public boolean isCompactableOperation() {
1582                 
1583                 return true;
1584         }
1585         
1586         public void optimizedBooleanConstant(int leftId, int operator, int rightId) {
1587
1588                 switch (operator) {
1589                         case AND :
1590                                 if ((leftId != T_boolean) || (rightId != T_boolean))
1591                                         return;
1592                         case AND_AND :
1593                                 Constant cst;
1594                                 if ((cst = left.conditionalConstant()) != NotAConstant) {
1595                                         if (cst.booleanValue() == false) { // left is equivalent to false
1596                                                 optimizedBooleanConstant = cst; // constant(false)
1597                                                 return;
1598                                         } else { //left is equivalent to true
1599                                                 if ((cst = right.conditionalConstant()) != NotAConstant) {
1600                                                         optimizedBooleanConstant = cst;
1601                                                         // the conditional result is equivalent to the right conditional value
1602                                                 }
1603                                                 return;
1604                                         }
1605                                 }
1606                                 if ((cst = right.conditionalConstant()) != NotAConstant) {
1607                                         if (cst.booleanValue() == false) { // right is equivalent to false
1608                                                 optimizedBooleanConstant = cst; // constant(false)
1609                                         }
1610                                 }
1611                                 return;
1612                         case OR :
1613                                 if ((leftId != T_boolean) || (rightId != T_boolean))
1614                                         return;
1615                         case OR_OR :
1616                                 if ((cst = left.conditionalConstant()) != NotAConstant) {
1617                                         if (cst.booleanValue() == true) { // left is equivalent to true
1618                                                 optimizedBooleanConstant = cst; // constant(true)
1619                                                 return;
1620                                         } else { //left is equivalent to false
1621                                                 if ((cst = right.conditionalConstant()) != NotAConstant) {
1622                                                         optimizedBooleanConstant = cst;
1623                                                 }
1624                                                 return;
1625                                         }
1626                                 }
1627                                 if ((cst = right.conditionalConstant()) != NotAConstant) {
1628                                         if (cst.booleanValue() == true) { // right is equivalent to true
1629                                                 optimizedBooleanConstant = cst; // constant(true)
1630                                         }
1631                                 }
1632                 }
1633         }
1634         
1635         public TypeBinding resolveType(BlockScope scope) {
1636
1637                 // use the id of the type to navigate into the table
1638                 TypeBinding leftTb = left.resolveType(scope);
1639                 TypeBinding rightTb = right.resolveType(scope);
1640                 if (leftTb == null || rightTb == null) {
1641                         constant = Constant.NotAConstant;
1642                         return null;
1643                 }
1644                 int leftId = leftTb.id;
1645                 int rightId = rightTb.id;
1646                 if (leftId > 15
1647                         || rightId > 15) { // must convert String + Object || Object + String
1648                         if (leftId == T_String) {
1649                                 rightId = T_Object;
1650                         } else if (rightId == T_String) {
1651                                 leftId = T_Object;
1652                         } else {
1653                                 constant = Constant.NotAConstant;
1654                                 scope.problemReporter().invalidOperator(this, leftTb, rightTb);
1655                                 return null;
1656                         }
1657                 }
1658                 if (((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) {
1659                         if (leftId == T_String
1660                                 && rightTb.isArrayType()
1661                                 && ((ArrayBinding) rightTb).elementsType(scope) == CharBinding)
1662                                 scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(
1663                                         right);
1664                         else if (
1665                                 rightId == T_String
1666                                         && leftTb.isArrayType()
1667                                         && ((ArrayBinding) leftTb).elementsType(scope) == CharBinding)
1668                                 scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(
1669                                         left);
1670                 }
1671
1672                 // the code is an int
1673                 // (cast)  left   Op (cast)  rigth --> result
1674                 //  0000   0000       0000   0000      0000
1675                 //  <<16   <<12       <<8    <<4       <<0
1676
1677                 // Don't test for result = 0. If it is zero, some more work is done.
1678                 // On the one hand when it is not zero (correct code) we avoid doing the test   
1679                 int result =
1680                         ResolveTypeTables[(bits & OperatorMASK) >> OperatorSHIFT][(leftId << 4)
1681                                 + rightId];
1682                 left.implicitConversion = result >>> 12;
1683                 right.implicitConversion = (result >>> 4) & 0x000FF;
1684
1685                 bits |= result & 0xF;
1686                 switch (result & 0xF) { // record the current ReturnTypeID
1687                         // only switch on possible result type.....
1688                         case T_boolean :
1689                                 this.typeBinding = BooleanBinding;
1690                                 break;
1691                         case T_byte :
1692                                 this.typeBinding = ByteBinding;
1693                                 break;
1694                         case T_char :
1695                                 this.typeBinding = CharBinding;
1696                                 break;
1697                         case T_double :
1698                                 this.typeBinding = DoubleBinding;
1699                                 break;
1700                         case T_float :
1701                                 this.typeBinding = FloatBinding;
1702                                 break;
1703                         case T_int :
1704                                 this.typeBinding = IntBinding;
1705                                 break;
1706                         case T_long :
1707                                 this.typeBinding = LongBinding;
1708                                 break;
1709                         case T_String :
1710                                 this.typeBinding = scope.getJavaLangString();
1711                                 break;
1712                         default : //error........
1713                                 constant = Constant.NotAConstant;
1714                                 scope.problemReporter().invalidOperator(this, leftTb, rightTb);
1715                                 return null;
1716                 }
1717
1718                 // compute the constant when valid
1719                 computeConstant(scope, leftId, rightId);
1720                 return this.typeBinding;
1721         }
1722         
1723         public String toStringExpressionNoParenthesis() {
1724
1725                 return left.toStringExpression() + " " + //$NON-NLS-1$
1726                 operatorToString() + " " + //$NON-NLS-1$
1727                 right.toStringExpression();
1728         }
1729
1730         public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
1731                 
1732                 if (visitor.visit(this, scope)) {
1733                         left.traverse(visitor, scope);
1734                         right.traverse(visitor, scope);
1735                 }
1736                 visitor.endVisit(this, scope);
1737         }
1738 }