1 /*******************************************************************************
2 * Copyright (c) 2000, 2004 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 org.eclipse.jdt.internal.compiler.ast;
13 import org.eclipse.jdt.internal.compiler.ASTVisitor;
14 import org.eclipse.jdt.internal.compiler.impl.*;
15 import org.eclipse.jdt.internal.compiler.codegen.*;
16 import org.eclipse.jdt.internal.compiler.flow.*;
17 import org.eclipse.jdt.internal.compiler.lookup.*;
19 public class BinaryExpression extends OperatorExpression {
21 public Expression left, right;
22 public Constant optimizedBooleanConstant;
24 public BinaryExpression(Expression left, Expression right, int operator) {
28 this.bits |= operator << OperatorSHIFT; // encode operator
29 this.sourceStart = left.sourceStart;
30 this.sourceEnd = right.sourceEnd;
33 public FlowInfo analyseCode(
34 BlockScope currentScope,
35 FlowContext flowContext,
42 left.analyseCode(currentScope, flowContext, flowInfo).unconditionalInits())
43 .unconditionalInits();
46 public void computeConstant(BlockScope scope, int leftId, int rightId) {
48 //compute the constant when valid
49 if ((this.left.constant != Constant.NotAConstant)
50 && (this.right.constant != Constant.NotAConstant)) {
53 Constant.computeConstantOperation(
56 (this.bits & OperatorMASK) >> OperatorSHIFT,
59 } catch (ArithmeticException e) {
60 this.constant = Constant.NotAConstant;
61 // 1.2 no longer throws an exception at compile-time
62 //scope.problemReporter().compileTimeConstantThrowsArithmeticException(this);
65 this.constant = Constant.NotAConstant;
66 //add some work for the boolean operators & |
67 this.optimizedBooleanConstant(
69 (this.bits & OperatorMASK) >> OperatorSHIFT,
74 public Constant optimizedBooleanConstant() {
76 return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant;
80 * Code generation for a binary operation
82 public void generateCode(
83 BlockScope currentScope,
84 CodeStream codeStream,
85 boolean valueRequired) {
87 int pc = codeStream.position;
88 Label falseLabel, endLabel;
89 if (constant != Constant.NotAConstant) {
91 codeStream.generateConstant(constant, implicitConversion);
92 codeStream.recordPositionsFrom(pc, this.sourceStart);
95 bits |= OnlyValueRequiredMASK;
96 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
98 switch (bits & ReturnTypeIDMASK) {
100 codeStream.generateStringAppend(currentScope, left, right);
105 left.generateCode(currentScope, codeStream, valueRequired);
106 right.generateCode(currentScope, codeStream, valueRequired);
111 left.generateCode(currentScope, codeStream, valueRequired);
112 right.generateCode(currentScope, codeStream, valueRequired);
117 left.generateCode(currentScope, codeStream, valueRequired);
118 right.generateCode(currentScope, codeStream, valueRequired);
123 left.generateCode(currentScope, codeStream, valueRequired);
124 right.generateCode(currentScope, codeStream, valueRequired);
131 switch (bits & ReturnTypeIDMASK) {
133 left.generateCode(currentScope, codeStream, valueRequired);
134 right.generateCode(currentScope, codeStream, valueRequired);
139 left.generateCode(currentScope, codeStream, valueRequired);
140 right.generateCode(currentScope, codeStream, valueRequired);
145 left.generateCode(currentScope, codeStream, valueRequired);
146 right.generateCode(currentScope, codeStream, valueRequired);
151 left.generateCode(currentScope, codeStream, valueRequired);
152 right.generateCode(currentScope, codeStream, valueRequired);
159 switch (bits & ReturnTypeIDMASK) {
161 left.generateCode(currentScope, codeStream, valueRequired);
162 right.generateCode(currentScope, codeStream, valueRequired);
167 left.generateCode(currentScope, codeStream, valueRequired);
168 right.generateCode(currentScope, codeStream, valueRequired);
173 left.generateCode(currentScope, codeStream, valueRequired);
174 right.generateCode(currentScope, codeStream, valueRequired);
179 left.generateCode(currentScope, codeStream, valueRequired);
180 right.generateCode(currentScope, codeStream, valueRequired);
187 switch (bits & ReturnTypeIDMASK) {
189 left.generateCode(currentScope, codeStream, true);
190 right.generateCode(currentScope, codeStream, true);
196 left.generateCode(currentScope, codeStream, true);
197 right.generateCode(currentScope, codeStream, true);
203 left.generateCode(currentScope, codeStream, valueRequired);
204 right.generateCode(currentScope, codeStream, valueRequired);
209 left.generateCode(currentScope, codeStream, valueRequired);
210 right.generateCode(currentScope, codeStream, valueRequired);
217 switch (bits & ReturnTypeIDMASK) {
219 left.generateCode(currentScope, codeStream, true);
220 right.generateCode(currentScope, codeStream, true);
226 left.generateCode(currentScope, codeStream, true);
227 right.generateCode(currentScope, codeStream, true);
233 left.generateCode(currentScope, codeStream, valueRequired);
234 right.generateCode(currentScope, codeStream, valueRequired);
239 left.generateCode(currentScope, codeStream, valueRequired);
240 right.generateCode(currentScope, codeStream, valueRequired);
247 switch (bits & ReturnTypeIDMASK) {
250 if ((left.constant != Constant.NotAConstant)
251 && (left.constant.typeID() == T_int)
252 && (left.constant.intValue() == 0)) {
253 right.generateCode(currentScope, codeStream, false);
255 codeStream.iconst_0();
258 if ((right.constant != Constant.NotAConstant)
259 && (right.constant.typeID() == T_int)
260 && (right.constant.intValue() == 0)) {
261 left.generateCode(currentScope, codeStream, false);
263 codeStream.iconst_0();
265 left.generateCode(currentScope, codeStream, valueRequired);
266 right.generateCode(currentScope, codeStream, valueRequired);
274 if ((left.constant != Constant.NotAConstant)
275 && (left.constant.typeID() == T_long)
276 && (left.constant.longValue() == 0L)) {
277 right.generateCode(currentScope, codeStream, false);
279 codeStream.lconst_0();
282 if ((right.constant != Constant.NotAConstant)
283 && (right.constant.typeID() == T_long)
284 && (right.constant.longValue() == 0L)) {
285 left.generateCode(currentScope, codeStream, false);
287 codeStream.lconst_0();
289 left.generateCode(currentScope, codeStream, valueRequired);
290 right.generateCode(currentScope, codeStream, valueRequired);
296 case T_boolean : // logical and
297 generateOptimizedLogicalAnd(
301 (falseLabel = new Label(codeStream)),
303 /* improving code gen for such a case: boolean b = i < 0 && false;
304 * since the label has never been used, we have the inlined value on the stack. */
305 if (falseLabel.hasForwardReferences()) {
307 codeStream.iconst_1();
308 if ((bits & ValueForReturnMASK) != 0) {
309 codeStream.ireturn();
311 codeStream.iconst_0();
313 codeStream.goto_(endLabel = new Label(codeStream));
314 codeStream.decrStackSize(1);
316 codeStream.iconst_0();
326 switch (bits & ReturnTypeIDMASK) {
329 if ((left.constant != Constant.NotAConstant)
330 && (left.constant.typeID() == T_int)
331 && (left.constant.intValue() == 0)) {
332 right.generateCode(currentScope, codeStream, valueRequired);
335 if ((right.constant != Constant.NotAConstant)
336 && (right.constant.typeID() == T_int)
337 && (right.constant.intValue() == 0)) {
338 left.generateCode(currentScope, codeStream, valueRequired);
340 left.generateCode(currentScope, codeStream, valueRequired);
341 right.generateCode(currentScope, codeStream, valueRequired);
349 if ((left.constant != Constant.NotAConstant)
350 && (left.constant.typeID() == T_long)
351 && (left.constant.longValue() == 0L)) {
352 right.generateCode(currentScope, codeStream, valueRequired);
355 if ((right.constant != Constant.NotAConstant)
356 && (right.constant.typeID() == T_long)
357 && (right.constant.longValue() == 0L)) {
358 left.generateCode(currentScope, codeStream, valueRequired);
360 left.generateCode(currentScope, codeStream, valueRequired);
361 right.generateCode(currentScope, codeStream, valueRequired);
367 case T_boolean : // logical or
368 generateOptimizedLogicalOr(
372 (falseLabel = new Label(codeStream)),
374 /* improving code gen for such a case: boolean b = i < 0 || true;
375 * since the label has never been used, we have the inlined value on the stack. */
376 if (falseLabel.hasForwardReferences()) {
378 codeStream.iconst_1();
379 if ((bits & ValueForReturnMASK) != 0) {
380 codeStream.ireturn();
382 codeStream.iconst_0();
384 codeStream.goto_(endLabel = new Label(codeStream));
385 codeStream.decrStackSize(1);
387 codeStream.iconst_0();
397 switch (bits & ReturnTypeIDMASK) {
400 if ((left.constant != Constant.NotAConstant)
401 && (left.constant.typeID() == T_int)
402 && (left.constant.intValue() == 0)) {
403 right.generateCode(currentScope, codeStream, valueRequired);
406 if ((right.constant != Constant.NotAConstant)
407 && (right.constant.typeID() == T_int)
408 && (right.constant.intValue() == 0)) {
409 left.generateCode(currentScope, codeStream, valueRequired);
411 left.generateCode(currentScope, codeStream, valueRequired);
412 right.generateCode(currentScope, codeStream, valueRequired);
420 if ((left.constant != Constant.NotAConstant)
421 && (left.constant.typeID() == T_long)
422 && (left.constant.longValue() == 0L)) {
423 right.generateCode(currentScope, codeStream, valueRequired);
426 if ((right.constant != Constant.NotAConstant)
427 && (right.constant.typeID() == T_long)
428 && (right.constant.longValue() == 0L)) {
429 left.generateCode(currentScope, codeStream, valueRequired);
431 left.generateCode(currentScope, codeStream, valueRequired);
432 right.generateCode(currentScope, codeStream, valueRequired);
439 generateOptimizedLogicalXor(
443 (falseLabel = new Label(codeStream)),
445 /* improving code gen for such a case: boolean b = i < 0 ^ bool;
446 * since the label has never been used, we have the inlined value on the stack. */
447 if (falseLabel.hasForwardReferences()) {
449 codeStream.iconst_1();
450 if ((bits & ValueForReturnMASK) != 0) {
451 codeStream.ireturn();
453 codeStream.iconst_0();
455 codeStream.goto_(endLabel = new Label(codeStream));
456 codeStream.decrStackSize(1);
458 codeStream.iconst_0();
468 switch (bits & ReturnTypeIDMASK) {
470 left.generateCode(currentScope, codeStream, valueRequired);
471 right.generateCode(currentScope, codeStream, valueRequired);
476 left.generateCode(currentScope, codeStream, valueRequired);
477 right.generateCode(currentScope, codeStream, valueRequired);
483 switch (bits & ReturnTypeIDMASK) {
485 left.generateCode(currentScope, codeStream, valueRequired);
486 right.generateCode(currentScope, codeStream, valueRequired);
491 left.generateCode(currentScope, codeStream, valueRequired);
492 right.generateCode(currentScope, codeStream, valueRequired);
497 case UNSIGNED_RIGHT_SHIFT :
498 switch (bits & ReturnTypeIDMASK) {
500 left.generateCode(currentScope, codeStream, valueRequired);
501 right.generateCode(currentScope, codeStream, valueRequired);
506 left.generateCode(currentScope, codeStream, valueRequired);
507 right.generateCode(currentScope, codeStream, valueRequired);
513 generateOptimizedGreaterThan(
517 (falseLabel = new Label(codeStream)),
520 codeStream.iconst_1();
521 if ((bits & ValueForReturnMASK) != 0) {
522 codeStream.ireturn();
524 codeStream.iconst_0();
526 codeStream.goto_(endLabel = new Label(codeStream));
527 codeStream.decrStackSize(1);
529 codeStream.iconst_0();
535 generateOptimizedGreaterThanOrEqual(
539 (falseLabel = new Label(codeStream)),
542 codeStream.iconst_1();
543 if ((bits & ValueForReturnMASK) != 0) {
544 codeStream.ireturn();
546 codeStream.iconst_0();
548 codeStream.goto_(endLabel = new Label(codeStream));
549 codeStream.decrStackSize(1);
551 codeStream.iconst_0();
557 generateOptimizedLessThan(
561 (falseLabel = new Label(codeStream)),
564 codeStream.iconst_1();
565 if ((bits & ValueForReturnMASK) != 0) {
566 codeStream.ireturn();
568 codeStream.iconst_0();
570 codeStream.goto_(endLabel = new Label(codeStream));
571 codeStream.decrStackSize(1);
573 codeStream.iconst_0();
579 generateOptimizedLessThanOrEqual(
583 (falseLabel = new Label(codeStream)),
586 codeStream.iconst_1();
587 if ((bits & ValueForReturnMASK) != 0) {
588 codeStream.ireturn();
590 codeStream.iconst_0();
592 codeStream.goto_(endLabel = new Label(codeStream));
593 codeStream.decrStackSize(1);
595 codeStream.iconst_0();
601 codeStream.generateImplicitConversion(implicitConversion);
603 codeStream.recordPositionsFrom(pc, this.sourceStart);
607 * Boolean operator code generation
608 * Optimized operations are: <, <=, >, >=, &, |, ^
610 public void generateOptimizedBoolean(
611 BlockScope currentScope,
612 CodeStream codeStream,
615 boolean valueRequired) {
617 if ((constant != Constant.NotAConstant) && (constant.typeID() == T_boolean)) {
618 super.generateOptimizedBoolean(
626 switch ((bits & OperatorMASK) >> OperatorSHIFT) {
628 generateOptimizedLessThan(
636 generateOptimizedLessThanOrEqual(
644 generateOptimizedGreaterThan(
652 generateOptimizedGreaterThanOrEqual(
660 generateOptimizedLogicalAnd(
668 generateOptimizedLogicalOr(
676 generateOptimizedLogicalXor(
684 super.generateOptimizedBoolean(
693 * Boolean generation for >
695 public void generateOptimizedGreaterThan(
696 BlockScope currentScope,
697 CodeStream codeStream,
700 boolean valueRequired) {
702 int promotedTypeID = left.implicitConversion >> 4;
703 // both sides got promoted in the same way
704 if (promotedTypeID == T_int) {
706 if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
707 right.generateCode(currentScope, codeStream, valueRequired);
709 if (falseLabel == null) {
710 if (trueLabel != null) {
711 // implicitly falling through the FALSE case
712 codeStream.iflt(trueLabel);
715 if (trueLabel == null) {
716 // implicitly falling through the TRUE case
717 codeStream.ifge(falseLabel);
719 // no implicit fall through TRUE/FALSE --> should never occur
723 // reposition the endPC
724 codeStream.updateLastRecordedEndPC(codeStream.position);
728 if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
729 left.generateCode(currentScope, codeStream, valueRequired);
731 if (falseLabel == null) {
732 if (trueLabel != null) {
733 // implicitly falling through the FALSE case
734 codeStream.ifgt(trueLabel);
737 if (trueLabel == null) {
738 // implicitly falling through the TRUE case
739 codeStream.ifle(falseLabel);
741 // no implicit fall through TRUE/FALSE --> should never occur
745 // reposition the endPC
746 codeStream.updateLastRecordedEndPC(codeStream.position);
750 // default comparison
751 left.generateCode(currentScope, codeStream, valueRequired);
752 right.generateCode(currentScope, codeStream, valueRequired);
754 if (falseLabel == null) {
755 if (trueLabel != null) {
756 // implicit falling through the FALSE case
757 switch (promotedTypeID) {
759 codeStream.if_icmpgt(trueLabel);
763 codeStream.ifgt(trueLabel);
767 codeStream.ifgt(trueLabel);
771 codeStream.ifgt(trueLabel);
773 // reposition the endPC
774 codeStream.updateLastRecordedEndPC(codeStream.position);
778 if (trueLabel == null) {
779 // implicit falling through the TRUE case
780 switch (promotedTypeID) {
782 codeStream.if_icmple(falseLabel);
786 codeStream.ifle(falseLabel);
790 codeStream.ifle(falseLabel);
794 codeStream.ifle(falseLabel);
796 // reposition the endPC
797 codeStream.updateLastRecordedEndPC(codeStream.position);
800 // no implicit fall through TRUE/FALSE --> should never occur
807 * Boolean generation for >=
809 public void generateOptimizedGreaterThanOrEqual(
810 BlockScope currentScope,
811 CodeStream codeStream,
814 boolean valueRequired) {
816 int promotedTypeID = left.implicitConversion >> 4;
817 // both sides got promoted in the same way
818 if (promotedTypeID == T_int) {
820 if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
821 right.generateCode(currentScope, codeStream, valueRequired);
823 if (falseLabel == null) {
824 if (trueLabel != null) {
825 // implicitly falling through the FALSE case
826 codeStream.ifle(trueLabel);
829 if (trueLabel == null) {
830 // implicitly falling through the TRUE case
831 codeStream.ifgt(falseLabel);
833 // no implicit fall through TRUE/FALSE --> should never occur
837 // reposition the endPC
838 codeStream.updateLastRecordedEndPC(codeStream.position);
842 if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
843 left.generateCode(currentScope, codeStream, valueRequired);
845 if (falseLabel == null) {
846 if (trueLabel != null) {
847 // implicitly falling through the FALSE case
848 codeStream.ifge(trueLabel);
851 if (trueLabel == null) {
852 // implicitly falling through the TRUE case
853 codeStream.iflt(falseLabel);
855 // no implicit fall through TRUE/FALSE --> should never occur
859 // reposition the endPC
860 codeStream.updateLastRecordedEndPC(codeStream.position);
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 // reposition the endPC
888 codeStream.updateLastRecordedEndPC(codeStream.position);
892 if (trueLabel == null) {
893 // implicit falling through the TRUE case
894 switch (promotedTypeID) {
896 codeStream.if_icmplt(falseLabel);
900 codeStream.iflt(falseLabel);
904 codeStream.iflt(falseLabel);
908 codeStream.iflt(falseLabel);
910 // reposition the endPC
911 codeStream.updateLastRecordedEndPC(codeStream.position);
914 // no implicit fall through TRUE/FALSE --> should never occur
921 * Boolean generation for <
923 public void generateOptimizedLessThan(
924 BlockScope currentScope,
925 CodeStream codeStream,
928 boolean valueRequired) {
930 int promotedTypeID = left.implicitConversion >> 4;
931 // both sides got promoted in the same way
932 if (promotedTypeID == T_int) {
934 if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
935 right.generateCode(currentScope, codeStream, valueRequired);
937 if (falseLabel == null) {
938 if (trueLabel != null) {
939 // implicitly falling through the FALSE case
940 codeStream.ifgt(trueLabel);
943 if (trueLabel == null) {
944 // implicitly falling through the TRUE case
945 codeStream.ifle(falseLabel);
947 // no implicit fall through TRUE/FALSE --> should never occur
951 codeStream.updateLastRecordedEndPC(codeStream.position);
955 if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
956 left.generateCode(currentScope, codeStream, valueRequired);
958 if (falseLabel == null) {
959 if (trueLabel != null) {
960 // implicitly falling through the FALSE case
961 codeStream.iflt(trueLabel);
964 if (trueLabel == null) {
965 // implicitly falling through the TRUE case
966 codeStream.ifge(falseLabel);
968 // no implicit fall through TRUE/FALSE --> should never occur
972 codeStream.updateLastRecordedEndPC(codeStream.position);
976 // default comparison
977 left.generateCode(currentScope, codeStream, valueRequired);
978 right.generateCode(currentScope, codeStream, valueRequired);
980 if (falseLabel == null) {
981 if (trueLabel != null) {
982 // implicit falling through the FALSE case
983 switch (promotedTypeID) {
985 codeStream.if_icmplt(trueLabel);
989 codeStream.iflt(trueLabel);
993 codeStream.iflt(trueLabel);
997 codeStream.iflt(trueLabel);
999 codeStream.updateLastRecordedEndPC(codeStream.position);
1003 if (trueLabel == null) {
1004 // implicit falling through the TRUE case
1005 switch (promotedTypeID) {
1007 codeStream.if_icmpge(falseLabel);
1011 codeStream.ifge(falseLabel);
1015 codeStream.ifge(falseLabel);
1019 codeStream.ifge(falseLabel);
1021 codeStream.updateLastRecordedEndPC(codeStream.position);
1024 // no implicit fall through TRUE/FALSE --> should never occur
1031 * Boolean generation for <=
1033 public void generateOptimizedLessThanOrEqual(
1034 BlockScope currentScope,
1035 CodeStream codeStream,
1038 boolean valueRequired) {
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 // reposition the endPC
1062 codeStream.updateLastRecordedEndPC(codeStream.position);
1066 if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) {
1067 left.generateCode(currentScope, codeStream, valueRequired);
1068 if (valueRequired) {
1069 if (falseLabel == null) {
1070 if (trueLabel != null) {
1071 // implicitly falling through the FALSE case
1072 codeStream.ifle(trueLabel);
1075 if (trueLabel == null) {
1076 // implicitly falling through the TRUE case
1077 codeStream.ifgt(falseLabel);
1079 // no implicit fall through TRUE/FALSE --> should never occur
1083 // reposition the endPC
1084 codeStream.updateLastRecordedEndPC(codeStream.position);
1088 // default comparison
1089 left.generateCode(currentScope, codeStream, valueRequired);
1090 right.generateCode(currentScope, codeStream, valueRequired);
1091 if (valueRequired) {
1092 if (falseLabel == null) {
1093 if (trueLabel != null) {
1094 // implicit falling through the FALSE case
1095 switch (promotedTypeID) {
1097 codeStream.if_icmple(trueLabel);
1101 codeStream.ifle(trueLabel);
1105 codeStream.ifle(trueLabel);
1109 codeStream.ifle(trueLabel);
1111 // reposition the endPC
1112 codeStream.updateLastRecordedEndPC(codeStream.position);
1116 if (trueLabel == null) {
1117 // implicit falling through the TRUE case
1118 switch (promotedTypeID) {
1120 codeStream.if_icmpgt(falseLabel);
1124 codeStream.ifgt(falseLabel);
1128 codeStream.ifgt(falseLabel);
1132 codeStream.ifgt(falseLabel);
1134 // reposition the endPC
1135 codeStream.updateLastRecordedEndPC(codeStream.position);
1138 // no implicit fall through TRUE/FALSE --> should never occur
1145 * Boolean generation for &
1147 public void generateOptimizedLogicalAnd(
1148 BlockScope currentScope,
1149 CodeStream codeStream,
1152 boolean valueRequired) {
1155 if ((left.implicitConversion & 0xF) == T_boolean) {
1156 if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) {
1157 if (condConst.booleanValue() == true) {
1158 // <something equivalent to true> & x
1159 left.generateOptimizedBoolean(
1165 if ((bits & OnlyValueRequiredMASK) != 0) {
1166 right.generateCode(currentScope, codeStream, valueRequired);
1168 right.generateOptimizedBoolean(
1176 // <something equivalent to false> & x
1177 left.generateOptimizedBoolean(
1183 Label internalTrueLabel = new Label(codeStream);
1184 right.generateOptimizedBoolean(
1190 internalTrueLabel.place();
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 Label internalTrueLabel = new Label(codeStream);
1228 left.generateOptimizedBoolean(
1234 internalTrueLabel.place();
1235 right.generateOptimizedBoolean(
1241 if (valueRequired) {
1242 if ((bits & OnlyValueRequiredMASK) != 0) {
1243 codeStream.iconst_0();
1245 if (falseLabel != null) {
1246 // implicit falling through the TRUE case
1247 codeStream.goto_(falseLabel);
1251 // reposition the endPC
1252 codeStream.updateLastRecordedEndPC(codeStream.position);
1258 left.generateCode(currentScope, codeStream, valueRequired);
1259 right.generateCode(currentScope, codeStream, valueRequired);
1260 if (valueRequired) {
1262 if ((bits & OnlyValueRequiredMASK) == 0) {
1263 if (falseLabel == null) {
1264 if (trueLabel != null) {
1265 // implicit falling through the FALSE case
1266 codeStream.ifne(trueLabel);
1269 // implicit falling through the TRUE case
1270 if (trueLabel == null) {
1271 codeStream.ifeq(falseLabel);
1273 // no implicit fall through TRUE/FALSE --> should never occur
1278 // reposition the endPC
1279 codeStream.updateLastRecordedEndPC(codeStream.position);
1283 * Boolean generation for |
1285 public void generateOptimizedLogicalOr(
1286 BlockScope currentScope,
1287 CodeStream codeStream,
1290 boolean valueRequired) {
1293 if ((left.implicitConversion & 0xF) == T_boolean) {
1294 if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) {
1295 if (condConst.booleanValue() == true) {
1296 // <something equivalent to true> | x
1297 left.generateOptimizedBoolean(
1303 Label internalFalseLabel = new Label(codeStream);
1304 right.generateOptimizedBoolean(
1310 internalFalseLabel.place();
1311 if (valueRequired) {
1312 if ((bits & OnlyValueRequiredMASK) != 0) {
1313 codeStream.iconst_1();
1315 if (trueLabel != null) {
1316 codeStream.goto_(trueLabel);
1320 // reposition the endPC
1321 codeStream.updateLastRecordedEndPC(codeStream.position);
1323 // <something equivalent to false> | x
1324 left.generateOptimizedBoolean(
1330 if ((bits & OnlyValueRequiredMASK) != 0) {
1331 right.generateCode(currentScope, codeStream, valueRequired);
1333 right.generateOptimizedBoolean(
1343 if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) {
1344 if (condConst.booleanValue() == true) {
1345 // x | <something equivalent to true>
1346 Label internalFalseLabel = new Label(codeStream);
1347 left.generateOptimizedBoolean(
1353 internalFalseLabel.place();
1354 right.generateOptimizedBoolean(
1360 if (valueRequired) {
1361 if ((bits & OnlyValueRequiredMASK) != 0) {
1362 codeStream.iconst_1();
1364 if (trueLabel != null) {
1365 codeStream.goto_(trueLabel);
1369 // reposition the endPC
1370 codeStream.updateLastRecordedEndPC(codeStream.position);
1372 // x | <something equivalent to false>
1373 if ((bits & OnlyValueRequiredMASK) != 0) {
1374 left.generateCode(currentScope, codeStream, valueRequired);
1376 left.generateOptimizedBoolean(
1383 right.generateOptimizedBoolean(
1394 left.generateCode(currentScope, codeStream, valueRequired);
1395 right.generateCode(currentScope, codeStream, valueRequired);
1396 if (valueRequired) {
1398 if ((bits & OnlyValueRequiredMASK) == 0) {
1399 if (falseLabel == null) {
1400 if (trueLabel != null) {
1401 // implicit falling through the FALSE case
1402 codeStream.ifne(trueLabel);
1405 // implicit falling through the TRUE case
1406 if (trueLabel == null) {
1407 codeStream.ifeq(falseLabel);
1409 // no implicit fall through TRUE/FALSE --> should never occur
1414 // reposition the endPC
1415 codeStream.updateLastRecordedEndPC(codeStream.position);
1419 * Boolean generation for ^
1421 public void generateOptimizedLogicalXor(
1422 BlockScope currentScope,
1423 CodeStream codeStream,
1426 boolean valueRequired) {
1429 if ((left.implicitConversion & 0xF) == T_boolean) {
1430 if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) {
1431 if (condConst.booleanValue() == true) {
1432 // <something equivalent to true> ^ x
1433 left.generateOptimizedBoolean(
1439 right.generateOptimizedBoolean(
1446 // <something equivalent to false> ^ x
1447 left.generateOptimizedBoolean(
1453 if ((bits & OnlyValueRequiredMASK) != 0) {
1454 right.generateCode(currentScope, codeStream, valueRequired);
1456 right.generateOptimizedBoolean(
1466 if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) {
1467 if (condConst.booleanValue() == true) {
1468 // x ^ <something equivalent to true>
1469 left.generateOptimizedBoolean(
1475 right.generateOptimizedBoolean(
1482 // x ^ <something equivalent to false>
1483 if ((bits & OnlyValueRequiredMASK) != 0) {
1484 left.generateCode(currentScope, codeStream, valueRequired);
1486 left.generateOptimizedBoolean(
1493 right.generateOptimizedBoolean(
1504 left.generateCode(currentScope, codeStream, valueRequired);
1505 right.generateCode(currentScope, codeStream, valueRequired);
1506 if (valueRequired) {
1508 if ((bits & OnlyValueRequiredMASK) == 0) {
1509 if (falseLabel == null) {
1510 if (trueLabel != null) {
1511 // implicit falling through the FALSE case
1512 codeStream.ifne(trueLabel);
1515 // implicit falling through the TRUE case
1516 if (trueLabel == null) {
1517 codeStream.ifeq(falseLabel);
1519 // no implicit fall through TRUE/FALSE --> should never occur
1524 // reposition the endPC
1525 codeStream.updateLastRecordedEndPC(codeStream.position);
1528 public void generateOptimizedStringBuffer(
1529 BlockScope blockScope,
1530 CodeStream codeStream,
1533 /* In the case trying to make a string concatenation, there is no need to create a new
1534 * string buffer, thus use a lower-level API for code generation involving only the
1535 * appending of arguments to the existing StringBuffer
1538 if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS)
1539 && ((bits & ReturnTypeIDMASK) == T_String)) {
1540 if (constant != NotAConstant) {
1541 codeStream.generateConstant(constant, implicitConversion);
1542 codeStream.invokeStringBufferAppendForType(implicitConversion & 0xF);
1544 int pc = codeStream.position;
1545 left.generateOptimizedStringBuffer(
1548 left.implicitConversion & 0xF);
1549 codeStream.recordPositionsFrom(pc, left.sourceStart);
1550 pc = codeStream.position;
1551 right.generateOptimizedStringBuffer(
1554 right.implicitConversion & 0xF);
1555 codeStream.recordPositionsFrom(pc, right.sourceStart);
1558 super.generateOptimizedStringBuffer(blockScope, codeStream, typeID);
1562 public void generateOptimizedStringBufferCreation(
1563 BlockScope blockScope,
1564 CodeStream codeStream,
1567 /* In the case trying to make a string concatenation, there is no need to create a new
1568 * string buffer, thus use a lower-level API for code generation involving only the
1569 * appending of arguments to the existing StringBuffer
1572 if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS)
1573 && ((bits & ReturnTypeIDMASK) == T_String)) {
1574 if (constant != NotAConstant) {
1575 codeStream.newStringBuffer(); // new: java.lang.StringBuffer
1577 codeStream.ldc(constant.stringValue());
1578 codeStream.invokeStringBufferStringConstructor();
1579 // invokespecial: java.lang.StringBuffer.<init>(Ljava.lang.String;)V
1581 int pc = codeStream.position;
1582 left.generateOptimizedStringBufferCreation(
1585 left.implicitConversion & 0xF);
1586 codeStream.recordPositionsFrom(pc, left.sourceStart);
1587 pc = codeStream.position;
1588 right.generateOptimizedStringBuffer(
1591 right.implicitConversion & 0xF);
1592 codeStream.recordPositionsFrom(pc, right.sourceStart);
1595 super.generateOptimizedStringBufferCreation(blockScope, codeStream, typeID);
1599 public boolean isCompactableOperation() {
1604 public void optimizedBooleanConstant(int leftId, int operator, int rightId) {
1608 if ((leftId != T_boolean) || (rightId != T_boolean))
1612 if ((cst = left.optimizedBooleanConstant()) != NotAConstant) {
1613 if (cst.booleanValue() == false) { // left is equivalent to false
1614 optimizedBooleanConstant = cst; // constant(false)
1616 } else { //left is equivalent to true
1617 if ((cst = right.optimizedBooleanConstant()) != NotAConstant) {
1618 optimizedBooleanConstant = cst;
1619 // the conditional result is equivalent to the right conditional value
1624 if ((cst = right.optimizedBooleanConstant()) != NotAConstant) {
1625 if (cst.booleanValue() == false) { // right is equivalent to false
1626 optimizedBooleanConstant = cst; // constant(false)
1631 if ((leftId != T_boolean) || (rightId != T_boolean))
1634 if ((cst = left.optimizedBooleanConstant()) != NotAConstant) {
1635 if (cst.booleanValue() == true) { // left is equivalent to true
1636 optimizedBooleanConstant = cst; // constant(true)
1638 } else { //left is equivalent to false
1639 if ((cst = right.optimizedBooleanConstant()) != NotAConstant) {
1640 optimizedBooleanConstant = cst;
1645 if ((cst = right.optimizedBooleanConstant()) != NotAConstant) {
1646 if (cst.booleanValue() == true) { // right is equivalent to true
1647 optimizedBooleanConstant = cst; // constant(true)
1653 public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) {
1655 left.printExpression(indent, output).append(' ').append(operatorToString()).append(' ');
1656 return right.printExpression(0, output);
1659 public TypeBinding resolveType(BlockScope scope) {
1661 boolean leftIsCast, rightIsCast;
1662 if ((leftIsCast = left instanceof CastExpression) == true) left.bits |= IgnoreNeedForCastCheckMASK; // will check later on
1663 TypeBinding leftType = left.resolveType(scope);
1665 if ((rightIsCast = right instanceof CastExpression) == true) right.bits |= IgnoreNeedForCastCheckMASK; // will check later on
1666 TypeBinding rightType = right.resolveType(scope);
1668 // use the id of the type to navigate into the table
1669 if (leftType == null || rightType == null) {
1670 constant = Constant.NotAConstant;
1673 int leftTypeId = leftType.id;
1674 int rightTypeId = rightType.id;
1676 || rightTypeId > 15) { // must convert String + Object || Object + String
1677 if (leftTypeId == T_String) {
1678 rightTypeId = T_Object;
1679 } else if (rightTypeId == T_String) {
1680 leftTypeId = T_Object;
1682 constant = Constant.NotAConstant;
1683 scope.problemReporter().invalidOperator(this, leftType, rightType);
1687 if (((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) {
1688 if (leftTypeId == T_String
1689 && rightType.isArrayType()
1690 && ((ArrayBinding) rightType).elementsType(scope) == CharBinding) {
1691 scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(right);
1692 } else if (rightTypeId == T_String
1693 && leftType.isArrayType()
1694 && ((ArrayBinding) leftType).elementsType(scope) == CharBinding) {
1695 scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(left);
1699 // the code is an int
1700 // (cast) left Op (cast) right --> result
1701 // 0000 0000 0000 0000 0000
1702 // <<16 <<12 <<8 <<4 <<0
1704 // Don't test for result = 0. If it is zero, some more work is done.
1705 // On the one hand when it is not zero (correct code) we avoid doing the test
1706 int operator = (bits & OperatorMASK) >> OperatorSHIFT;
1707 int operatorSignature = OperatorSignatures[operator][(leftTypeId << 4) + rightTypeId];
1708 left.implicitConversion = operatorSignature >>> 12;
1709 right.implicitConversion = (operatorSignature >>> 4) & 0x000FF;
1711 bits |= operatorSignature & 0xF;
1712 switch (operatorSignature & 0xF) { // record the current ReturnTypeID
1713 // only switch on possible result type.....
1715 this.resolvedType = BooleanBinding;
1718 this.resolvedType = ByteBinding;
1721 this.resolvedType = CharBinding;
1724 this.resolvedType = DoubleBinding;
1727 this.resolvedType = FloatBinding;
1730 this.resolvedType = IntBinding;
1733 this.resolvedType = LongBinding;
1736 this.resolvedType = scope.getJavaLangString();
1738 default : //error........
1739 constant = Constant.NotAConstant;
1740 scope.problemReporter().invalidOperator(this, leftType, rightType);
1744 // check need for operand cast
1745 if (leftIsCast || rightIsCast) {
1746 CastExpression.checkNeedForArgumentCasts(scope, operator, operatorSignature, left, leftTypeId, leftIsCast, right, rightTypeId, rightIsCast);
1748 // compute the constant when valid
1749 computeConstant(scope, leftTypeId, rightTypeId);
1750 return this.resolvedType;
1753 public void traverse(ASTVisitor visitor, BlockScope scope) {
1755 if (visitor.visit(this, scope)) {
1756 left.traverse(visitor, scope);
1757 right.traverse(visitor, scope);
1759 visitor.endVisit(this, scope);