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
9 * IBM Corporation - initial API and implementation
10 ******************************************************************************/
11 package net.sourceforge.phpdt.internal.compiler.ast;
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;
23 public class BinaryExpression extends OperatorExpression {
25 public Expression left, right;
26 public Constant optimizedBooleanConstant;
28 public BinaryExpression(Expression left, Expression right, int operator) {
32 this.bits |= operator << OperatorSHIFT; // encode operator
33 this.sourceStart = left.sourceStart;
34 this.sourceEnd = right.sourceEnd;
37 public FlowInfo analyseCode(
38 BlockScope currentScope,
39 FlowContext flowContext,
46 left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
47 .unconditionalInits();
50 public void computeConstant(BlockScope scope, int leftId, int rightId) {
52 //compute the constant when valid
53 if ((left.constant != Constant.NotAConstant)
54 && (right.constant != Constant.NotAConstant)) {
57 Constant.computeConstantOperation(
60 (bits & OperatorMASK) >> OperatorSHIFT,
63 } catch (ArithmeticException e) {
64 constant = Constant.NotAConstant;
65 // 1.2 no longer throws an exception at compile-time
66 //scope.problemReporter().compileTimeConstantThrowsArithmeticException(this);
69 constant = Constant.NotAConstant;
70 //add some work for the boolean operators & |
71 optimizedBooleanConstant(
73 (bits & OperatorMASK) >> OperatorSHIFT,
78 public Constant conditionalConstant() {
80 return optimizedBooleanConstant == null ? constant : optimizedBooleanConstant;
84 * Code generation for a binary operation
86 public void generateCode(
87 BlockScope currentScope,
88 CodeStream codeStream,
89 boolean valueRequired) {
91 int pc = codeStream.position;
92 Label falseLabel, endLabel;
93 if (constant != Constant.NotAConstant) {
95 codeStream.generateConstant(constant, implicitConversion);
96 codeStream.recordPositionsFrom(pc, this.sourceStart);
99 bits |= OnlyValueRequiredMASK;
100 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
102 switch (bits & ReturnTypeIDMASK) {
104 codeStream.generateStringAppend(currentScope, left, right);
109 left.generateCode(currentScope, codeStream, valueRequired);
110 right.generateCode(currentScope, codeStream, valueRequired);
115 left.generateCode(currentScope, codeStream, valueRequired);
116 right.generateCode(currentScope, codeStream, valueRequired);
121 left.generateCode(currentScope, codeStream, valueRequired);
122 right.generateCode(currentScope, codeStream, valueRequired);
127 left.generateCode(currentScope, codeStream, valueRequired);
128 right.generateCode(currentScope, codeStream, valueRequired);
135 switch (bits & ReturnTypeIDMASK) {
137 left.generateCode(currentScope, codeStream, valueRequired);
138 right.generateCode(currentScope, codeStream, valueRequired);
143 left.generateCode(currentScope, codeStream, valueRequired);
144 right.generateCode(currentScope, codeStream, valueRequired);
149 left.generateCode(currentScope, codeStream, valueRequired);
150 right.generateCode(currentScope, codeStream, valueRequired);
155 left.generateCode(currentScope, codeStream, valueRequired);
156 right.generateCode(currentScope, codeStream, valueRequired);
163 switch (bits & ReturnTypeIDMASK) {
165 left.generateCode(currentScope, codeStream, valueRequired);
166 right.generateCode(currentScope, codeStream, valueRequired);
171 left.generateCode(currentScope, codeStream, valueRequired);
172 right.generateCode(currentScope, codeStream, valueRequired);
177 left.generateCode(currentScope, codeStream, valueRequired);
178 right.generateCode(currentScope, codeStream, valueRequired);
183 left.generateCode(currentScope, codeStream, valueRequired);
184 right.generateCode(currentScope, codeStream, valueRequired);
191 switch (bits & ReturnTypeIDMASK) {
193 left.generateCode(currentScope, codeStream, true);
194 right.generateCode(currentScope, codeStream, true);
200 left.generateCode(currentScope, codeStream, true);
201 right.generateCode(currentScope, codeStream, true);
207 left.generateCode(currentScope, codeStream, valueRequired);
208 right.generateCode(currentScope, codeStream, valueRequired);
213 left.generateCode(currentScope, codeStream, valueRequired);
214 right.generateCode(currentScope, codeStream, valueRequired);
221 switch (bits & ReturnTypeIDMASK) {
223 left.generateCode(currentScope, codeStream, true);
224 right.generateCode(currentScope, codeStream, true);
230 left.generateCode(currentScope, codeStream, true);
231 right.generateCode(currentScope, codeStream, true);
237 left.generateCode(currentScope, codeStream, valueRequired);
238 right.generateCode(currentScope, codeStream, valueRequired);
243 left.generateCode(currentScope, codeStream, valueRequired);
244 right.generateCode(currentScope, codeStream, valueRequired);
251 switch (bits & ReturnTypeIDMASK) {
254 if ((left.constant != Constant.NotAConstant)
255 && (left.constant.typeID() == T_int)
256 && (left.constant.intValue() == 0)) {
257 right.generateCode(currentScope, codeStream, false);
259 codeStream.iconst_0();
262 if ((right.constant != Constant.NotAConstant)
263 && (right.constant.typeID() == T_int)
264 && (right.constant.intValue() == 0)) {
265 left.generateCode(currentScope, codeStream, false);
267 codeStream.iconst_0();
269 left.generateCode(currentScope, codeStream, valueRequired);
270 right.generateCode(currentScope, codeStream, valueRequired);
278 if ((left.constant != Constant.NotAConstant)
279 && (left.constant.typeID() == T_long)
280 && (left.constant.longValue() == 0L)) {
281 right.generateCode(currentScope, codeStream, false);
283 codeStream.lconst_0();
286 if ((right.constant != Constant.NotAConstant)
287 && (right.constant.typeID() == T_long)
288 && (right.constant.longValue() == 0L)) {
289 left.generateCode(currentScope, codeStream, false);
291 codeStream.lconst_0();
293 left.generateCode(currentScope, codeStream, valueRequired);
294 right.generateCode(currentScope, codeStream, valueRequired);
300 case T_boolean : // logical and
301 generateOptimizedLogicalAnd(
305 (falseLabel = new Label(codeStream)),
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()) {
311 codeStream.iconst_1();
312 if ((bits & ValueForReturnMASK) != 0) {
313 codeStream.ireturn();
315 codeStream.iconst_0();
317 codeStream.goto_(endLabel = new Label(codeStream));
318 codeStream.decrStackSize(1);
320 codeStream.iconst_0();
330 switch (bits & ReturnTypeIDMASK) {
333 if ((left.constant != Constant.NotAConstant)
334 && (left.constant.typeID() == T_int)
335 && (left.constant.intValue() == 0)) {
336 right.generateCode(currentScope, codeStream, valueRequired);
339 if ((right.constant != Constant.NotAConstant)
340 && (right.constant.typeID() == T_int)
341 && (right.constant.intValue() == 0)) {
342 left.generateCode(currentScope, codeStream, valueRequired);
344 left.generateCode(currentScope, codeStream, valueRequired);
345 right.generateCode(currentScope, codeStream, valueRequired);
353 if ((left.constant != Constant.NotAConstant)
354 && (left.constant.typeID() == T_long)
355 && (left.constant.longValue() == 0L)) {
356 right.generateCode(currentScope, codeStream, valueRequired);
359 if ((right.constant != Constant.NotAConstant)
360 && (right.constant.typeID() == T_long)
361 && (right.constant.longValue() == 0L)) {
362 left.generateCode(currentScope, codeStream, valueRequired);
364 left.generateCode(currentScope, codeStream, valueRequired);
365 right.generateCode(currentScope, codeStream, valueRequired);
371 case T_boolean : // logical or
372 generateOptimizedLogicalOr(
376 (falseLabel = new Label(codeStream)),
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()) {
382 codeStream.iconst_1();
383 if ((bits & ValueForReturnMASK) != 0) {
384 codeStream.ireturn();
386 codeStream.iconst_0();
388 codeStream.goto_(endLabel = new Label(codeStream));
389 codeStream.decrStackSize(1);
391 codeStream.iconst_0();
401 switch (bits & ReturnTypeIDMASK) {
404 if ((left.constant != Constant.NotAConstant)
405 && (left.constant.typeID() == T_int)
406 && (left.constant.intValue() == 0)) {
407 right.generateCode(currentScope, codeStream, valueRequired);
410 if ((right.constant != Constant.NotAConstant)
411 && (right.constant.typeID() == T_int)
412 && (right.constant.intValue() == 0)) {
413 left.generateCode(currentScope, codeStream, valueRequired);
415 left.generateCode(currentScope, codeStream, valueRequired);
416 right.generateCode(currentScope, codeStream, valueRequired);
424 if ((left.constant != Constant.NotAConstant)
425 && (left.constant.typeID() == T_long)
426 && (left.constant.longValue() == 0L)) {
427 right.generateCode(currentScope, codeStream, valueRequired);
430 if ((right.constant != Constant.NotAConstant)
431 && (right.constant.typeID() == T_long)
432 && (right.constant.longValue() == 0L)) {
433 left.generateCode(currentScope, codeStream, valueRequired);
435 left.generateCode(currentScope, codeStream, valueRequired);
436 right.generateCode(currentScope, codeStream, valueRequired);
443 generateOptimizedLogicalXor(
447 (falseLabel = new Label(codeStream)),
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()) {
453 codeStream.iconst_1();
454 if ((bits & ValueForReturnMASK) != 0) {
455 codeStream.ireturn();
457 codeStream.iconst_0();
459 codeStream.goto_(endLabel = new Label(codeStream));
460 codeStream.decrStackSize(1);
462 codeStream.iconst_0();
472 switch (bits & ReturnTypeIDMASK) {
474 left.generateCode(currentScope, codeStream, valueRequired);
475 right.generateCode(currentScope, codeStream, valueRequired);
480 left.generateCode(currentScope, codeStream, valueRequired);
481 right.generateCode(currentScope, codeStream, valueRequired);
487 switch (bits & ReturnTypeIDMASK) {
489 left.generateCode(currentScope, codeStream, valueRequired);
490 right.generateCode(currentScope, codeStream, valueRequired);
495 left.generateCode(currentScope, codeStream, valueRequired);
496 right.generateCode(currentScope, codeStream, valueRequired);
501 case UNSIGNED_RIGHT_SHIFT :
502 switch (bits & ReturnTypeIDMASK) {
504 left.generateCode(currentScope, codeStream, valueRequired);
505 right.generateCode(currentScope, codeStream, valueRequired);
510 left.generateCode(currentScope, codeStream, valueRequired);
511 right.generateCode(currentScope, codeStream, valueRequired);
517 generateOptimizedGreaterThan(
521 (falseLabel = new Label(codeStream)),
524 codeStream.iconst_1();
525 if ((bits & ValueForReturnMASK) != 0) {
526 codeStream.ireturn();
528 codeStream.iconst_0();
530 codeStream.goto_(endLabel = new Label(codeStream));
531 codeStream.decrStackSize(1);
533 codeStream.iconst_0();
539 generateOptimizedGreaterThanOrEqual(
543 (falseLabel = new Label(codeStream)),
546 codeStream.iconst_1();
547 if ((bits & ValueForReturnMASK) != 0) {
548 codeStream.ireturn();
550 codeStream.iconst_0();
552 codeStream.goto_(endLabel = new Label(codeStream));
553 codeStream.decrStackSize(1);
555 codeStream.iconst_0();
561 generateOptimizedLessThan(
565 (falseLabel = new Label(codeStream)),
568 codeStream.iconst_1();
569 if ((bits & ValueForReturnMASK) != 0) {
570 codeStream.ireturn();
572 codeStream.iconst_0();
574 codeStream.goto_(endLabel = new Label(codeStream));
575 codeStream.decrStackSize(1);
577 codeStream.iconst_0();
583 generateOptimizedLessThanOrEqual(
587 (falseLabel = new Label(codeStream)),
590 codeStream.iconst_1();
591 if ((bits & ValueForReturnMASK) != 0) {
592 codeStream.ireturn();
594 codeStream.iconst_0();
596 codeStream.goto_(endLabel = new Label(codeStream));
597 codeStream.decrStackSize(1);
599 codeStream.iconst_0();
605 codeStream.generateImplicitConversion(implicitConversion);
607 codeStream.recordPositionsFrom(pc, this.sourceStart);
611 * Boolean operator code generation
612 * Optimized operations are: <, <=, >, >=, &, |, ^
614 public void generateOptimizedBoolean(
615 BlockScope currentScope,
616 CodeStream codeStream,
619 boolean valueRequired) {
621 if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
622 super.generateOptimizedBoolean(
630 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
632 generateOptimizedLessThan(
640 generateOptimizedLessThanOrEqual(
648 generateOptimizedGreaterThan(
656 generateOptimizedGreaterThanOrEqual(
664 generateOptimizedLogicalAnd(
672 generateOptimizedLogicalOr(
680 generateOptimizedLogicalXor(
688 super.generateOptimizedBoolean(
697 * Boolean generation for >
699 public void generateOptimizedGreaterThan(
700 BlockScope currentScope,
701 CodeStream codeStream,
704 boolean valueRequired) {
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) {
711 if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
712 right.generateCode(currentScope, codeStream, valueRequired);
714 if (falseLabel == null) {
715 if (trueLabel != null) {
716 // implicitly falling through the FALSE case
717 codeStream.iflt(trueLabel);
720 if (trueLabel == null) {
721 // implicitly falling through the TRUE case
722 codeStream.ifge(falseLabel);
724 // no implicit fall through TRUE/FALSE --> should never occur
728 codeStream.recordPositionsFrom(pc, this.sourceStart);
732 if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
733 left.generateCode(currentScope, codeStream, valueRequired);
735 if (falseLabel == null) {
736 if (trueLabel != null) {
737 // implicitly falling through the FALSE case
738 codeStream.ifgt(trueLabel);
741 if (trueLabel == null) {
742 // implicitly falling through the TRUE case
743 codeStream.ifle(falseLabel);
745 // no implicit fall through TRUE/FALSE --> should never occur
749 codeStream.recordPositionsFrom(pc, this.sourceStart);
753 // default comparison
754 left.generateCode(currentScope, codeStream, valueRequired);
755 right.generateCode(currentScope, codeStream, valueRequired);
757 if (falseLabel == null) {
758 if (trueLabel != null) {
759 // implicit falling through the FALSE case
760 switch (promotedTypeID) {
762 codeStream.if_icmpgt(trueLabel);
766 codeStream.ifgt(trueLabel);
770 codeStream.ifgt(trueLabel);
774 codeStream.ifgt(trueLabel);
776 codeStream.recordPositionsFrom(pc, this.sourceStart);
780 if (trueLabel == null) {
781 // implicit falling through the TRUE case
782 switch (promotedTypeID) {
784 codeStream.if_icmple(falseLabel);
788 codeStream.ifle(falseLabel);
792 codeStream.ifle(falseLabel);
796 codeStream.ifle(falseLabel);
798 codeStream.recordPositionsFrom(pc, this.sourceStart);
801 // no implicit fall through TRUE/FALSE --> should never occur
808 * Boolean generation for >=
810 public void generateOptimizedGreaterThanOrEqual(
811 BlockScope currentScope,
812 CodeStream codeStream,
815 boolean valueRequired) {
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) {
822 if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
823 right.generateCode(currentScope, codeStream, 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 codeStream.recordPositionsFrom(pc, this.sourceStart);
843 if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
844 left.generateCode(currentScope, codeStream, valueRequired);
846 if (falseLabel == null) {
847 if (trueLabel != null) {
848 // implicitly falling through the FALSE case
849 codeStream.ifge(trueLabel);
852 if (trueLabel == null) {
853 // implicitly falling through the TRUE case
854 codeStream.iflt(falseLabel);
856 // no implicit fall through TRUE/FALSE --> should never occur
860 codeStream.recordPositionsFrom(pc, this.sourceStart);
864 // default comparison
865 left.generateCode(currentScope, codeStream, valueRequired);
866 right.generateCode(currentScope, codeStream, valueRequired);
868 if (falseLabel == null) {
869 if (trueLabel != null) {
870 // implicit falling through the FALSE case
871 switch (promotedTypeID) {
873 codeStream.if_icmpge(trueLabel);
877 codeStream.ifge(trueLabel);
881 codeStream.ifge(trueLabel);
885 codeStream.ifge(trueLabel);
887 codeStream.recordPositionsFrom(pc, this.sourceStart);
891 if (trueLabel == null) {
892 // implicit falling through the TRUE case
893 switch (promotedTypeID) {
895 codeStream.if_icmplt(falseLabel);
899 codeStream.iflt(falseLabel);
903 codeStream.iflt(falseLabel);
907 codeStream.iflt(falseLabel);
909 codeStream.recordPositionsFrom(pc, this.sourceStart);
912 // no implicit fall through TRUE/FALSE --> should never occur
919 * Boolean generation for <
921 public void generateOptimizedLessThan(
922 BlockScope currentScope,
923 CodeStream codeStream,
926 boolean valueRequired) {
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) {
933 if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
934 right.generateCode(currentScope, codeStream, valueRequired);
936 if (falseLabel == null) {
937 if (trueLabel != null) {
938 // implicitly falling through the FALSE case
939 codeStream.ifgt(trueLabel);
942 if (trueLabel == null) {
943 // implicitly falling through the TRUE case
944 codeStream.ifle(falseLabel);
946 // no implicit fall through TRUE/FALSE --> should never occur
950 codeStream.recordPositionsFrom(pc, this.sourceStart);
954 if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
955 left.generateCode(currentScope, codeStream, valueRequired);
957 if (falseLabel == null) {
958 if (trueLabel != null) {
959 // implicitly falling through the FALSE case
960 codeStream.iflt(trueLabel);
963 if (trueLabel == null) {
964 // implicitly falling through the TRUE case
965 codeStream.ifge(falseLabel);
967 // no implicit fall through TRUE/FALSE --> should never occur
971 codeStream.recordPositionsFrom(pc, this.sourceStart);
975 // default comparison
976 left.generateCode(currentScope, codeStream, valueRequired);
977 right.generateCode(currentScope, codeStream, valueRequired);
979 if (falseLabel == null) {
980 if (trueLabel != null) {
981 // implicit falling through the FALSE case
982 switch (promotedTypeID) {
984 codeStream.if_icmplt(trueLabel);
988 codeStream.iflt(trueLabel);
992 codeStream.iflt(trueLabel);
996 codeStream.iflt(trueLabel);
998 codeStream.recordPositionsFrom(pc, this.sourceStart);
1002 if (trueLabel == null) {
1003 // implicit falling through the TRUE case
1004 switch (promotedTypeID) {
1006 codeStream.if_icmpge(falseLabel);
1010 codeStream.ifge(falseLabel);
1014 codeStream.ifge(falseLabel);
1018 codeStream.ifge(falseLabel);
1020 codeStream.recordPositionsFrom(pc, this.sourceStart);
1023 // no implicit fall through TRUE/FALSE --> should never occur
1030 * Boolean generation for <=
1032 public void generateOptimizedLessThanOrEqual(
1033 BlockScope currentScope,
1034 CodeStream codeStream,
1037 boolean valueRequired) {
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) {
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);
1053 if (trueLabel == null) {
1054 // implicitly falling through the TRUE case
1055 codeStream.iflt(falseLabel);
1057 // no implicit fall through TRUE/FALSE --> should never occur
1061 codeStream.recordPositionsFrom(pc, this.sourceStart);
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);
1074 if (trueLabel == null) {
1075 // implicitly falling through the TRUE case
1076 codeStream.ifgt(falseLabel);
1078 // no implicit fall through TRUE/FALSE --> should never occur
1082 codeStream.recordPositionsFrom(pc, this.sourceStart);
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) {
1095 codeStream.if_icmple(trueLabel);
1099 codeStream.ifle(trueLabel);
1103 codeStream.ifle(trueLabel);
1107 codeStream.ifle(trueLabel);
1109 codeStream.recordPositionsFrom(pc, this.sourceStart);
1113 if (trueLabel == null) {
1114 // implicit falling through the TRUE case
1115 switch (promotedTypeID) {
1117 codeStream.if_icmpgt(falseLabel);
1121 codeStream.ifgt(falseLabel);
1125 codeStream.ifgt(falseLabel);
1129 codeStream.ifgt(falseLabel);
1131 codeStream.recordPositionsFrom(pc, this.sourceStart);
1134 // no implicit fall through TRUE/FALSE --> should never occur
1141 * Boolean generation for &
1143 public void generateOptimizedLogicalAnd(
1144 BlockScope currentScope,
1145 CodeStream codeStream,
1148 boolean valueRequired) {
1150 int pc = codeStream.position;
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(
1162 if ((bits & OnlyValueRequiredMASK) != 0) {
1163 right.generateCode(currentScope, codeStream, valueRequired);
1165 right.generateOptimizedBoolean(
1173 // <something equivalent to false> & x
1174 left.generateOptimizedBoolean(
1180 right.generateOptimizedBoolean(
1186 if (valueRequired) {
1187 if ((bits & OnlyValueRequiredMASK) != 0) {
1188 codeStream.iconst_0();
1190 if (falseLabel != null) {
1191 // implicit falling through the TRUE case
1192 codeStream.goto_(falseLabel);
1197 codeStream.recordPositionsFrom(pc, this.sourceStart);
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);
1206 left.generateOptimizedBoolean(
1213 right.generateOptimizedBoolean(
1220 // x & <something equivalent to false>
1221 left.generateOptimizedBoolean(
1227 right.generateOptimizedBoolean(
1233 if (valueRequired) {
1234 if ((bits & OnlyValueRequiredMASK) != 0) {
1235 codeStream.iconst_0();
1237 if (falseLabel != null) {
1238 // implicit falling through the TRUE case
1239 codeStream.goto_(falseLabel);
1244 codeStream.recordPositionsFrom(pc, this.sourceStart);
1249 left.generateCode(currentScope, codeStream, valueRequired);
1250 right.generateCode(currentScope, codeStream, valueRequired);
1251 if (valueRequired) {
1253 if ((bits & OnlyValueRequiredMASK) == 0) {
1254 if (falseLabel == null) {
1255 if (trueLabel != null) {
1256 // implicit falling through the FALSE case
1257 codeStream.ifne(trueLabel);
1260 // implicit falling through the TRUE case
1261 if (trueLabel == null) {
1262 codeStream.ifeq(falseLabel);
1264 // no implicit fall through TRUE/FALSE --> should never occur
1269 codeStream.recordPositionsFrom(pc, this.sourceStart);
1273 * Boolean generation for |
1275 public void generateOptimizedLogicalOr(
1276 BlockScope currentScope,
1277 CodeStream codeStream,
1280 boolean valueRequired) {
1282 int pc = codeStream.position;
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(
1294 right.generateOptimizedBoolean(
1300 if (valueRequired) {
1301 if ((bits & OnlyValueRequiredMASK) != 0) {
1302 codeStream.iconst_1();
1304 if (trueLabel != null) {
1305 codeStream.goto_(trueLabel);
1310 // <something equivalent to false> | x
1311 left.generateOptimizedBoolean(
1317 if ((bits & OnlyValueRequiredMASK) != 0) {
1318 right.generateCode(currentScope, codeStream, valueRequired);
1320 right.generateOptimizedBoolean(
1328 codeStream.recordPositionsFrom(pc, this.sourceStart);
1331 if ((condConst = right.conditionalConstant()) != NotAConstant) {
1332 if (condConst.booleanValue() == true) {
1333 // x | <something equivalent to true>
1334 left.generateOptimizedBoolean(
1340 right.generateOptimizedBoolean(
1346 if (valueRequired) {
1347 if ((bits & OnlyValueRequiredMASK) != 0) {
1348 codeStream.iconst_1();
1350 if (trueLabel != null) {
1351 codeStream.goto_(trueLabel);
1356 // x | <something equivalent to false>
1357 if ((bits & OnlyValueRequiredMASK) != 0) {
1358 left.generateCode(currentScope, codeStream, valueRequired);
1360 left.generateOptimizedBoolean(
1367 right.generateOptimizedBoolean(
1374 codeStream.recordPositionsFrom(pc, this.sourceStart);
1379 left.generateCode(currentScope, codeStream, valueRequired);
1380 right.generateCode(currentScope, codeStream, valueRequired);
1381 if (valueRequired) {
1383 if ((bits & OnlyValueRequiredMASK) == 0) {
1384 if (falseLabel == null) {
1385 if (trueLabel != null) {
1386 // implicit falling through the FALSE case
1387 codeStream.ifne(trueLabel);
1390 // implicit falling through the TRUE case
1391 if (trueLabel == null) {
1392 codeStream.ifeq(falseLabel);
1394 // no implicit fall through TRUE/FALSE --> should never occur
1399 codeStream.recordPositionsFrom(pc, this.sourceStart);
1403 * Boolean generation for ^
1405 public void generateOptimizedLogicalXor(
1406 BlockScope currentScope,
1407 CodeStream codeStream,
1410 boolean valueRequired) {
1412 int pc = codeStream.position;
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(
1424 right.generateOptimizedBoolean(
1431 // <something equivalent to false> ^ x
1432 left.generateOptimizedBoolean(
1438 if ((bits & OnlyValueRequiredMASK) != 0) {
1439 right.generateCode(currentScope, codeStream, valueRequired);
1441 right.generateOptimizedBoolean(
1449 codeStream.recordPositionsFrom(pc, this.sourceStart);
1452 if ((condConst = right.conditionalConstant()) != NotAConstant) {
1453 if (condConst.booleanValue() == true) {
1454 // x ^ <something equivalent to true>
1455 left.generateOptimizedBoolean(
1461 right.generateOptimizedBoolean(
1468 // x ^ <something equivalent to false>
1469 if ((bits & OnlyValueRequiredMASK) != 0) {
1470 left.generateCode(currentScope, codeStream, valueRequired);
1472 left.generateOptimizedBoolean(
1479 right.generateOptimizedBoolean(
1486 codeStream.recordPositionsFrom(pc, this.sourceStart);
1491 left.generateCode(currentScope, codeStream, valueRequired);
1492 right.generateCode(currentScope, codeStream, valueRequired);
1493 if (valueRequired) {
1495 if ((bits & OnlyValueRequiredMASK) == 0) {
1496 if (falseLabel == null) {
1497 if (trueLabel != null) {
1498 // implicit falling through the FALSE case
1499 codeStream.ifne(trueLabel);
1502 // implicit falling through the TRUE case
1503 if (trueLabel == null) {
1504 codeStream.ifeq(falseLabel);
1506 // no implicit fall through TRUE/FALSE --> should never occur
1511 codeStream.recordPositionsFrom(pc, this.sourceStart);
1514 public void generateOptimizedStringBuffer(
1515 BlockScope blockScope,
1516 CodeStream codeStream,
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
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);
1530 int pc = codeStream.position;
1531 left.generateOptimizedStringBuffer(
1534 left.implicitConversion & 0xF);
1535 codeStream.recordPositionsFrom(pc, left.sourceStart);
1536 pc = codeStream.position;
1537 right.generateOptimizedStringBuffer(
1540 right.implicitConversion & 0xF);
1541 codeStream.recordPositionsFrom(pc, right.sourceStart);
1544 super.generateOptimizedStringBuffer(blockScope, codeStream, typeID);
1548 public void generateOptimizedStringBufferCreation(
1549 BlockScope blockScope,
1550 CodeStream codeStream,
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
1558 if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS)
1559 && ((bits & ReturnTypeIDMASK) == T_String)) {
1560 if (constant != NotAConstant) {
1561 codeStream.newStringBuffer(); // new: java.lang.StringBuffer
1563 codeStream.ldc(constant.stringValue());
1564 codeStream.invokeStringBufferStringConstructor();
1565 // invokespecial: java.lang.StringBuffer.<init>(Ljava.lang.String;)V
1567 int pc = codeStream.position;
1568 left.generateOptimizedStringBufferCreation(
1571 left.implicitConversion & 0xF);
1572 codeStream.recordPositionsFrom(pc, left.sourceStart);
1573 pc = codeStream.position;
1574 right.generateOptimizedStringBuffer(
1577 right.implicitConversion & 0xF);
1578 codeStream.recordPositionsFrom(pc, right.sourceStart);
1581 super.generateOptimizedStringBufferCreation(blockScope, codeStream, typeID);
1585 public boolean isCompactableOperation() {
1590 public void optimizedBooleanConstant(int leftId, int operator, int rightId) {
1594 if ((leftId != T_boolean) || (rightId != T_boolean))
1598 if ((cst = left.conditionalConstant()) != NotAConstant) {
1599 if (cst.booleanValue() == false) { // left is equivalent to false
1600 optimizedBooleanConstant = cst; // constant(false)
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
1610 if ((cst = right.conditionalConstant()) != NotAConstant) {
1611 if (cst.booleanValue() == false) { // right is equivalent to false
1612 optimizedBooleanConstant = cst; // constant(false)
1617 if ((leftId != T_boolean) || (rightId != T_boolean))
1620 if ((cst = left.conditionalConstant()) != NotAConstant) {
1621 if (cst.booleanValue() == true) { // left is equivalent to true
1622 optimizedBooleanConstant = cst; // constant(true)
1624 } else { //left is equivalent to false
1625 if ((cst = right.conditionalConstant()) != NotAConstant) {
1626 optimizedBooleanConstant = cst;
1631 if ((cst = right.conditionalConstant()) != NotAConstant) {
1632 if (cst.booleanValue() == true) { // right is equivalent to true
1633 optimizedBooleanConstant = cst; // constant(true)
1639 public TypeBinding resolveType(BlockScope scope) {
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;
1648 int leftId = leftTb.id;
1649 int rightId = rightTb.id;
1651 || rightId > 15) { // must convert String + Object || Object + String
1652 if (leftId == T_String) {
1654 } else if (rightId == T_String) {
1657 constant = Constant.NotAConstant;
1658 scope.problemReporter().invalidOperator(this, leftTb, rightTb);
1662 if (((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) {
1663 if (leftId == T_String
1664 && rightTb.isArrayType()
1665 && ((ArrayBinding) rightTb).elementsType(scope) == CharBinding)
1666 scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(
1670 && leftTb.isArrayType()
1671 && ((ArrayBinding) leftTb).elementsType(scope) == CharBinding)
1672 scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(
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
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
1684 ResolveTypeTables[(bits & OperatorMASK) >> OperatorSHIFT][(leftId << 4)
1686 left.implicitConversion = result >>> 12;
1687 right.implicitConversion = (result >>> 4) & 0x000FF;
1689 bits |= result & 0xF;
1690 switch (result & 0xF) { // record the current ReturnTypeID
1691 // only switch on possible result type.....
1693 this.typeBinding = BooleanBinding;
1696 this.typeBinding = ByteBinding;
1699 this.typeBinding = CharBinding;
1702 this.typeBinding = DoubleBinding;
1705 this.typeBinding = FloatBinding;
1708 this.typeBinding = IntBinding;
1711 this.typeBinding = LongBinding;
1714 this.typeBinding = scope.getJavaLangString();
1716 default : //error........
1717 constant = Constant.NotAConstant;
1718 scope.problemReporter().invalidOperator(this, leftTb, rightTb);
1722 // compute the constant when valid
1723 computeConstant(scope, leftId, rightId);
1724 return this.typeBinding;
1727 public String toStringExpressionNoParenthesis() {
1729 return left.toStringExpression() + " " + //$NON-NLS-1$
1730 operatorToString() + " " + //$NON-NLS-1$
1731 right.toStringExpression();
1734 public void traverse(IAbstractSyntaxTreeVisitor visitor, BlockScope scope) {
1736 if (visitor.visit(this, scope)) {
1737 left.traverse(visitor, scope);
1738 right.traverse(visitor, scope);
1740 visitor.endVisit(this, scope);