/** Boolean generation for == with non-boolean operands */
  public void generateOptimizedNonBooleanEqual(
      BlockScope currentScope,
      CodeStream codeStream,
      BranchLabel trueLabel,
      BranchLabel falseLabel,
      boolean valueRequired) {

    int pc = codeStream.position;
    Constant inline;
    if ((inline = this.right.constant) != Constant.NotAConstant) {
      // optimized case: x == 0
      if ((((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_int)
          && (inline.intValue() == 0)) {
        this.left.generateCode(currentScope, codeStream, valueRequired);
        if (valueRequired) {
          if (falseLabel == null) {
            if (trueLabel != null) {
              // implicit falling through the FALSE case
              codeStream.ifeq(trueLabel);
            }
          } else {
            // implicit falling through the TRUE case
            if (trueLabel == null) {
              codeStream.ifne(falseLabel);
            } else {
              // no implicit fall through TRUE/FALSE --> should never occur
            }
          }
        }
        codeStream.recordPositionsFrom(pc, this.sourceStart);
        return;
      }
    }
    if ((inline = this.left.constant) != Constant.NotAConstant) {
      // optimized case: 0 == x
      if ((((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_int)
          && (inline.intValue() == 0)) {
        this.right.generateCode(currentScope, codeStream, valueRequired);
        if (valueRequired) {
          if (falseLabel == null) {
            if (trueLabel != null) {
              // implicit falling through the FALSE case
              codeStream.ifeq(trueLabel);
            }
          } else {
            // implicit falling through the TRUE case
            if (trueLabel == null) {
              codeStream.ifne(falseLabel);
            } else {
              // no implicit fall through TRUE/FALSE --> should never occur
            }
          }
        }
        codeStream.recordPositionsFrom(pc, this.sourceStart);
        return;
      }
    }
    // null cases
    // optimized case: x == null
    if (this.right instanceof NullLiteral) {
      if (this.left instanceof NullLiteral) {
        // null == null
        if (valueRequired) {
          if (falseLabel == null) {
            // implicit falling through the FALSE case
            if (trueLabel != null) {
              codeStream.goto_(trueLabel);
            }
          }
        }
      } else {
        this.left.generateCode(currentScope, codeStream, valueRequired);
        if (valueRequired) {
          if (falseLabel == null) {
            if (trueLabel != null) {
              // implicit falling through the FALSE case
              codeStream.ifnull(trueLabel);
            }
          } else {
            // implicit falling through the TRUE case
            if (trueLabel == null) {
              codeStream.ifnonnull(falseLabel);
            } else {
              // no implicit fall through TRUE/FALSE --> should never occur
            }
          }
        }
      }
      codeStream.recordPositionsFrom(pc, this.sourceStart);
      return;
    } else if (this.left instanceof NullLiteral) { // optimized case: null == x
      this.right.generateCode(currentScope, codeStream, valueRequired);
      if (valueRequired) {
        if (falseLabel == null) {
          if (trueLabel != null) {
            // implicit falling through the FALSE case
            codeStream.ifnull(trueLabel);
          }
        } else {
          // implicit falling through the TRUE case
          if (trueLabel == null) {
            codeStream.ifnonnull(falseLabel);
          } else {
            // no implicit fall through TRUE/FALSE --> should never occur
          }
        }
      }
      codeStream.recordPositionsFrom(pc, this.sourceStart);
      return;
    }

    // default case
    this.left.generateCode(currentScope, codeStream, valueRequired);
    this.right.generateCode(currentScope, codeStream, valueRequired);
    if (valueRequired) {
      if (falseLabel == null) {
        if (trueLabel != null) {
          // implicit falling through the FALSE case
          switch ((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK)
              >> 4) { // operand runtime type
            case T_int:
              codeStream.if_icmpeq(trueLabel);
              break;
            case T_float:
              codeStream.fcmpl();
              codeStream.ifeq(trueLabel);
              break;
            case T_long:
              codeStream.lcmp();
              codeStream.ifeq(trueLabel);
              break;
            case T_double:
              codeStream.dcmpl();
              codeStream.ifeq(trueLabel);
              break;
            default:
              codeStream.if_acmpeq(trueLabel);
          }
        }
      } else {
        // implicit falling through the TRUE case
        if (trueLabel == null) {
          switch ((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK)
              >> 4) { // operand runtime type
            case T_int:
              codeStream.if_icmpne(falseLabel);
              break;
            case T_float:
              codeStream.fcmpl();
              codeStream.ifne(falseLabel);
              break;
            case T_long:
              codeStream.lcmp();
              codeStream.ifne(falseLabel);
              break;
            case T_double:
              codeStream.dcmpl();
              codeStream.ifne(falseLabel);
              break;
            default:
              codeStream.if_acmpne(falseLabel);
          }
        } else {
          // no implicit fall through TRUE/FALSE --> should never occur
        }
      }
    }
    codeStream.recordPositionsFrom(pc, this.sourceStart);
  }
  /** Boolean generation for == with non-boolean operands */
  public void generateNonBooleanEqual(
      BlockScope currentScope, CodeStream codeStream, boolean valueRequired) {

    boolean isEqualOperator = ((this.bits & OperatorMASK) >> OperatorSHIFT) == EQUAL_EQUAL;
    if (((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) == T_int) {
      Constant cst;
      if ((cst = this.left.constant) != Constant.NotAConstant && cst.intValue() == 0) {
        // optimized case: 0 == x, 0 != x
        this.right.generateCode(currentScope, codeStream, valueRequired);
        if (valueRequired) {
          BranchLabel falseLabel = new BranchLabel(codeStream);
          if (isEqualOperator) {
            codeStream.ifne(falseLabel);
          } else {
            codeStream.ifeq(falseLabel);
          }
          // comparison is TRUE
          codeStream.iconst_1();
          if ((this.bits & IsReturnedValue) != 0) {
            codeStream.generateImplicitConversion(this.implicitConversion);
            codeStream.generateReturnBytecode(this);
            // comparison is FALSE
            falseLabel.place();
            codeStream.iconst_0();
          } else {
            BranchLabel endLabel = new BranchLabel(codeStream);
            codeStream.goto_(endLabel);
            codeStream.decrStackSize(1);
            // comparison is FALSE
            falseLabel.place();
            codeStream.iconst_0();
            endLabel.place();
          }
        }
        return;
      }
      if ((cst = this.right.constant) != Constant.NotAConstant && cst.intValue() == 0) {
        // optimized case: x == 0, x != 0
        this.left.generateCode(currentScope, codeStream, valueRequired);
        if (valueRequired) {
          BranchLabel falseLabel = new BranchLabel(codeStream);
          if (isEqualOperator) {
            codeStream.ifne(falseLabel);
          } else {
            codeStream.ifeq(falseLabel);
          }
          // comparison is TRUE
          codeStream.iconst_1();
          if ((this.bits & IsReturnedValue) != 0) {
            codeStream.generateImplicitConversion(this.implicitConversion);
            codeStream.generateReturnBytecode(this);
            // comparison is FALSE
            falseLabel.place();
            codeStream.iconst_0();
          } else {
            BranchLabel endLabel = new BranchLabel(codeStream);
            codeStream.goto_(endLabel);
            codeStream.decrStackSize(1);
            // comparison is FALSE
            falseLabel.place();
            codeStream.iconst_0();
            endLabel.place();
          }
        }
        return;
      }
    }

    // null cases
    if (this.right instanceof NullLiteral) {
      if (this.left instanceof NullLiteral) {
        // null == null, null != null
        if (valueRequired) {
          if (isEqualOperator) {
            codeStream.iconst_1();
          } else {
            codeStream.iconst_0();
          }
        }
      } else {
        // x == null, x != null
        this.left.generateCode(currentScope, codeStream, valueRequired);
        if (valueRequired) {
          BranchLabel falseLabel = new BranchLabel(codeStream);
          if (isEqualOperator) {
            codeStream.ifnonnull(falseLabel);
          } else {
            codeStream.ifnull(falseLabel);
          }
          // comparison is TRUE
          codeStream.iconst_1();
          if ((this.bits & IsReturnedValue) != 0) {
            codeStream.generateImplicitConversion(this.implicitConversion);
            codeStream.generateReturnBytecode(this);
            // comparison is FALSE
            falseLabel.place();
            codeStream.iconst_0();
          } else {
            BranchLabel endLabel = new BranchLabel(codeStream);
            codeStream.goto_(endLabel);
            codeStream.decrStackSize(1);
            // comparison is FALSE
            falseLabel.place();
            codeStream.iconst_0();
            endLabel.place();
          }
        }
      }
      return;
    } else if (this.left instanceof NullLiteral) {
      // null = x, null != x
      this.right.generateCode(currentScope, codeStream, valueRequired);
      if (valueRequired) {
        BranchLabel falseLabel = new BranchLabel(codeStream);
        if (isEqualOperator) {
          codeStream.ifnonnull(falseLabel);
        } else {
          codeStream.ifnull(falseLabel);
        }
        // comparison is TRUE
        codeStream.iconst_1();
        if ((this.bits & IsReturnedValue) != 0) {
          codeStream.generateImplicitConversion(this.implicitConversion);
          codeStream.generateReturnBytecode(this);
          // comparison is FALSE
          falseLabel.place();
          codeStream.iconst_0();
        } else {
          BranchLabel endLabel = new BranchLabel(codeStream);
          codeStream.goto_(endLabel);
          codeStream.decrStackSize(1);
          // comparison is FALSE
          falseLabel.place();
          codeStream.iconst_0();
          endLabel.place();
        }
      }
      return;
    }

    // default case
    this.left.generateCode(currentScope, codeStream, valueRequired);
    this.right.generateCode(currentScope, codeStream, valueRequired);
    if (valueRequired) {
      BranchLabel falseLabel = new BranchLabel(codeStream);
      if (isEqualOperator) {
        switch ((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK)
            >> 4) { // operand runtime type
          case T_int:
            codeStream.if_icmpne(falseLabel);
            break;
          case T_float:
            codeStream.fcmpl();
            codeStream.ifne(falseLabel);
            break;
          case T_long:
            codeStream.lcmp();
            codeStream.ifne(falseLabel);
            break;
          case T_double:
            codeStream.dcmpl();
            codeStream.ifne(falseLabel);
            break;
          default:
            codeStream.if_acmpne(falseLabel);
        }
      } else {
        switch ((this.left.implicitConversion & IMPLICIT_CONVERSION_MASK)
            >> 4) { // operand runtime type
          case T_int:
            codeStream.if_icmpeq(falseLabel);
            break;
          case T_float:
            codeStream.fcmpl();
            codeStream.ifeq(falseLabel);
            break;
          case T_long:
            codeStream.lcmp();
            codeStream.ifeq(falseLabel);
            break;
          case T_double:
            codeStream.dcmpl();
            codeStream.ifeq(falseLabel);
            break;
          default:
            codeStream.if_acmpeq(falseLabel);
        }
      }
      // comparison is TRUE
      codeStream.iconst_1();
      if ((this.bits & IsReturnedValue) != 0) {
        codeStream.generateImplicitConversion(this.implicitConversion);
        codeStream.generateReturnBytecode(this);
        // comparison is FALSE
        falseLabel.place();
        codeStream.iconst_0();
      } else {
        BranchLabel endLabel = new BranchLabel(codeStream);
        codeStream.goto_(endLabel);
        codeStream.decrStackSize(1);
        // comparison is FALSE
        falseLabel.place();
        codeStream.iconst_0();
        endLabel.place();
      }
    }
  }