1 /*******************************************************************************
2 * Copyright (c) 2000, 2003 IBM Corporation and others.
3 * All rights reserved. This program and the accompanying materials
4 * are made available under the terms of the Common Public License v1.0
5 * which accompanies this distribution, and is available at
6 * http://www.eclipse.org/legal/cpl-v10.html
9 * IBM Corporation - initial API and implementation
10 *******************************************************************************/
11 package net.sourceforge.phpeclipse.internal.compiler.ast;
13 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
14 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
16 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
17 import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
18 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
19 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
21 public class BinaryExpression extends OperatorExpression {
23 public Expression left, right;
24 public Constant optimizedBooleanConstant;
26 public BinaryExpression(Expression left, Expression right, int operator) {
30 this.bits |= operator << OperatorSHIFT; // encode operator
31 this.sourceStart = left.sourceStart;
32 this.sourceEnd = right.sourceEnd;
35 public FlowInfo analyseCode(
36 BlockScope currentScope,
37 FlowContext flowContext,
44 left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
45 .unconditionalInits();
48 public void computeConstant(BlockScope scope, int leftId, int rightId) {
50 //compute the constant when valid
51 if ((this.left.constant != Constant.NotAConstant)
52 && (this.right.constant != Constant.NotAConstant)) {
55 Constant.computeConstantOperation(
58 (this.bits & OperatorMASK) >> OperatorSHIFT,
61 } catch (ArithmeticException e) {
62 this.constant = Constant.NotAConstant;
63 // 1.2 no longer throws an exception at compile-time
64 //scope.problemReporter().compileTimeConstantThrowsArithmeticException(this);
67 this.constant = Constant.NotAConstant;
68 //add some work for the boolean operators & |
69 // this.optimizedBooleanConstant(
71 // (this.bits & OperatorMASK) >> OperatorSHIFT,
76 public Constant optimizedBooleanConstant() {
78 return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant;
82 * Code generation for a binary operation
84 // public void generateCode(
85 // BlockScope currentScope,
86 // CodeStream codeStream,
87 // boolean valueRequired) {
89 // int pc = codeStream.position;
90 // Label falseLabel, endLabel;
91 // if (constant != Constant.NotAConstant) {
93 // codeStream.generateConstant(constant, implicitConversion);
94 // codeStream.recordPositionsFrom(pc, this.sourceStart);
97 // bits |= OnlyValueRequiredMASK;
98 // switch ((bits & OperatorMASK) >> OperatorSHIFT) {
100 // switch (bits & ReturnTypeIDMASK) {
102 // codeStream.generateStringAppend(currentScope, left, right);
103 // if (!valueRequired)
107 // left.generateCode(currentScope, codeStream, valueRequired);
108 // right.generateCode(currentScope, codeStream, valueRequired);
109 // if (valueRequired)
110 // codeStream.iadd();
113 // left.generateCode(currentScope, codeStream, valueRequired);
114 // right.generateCode(currentScope, codeStream, valueRequired);
115 // if (valueRequired)
116 // codeStream.ladd();
119 // left.generateCode(currentScope, codeStream, valueRequired);
120 // right.generateCode(currentScope, codeStream, valueRequired);
121 // if (valueRequired)
122 // codeStream.dadd();
125 // left.generateCode(currentScope, codeStream, valueRequired);
126 // right.generateCode(currentScope, codeStream, valueRequired);
127 // if (valueRequired)
128 // codeStream.fadd();
133 // switch (bits & ReturnTypeIDMASK) {
135 // left.generateCode(currentScope, codeStream, valueRequired);
136 // right.generateCode(currentScope, codeStream, valueRequired);
137 // if (valueRequired)
138 // codeStream.isub();
141 // left.generateCode(currentScope, codeStream, valueRequired);
142 // right.generateCode(currentScope, codeStream, valueRequired);
143 // if (valueRequired)
144 // codeStream.lsub();
147 // left.generateCode(currentScope, codeStream, valueRequired);
148 // right.generateCode(currentScope, codeStream, valueRequired);
149 // if (valueRequired)
150 // codeStream.dsub();
153 // left.generateCode(currentScope, codeStream, valueRequired);
154 // right.generateCode(currentScope, codeStream, valueRequired);
155 // if (valueRequired)
156 // codeStream.fsub();
161 // switch (bits & ReturnTypeIDMASK) {
163 // left.generateCode(currentScope, codeStream, valueRequired);
164 // right.generateCode(currentScope, codeStream, valueRequired);
165 // if (valueRequired)
166 // codeStream.imul();
169 // left.generateCode(currentScope, codeStream, valueRequired);
170 // right.generateCode(currentScope, codeStream, valueRequired);
171 // if (valueRequired)
172 // codeStream.lmul();
175 // left.generateCode(currentScope, codeStream, valueRequired);
176 // right.generateCode(currentScope, codeStream, valueRequired);
177 // if (valueRequired)
178 // codeStream.dmul();
181 // left.generateCode(currentScope, codeStream, valueRequired);
182 // right.generateCode(currentScope, codeStream, valueRequired);
183 // if (valueRequired)
184 // codeStream.fmul();
189 // switch (bits & ReturnTypeIDMASK) {
191 // left.generateCode(currentScope, codeStream, true);
192 // right.generateCode(currentScope, codeStream, true);
193 // codeStream.idiv();
194 // if (!valueRequired)
198 // left.generateCode(currentScope, codeStream, true);
199 // right.generateCode(currentScope, codeStream, true);
200 // codeStream.ldiv();
201 // if (!valueRequired)
202 // codeStream.pop2();
205 // left.generateCode(currentScope, codeStream, valueRequired);
206 // right.generateCode(currentScope, codeStream, valueRequired);
207 // if (valueRequired)
208 // codeStream.ddiv();
211 // left.generateCode(currentScope, codeStream, valueRequired);
212 // right.generateCode(currentScope, codeStream, valueRequired);
213 // if (valueRequired)
214 // codeStream.fdiv();
219 // switch (bits & ReturnTypeIDMASK) {
221 // left.generateCode(currentScope, codeStream, true);
222 // right.generateCode(currentScope, codeStream, true);
223 // codeStream.irem();
224 // if (!valueRequired)
228 // left.generateCode(currentScope, codeStream, true);
229 // right.generateCode(currentScope, codeStream, true);
230 // codeStream.lrem();
231 // if (!valueRequired)
232 // codeStream.pop2();
235 // left.generateCode(currentScope, codeStream, valueRequired);
236 // right.generateCode(currentScope, codeStream, valueRequired);
237 // if (valueRequired)
238 // codeStream.drem();
241 // left.generateCode(currentScope, codeStream, valueRequired);
242 // right.generateCode(currentScope, codeStream, valueRequired);
243 // if (valueRequired)
244 // codeStream.frem();
249 // switch (bits & ReturnTypeIDMASK) {
252 // if ((left.constant != Constant.NotAConstant)
253 // && (left.constant.typeID() == T_int)
254 // && (left.constant.intValue() == 0)) {
255 // right.generateCode(currentScope, codeStream, false);
256 // if (valueRequired)
257 // codeStream.iconst_0();
260 // if ((right.constant != Constant.NotAConstant)
261 // && (right.constant.typeID() == T_int)
262 // && (right.constant.intValue() == 0)) {
263 // left.generateCode(currentScope, codeStream, false);
264 // if (valueRequired)
265 // codeStream.iconst_0();
267 // left.generateCode(currentScope, codeStream, valueRequired);
268 // right.generateCode(currentScope, codeStream, valueRequired);
269 // if (valueRequired)
270 // codeStream.iand();
276 // if ((left.constant != Constant.NotAConstant)
277 // && (left.constant.typeID() == T_long)
278 // && (left.constant.longValue() == 0L)) {
279 // right.generateCode(currentScope, codeStream, false);
280 // if (valueRequired)
281 // codeStream.lconst_0();
284 // if ((right.constant != Constant.NotAConstant)
285 // && (right.constant.typeID() == T_long)
286 // && (right.constant.longValue() == 0L)) {
287 // left.generateCode(currentScope, codeStream, false);
288 // if (valueRequired)
289 // codeStream.lconst_0();
291 // left.generateCode(currentScope, codeStream, valueRequired);
292 // right.generateCode(currentScope, codeStream, valueRequired);
293 // if (valueRequired)
294 // codeStream.land();
298 // case T_boolean : // logical and
299 // generateOptimizedLogicalAnd(
303 // (falseLabel = new Label(codeStream)),
305 // /* improving code gen for such a case: boolean b = i < 0 && false;
306 // * since the label has never been used, we have the inlined value on the stack. */
307 // if (falseLabel.hasForwardReferences()) {
308 // if (valueRequired) {
309 // codeStream.iconst_1();
310 // if ((bits & ValueForReturnMASK) != 0) {
311 // codeStream.ireturn();
312 // falseLabel.place();
313 // codeStream.iconst_0();
315 // codeStream.goto_(endLabel = new Label(codeStream));
316 // codeStream.decrStackSize(1);
317 // falseLabel.place();
318 // codeStream.iconst_0();
322 // falseLabel.place();
328 // switch (bits & ReturnTypeIDMASK) {
331 // if ((left.constant != Constant.NotAConstant)
332 // && (left.constant.typeID() == T_int)
333 // && (left.constant.intValue() == 0)) {
334 // right.generateCode(currentScope, codeStream, valueRequired);
337 // if ((right.constant != Constant.NotAConstant)
338 // && (right.constant.typeID() == T_int)
339 // && (right.constant.intValue() == 0)) {
340 // left.generateCode(currentScope, codeStream, valueRequired);
342 // left.generateCode(currentScope, codeStream, valueRequired);
343 // right.generateCode(currentScope, codeStream, valueRequired);
344 // if (valueRequired)
351 // if ((left.constant != Constant.NotAConstant)
352 // && (left.constant.typeID() == T_long)
353 // && (left.constant.longValue() == 0L)) {
354 // right.generateCode(currentScope, codeStream, valueRequired);
357 // if ((right.constant != Constant.NotAConstant)
358 // && (right.constant.typeID() == T_long)
359 // && (right.constant.longValue() == 0L)) {
360 // left.generateCode(currentScope, codeStream, valueRequired);
362 // left.generateCode(currentScope, codeStream, valueRequired);
363 // right.generateCode(currentScope, codeStream, valueRequired);
364 // if (valueRequired)
369 // case T_boolean : // logical or
370 // generateOptimizedLogicalOr(
374 // (falseLabel = new Label(codeStream)),
376 // /* improving code gen for such a case: boolean b = i < 0 || true;
377 // * since the label has never been used, we have the inlined value on the stack. */
378 // if (falseLabel.hasForwardReferences()) {
379 // if (valueRequired) {
380 // codeStream.iconst_1();
381 // if ((bits & ValueForReturnMASK) != 0) {
382 // codeStream.ireturn();
383 // falseLabel.place();
384 // codeStream.iconst_0();
386 // codeStream.goto_(endLabel = new Label(codeStream));
387 // codeStream.decrStackSize(1);
388 // falseLabel.place();
389 // codeStream.iconst_0();
393 // falseLabel.place();
399 // switch (bits & ReturnTypeIDMASK) {
402 // if ((left.constant != Constant.NotAConstant)
403 // && (left.constant.typeID() == T_int)
404 // && (left.constant.intValue() == 0)) {
405 // right.generateCode(currentScope, codeStream, valueRequired);
408 // if ((right.constant != Constant.NotAConstant)
409 // && (right.constant.typeID() == T_int)
410 // && (right.constant.intValue() == 0)) {
411 // left.generateCode(currentScope, codeStream, valueRequired);
413 // left.generateCode(currentScope, codeStream, valueRequired);
414 // right.generateCode(currentScope, codeStream, valueRequired);
415 // if (valueRequired)
416 // codeStream.ixor();
422 // if ((left.constant != Constant.NotAConstant)
423 // && (left.constant.typeID() == T_long)
424 // && (left.constant.longValue() == 0L)) {
425 // right.generateCode(currentScope, codeStream, valueRequired);
428 // if ((right.constant != Constant.NotAConstant)
429 // && (right.constant.typeID() == T_long)
430 // && (right.constant.longValue() == 0L)) {
431 // left.generateCode(currentScope, codeStream, valueRequired);
433 // left.generateCode(currentScope, codeStream, valueRequired);
434 // right.generateCode(currentScope, codeStream, valueRequired);
435 // if (valueRequired)
436 // codeStream.lxor();
441 // generateOptimizedLogicalXor(
445 // (falseLabel = new Label(codeStream)),
447 // /* improving code gen for such a case: boolean b = i < 0 ^ bool;
448 // * since the label has never been used, we have the inlined value on the stack. */
449 // if (falseLabel.hasForwardReferences()) {
450 // if (valueRequired) {
451 // codeStream.iconst_1();
452 // if ((bits & ValueForReturnMASK) != 0) {
453 // codeStream.ireturn();
454 // falseLabel.place();
455 // codeStream.iconst_0();
457 // codeStream.goto_(endLabel = new Label(codeStream));
458 // codeStream.decrStackSize(1);
459 // falseLabel.place();
460 // codeStream.iconst_0();
464 // falseLabel.place();
470 // switch (bits & ReturnTypeIDMASK) {
472 // left.generateCode(currentScope, codeStream, valueRequired);
473 // right.generateCode(currentScope, codeStream, valueRequired);
474 // if (valueRequired)
475 // codeStream.ishl();
478 // left.generateCode(currentScope, codeStream, valueRequired);
479 // right.generateCode(currentScope, codeStream, valueRequired);
480 // if (valueRequired)
481 // codeStream.lshl();
484 // case RIGHT_SHIFT :
485 // switch (bits & ReturnTypeIDMASK) {
487 // left.generateCode(currentScope, codeStream, valueRequired);
488 // right.generateCode(currentScope, codeStream, valueRequired);
489 // if (valueRequired)
490 // codeStream.ishr();
493 // left.generateCode(currentScope, codeStream, valueRequired);
494 // right.generateCode(currentScope, codeStream, valueRequired);
495 // if (valueRequired)
496 // codeStream.lshr();
499 // case UNSIGNED_RIGHT_SHIFT :
500 // switch (bits & ReturnTypeIDMASK) {
502 // left.generateCode(currentScope, codeStream, valueRequired);
503 // right.generateCode(currentScope, codeStream, valueRequired);
504 // if (valueRequired)
505 // codeStream.iushr();
508 // left.generateCode(currentScope, codeStream, valueRequired);
509 // right.generateCode(currentScope, codeStream, valueRequired);
510 // if (valueRequired)
511 // codeStream.lushr();
515 // generateOptimizedGreaterThan(
519 // (falseLabel = new Label(codeStream)),
521 // if (valueRequired) {
522 // codeStream.iconst_1();
523 // if ((bits & ValueForReturnMASK) != 0) {
524 // codeStream.ireturn();
525 // falseLabel.place();
526 // codeStream.iconst_0();
528 // codeStream.goto_(endLabel = new Label(codeStream));
529 // codeStream.decrStackSize(1);
530 // falseLabel.place();
531 // codeStream.iconst_0();
536 // case GREATER_EQUAL :
537 // generateOptimizedGreaterThanOrEqual(
541 // (falseLabel = new Label(codeStream)),
543 // if (valueRequired) {
544 // codeStream.iconst_1();
545 // if ((bits & ValueForReturnMASK) != 0) {
546 // codeStream.ireturn();
547 // falseLabel.place();
548 // codeStream.iconst_0();
550 // codeStream.goto_(endLabel = new Label(codeStream));
551 // codeStream.decrStackSize(1);
552 // falseLabel.place();
553 // codeStream.iconst_0();
559 // generateOptimizedLessThan(
563 // (falseLabel = new Label(codeStream)),
565 // if (valueRequired) {
566 // codeStream.iconst_1();
567 // if ((bits & ValueForReturnMASK) != 0) {
568 // codeStream.ireturn();
569 // falseLabel.place();
570 // codeStream.iconst_0();
572 // codeStream.goto_(endLabel = new Label(codeStream));
573 // codeStream.decrStackSize(1);
574 // falseLabel.place();
575 // codeStream.iconst_0();
581 // generateOptimizedLessThanOrEqual(
585 // (falseLabel = new Label(codeStream)),
587 // if (valueRequired) {
588 // codeStream.iconst_1();
589 // if ((bits & ValueForReturnMASK) != 0) {
590 // codeStream.ireturn();
591 // falseLabel.place();
592 // codeStream.iconst_0();
594 // codeStream.goto_(endLabel = new Label(codeStream));
595 // codeStream.decrStackSize(1);
596 // falseLabel.place();
597 // codeStream.iconst_0();
602 // if (valueRequired) {
603 // codeStream.generateImplicitConversion(implicitConversion);
605 // codeStream.recordPositionsFrom(pc, this.sourceStart);
609 * Boolean operator code generation
610 * Optimized operations are: <, <=, >, >=, &, |, ^
612 // public void generateOptimizedBoolean(
613 // BlockScope currentScope,
614 // CodeStream codeStream,
617 // boolean valueRequired) {
619 // if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
620 // super.generateOptimizedBoolean(
628 // switch ((bits & OperatorMASK) >> OperatorSHIFT) {
630 // generateOptimizedLessThan(
638 // generateOptimizedLessThanOrEqual(
646 // generateOptimizedGreaterThan(
653 // case GREATER_EQUAL :
654 // generateOptimizedGreaterThanOrEqual(
662 // generateOptimizedLogicalAnd(
670 // generateOptimizedLogicalOr(
678 // generateOptimizedLogicalXor(
686 // super.generateOptimizedBoolean(
695 // * Boolean generation for >
697 // public void generateOptimizedGreaterThan(
698 // BlockScope currentScope,
699 // CodeStream codeStream,
702 // boolean valueRequired) {
704 // int promotedTypeID = left.implicitConversion >> 4;
705 // // both sides got promoted in the same way
706 // if (promotedTypeID == T_int) {
708 // if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
709 // right.generateCode(currentScope, codeStream, valueRequired);
710 // if (valueRequired) {
711 // if (falseLabel == null) {
712 // if (trueLabel != null) {
713 // // implicitly falling through the FALSE case
714 // codeStream.iflt(trueLabel);
717 // if (trueLabel == null) {
718 // // implicitly falling through the TRUE case
719 // codeStream.ifge(falseLabel);
721 // // no implicit fall through TRUE/FALSE --> should never occur
725 // // reposition the endPC
726 // codeStream.updateLastRecordedEndPC(codeStream.position);
730 // if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
731 // left.generateCode(currentScope, codeStream, valueRequired);
732 // if (valueRequired) {
733 // if (falseLabel == null) {
734 // if (trueLabel != null) {
735 // // implicitly falling through the FALSE case
736 // codeStream.ifgt(trueLabel);
739 // if (trueLabel == null) {
740 // // implicitly falling through the TRUE case
741 // codeStream.ifle(falseLabel);
743 // // no implicit fall through TRUE/FALSE --> should never occur
747 // // reposition the endPC
748 // codeStream.updateLastRecordedEndPC(codeStream.position);
752 // // default comparison
753 // left.generateCode(currentScope, codeStream, valueRequired);
754 // right.generateCode(currentScope, codeStream, valueRequired);
755 // if (valueRequired) {
756 // if (falseLabel == null) {
757 // if (trueLabel != null) {
758 // // implicit falling through the FALSE case
759 // switch (promotedTypeID) {
761 // codeStream.if_icmpgt(trueLabel);
764 // codeStream.fcmpl();
765 // codeStream.ifgt(trueLabel);
768 // codeStream.lcmp();
769 // codeStream.ifgt(trueLabel);
772 // codeStream.dcmpl();
773 // codeStream.ifgt(trueLabel);
775 // // reposition the endPC
776 // codeStream.updateLastRecordedEndPC(codeStream.position);
780 // if (trueLabel == null) {
781 // // implicit falling through the TRUE case
782 // switch (promotedTypeID) {
784 // codeStream.if_icmple(falseLabel);
787 // codeStream.fcmpl();
788 // codeStream.ifle(falseLabel);
791 // codeStream.lcmp();
792 // codeStream.ifle(falseLabel);
795 // codeStream.dcmpl();
796 // codeStream.ifle(falseLabel);
798 // // reposition the endPC
799 // codeStream.updateLastRecordedEndPC(codeStream.position);
802 // // no implicit fall through TRUE/FALSE --> should never occur
809 * Boolean generation for >=
811 // public void generateOptimizedGreaterThanOrEqual(
812 // BlockScope currentScope,
813 // CodeStream codeStream,
816 // boolean valueRequired) {
818 // int promotedTypeID = left.implicitConversion >> 4;
819 // // both sides got promoted in the same way
820 // if (promotedTypeID == T_int) {
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);
831 // if (trueLabel == null) {
832 // // implicitly falling through the TRUE case
833 // codeStream.ifgt(falseLabel);
835 // // no implicit fall through TRUE/FALSE --> should never occur
839 // // reposition the endPC
840 // codeStream.updateLastRecordedEndPC(codeStream.position);
844 // if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
845 // left.generateCode(currentScope, codeStream, valueRequired);
846 // if (valueRequired) {
847 // if (falseLabel == null) {
848 // if (trueLabel != null) {
849 // // implicitly falling through the FALSE case
850 // codeStream.ifge(trueLabel);
853 // if (trueLabel == null) {
854 // // implicitly falling through the TRUE case
855 // codeStream.iflt(falseLabel);
857 // // no implicit fall through TRUE/FALSE --> should never occur
861 // // reposition the endPC
862 // codeStream.updateLastRecordedEndPC(codeStream.position);
866 // // default comparison
867 // left.generateCode(currentScope, codeStream, valueRequired);
868 // right.generateCode(currentScope, codeStream, valueRequired);
869 // if (valueRequired) {
870 // if (falseLabel == null) {
871 // if (trueLabel != null) {
872 // // implicit falling through the FALSE case
873 // switch (promotedTypeID) {
875 // codeStream.if_icmpge(trueLabel);
878 // codeStream.fcmpl();
879 // codeStream.ifge(trueLabel);
882 // codeStream.lcmp();
883 // codeStream.ifge(trueLabel);
886 // codeStream.dcmpl();
887 // codeStream.ifge(trueLabel);
889 // // reposition the endPC
890 // codeStream.updateLastRecordedEndPC(codeStream.position);
894 // if (trueLabel == null) {
895 // // implicit falling through the TRUE case
896 // switch (promotedTypeID) {
898 // codeStream.if_icmplt(falseLabel);
901 // codeStream.fcmpl();
902 // codeStream.iflt(falseLabel);
905 // codeStream.lcmp();
906 // codeStream.iflt(falseLabel);
909 // codeStream.dcmpl();
910 // codeStream.iflt(falseLabel);
912 // // reposition the endPC
913 // codeStream.updateLastRecordedEndPC(codeStream.position);
916 // // no implicit fall through TRUE/FALSE --> should never occur
923 // * Boolean generation for <
925 // public void generateOptimizedLessThan(
926 // BlockScope currentScope,
927 // CodeStream codeStream,
930 // boolean valueRequired) {
932 // int promotedTypeID = left.implicitConversion >> 4;
933 // // both sides got promoted in the same way
934 // if (promotedTypeID == T_int) {
936 // if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
937 // right.generateCode(currentScope, codeStream, valueRequired);
938 // if (valueRequired) {
939 // if (falseLabel == null) {
940 // if (trueLabel != null) {
941 // // implicitly falling through the FALSE case
942 // codeStream.ifgt(trueLabel);
945 // if (trueLabel == null) {
946 // // implicitly falling through the TRUE case
947 // codeStream.ifle(falseLabel);
949 // // no implicit fall through TRUE/FALSE --> should never occur
953 // codeStream.updateLastRecordedEndPC(codeStream.position);
957 // if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
958 // left.generateCode(currentScope, codeStream, valueRequired);
959 // if (valueRequired) {
960 // if (falseLabel == null) {
961 // if (trueLabel != null) {
962 // // implicitly falling through the FALSE case
963 // codeStream.iflt(trueLabel);
966 // if (trueLabel == null) {
967 // // implicitly falling through the TRUE case
968 // codeStream.ifge(falseLabel);
970 // // no implicit fall through TRUE/FALSE --> should never occur
974 // codeStream.updateLastRecordedEndPC(codeStream.position);
978 // // default comparison
979 // left.generateCode(currentScope, codeStream, valueRequired);
980 // right.generateCode(currentScope, codeStream, valueRequired);
981 // if (valueRequired) {
982 // if (falseLabel == null) {
983 // if (trueLabel != null) {
984 // // implicit falling through the FALSE case
985 // switch (promotedTypeID) {
987 // codeStream.if_icmplt(trueLabel);
990 // codeStream.fcmpg();
991 // codeStream.iflt(trueLabel);
994 // codeStream.lcmp();
995 // codeStream.iflt(trueLabel);
998 // codeStream.dcmpg();
999 // codeStream.iflt(trueLabel);
1001 // codeStream.updateLastRecordedEndPC(codeStream.position);
1005 // if (trueLabel == null) {
1006 // // implicit falling through the TRUE case
1007 // switch (promotedTypeID) {
1009 // codeStream.if_icmpge(falseLabel);
1012 // codeStream.fcmpg();
1013 // codeStream.ifge(falseLabel);
1016 // codeStream.lcmp();
1017 // codeStream.ifge(falseLabel);
1020 // codeStream.dcmpg();
1021 // codeStream.ifge(falseLabel);
1023 // codeStream.updateLastRecordedEndPC(codeStream.position);
1026 // // no implicit fall through TRUE/FALSE --> should never occur
1033 // * Boolean generation for <=
1035 // public void generateOptimizedLessThanOrEqual(
1036 // BlockScope currentScope,
1037 // CodeStream codeStream,
1039 // Label falseLabel,
1040 // boolean valueRequired) {
1042 // int promotedTypeID = left.implicitConversion >> 4;
1043 // // both sides got promoted in the same way
1044 // if (promotedTypeID == T_int) {
1046 // if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
1047 // right.generateCode(currentScope, codeStream, valueRequired);
1048 // if (valueRequired) {
1049 // if (falseLabel == null) {
1050 // if (trueLabel != null) {
1051 // // implicitly falling through the FALSE case
1052 // codeStream.ifge(trueLabel);
1055 // if (trueLabel == null) {
1056 // // implicitly falling through the TRUE case
1057 // codeStream.iflt(falseLabel);
1059 // // no implicit fall through TRUE/FALSE --> should never occur
1063 // // reposition the endPC
1064 // codeStream.updateLastRecordedEndPC(codeStream.position);
1068 // if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
1069 // left.generateCode(currentScope, codeStream, valueRequired);
1070 // if (valueRequired) {
1071 // if (falseLabel == null) {
1072 // if (trueLabel != null) {
1073 // // implicitly falling through the FALSE case
1074 // codeStream.ifle(trueLabel);
1077 // if (trueLabel == null) {
1078 // // implicitly falling through the TRUE case
1079 // codeStream.ifgt(falseLabel);
1081 // // no implicit fall through TRUE/FALSE --> should never occur
1085 // // reposition the endPC
1086 // codeStream.updateLastRecordedEndPC(codeStream.position);
1090 // // default comparison
1091 // left.generateCode(currentScope, codeStream, valueRequired);
1092 // right.generateCode(currentScope, codeStream, valueRequired);
1093 // if (valueRequired) {
1094 // if (falseLabel == null) {
1095 // if (trueLabel != null) {
1096 // // implicit falling through the FALSE case
1097 // switch (promotedTypeID) {
1099 // codeStream.if_icmple(trueLabel);
1102 // codeStream.fcmpg();
1103 // codeStream.ifle(trueLabel);
1106 // codeStream.lcmp();
1107 // codeStream.ifle(trueLabel);
1110 // codeStream.dcmpg();
1111 // codeStream.ifle(trueLabel);
1113 // // reposition the endPC
1114 // codeStream.updateLastRecordedEndPC(codeStream.position);
1118 // if (trueLabel == null) {
1119 // // implicit falling through the TRUE case
1120 // switch (promotedTypeID) {
1122 // codeStream.if_icmpgt(falseLabel);
1125 // codeStream.fcmpg();
1126 // codeStream.ifgt(falseLabel);
1129 // codeStream.lcmp();
1130 // codeStream.ifgt(falseLabel);
1133 // codeStream.dcmpg();
1134 // codeStream.ifgt(falseLabel);
1136 // // reposition the endPC
1137 // codeStream.updateLastRecordedEndPC(codeStream.position);
1140 // // no implicit fall through TRUE/FALSE --> should never occur
1147 // * Boolean generation for &
1149 // public void generateOptimizedLogicalAnd(
1150 // BlockScope currentScope,
1151 // CodeStream codeStream,
1153 // Label falseLabel,
1154 // boolean valueRequired) {
1156 // Constant condConst;
1157 // if ((left.implicitConversion & 0xF) == T_boolean) {
1158 // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) {
1159 // if (condConst.booleanValue() == true) {
1160 // // <something equivalent to true> & x
1161 // left.generateOptimizedBoolean(
1167 // if ((bits & OnlyValueRequiredMASK) != 0) {
1168 // right.generateCode(currentScope, codeStream, valueRequired);
1170 // right.generateOptimizedBoolean(
1178 // // <something equivalent to false> & x
1179 // left.generateOptimizedBoolean(
1185 // right.generateOptimizedBoolean(
1191 // if (valueRequired) {
1192 // if ((bits & OnlyValueRequiredMASK) != 0) {
1193 // codeStream.iconst_0();
1195 // if (falseLabel != null) {
1196 // // implicit falling through the TRUE case
1197 // codeStream.goto_(falseLabel);
1201 // // reposition the endPC
1202 // codeStream.updateLastRecordedEndPC(codeStream.position);
1206 // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) {
1207 // if (condConst.booleanValue() == true) {
1208 // // x & <something equivalent to true>
1209 // if ((bits & OnlyValueRequiredMASK) != 0) {
1210 // left.generateCode(currentScope, codeStream, valueRequired);
1212 // left.generateOptimizedBoolean(
1219 // right.generateOptimizedBoolean(
1226 // // x & <something equivalent to false>
1227 // left.generateOptimizedBoolean(
1233 // right.generateOptimizedBoolean(
1239 // if (valueRequired) {
1240 // if ((bits & OnlyValueRequiredMASK) != 0) {
1241 // codeStream.iconst_0();
1243 // if (falseLabel != null) {
1244 // // implicit falling through the TRUE case
1245 // codeStream.goto_(falseLabel);
1249 // // reposition the endPC
1250 // codeStream.updateLastRecordedEndPC(codeStream.position);
1256 // left.generateCode(currentScope, codeStream, valueRequired);
1257 // right.generateCode(currentScope, codeStream, valueRequired);
1258 // if (valueRequired) {
1259 // codeStream.iand();
1260 // if ((bits & OnlyValueRequiredMASK) == 0) {
1261 // if (falseLabel == null) {
1262 // if (trueLabel != null) {
1263 // // implicit falling through the FALSE case
1264 // codeStream.ifne(trueLabel);
1267 // // implicit falling through the TRUE case
1268 // if (trueLabel == null) {
1269 // codeStream.ifeq(falseLabel);
1271 // // no implicit fall through TRUE/FALSE --> should never occur
1276 // // reposition the endPC
1277 // codeStream.updateLastRecordedEndPC(codeStream.position);
1281 // * Boolean generation for |
1283 // public void generateOptimizedLogicalOr(
1284 // BlockScope currentScope,
1285 // CodeStream codeStream,
1287 // Label falseLabel,
1288 // boolean valueRequired) {
1290 // Constant condConst;
1291 // if ((left.implicitConversion & 0xF) == T_boolean) {
1292 // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) {
1293 // if (condConst.booleanValue() == true) {
1294 // // <something equivalent to true> | x
1295 // left.generateOptimizedBoolean(
1301 // right.generateOptimizedBoolean(
1307 // if (valueRequired) {
1308 // if ((bits & OnlyValueRequiredMASK) != 0) {
1309 // codeStream.iconst_1();
1311 // if (trueLabel != null) {
1312 // codeStream.goto_(trueLabel);
1316 // // reposition the endPC
1317 // codeStream.updateLastRecordedEndPC(codeStream.position);
1319 // // <something equivalent to false> | x
1320 // left.generateOptimizedBoolean(
1326 // if ((bits & OnlyValueRequiredMASK) != 0) {
1327 // right.generateCode(currentScope, codeStream, valueRequired);
1329 // right.generateOptimizedBoolean(
1339 // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) {
1340 // if (condConst.booleanValue() == true) {
1341 // // x | <something equivalent to true>
1342 // left.generateOptimizedBoolean(
1348 // right.generateOptimizedBoolean(
1354 // if (valueRequired) {
1355 // if ((bits & OnlyValueRequiredMASK) != 0) {
1356 // codeStream.iconst_1();
1358 // if (trueLabel != null) {
1359 // codeStream.goto_(trueLabel);
1363 // // reposition the endPC
1364 // codeStream.updateLastRecordedEndPC(codeStream.position);
1366 // // x | <something equivalent to false>
1367 // if ((bits & OnlyValueRequiredMASK) != 0) {
1368 // left.generateCode(currentScope, codeStream, valueRequired);
1370 // left.generateOptimizedBoolean(
1377 // right.generateOptimizedBoolean(
1388 // left.generateCode(currentScope, codeStream, valueRequired);
1389 // right.generateCode(currentScope, codeStream, valueRequired);
1390 // if (valueRequired) {
1391 // codeStream.ior();
1392 // if ((bits & OnlyValueRequiredMASK) == 0) {
1393 // if (falseLabel == null) {
1394 // if (trueLabel != null) {
1395 // // implicit falling through the FALSE case
1396 // codeStream.ifne(trueLabel);
1399 // // implicit falling through the TRUE case
1400 // if (trueLabel == null) {
1401 // codeStream.ifeq(falseLabel);
1403 // // no implicit fall through TRUE/FALSE --> should never occur
1408 // // reposition the endPC
1409 // codeStream.updateLastRecordedEndPC(codeStream.position);
1413 // * Boolean generation for ^
1415 // public void generateOptimizedLogicalXor(
1416 // BlockScope currentScope,
1417 // CodeStream codeStream,
1419 // Label falseLabel,
1420 // boolean valueRequired) {
1422 // Constant condConst;
1423 // if ((left.implicitConversion & 0xF) == T_boolean) {
1424 // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) {
1425 // if (condConst.booleanValue() == true) {
1426 // // <something equivalent to true> ^ x
1427 // left.generateOptimizedBoolean(
1433 // right.generateOptimizedBoolean(
1440 // // <something equivalent to false> ^ x
1441 // left.generateOptimizedBoolean(
1447 // if ((bits & OnlyValueRequiredMASK) != 0) {
1448 // right.generateCode(currentScope, codeStream, valueRequired);
1450 // right.generateOptimizedBoolean(
1460 // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) {
1461 // if (condConst.booleanValue() == true) {
1462 // // x ^ <something equivalent to true>
1463 // left.generateOptimizedBoolean(
1469 // right.generateOptimizedBoolean(
1476 // // x ^ <something equivalent to false>
1477 // if ((bits & OnlyValueRequiredMASK) != 0) {
1478 // left.generateCode(currentScope, codeStream, valueRequired);
1480 // left.generateOptimizedBoolean(
1487 // right.generateOptimizedBoolean(
1498 // left.generateCode(currentScope, codeStream, valueRequired);
1499 // right.generateCode(currentScope, codeStream, valueRequired);
1500 // if (valueRequired) {
1501 // codeStream.ixor();
1502 // if ((bits & OnlyValueRequiredMASK) == 0) {
1503 // if (falseLabel == null) {
1504 // if (trueLabel != null) {
1505 // // implicit falling through the FALSE case
1506 // codeStream.ifne(trueLabel);
1509 // // implicit falling through the TRUE case
1510 // if (trueLabel == null) {
1511 // codeStream.ifeq(falseLabel);
1513 // // no implicit fall through TRUE/FALSE --> should never occur
1518 // // reposition the endPC
1519 // codeStream.updateLastRecordedEndPC(codeStream.position);
1522 // public void generateOptimizedStringBuffer(
1523 // BlockScope blockScope,
1524 // CodeStream codeStream,
1527 // /* In the case trying to make a string concatenation, there is no need to create a new
1528 // * string buffer, thus use a lower-level API for code generation involving only the
1529 // * appending of arguments to the existing StringBuffer
1532 // if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS)
1533 // && ((bits & ReturnTypeIDMASK) == T_String)) {
1534 // if (constant != NotAConstant) {
1535 // codeStream.generateConstant(constant, implicitConversion);
1536 // codeStream.invokeStringBufferAppendForType(implicitConversion & 0xF);
1538 // int pc = codeStream.position;
1539 // left.generateOptimizedStringBuffer(
1542 // left.implicitConversion & 0xF);
1543 // codeStream.recordPositionsFrom(pc, left.sourceStart);
1544 // pc = codeStream.position;
1545 // right.generateOptimizedStringBuffer(
1548 // right.implicitConversion & 0xF);
1549 // codeStream.recordPositionsFrom(pc, right.sourceStart);
1552 // super.generateOptimizedStringBuffer(blockScope, codeStream, typeID);
1556 // public void generateOptimizedStringBufferCreation(
1557 // BlockScope blockScope,
1558 // CodeStream codeStream,
1561 // /* In the case trying to make a string concatenation, there is no need to create a new
1562 // * string buffer, thus use a lower-level API for code generation involving only the
1563 // * appending of arguments to the existing StringBuffer
1566 // if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS)
1567 // && ((bits & ReturnTypeIDMASK) == T_String)) {
1568 // if (constant != NotAConstant) {
1569 // codeStream.newStringBuffer(); // new: java.lang.StringBuffer
1570 // codeStream.dup();
1571 // codeStream.ldc(constant.stringValue());
1572 // codeStream.invokeStringBufferStringConstructor();
1573 // // invokespecial: java.lang.StringBuffer.<init>(Ljava.lang.String;)V
1575 // int pc = codeStream.position;
1576 // left.generateOptimizedStringBufferCreation(
1579 // left.implicitConversion & 0xF);
1580 // codeStream.recordPositionsFrom(pc, left.sourceStart);
1581 // pc = codeStream.position;
1582 // right.generateOptimizedStringBuffer(
1585 // right.implicitConversion & 0xF);
1586 // codeStream.recordPositionsFrom(pc, right.sourceStart);
1589 // super.generateOptimizedStringBufferCreation(blockScope, codeStream, typeID);
1593 // public boolean isCompactableOperation() {
1598 // public void optimizedBooleanConstant(int leftId, int operator, int rightId) {
1600 // switch (operator) {
1602 // if ((leftId != T_boolean) || (rightId != T_boolean))
1606 // if ((cst = left.optimizedBooleanConstant()) != NotAConstant) {
1607 // if (cst.booleanValue() == false) { // left is equivalent to false
1608 // optimizedBooleanConstant = cst; // constant(false)
1610 // } else { //left is equivalent to true
1611 // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) {
1612 // optimizedBooleanConstant = cst;
1613 // // the conditional result is equivalent to the right conditional value
1618 // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) {
1619 // if (cst.booleanValue() == false) { // right is equivalent to false
1620 // optimizedBooleanConstant = cst; // constant(false)
1625 // if ((leftId != T_boolean) || (rightId != T_boolean))
1628 // if ((cst = left.optimizedBooleanConstant()) != NotAConstant) {
1629 // if (cst.booleanValue() == true) { // left is equivalent to true
1630 // optimizedBooleanConstant = cst; // constant(true)
1632 // } else { //left is equivalent to false
1633 // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) {
1634 // optimizedBooleanConstant = cst;
1639 // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) {
1640 // if (cst.booleanValue() == true) { // right is equivalent to true
1641 // optimizedBooleanConstant = cst; // constant(true)
1646 public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
1648 left.printExpression(indent, output).append(' ').append(operatorToString()).append(' ');
1649 return right.printExpression(0, output);
1651 public TypeBinding resolveType(BlockScope scope) {
1653 // use the id of the type to navigate into the table
1654 TypeBinding leftTb = left.resolveType(scope);
1655 TypeBinding rightTb = right.resolveType(scope);
1656 if (leftTb == null || rightTb == null) {
1657 constant = Constant.NotAConstant;
1660 int leftId = leftTb.id;
1661 int rightId = rightTb.id;
1663 || rightId > 15) { // must convert String + Object || Object + String
1664 if (leftId == T_String) {
1666 } else if (rightId == T_String) {
1669 constant = Constant.NotAConstant;
1670 scope.problemReporter().invalidOperator(this, leftTb, rightTb);
1674 if (((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) {
1675 if (leftId == T_String
1676 && rightTb.isArrayType()
1677 && ((ArrayBinding) rightTb).elementsType(scope) == CharBinding)
1678 scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(
1682 && leftTb.isArrayType()
1683 && ((ArrayBinding) leftTb).elementsType(scope) == CharBinding)
1684 scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(
1688 // the code is an int
1689 // (cast) left Op (cast) rigth --> result
1690 // 0000 0000 0000 0000 0000
1691 // <<16 <<12 <<8 <<4 <<0
1693 // Don't test for result = 0. If it is zero, some more work is done.
1694 // On the one hand when it is not zero (correct code) we avoid doing the test
1696 ResolveTypeTables[(bits & OperatorMASK) >> OperatorSHIFT][(leftId << 4)
1698 left.implicitConversion = result >>> 12;
1699 right.implicitConversion = (result >>> 4) & 0x000FF;
1701 bits |= result & 0xF;
1702 switch (result & 0xF) { // record the current ReturnTypeID
1703 // only switch on possible result type.....
1705 this.resolvedType = BooleanBinding;
1708 this.resolvedType = ByteBinding;
1711 this.resolvedType = CharBinding;
1714 this.resolvedType = DoubleBinding;
1717 this.resolvedType = FloatBinding;
1720 this.resolvedType = IntBinding;
1723 this.resolvedType = LongBinding;
1726 this.resolvedType = scope.getJavaLangString();
1728 default : //error........
1729 constant = Constant.NotAConstant;
1730 scope.problemReporter().invalidOperator(this, leftTb, rightTb);
1734 // compute the constant when valid
1735 computeConstant(scope, leftId, rightId);
1736 return this.resolvedType;
1739 public String toStringExpressionNoParenthesis() {
1741 return left.toStringExpression() + " " + //$NON-NLS-1$
1742 operatorToString() + " " + //$NON-NLS-1$
1743 right.toStringExpression();
1746 public void traverse(ASTVisitor visitor, BlockScope scope) {
1748 if (visitor.visit(this, scope)) {
1749 left.traverse(visitor, scope);
1750 right.traverse(visitor, scope);
1752 visitor.endVisit(this, scope);