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.phpdt.internal.compiler.ast;
13 import net.sourceforge.phpdt.core.compiler.ITerminalSymbols.TokenName;
14 import net.sourceforge.phpdt.internal.compiler.ASTVisitor;
15 import net.sourceforge.phpdt.internal.compiler.flow.FlowContext;
16 import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo;
17 import net.sourceforge.phpdt.internal.compiler.impl.Constant;
18 import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding;
19 import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope;
20 import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding;
22 public class BinaryExpression extends OperatorExpression {
24 public Expression left, right;
26 public Constant optimizedBooleanConstant;
28 public BinaryExpression(Expression left, Expression right, int operator) {
31 this.bits |= operator << OperatorSHIFT; // encode operator
32 this.sourceStart = left.sourceStart;
33 this.sourceEnd = right.sourceEnd;
36 public FlowInfo analyseCode(BlockScope currentScope,
37 FlowContext flowContext, FlowInfo flowInfo) {
39 return right.analyseCode(
42 left.analyseCode(currentScope, flowContext, flowInfo)
43 .unconditionalInits()).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)) {
52 this.constant = Constant.computeConstantOperation(
53 this.left.constant, leftId,
54 (this.bits & OperatorMASK) >> OperatorSHIFT,
55 this.right.constant, rightId);
56 } catch (ArithmeticException e) {
57 this.constant = Constant.NotAConstant;
58 // 1.2 no longer throws an exception at compile-time
59 // scope.problemReporter().compileTimeConstantThrowsArithmeticException(this);
62 this.constant = Constant.NotAConstant;
63 // add some work for the boolean operators & |
64 // this.optimizedBooleanConstant(
66 // (this.bits & OperatorMASK) >> OperatorSHIFT,
71 public Constant optimizedBooleanConstant() {
73 return this.optimizedBooleanConstant == null ? this.constant
74 : this.optimizedBooleanConstant;
78 * Code generation for a binary operation
80 // public void generateCode(
81 // BlockScope currentScope,
82 // CodeStream codeStream,
83 // boolean valueRequired) {
85 // int pc = codeStream.position;
86 // Label falseLabel, endLabel;
87 // if (constant != Constant.NotAConstant) {
89 // codeStream.generateConstant(constant, implicitConversion);
90 // codeStream.recordPositionsFrom(pc, this.sourceStart);
93 // bits |= OnlyValueRequiredMASK;
94 // switch ((bits & OperatorMASK) >> OperatorSHIFT) {
96 // switch (bits & ReturnTypeIDMASK) {
98 // codeStream.generateStringAppend(currentScope, left, right);
99 // if (!valueRequired)
103 // left.generateCode(currentScope, codeStream, valueRequired);
104 // right.generateCode(currentScope, codeStream, valueRequired);
105 // if (valueRequired)
106 // codeStream.iadd();
109 // left.generateCode(currentScope, codeStream, valueRequired);
110 // right.generateCode(currentScope, codeStream, valueRequired);
111 // if (valueRequired)
112 // codeStream.ladd();
115 // left.generateCode(currentScope, codeStream, valueRequired);
116 // right.generateCode(currentScope, codeStream, valueRequired);
117 // if (valueRequired)
118 // codeStream.dadd();
121 // left.generateCode(currentScope, codeStream, valueRequired);
122 // right.generateCode(currentScope, codeStream, valueRequired);
123 // if (valueRequired)
124 // codeStream.fadd();
129 // switch (bits & ReturnTypeIDMASK) {
131 // left.generateCode(currentScope, codeStream, valueRequired);
132 // right.generateCode(currentScope, codeStream, valueRequired);
133 // if (valueRequired)
134 // codeStream.isub();
137 // left.generateCode(currentScope, codeStream, valueRequired);
138 // right.generateCode(currentScope, codeStream, valueRequired);
139 // if (valueRequired)
140 // codeStream.lsub();
143 // left.generateCode(currentScope, codeStream, valueRequired);
144 // right.generateCode(currentScope, codeStream, valueRequired);
145 // if (valueRequired)
146 // codeStream.dsub();
149 // left.generateCode(currentScope, codeStream, valueRequired);
150 // right.generateCode(currentScope, codeStream, valueRequired);
151 // if (valueRequired)
152 // codeStream.fsub();
157 // switch (bits & ReturnTypeIDMASK) {
159 // left.generateCode(currentScope, codeStream, valueRequired);
160 // right.generateCode(currentScope, codeStream, valueRequired);
161 // if (valueRequired)
162 // codeStream.imul();
165 // left.generateCode(currentScope, codeStream, valueRequired);
166 // right.generateCode(currentScope, codeStream, valueRequired);
167 // if (valueRequired)
168 // codeStream.lmul();
171 // left.generateCode(currentScope, codeStream, valueRequired);
172 // right.generateCode(currentScope, codeStream, valueRequired);
173 // if (valueRequired)
174 // codeStream.dmul();
177 // left.generateCode(currentScope, codeStream, valueRequired);
178 // right.generateCode(currentScope, codeStream, valueRequired);
179 // if (valueRequired)
180 // codeStream.fmul();
185 // switch (bits & ReturnTypeIDMASK) {
187 // left.generateCode(currentScope, codeStream, true);
188 // right.generateCode(currentScope, codeStream, true);
189 // codeStream.idiv();
190 // if (!valueRequired)
194 // left.generateCode(currentScope, codeStream, true);
195 // right.generateCode(currentScope, codeStream, true);
196 // codeStream.ldiv();
197 // if (!valueRequired)
198 // codeStream.pop2();
201 // left.generateCode(currentScope, codeStream, valueRequired);
202 // right.generateCode(currentScope, codeStream, valueRequired);
203 // if (valueRequired)
204 // codeStream.ddiv();
207 // left.generateCode(currentScope, codeStream, valueRequired);
208 // right.generateCode(currentScope, codeStream, valueRequired);
209 // if (valueRequired)
210 // codeStream.fdiv();
215 // switch (bits & ReturnTypeIDMASK) {
217 // left.generateCode(currentScope, codeStream, true);
218 // right.generateCode(currentScope, codeStream, true);
219 // codeStream.irem();
220 // if (!valueRequired)
224 // left.generateCode(currentScope, codeStream, true);
225 // right.generateCode(currentScope, codeStream, true);
226 // codeStream.lrem();
227 // if (!valueRequired)
228 // codeStream.pop2();
231 // left.generateCode(currentScope, codeStream, valueRequired);
232 // right.generateCode(currentScope, codeStream, valueRequired);
233 // if (valueRequired)
234 // codeStream.drem();
237 // left.generateCode(currentScope, codeStream, valueRequired);
238 // right.generateCode(currentScope, codeStream, valueRequired);
239 // if (valueRequired)
240 // codeStream.frem();
245 // switch (bits & ReturnTypeIDMASK) {
248 // if ((left.constant != Constant.NotAConstant)
249 // && (left.constant.typeID() == T_int)
250 // && (left.constant.intValue() == 0)) {
251 // right.generateCode(currentScope, codeStream, false);
252 // if (valueRequired)
253 // codeStream.iconst_0();
256 // if ((right.constant != Constant.NotAConstant)
257 // && (right.constant.typeID() == T_int)
258 // && (right.constant.intValue() == 0)) {
259 // left.generateCode(currentScope, codeStream, false);
260 // if (valueRequired)
261 // codeStream.iconst_0();
263 // left.generateCode(currentScope, codeStream, valueRequired);
264 // right.generateCode(currentScope, codeStream, valueRequired);
265 // if (valueRequired)
266 // codeStream.iand();
272 // if ((left.constant != Constant.NotAConstant)
273 // && (left.constant.typeID() == T_long)
274 // && (left.constant.longValue() == 0L)) {
275 // right.generateCode(currentScope, codeStream, false);
276 // if (valueRequired)
277 // codeStream.lconst_0();
280 // if ((right.constant != Constant.NotAConstant)
281 // && (right.constant.typeID() == T_long)
282 // && (right.constant.longValue() == 0L)) {
283 // left.generateCode(currentScope, codeStream, false);
284 // if (valueRequired)
285 // codeStream.lconst_0();
287 // left.generateCode(currentScope, codeStream, valueRequired);
288 // right.generateCode(currentScope, codeStream, valueRequired);
289 // if (valueRequired)
290 // codeStream.land();
294 // case T_boolean : // logical and
295 // generateOptimizedLogicalAnd(
299 // (falseLabel = new Label(codeStream)),
301 // /* improving code gen for such a case: boolean b = i < 0 && false;
302 // * since the label has never been used, we have the inlined value on the
304 // if (falseLabel.hasForwardReferences()) {
305 // if (valueRequired) {
306 // codeStream.iconst_1();
307 // if ((bits & ValueForReturnMASK) != 0) {
308 // codeStream.ireturn();
309 // falseLabel.place();
310 // codeStream.iconst_0();
312 // codeStream.goto_(endLabel = new Label(codeStream));
313 // codeStream.decrStackSize(1);
314 // falseLabel.place();
315 // codeStream.iconst_0();
319 // falseLabel.place();
325 // switch (bits & ReturnTypeIDMASK) {
328 // if ((left.constant != Constant.NotAConstant)
329 // && (left.constant.typeID() == T_int)
330 // && (left.constant.intValue() == 0)) {
331 // right.generateCode(currentScope, codeStream, valueRequired);
334 // if ((right.constant != Constant.NotAConstant)
335 // && (right.constant.typeID() == T_int)
336 // && (right.constant.intValue() == 0)) {
337 // left.generateCode(currentScope, codeStream, valueRequired);
339 // left.generateCode(currentScope, codeStream, valueRequired);
340 // right.generateCode(currentScope, codeStream, valueRequired);
341 // if (valueRequired)
348 // if ((left.constant != Constant.NotAConstant)
349 // && (left.constant.typeID() == T_long)
350 // && (left.constant.longValue() == 0L)) {
351 // right.generateCode(currentScope, codeStream, valueRequired);
354 // if ((right.constant != Constant.NotAConstant)
355 // && (right.constant.typeID() == T_long)
356 // && (right.constant.longValue() == 0L)) {
357 // left.generateCode(currentScope, codeStream, valueRequired);
359 // left.generateCode(currentScope, codeStream, valueRequired);
360 // right.generateCode(currentScope, codeStream, valueRequired);
361 // if (valueRequired)
366 // case T_boolean : // logical or
367 // generateOptimizedLogicalOr(
371 // (falseLabel = new Label(codeStream)),
373 // /* improving code gen for such a case: boolean b = i < 0 || true;
374 // * since the label has never been used, we have the inlined value on the
376 // if (falseLabel.hasForwardReferences()) {
377 // if (valueRequired) {
378 // codeStream.iconst_1();
379 // if ((bits & ValueForReturnMASK) != 0) {
380 // codeStream.ireturn();
381 // falseLabel.place();
382 // codeStream.iconst_0();
384 // codeStream.goto_(endLabel = new Label(codeStream));
385 // codeStream.decrStackSize(1);
386 // falseLabel.place();
387 // codeStream.iconst_0();
391 // falseLabel.place();
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);
413 // if (valueRequired)
414 // codeStream.ixor();
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);
433 // if (valueRequired)
434 // codeStream.lxor();
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
448 // if (falseLabel.hasForwardReferences()) {
449 // if (valueRequired) {
450 // codeStream.iconst_1();
451 // if ((bits & ValueForReturnMASK) != 0) {
452 // codeStream.ireturn();
453 // falseLabel.place();
454 // codeStream.iconst_0();
456 // codeStream.goto_(endLabel = new Label(codeStream));
457 // codeStream.decrStackSize(1);
458 // falseLabel.place();
459 // codeStream.iconst_0();
463 // falseLabel.place();
469 // switch (bits & ReturnTypeIDMASK) {
471 // left.generateCode(currentScope, codeStream, valueRequired);
472 // right.generateCode(currentScope, codeStream, valueRequired);
473 // if (valueRequired)
474 // codeStream.ishl();
477 // left.generateCode(currentScope, codeStream, valueRequired);
478 // right.generateCode(currentScope, codeStream, valueRequired);
479 // if (valueRequired)
480 // codeStream.lshl();
483 // case RIGHT_SHIFT :
484 // switch (bits & ReturnTypeIDMASK) {
486 // left.generateCode(currentScope, codeStream, valueRequired);
487 // right.generateCode(currentScope, codeStream, valueRequired);
488 // if (valueRequired)
489 // codeStream.ishr();
492 // left.generateCode(currentScope, codeStream, valueRequired);
493 // right.generateCode(currentScope, codeStream, valueRequired);
494 // if (valueRequired)
495 // codeStream.lshr();
498 // case UNSIGNED_RIGHT_SHIFT :
499 // switch (bits & ReturnTypeIDMASK) {
501 // left.generateCode(currentScope, codeStream, valueRequired);
502 // right.generateCode(currentScope, codeStream, valueRequired);
503 // if (valueRequired)
504 // codeStream.iushr();
507 // left.generateCode(currentScope, codeStream, valueRequired);
508 // right.generateCode(currentScope, codeStream, valueRequired);
509 // if (valueRequired)
510 // codeStream.lushr();
514 // generateOptimizedGreaterThan(
518 // (falseLabel = new Label(codeStream)),
520 // if (valueRequired) {
521 // codeStream.iconst_1();
522 // if ((bits & ValueForReturnMASK) != 0) {
523 // codeStream.ireturn();
524 // falseLabel.place();
525 // codeStream.iconst_0();
527 // codeStream.goto_(endLabel = new Label(codeStream));
528 // codeStream.decrStackSize(1);
529 // falseLabel.place();
530 // codeStream.iconst_0();
535 // case GREATER_EQUAL :
536 // generateOptimizedGreaterThanOrEqual(
540 // (falseLabel = new Label(codeStream)),
542 // if (valueRequired) {
543 // codeStream.iconst_1();
544 // if ((bits & ValueForReturnMASK) != 0) {
545 // codeStream.ireturn();
546 // falseLabel.place();
547 // codeStream.iconst_0();
549 // codeStream.goto_(endLabel = new Label(codeStream));
550 // codeStream.decrStackSize(1);
551 // falseLabel.place();
552 // codeStream.iconst_0();
558 // generateOptimizedLessThan(
562 // (falseLabel = new Label(codeStream)),
564 // if (valueRequired) {
565 // codeStream.iconst_1();
566 // if ((bits & ValueForReturnMASK) != 0) {
567 // codeStream.ireturn();
568 // falseLabel.place();
569 // codeStream.iconst_0();
571 // codeStream.goto_(endLabel = new Label(codeStream));
572 // codeStream.decrStackSize(1);
573 // falseLabel.place();
574 // codeStream.iconst_0();
580 // generateOptimizedLessThanOrEqual(
584 // (falseLabel = new Label(codeStream)),
586 // if (valueRequired) {
587 // codeStream.iconst_1();
588 // if ((bits & ValueForReturnMASK) != 0) {
589 // codeStream.ireturn();
590 // falseLabel.place();
591 // codeStream.iconst_0();
593 // codeStream.goto_(endLabel = new Label(codeStream));
594 // codeStream.decrStackSize(1);
595 // falseLabel.place();
596 // codeStream.iconst_0();
601 // if (valueRequired) {
602 // codeStream.generateImplicitConversion(implicitConversion);
604 // codeStream.recordPositionsFrom(pc, this.sourceStart);
607 * Boolean operator code generation Optimized operations are: <, <=, >, >=, &, |, ^
609 // public void generateOptimizedBoolean(
610 // BlockScope currentScope,
611 // CodeStream codeStream,
614 // boolean valueRequired) {
616 // if ((constant != Constant.NotAConstant) && (constant.typeID() ==
618 // super.generateOptimizedBoolean(
626 // switch ((bits & OperatorMASK) >> OperatorSHIFT) {
628 // generateOptimizedLessThan(
636 // generateOptimizedLessThanOrEqual(
644 // generateOptimizedGreaterThan(
651 // case GREATER_EQUAL :
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);
708 // if (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))
730 // left.generateCode(currentScope, codeStream, valueRequired);
731 // if (valueRequired) {
732 // if (falseLabel == null) {
733 // if (trueLabel != null) {
734 // // implicitly falling through the FALSE case
735 // codeStream.ifgt(trueLabel);
738 // if (trueLabel == null) {
739 // // implicitly falling through the TRUE case
740 // codeStream.ifle(falseLabel);
742 // // no implicit fall through TRUE/FALSE --> should never occur
746 // // reposition the endPC
747 // codeStream.updateLastRecordedEndPC(codeStream.position);
751 // // default comparison
752 // left.generateCode(currentScope, codeStream, valueRequired);
753 // right.generateCode(currentScope, codeStream, valueRequired);
754 // if (valueRequired) {
755 // if (falseLabel == null) {
756 // if (trueLabel != null) {
757 // // implicit falling through the FALSE case
758 // switch (promotedTypeID) {
760 // codeStream.if_icmpgt(trueLabel);
763 // codeStream.fcmpl();
764 // codeStream.ifgt(trueLabel);
767 // codeStream.lcmp();
768 // codeStream.ifgt(trueLabel);
771 // codeStream.dcmpl();
772 // codeStream.ifgt(trueLabel);
774 // // reposition the endPC
775 // codeStream.updateLastRecordedEndPC(codeStream.position);
779 // if (trueLabel == null) {
780 // // implicit falling through the TRUE case
781 // switch (promotedTypeID) {
783 // codeStream.if_icmple(falseLabel);
786 // codeStream.fcmpl();
787 // codeStream.ifle(falseLabel);
790 // codeStream.lcmp();
791 // codeStream.ifle(falseLabel);
794 // codeStream.dcmpl();
795 // codeStream.ifle(falseLabel);
797 // // reposition the endPC
798 // codeStream.updateLastRecordedEndPC(codeStream.position);
801 // // 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);
822 // if (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))
844 // left.generateCode(currentScope, codeStream, valueRequired);
845 // if (valueRequired) {
846 // if (falseLabel == null) {
847 // if (trueLabel != null) {
848 // // implicitly falling through the FALSE case
849 // codeStream.ifge(trueLabel);
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 // // reposition the endPC
861 // codeStream.updateLastRecordedEndPC(codeStream.position);
865 // // default comparison
866 // left.generateCode(currentScope, codeStream, valueRequired);
867 // right.generateCode(currentScope, codeStream, valueRequired);
868 // if (valueRequired) {
869 // if (falseLabel == null) {
870 // if (trueLabel != null) {
871 // // implicit falling through the FALSE case
872 // switch (promotedTypeID) {
874 // codeStream.if_icmpge(trueLabel);
877 // codeStream.fcmpl();
878 // codeStream.ifge(trueLabel);
881 // codeStream.lcmp();
882 // codeStream.ifge(trueLabel);
885 // codeStream.dcmpl();
886 // codeStream.ifge(trueLabel);
888 // // reposition the endPC
889 // codeStream.updateLastRecordedEndPC(codeStream.position);
893 // if (trueLabel == null) {
894 // // implicit falling through the TRUE case
895 // switch (promotedTypeID) {
897 // codeStream.if_icmplt(falseLabel);
900 // codeStream.fcmpl();
901 // codeStream.iflt(falseLabel);
904 // codeStream.lcmp();
905 // codeStream.iflt(falseLabel);
908 // codeStream.dcmpl();
909 // codeStream.iflt(falseLabel);
911 // // reposition the endPC
912 // codeStream.updateLastRecordedEndPC(codeStream.position);
915 // // no implicit fall through TRUE/FALSE --> should never occur
922 // * Boolean generation for <
924 // public void generateOptimizedLessThan(
925 // BlockScope currentScope,
926 // CodeStream codeStream,
929 // boolean valueRequired) {
931 // int promotedTypeID = left.implicitConversion >> 4;
932 // // both sides got promoted in the same way
933 // if (promotedTypeID == T_int) {
935 // if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) {
936 // right.generateCode(currentScope, codeStream, valueRequired);
937 // if (valueRequired) {
938 // if (falseLabel == null) {
939 // if (trueLabel != null) {
940 // // implicitly falling through the FALSE case
941 // codeStream.ifgt(trueLabel);
944 // if (trueLabel == null) {
945 // // implicitly falling through the TRUE case
946 // codeStream.ifle(falseLabel);
948 // // no implicit fall through TRUE/FALSE --> should never occur
952 // codeStream.updateLastRecordedEndPC(codeStream.position);
956 // 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))
1070 // left.generateCode(currentScope, codeStream, valueRequired);
1071 // if (valueRequired) {
1072 // if (falseLabel == null) {
1073 // if (trueLabel != null) {
1074 // // implicitly falling through the FALSE case
1075 // codeStream.ifle(trueLabel);
1078 // if (trueLabel == null) {
1079 // // implicitly falling through the TRUE case
1080 // codeStream.ifgt(falseLabel);
1082 // // no implicit fall through TRUE/FALSE --> should never occur
1086 // // reposition the endPC
1087 // codeStream.updateLastRecordedEndPC(codeStream.position);
1091 // // default comparison
1092 // left.generateCode(currentScope, codeStream, valueRequired);
1093 // right.generateCode(currentScope, codeStream, valueRequired);
1094 // if (valueRequired) {
1095 // if (falseLabel == null) {
1096 // if (trueLabel != null) {
1097 // // implicit falling through the FALSE case
1098 // switch (promotedTypeID) {
1100 // codeStream.if_icmple(trueLabel);
1103 // codeStream.fcmpg();
1104 // codeStream.ifle(trueLabel);
1107 // codeStream.lcmp();
1108 // codeStream.ifle(trueLabel);
1111 // codeStream.dcmpg();
1112 // codeStream.ifle(trueLabel);
1114 // // reposition the endPC
1115 // codeStream.updateLastRecordedEndPC(codeStream.position);
1119 // if (trueLabel == null) {
1120 // // implicit falling through the TRUE case
1121 // switch (promotedTypeID) {
1123 // codeStream.if_icmpgt(falseLabel);
1126 // codeStream.fcmpg();
1127 // codeStream.ifgt(falseLabel);
1130 // codeStream.lcmp();
1131 // codeStream.ifgt(falseLabel);
1134 // codeStream.dcmpg();
1135 // codeStream.ifgt(falseLabel);
1137 // // reposition the endPC
1138 // codeStream.updateLastRecordedEndPC(codeStream.position);
1141 // // no implicit fall through TRUE/FALSE --> should never occur
1148 // * Boolean generation for &
1150 // public void generateOptimizedLogicalAnd(
1151 // BlockScope currentScope,
1152 // CodeStream codeStream,
1154 // Label falseLabel,
1155 // boolean valueRequired) {
1157 // Constant condConst;
1158 // if ((left.implicitConversion & 0xF) == T_boolean) {
1159 // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) {
1160 // if (condConst.booleanValue() == true) {
1161 // // <something equivalent to true> & x
1162 // left.generateOptimizedBoolean(
1168 // if ((bits & OnlyValueRequiredMASK) != 0) {
1169 // right.generateCode(currentScope, codeStream, valueRequired);
1171 // right.generateOptimizedBoolean(
1179 // // <something equivalent to false> & x
1180 // left.generateOptimizedBoolean(
1186 // right.generateOptimizedBoolean(
1192 // if (valueRequired) {
1193 // if ((bits & OnlyValueRequiredMASK) != 0) {
1194 // codeStream.iconst_0();
1196 // if (falseLabel != null) {
1197 // // implicit falling through the TRUE case
1198 // codeStream.goto_(falseLabel);
1202 // // reposition the endPC
1203 // codeStream.updateLastRecordedEndPC(codeStream.position);
1207 // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) {
1208 // if (condConst.booleanValue() == true) {
1209 // // x & <something equivalent to true>
1210 // if ((bits & OnlyValueRequiredMASK) != 0) {
1211 // left.generateCode(currentScope, codeStream, valueRequired);
1213 // left.generateOptimizedBoolean(
1220 // right.generateOptimizedBoolean(
1227 // // x & <something equivalent to false>
1228 // left.generateOptimizedBoolean(
1234 // right.generateOptimizedBoolean(
1240 // if (valueRequired) {
1241 // if ((bits & OnlyValueRequiredMASK) != 0) {
1242 // codeStream.iconst_0();
1244 // if (falseLabel != null) {
1245 // // implicit falling through the TRUE case
1246 // codeStream.goto_(falseLabel);
1250 // // reposition the endPC
1251 // codeStream.updateLastRecordedEndPC(codeStream.position);
1257 // left.generateCode(currentScope, codeStream, valueRequired);
1258 // right.generateCode(currentScope, codeStream, valueRequired);
1259 // if (valueRequired) {
1260 // codeStream.iand();
1261 // if ((bits & OnlyValueRequiredMASK) == 0) {
1262 // if (falseLabel == null) {
1263 // if (trueLabel != null) {
1264 // // implicit falling through the FALSE case
1265 // codeStream.ifne(trueLabel);
1268 // // implicit falling through the TRUE case
1269 // if (trueLabel == null) {
1270 // codeStream.ifeq(falseLabel);
1272 // // no implicit fall through TRUE/FALSE --> should never occur
1277 // // reposition the endPC
1278 // codeStream.updateLastRecordedEndPC(codeStream.position);
1282 // * Boolean generation for |
1284 // public void generateOptimizedLogicalOr(
1285 // BlockScope currentScope,
1286 // CodeStream codeStream,
1288 // Label falseLabel,
1289 // boolean valueRequired) {
1291 // Constant condConst;
1292 // if ((left.implicitConversion & 0xF) == T_boolean) {
1293 // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) {
1294 // if (condConst.booleanValue() == true) {
1295 // // <something equivalent to true> | x
1296 // left.generateOptimizedBoolean(
1302 // right.generateOptimizedBoolean(
1308 // if (valueRequired) {
1309 // if ((bits & OnlyValueRequiredMASK) != 0) {
1310 // codeStream.iconst_1();
1312 // if (trueLabel != null) {
1313 // codeStream.goto_(trueLabel);
1317 // // reposition the endPC
1318 // codeStream.updateLastRecordedEndPC(codeStream.position);
1320 // // <something equivalent to false> | x
1321 // left.generateOptimizedBoolean(
1327 // if ((bits & OnlyValueRequiredMASK) != 0) {
1328 // right.generateCode(currentScope, codeStream, valueRequired);
1330 // right.generateOptimizedBoolean(
1340 // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) {
1341 // if (condConst.booleanValue() == true) {
1342 // // x | <something equivalent to true>
1343 // left.generateOptimizedBoolean(
1349 // right.generateOptimizedBoolean(
1355 // if (valueRequired) {
1356 // if ((bits & OnlyValueRequiredMASK) != 0) {
1357 // codeStream.iconst_1();
1359 // if (trueLabel != null) {
1360 // codeStream.goto_(trueLabel);
1364 // // reposition the endPC
1365 // codeStream.updateLastRecordedEndPC(codeStream.position);
1367 // // x | <something equivalent to false>
1368 // if ((bits & OnlyValueRequiredMASK) != 0) {
1369 // left.generateCode(currentScope, codeStream, valueRequired);
1371 // left.generateOptimizedBoolean(
1378 // right.generateOptimizedBoolean(
1389 // left.generateCode(currentScope, codeStream, valueRequired);
1390 // right.generateCode(currentScope, codeStream, valueRequired);
1391 // if (valueRequired) {
1392 // codeStream.ior();
1393 // if ((bits & OnlyValueRequiredMASK) == 0) {
1394 // if (falseLabel == null) {
1395 // if (trueLabel != null) {
1396 // // implicit falling through the FALSE case
1397 // codeStream.ifne(trueLabel);
1400 // // implicit falling through the TRUE case
1401 // if (trueLabel == null) {
1402 // codeStream.ifeq(falseLabel);
1404 // // no implicit fall through TRUE/FALSE --> should never occur
1409 // // reposition the endPC
1410 // codeStream.updateLastRecordedEndPC(codeStream.position);
1414 // * Boolean generation for ^
1416 // public void generateOptimizedLogicalXor(
1417 // BlockScope currentScope,
1418 // CodeStream codeStream,
1420 // Label falseLabel,
1421 // boolean valueRequired) {
1423 // Constant condConst;
1424 // if ((left.implicitConversion & 0xF) == T_boolean) {
1425 // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) {
1426 // if (condConst.booleanValue() == true) {
1427 // // <something equivalent to true> ^ x
1428 // left.generateOptimizedBoolean(
1434 // right.generateOptimizedBoolean(
1441 // // <something equivalent to false> ^ x
1442 // left.generateOptimizedBoolean(
1448 // if ((bits & OnlyValueRequiredMASK) != 0) {
1449 // right.generateCode(currentScope, codeStream, valueRequired);
1451 // right.generateOptimizedBoolean(
1461 // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) {
1462 // if (condConst.booleanValue() == true) {
1463 // // x ^ <something equivalent to true>
1464 // left.generateOptimizedBoolean(
1470 // right.generateOptimizedBoolean(
1477 // // x ^ <something equivalent to false>
1478 // if ((bits & OnlyValueRequiredMASK) != 0) {
1479 // left.generateCode(currentScope, codeStream, valueRequired);
1481 // left.generateOptimizedBoolean(
1488 // right.generateOptimizedBoolean(
1499 // left.generateCode(currentScope, codeStream, valueRequired);
1500 // right.generateCode(currentScope, codeStream, valueRequired);
1501 // if (valueRequired) {
1502 // codeStream.ixor();
1503 // if ((bits & OnlyValueRequiredMASK) == 0) {
1504 // if (falseLabel == null) {
1505 // if (trueLabel != null) {
1506 // // implicit falling through the FALSE case
1507 // codeStream.ifne(trueLabel);
1510 // // implicit falling through the TRUE case
1511 // if (trueLabel == null) {
1512 // codeStream.ifeq(falseLabel);
1514 // // no implicit fall through TRUE/FALSE --> should never occur
1519 // // reposition the endPC
1520 // codeStream.updateLastRecordedEndPC(codeStream.position);
1523 // public void generateOptimizedStringBuffer(
1524 // BlockScope blockScope,
1525 // CodeStream codeStream,
1528 // /* In the case trying to make a string concatenation, there is no need to
1530 // * string buffer, thus use a lower-level API for code generation involving
1532 // * appending of arguments to the existing StringBuffer
1535 // if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS)
1536 // && ((bits & ReturnTypeIDMASK) == T_String)) {
1537 // if (constant != NotAConstant) {
1538 // codeStream.generateConstant(constant, implicitConversion);
1539 // codeStream.invokeStringBufferAppendForType(implicitConversion & 0xF);
1541 // int pc = codeStream.position;
1542 // left.generateOptimizedStringBuffer(
1545 // left.implicitConversion & 0xF);
1546 // codeStream.recordPositionsFrom(pc, left.sourceStart);
1547 // pc = codeStream.position;
1548 // right.generateOptimizedStringBuffer(
1551 // right.implicitConversion & 0xF);
1552 // codeStream.recordPositionsFrom(pc, right.sourceStart);
1555 // super.generateOptimizedStringBuffer(blockScope, codeStream, typeID);
1559 // public void generateOptimizedStringBufferCreation(
1560 // BlockScope blockScope,
1561 // CodeStream codeStream,
1564 // /* In the case trying to make a string concatenation, there is no need to
1566 // * string buffer, thus use a lower-level API for code generation involving
1568 // * appending of arguments to the existing StringBuffer
1571 // if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS)
1572 // && ((bits & ReturnTypeIDMASK) == T_String)) {
1573 // if (constant != NotAConstant) {
1574 // codeStream.newStringBuffer(); // new: java.lang.StringBuffer
1575 // codeStream.dup();
1576 // codeStream.ldc(constant.stringValue());
1577 // codeStream.invokeStringBufferStringConstructor();
1578 // // invokespecial: java.lang.StringBuffer.<init>(Ljava.lang.String;)V
1580 // int pc = codeStream.position;
1581 // left.generateOptimizedStringBufferCreation(
1584 // left.implicitConversion & 0xF);
1585 // codeStream.recordPositionsFrom(pc, left.sourceStart);
1586 // pc = codeStream.position;
1587 // right.generateOptimizedStringBuffer(
1590 // right.implicitConversion & 0xF);
1591 // codeStream.recordPositionsFrom(pc, right.sourceStart);
1594 // super.generateOptimizedStringBufferCreation(blockScope, codeStream,
1599 // public boolean isCompactableOperation() {
1604 // public void optimizedBooleanConstant(int leftId, int operator, int
1607 // switch (operator) {
1609 // if ((leftId != T_boolean) || (rightId != T_boolean))
1613 // if ((cst = left.optimizedBooleanConstant()) != NotAConstant) {
1614 // if (cst.booleanValue() == false) { // left is equivalent to false
1615 // optimizedBooleanConstant = cst; // constant(false)
1617 // } else { //left is equivalent to true
1618 // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) {
1619 // optimizedBooleanConstant = cst;
1620 // // the conditional result is equivalent to the right conditional value
1625 // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) {
1626 // if (cst.booleanValue() == false) { // right is equivalent to false
1627 // optimizedBooleanConstant = cst; // constant(false)
1632 // if ((leftId != T_boolean) || (rightId != T_boolean))
1635 // if ((cst = left.optimizedBooleanConstant()) != NotAConstant) {
1636 // if (cst.booleanValue() == true) { // left is equivalent to true
1637 // optimizedBooleanConstant = cst; // constant(true)
1639 // } else { //left is equivalent to false
1640 // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) {
1641 // optimizedBooleanConstant = cst;
1646 // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) {
1647 // if (cst.booleanValue() == true) { // right is equivalent to true
1648 // optimizedBooleanConstant = cst; // constant(true)
1653 public StringBuffer printExpressionNoParenthesis(int indent,
1654 StringBuffer output) {
1656 left.printExpression(indent, output).append(' ').append(
1657 operatorToString()).append(' ');
1658 return right.printExpression(0, output);
1661 public TypeBinding resolveType(BlockScope scope) {
1663 // use the id of the type to navigate into the table
1664 TypeBinding leftTb = left.resolveType(scope);
1665 TypeBinding rightTb = right.resolveType(scope);
1666 if (leftTb == null || rightTb == null) {
1667 constant = Constant.NotAConstant;
1670 int leftId = leftTb.id;
1671 int rightId = rightTb.id;
1672 if (leftId > 15 || rightId > 15) { // must convert String + Object ||
1674 if (leftId == T_String) {
1676 } else if (rightId == T_String) {
1679 constant = Constant.NotAConstant;
1680 scope.problemReporter().invalidOperator(this, leftTb, rightTb);
1684 if (((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) {
1685 if (leftId == T_String
1686 && rightTb.isArrayType()
1687 && ((ArrayBinding) rightTb).elementsType(scope) == CharBinding)
1690 .signalNoImplicitStringConversionForCharArrayExpression(
1692 else if (rightId == T_String
1693 && leftTb.isArrayType()
1694 && ((ArrayBinding) leftTb).elementsType(scope) == CharBinding)
1697 .signalNoImplicitStringConversionForCharArrayExpression(
1701 // the code is an int
1702 // (cast) left Op (cast) rigth --> result
1703 // 0000 0000 0000 0000 0000
1704 // <<16 <<12 <<8 <<4 <<0
1706 // Don't test for result = 0. If it is zero, some more work is done.
1707 // On the one hand when it is not zero (correct code) we avoid doing the
1709 int result = ResolveTypeTables[(bits & OperatorMASK) >> OperatorSHIFT][(leftId << 4)
1711 left.implicitConversion = result >>> 12;
1712 right.implicitConversion = (result >>> 4) & 0x000FF;
1714 bits |= result & 0xF;
1715 switch (result & 0xF) { // record the current ReturnTypeID
1716 // only switch on possible result type.....
1718 this.resolvedType = BooleanBinding;
1721 this.resolvedType = ByteBinding;
1724 this.resolvedType = CharBinding;
1727 this.resolvedType = DoubleBinding;
1730 this.resolvedType = FloatBinding;
1733 this.resolvedType = IntBinding;
1736 this.resolvedType = LongBinding;
1739 this.resolvedType = scope.getJavaLangString();
1741 default: // error........
1742 constant = Constant.NotAConstant;
1743 scope.problemReporter().invalidOperator(this, leftTb, rightTb);
1747 // compute the constant when valid
1748 computeConstant(scope, leftId, rightId);
1749 return this.resolvedType;
1752 public String toStringExpressionNoParenthesis() {
1754 return left.toStringExpression() + " " + //$NON-NLS-1$
1755 operatorToString() + " " + //$NON-NLS-1$
1756 right.toStringExpression();
1759 public void traverse(ASTVisitor visitor, BlockScope scope) {
1761 if (visitor.visit(this, scope)) {
1762 left.traverse(visitor, scope);
1763 right.traverse(visitor, scope);
1765 visitor.endVisit(this, scope);