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