/******************************************************************************* * Copyright (c) 2000, 2003 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package net.sourceforge.phpdt.internal.compiler.ast; import net.sourceforge.phpdt.core.compiler.ITerminalSymbols.TokenName; import net.sourceforge.phpdt.internal.compiler.ASTVisitor; import net.sourceforge.phpdt.internal.compiler.flow.FlowContext; import net.sourceforge.phpdt.internal.compiler.flow.FlowInfo; import net.sourceforge.phpdt.internal.compiler.impl.Constant; import net.sourceforge.phpdt.internal.compiler.lookup.ArrayBinding; import net.sourceforge.phpdt.internal.compiler.lookup.BlockScope; import net.sourceforge.phpdt.internal.compiler.lookup.TypeBinding; public class BinaryExpression extends OperatorExpression { public Expression left, right; public Constant optimizedBooleanConstant; public BinaryExpression(Expression left, Expression right, int operator) { this.left = left; this.right = right; this.bits |= operator << OperatorSHIFT; // encode operator this.sourceStart = left.sourceStart; this.sourceEnd = right.sourceEnd; } public FlowInfo analyseCode(BlockScope currentScope, FlowContext flowContext, FlowInfo flowInfo) { return right.analyseCode( currentScope, flowContext, left.analyseCode(currentScope, flowContext, flowInfo) .unconditionalInits()).unconditionalInits(); } public void computeConstant(BlockScope scope, int leftId, int rightId) { // compute the constant when valid if ((this.left.constant != Constant.NotAConstant) && (this.right.constant != Constant.NotAConstant)) { try { this.constant = Constant.computeConstantOperation( this.left.constant, leftId, (this.bits & OperatorMASK) >> OperatorSHIFT, this.right.constant, rightId); } catch (ArithmeticException e) { this.constant = Constant.NotAConstant; // 1.2 no longer throws an exception at compile-time // scope.problemReporter().compileTimeConstantThrowsArithmeticException(this); } } else { this.constant = Constant.NotAConstant; // add some work for the boolean operators & | // this.optimizedBooleanConstant( // leftId, // (this.bits & OperatorMASK) >> OperatorSHIFT, // rightId); } } public Constant optimizedBooleanConstant() { return this.optimizedBooleanConstant == null ? this.constant : this.optimizedBooleanConstant; } /** * Code generation for a binary operation */ // public void generateCode( // BlockScope currentScope, // CodeStream codeStream, // boolean valueRequired) { // // int pc = codeStream.position; // Label falseLabel, endLabel; // if (constant != Constant.NotAConstant) { // if (valueRequired) // codeStream.generateConstant(constant, implicitConversion); // codeStream.recordPositionsFrom(pc, this.sourceStart); // return; // } // bits |= OnlyValueRequiredMASK; // switch ((bits & OperatorMASK) >> OperatorSHIFT) { // case PLUS : // switch (bits & ReturnTypeIDMASK) { // case T_String : // codeStream.generateStringAppend(currentScope, left, right); // if (!valueRequired) // codeStream.pop(); // break; // case T_int : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.iadd(); // break; // case T_long : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.ladd(); // break; // case T_double : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.dadd(); // break; // case T_float : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.fadd(); // break; // } // break; // case MINUS : // switch (bits & ReturnTypeIDMASK) { // case T_int : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.isub(); // break; // case T_long : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.lsub(); // break; // case T_double : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.dsub(); // break; // case T_float : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.fsub(); // break; // } // break; // case MULTIPLY : // switch (bits & ReturnTypeIDMASK) { // case T_int : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.imul(); // break; // case T_long : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.lmul(); // break; // case T_double : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.dmul(); // break; // case T_float : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.fmul(); // break; // } // break; // case DIVIDE : // switch (bits & ReturnTypeIDMASK) { // case T_int : // left.generateCode(currentScope, codeStream, true); // right.generateCode(currentScope, codeStream, true); // codeStream.idiv(); // if (!valueRequired) // codeStream.pop(); // break; // case T_long : // left.generateCode(currentScope, codeStream, true); // right.generateCode(currentScope, codeStream, true); // codeStream.ldiv(); // if (!valueRequired) // codeStream.pop2(); // break; // case T_double : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.ddiv(); // break; // case T_float : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.fdiv(); // break; // } // break; // case REMAINDER : // switch (bits & ReturnTypeIDMASK) { // case T_int : // left.generateCode(currentScope, codeStream, true); // right.generateCode(currentScope, codeStream, true); // codeStream.irem(); // if (!valueRequired) // codeStream.pop(); // break; // case T_long : // left.generateCode(currentScope, codeStream, true); // right.generateCode(currentScope, codeStream, true); // codeStream.lrem(); // if (!valueRequired) // codeStream.pop2(); // break; // case T_double : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.drem(); // break; // case T_float : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.frem(); // break; // } // break; // case AND : // switch (bits & ReturnTypeIDMASK) { // case T_int : // // 0 & x // if ((left.constant != Constant.NotAConstant) // && (left.constant.typeID() == T_int) // && (left.constant.intValue() == 0)) { // right.generateCode(currentScope, codeStream, false); // if (valueRequired) // codeStream.iconst_0(); // } else { // // x & 0 // if ((right.constant != Constant.NotAConstant) // && (right.constant.typeID() == T_int) // && (right.constant.intValue() == 0)) { // left.generateCode(currentScope, codeStream, false); // if (valueRequired) // codeStream.iconst_0(); // } else { // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.iand(); // } // } // break; // case T_long : // // 0 & x // if ((left.constant != Constant.NotAConstant) // && (left.constant.typeID() == T_long) // && (left.constant.longValue() == 0L)) { // right.generateCode(currentScope, codeStream, false); // if (valueRequired) // codeStream.lconst_0(); // } else { // // x & 0 // if ((right.constant != Constant.NotAConstant) // && (right.constant.typeID() == T_long) // && (right.constant.longValue() == 0L)) { // left.generateCode(currentScope, codeStream, false); // if (valueRequired) // codeStream.lconst_0(); // } else { // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.land(); // } // } // break; // case T_boolean : // logical and // generateOptimizedLogicalAnd( // currentScope, // codeStream, // null, // (falseLabel = new Label(codeStream)), // valueRequired); // /* improving code gen for such a case: boolean b = i < 0 && false; // * since the label has never been used, we have the inlined value on the // stack. */ // if (falseLabel.hasForwardReferences()) { // if (valueRequired) { // codeStream.iconst_1(); // if ((bits & ValueForReturnMASK) != 0) { // codeStream.ireturn(); // falseLabel.place(); // codeStream.iconst_0(); // } else { // codeStream.goto_(endLabel = new Label(codeStream)); // codeStream.decrStackSize(1); // falseLabel.place(); // codeStream.iconst_0(); // endLabel.place(); // } // } else { // falseLabel.place(); // } // } // } // break; // case OR : // switch (bits & ReturnTypeIDMASK) { // case T_int : // // 0 | x // if ((left.constant != Constant.NotAConstant) // && (left.constant.typeID() == T_int) // && (left.constant.intValue() == 0)) { // right.generateCode(currentScope, codeStream, valueRequired); // } else { // // x | 0 // if ((right.constant != Constant.NotAConstant) // && (right.constant.typeID() == T_int) // && (right.constant.intValue() == 0)) { // left.generateCode(currentScope, codeStream, valueRequired); // } else { // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.ior(); // } // } // break; // case T_long : // // 0 | x // if ((left.constant != Constant.NotAConstant) // && (left.constant.typeID() == T_long) // && (left.constant.longValue() == 0L)) { // right.generateCode(currentScope, codeStream, valueRequired); // } else { // // x | 0 // if ((right.constant != Constant.NotAConstant) // && (right.constant.typeID() == T_long) // && (right.constant.longValue() == 0L)) { // left.generateCode(currentScope, codeStream, valueRequired); // } else { // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.lor(); // } // } // break; // case T_boolean : // logical or // generateOptimizedLogicalOr( // currentScope, // codeStream, // null, // (falseLabel = new Label(codeStream)), // valueRequired); // /* improving code gen for such a case: boolean b = i < 0 || true; // * since the label has never been used, we have the inlined value on the // stack. */ // if (falseLabel.hasForwardReferences()) { // if (valueRequired) { // codeStream.iconst_1(); // if ((bits & ValueForReturnMASK) != 0) { // codeStream.ireturn(); // falseLabel.place(); // codeStream.iconst_0(); // } else { // codeStream.goto_(endLabel = new Label(codeStream)); // codeStream.decrStackSize(1); // falseLabel.place(); // codeStream.iconst_0(); // endLabel.place(); // } // } else { // falseLabel.place(); // } // } // } // break; // case XOR : // switch (bits & ReturnTypeIDMASK) { // case T_int : // // 0 ^ x // if ((left.constant != Constant.NotAConstant) // && (left.constant.typeID() == T_int) // && (left.constant.intValue() == 0)) { // right.generateCode(currentScope, codeStream, valueRequired); // } else { // // x ^ 0 // if ((right.constant != Constant.NotAConstant) // && (right.constant.typeID() == T_int) // && (right.constant.intValue() == 0)) { // left.generateCode(currentScope, codeStream, valueRequired); // } else { // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.ixor(); // } // } // break; // case T_long : // // 0 ^ x // if ((left.constant != Constant.NotAConstant) // && (left.constant.typeID() == T_long) // && (left.constant.longValue() == 0L)) { // right.generateCode(currentScope, codeStream, valueRequired); // } else { // // x ^ 0 // if ((right.constant != Constant.NotAConstant) // && (right.constant.typeID() == T_long) // && (right.constant.longValue() == 0L)) { // left.generateCode(currentScope, codeStream, valueRequired); // } else { // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.lxor(); // } // } // break; // case T_boolean : // generateOptimizedLogicalXor( // currentScope, // codeStream, // null, // (falseLabel = new Label(codeStream)), // valueRequired); // /* improving code gen for such a case: boolean b = i < 0 ^ bool; // * since the label has never been used, we have the inlined value on the // stack. */ // if (falseLabel.hasForwardReferences()) { // if (valueRequired) { // codeStream.iconst_1(); // if ((bits & ValueForReturnMASK) != 0) { // codeStream.ireturn(); // falseLabel.place(); // codeStream.iconst_0(); // } else { // codeStream.goto_(endLabel = new Label(codeStream)); // codeStream.decrStackSize(1); // falseLabel.place(); // codeStream.iconst_0(); // endLabel.place(); // } // } else { // falseLabel.place(); // } // } // } // break; // case LEFT_SHIFT : // switch (bits & ReturnTypeIDMASK) { // case T_int : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.ishl(); // break; // case T_long : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.lshl(); // } // break; // case RIGHT_SHIFT : // switch (bits & ReturnTypeIDMASK) { // case T_int : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.ishr(); // break; // case T_long : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.lshr(); // } // break; // case UNSIGNED_RIGHT_SHIFT : // switch (bits & ReturnTypeIDMASK) { // case T_int : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.iushr(); // break; // case T_long : // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) // codeStream.lushr(); // } // break; // case GREATER : // generateOptimizedGreaterThan( // currentScope, // codeStream, // null, // (falseLabel = new Label(codeStream)), // valueRequired); // if (valueRequired) { // codeStream.iconst_1(); // if ((bits & ValueForReturnMASK) != 0) { // codeStream.ireturn(); // falseLabel.place(); // codeStream.iconst_0(); // } else { // codeStream.goto_(endLabel = new Label(codeStream)); // codeStream.decrStackSize(1); // falseLabel.place(); // codeStream.iconst_0(); // endLabel.place(); // } // } // break; // case GREATER_EQUAL : // generateOptimizedGreaterThanOrEqual( // currentScope, // codeStream, // null, // (falseLabel = new Label(codeStream)), // valueRequired); // if (valueRequired) { // codeStream.iconst_1(); // if ((bits & ValueForReturnMASK) != 0) { // codeStream.ireturn(); // falseLabel.place(); // codeStream.iconst_0(); // } else { // codeStream.goto_(endLabel = new Label(codeStream)); // codeStream.decrStackSize(1); // falseLabel.place(); // codeStream.iconst_0(); // endLabel.place(); // } // } // break; // case LESS : // generateOptimizedLessThan( // currentScope, // codeStream, // null, // (falseLabel = new Label(codeStream)), // valueRequired); // if (valueRequired) { // codeStream.iconst_1(); // if ((bits & ValueForReturnMASK) != 0) { // codeStream.ireturn(); // falseLabel.place(); // codeStream.iconst_0(); // } else { // codeStream.goto_(endLabel = new Label(codeStream)); // codeStream.decrStackSize(1); // falseLabel.place(); // codeStream.iconst_0(); // endLabel.place(); // } // } // break; // case LESS_EQUAL : // generateOptimizedLessThanOrEqual( // currentScope, // codeStream, // null, // (falseLabel = new Label(codeStream)), // valueRequired); // if (valueRequired) { // codeStream.iconst_1(); // if ((bits & ValueForReturnMASK) != 0) { // codeStream.ireturn(); // falseLabel.place(); // codeStream.iconst_0(); // } else { // codeStream.goto_(endLabel = new Label(codeStream)); // codeStream.decrStackSize(1); // falseLabel.place(); // codeStream.iconst_0(); // endLabel.place(); // } // } // } // if (valueRequired) { // codeStream.generateImplicitConversion(implicitConversion); // } // codeStream.recordPositionsFrom(pc, this.sourceStart); // } /** * Boolean operator code generation Optimized operations are: <, <=, >, >=, &, |, ^ */ // public void generateOptimizedBoolean( // BlockScope currentScope, // CodeStream codeStream, // Label trueLabel, // Label falseLabel, // boolean valueRequired) { // // if ((constant != Constant.NotAConstant) && (constant.typeID() == // T_boolean)) { // super.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // return; // } // switch ((bits & OperatorMASK) >> OperatorSHIFT) { // case LESS : // generateOptimizedLessThan( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // return; // case LESS_EQUAL : // generateOptimizedLessThanOrEqual( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // return; // case GREATER : // generateOptimizedGreaterThan( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // return; // case GREATER_EQUAL : // generateOptimizedGreaterThanOrEqual( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // return; // case AND : // generateOptimizedLogicalAnd( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // return; // case OR : // generateOptimizedLogicalOr( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // return; // case XOR : // generateOptimizedLogicalXor( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // return; // } // super.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // } // // /** // * Boolean generation for > // */ // public void generateOptimizedGreaterThan( // BlockScope currentScope, // CodeStream codeStream, // Label trueLabel, // Label falseLabel, // boolean valueRequired) { // // int promotedTypeID = left.implicitConversion >> 4; // // both sides got promoted in the same way // if (promotedTypeID == T_int) { // // 0 > x // if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicitly falling through the FALSE case // codeStream.iflt(trueLabel); // } // } else { // if (trueLabel == null) { // // implicitly falling through the TRUE case // codeStream.ifge(falseLabel); // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } // // x > 0 // if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) // { // left.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicitly falling through the FALSE case // codeStream.ifgt(trueLabel); // } // } else { // if (trueLabel == null) { // // implicitly falling through the TRUE case // codeStream.ifle(falseLabel); // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } // } // // default comparison // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicit falling through the FALSE case // switch (promotedTypeID) { // case T_int : // codeStream.if_icmpgt(trueLabel); // break; // case T_float : // codeStream.fcmpl(); // codeStream.ifgt(trueLabel); // break; // case T_long : // codeStream.lcmp(); // codeStream.ifgt(trueLabel); // break; // case T_double : // codeStream.dcmpl(); // codeStream.ifgt(trueLabel); // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } // } else { // if (trueLabel == null) { // // implicit falling through the TRUE case // switch (promotedTypeID) { // case T_int : // codeStream.if_icmple(falseLabel); // break; // case T_float : // codeStream.fcmpl(); // codeStream.ifle(falseLabel); // break; // case T_long : // codeStream.lcmp(); // codeStream.ifle(falseLabel); // break; // case T_double : // codeStream.dcmpl(); // codeStream.ifle(falseLabel); // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // } /** * Boolean generation for >= */ // public void generateOptimizedGreaterThanOrEqual( // BlockScope currentScope, // CodeStream codeStream, // Label trueLabel, // Label falseLabel, // boolean valueRequired) { // // int promotedTypeID = left.implicitConversion >> 4; // // both sides got promoted in the same way // if (promotedTypeID == T_int) { // // 0 >= x // if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicitly falling through the FALSE case // codeStream.ifle(trueLabel); // } // } else { // if (trueLabel == null) { // // implicitly falling through the TRUE case // codeStream.ifgt(falseLabel); // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } // // x >= 0 // if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) // { // left.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicitly falling through the FALSE case // codeStream.ifge(trueLabel); // } // } else { // if (trueLabel == null) { // // implicitly falling through the TRUE case // codeStream.iflt(falseLabel); // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } // } // // default comparison // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicit falling through the FALSE case // switch (promotedTypeID) { // case T_int : // codeStream.if_icmpge(trueLabel); // break; // case T_float : // codeStream.fcmpl(); // codeStream.ifge(trueLabel); // break; // case T_long : // codeStream.lcmp(); // codeStream.ifge(trueLabel); // break; // case T_double : // codeStream.dcmpl(); // codeStream.ifge(trueLabel); // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } // } else { // if (trueLabel == null) { // // implicit falling through the TRUE case // switch (promotedTypeID) { // case T_int : // codeStream.if_icmplt(falseLabel); // break; // case T_float : // codeStream.fcmpl(); // codeStream.iflt(falseLabel); // break; // case T_long : // codeStream.lcmp(); // codeStream.iflt(falseLabel); // break; // case T_double : // codeStream.dcmpl(); // codeStream.iflt(falseLabel); // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // } // // /** // * Boolean generation for < // */ // public void generateOptimizedLessThan( // BlockScope currentScope, // CodeStream codeStream, // Label trueLabel, // Label falseLabel, // boolean valueRequired) { // // int promotedTypeID = left.implicitConversion >> 4; // // both sides got promoted in the same way // if (promotedTypeID == T_int) { // // 0 < x // if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicitly falling through the FALSE case // codeStream.ifgt(trueLabel); // } // } else { // if (trueLabel == null) { // // implicitly falling through the TRUE case // codeStream.ifle(falseLabel); // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } // // x < 0 // if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) // { // left.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicitly falling through the FALSE case // codeStream.iflt(trueLabel); // } // } else { // if (trueLabel == null) { // // implicitly falling through the TRUE case // codeStream.ifge(falseLabel); // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } // } // // default comparison // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicit falling through the FALSE case // switch (promotedTypeID) { // case T_int : // codeStream.if_icmplt(trueLabel); // break; // case T_float : // codeStream.fcmpg(); // codeStream.iflt(trueLabel); // break; // case T_long : // codeStream.lcmp(); // codeStream.iflt(trueLabel); // break; // case T_double : // codeStream.dcmpg(); // codeStream.iflt(trueLabel); // } // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } // } else { // if (trueLabel == null) { // // implicit falling through the TRUE case // switch (promotedTypeID) { // case T_int : // codeStream.if_icmpge(falseLabel); // break; // case T_float : // codeStream.fcmpg(); // codeStream.ifge(falseLabel); // break; // case T_long : // codeStream.lcmp(); // codeStream.ifge(falseLabel); // break; // case T_double : // codeStream.dcmpg(); // codeStream.ifge(falseLabel); // } // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // } // // /** // * Boolean generation for <= // */ // public void generateOptimizedLessThanOrEqual( // BlockScope currentScope, // CodeStream codeStream, // Label trueLabel, // Label falseLabel, // boolean valueRequired) { // // int promotedTypeID = left.implicitConversion >> 4; // // both sides got promoted in the same way // if (promotedTypeID == T_int) { // // 0 <= x // if ((left.constant != NotAConstant) && (left.constant.intValue() == 0)) { // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicitly falling through the FALSE case // codeStream.ifge(trueLabel); // } // } else { // if (trueLabel == null) { // // implicitly falling through the TRUE case // codeStream.iflt(falseLabel); // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } // // x <= 0 // if ((right.constant != NotAConstant) && (right.constant.intValue() == 0)) // { // left.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicitly falling through the FALSE case // codeStream.ifle(trueLabel); // } // } else { // if (trueLabel == null) { // // implicitly falling through the TRUE case // codeStream.ifgt(falseLabel); // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } // } // // default comparison // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicit falling through the FALSE case // switch (promotedTypeID) { // case T_int : // codeStream.if_icmple(trueLabel); // break; // case T_float : // codeStream.fcmpg(); // codeStream.ifle(trueLabel); // break; // case T_long : // codeStream.lcmp(); // codeStream.ifle(trueLabel); // break; // case T_double : // codeStream.dcmpg(); // codeStream.ifle(trueLabel); // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } // } else { // if (trueLabel == null) { // // implicit falling through the TRUE case // switch (promotedTypeID) { // case T_int : // codeStream.if_icmpgt(falseLabel); // break; // case T_float : // codeStream.fcmpg(); // codeStream.ifgt(falseLabel); // break; // case T_long : // codeStream.lcmp(); // codeStream.ifgt(falseLabel); // break; // case T_double : // codeStream.dcmpg(); // codeStream.ifgt(falseLabel); // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // return; // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // } // // /** // * Boolean generation for & // */ // public void generateOptimizedLogicalAnd( // BlockScope currentScope, // CodeStream codeStream, // Label trueLabel, // Label falseLabel, // boolean valueRequired) { // // Constant condConst; // if ((left.implicitConversion & 0xF) == T_boolean) { // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) { // if (condConst.booleanValue() == true) { // // & x // left.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // if ((bits & OnlyValueRequiredMASK) != 0) { // right.generateCode(currentScope, codeStream, valueRequired); // } else { // right.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // } // } else { // // & x // left.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // right.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // if (valueRequired) { // if ((bits & OnlyValueRequiredMASK) != 0) { // codeStream.iconst_0(); // } else { // if (falseLabel != null) { // // implicit falling through the TRUE case // codeStream.goto_(falseLabel); // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // } // return; // } // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) { // if (condConst.booleanValue() == true) { // // x & // if ((bits & OnlyValueRequiredMASK) != 0) { // left.generateCode(currentScope, codeStream, valueRequired); // } else { // left.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // } // right.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // } else { // // x & // left.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // right.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // if (valueRequired) { // if ((bits & OnlyValueRequiredMASK) != 0) { // codeStream.iconst_0(); // } else { // if (falseLabel != null) { // // implicit falling through the TRUE case // codeStream.goto_(falseLabel); // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // } // return; // } // } // // default case // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // codeStream.iand(); // if ((bits & OnlyValueRequiredMASK) == 0) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicit falling through the FALSE case // codeStream.ifne(trueLabel); // } // } else { // // implicit falling through the TRUE case // if (trueLabel == null) { // codeStream.ifeq(falseLabel); // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // } // // /** // * Boolean generation for | // */ // public void generateOptimizedLogicalOr( // BlockScope currentScope, // CodeStream codeStream, // Label trueLabel, // Label falseLabel, // boolean valueRequired) { // // Constant condConst; // if ((left.implicitConversion & 0xF) == T_boolean) { // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) { // if (condConst.booleanValue() == true) { // // | x // left.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // right.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // if (valueRequired) { // if ((bits & OnlyValueRequiredMASK) != 0) { // codeStream.iconst_1(); // } else { // if (trueLabel != null) { // codeStream.goto_(trueLabel); // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // } else { // // | x // left.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // if ((bits & OnlyValueRequiredMASK) != 0) { // right.generateCode(currentScope, codeStream, valueRequired); // } else { // right.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // } // } // return; // } // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) { // if (condConst.booleanValue() == true) { // // x | // left.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // right.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // if (valueRequired) { // if ((bits & OnlyValueRequiredMASK) != 0) { // codeStream.iconst_1(); // } else { // if (trueLabel != null) { // codeStream.goto_(trueLabel); // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // } else { // // x | // if ((bits & OnlyValueRequiredMASK) != 0) { // left.generateCode(currentScope, codeStream, valueRequired); // } else { // left.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // } // right.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // } // return; // } // } // // default case // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // codeStream.ior(); // if ((bits & OnlyValueRequiredMASK) == 0) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicit falling through the FALSE case // codeStream.ifne(trueLabel); // } // } else { // // implicit falling through the TRUE case // if (trueLabel == null) { // codeStream.ifeq(falseLabel); // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // } // // /** // * Boolean generation for ^ // */ // public void generateOptimizedLogicalXor( // BlockScope currentScope, // CodeStream codeStream, // Label trueLabel, // Label falseLabel, // boolean valueRequired) { // // Constant condConst; // if ((left.implicitConversion & 0xF) == T_boolean) { // if ((condConst = left.optimizedBooleanConstant()) != NotAConstant) { // if (condConst.booleanValue() == true) { // // ^ x // left.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // right.generateOptimizedBoolean( // currentScope, // codeStream, // falseLabel, // trueLabel, // valueRequired); // } else { // // ^ x // left.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // if ((bits & OnlyValueRequiredMASK) != 0) { // right.generateCode(currentScope, codeStream, valueRequired); // } else { // right.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // } // } // return; // } // if ((condConst = right.optimizedBooleanConstant()) != NotAConstant) { // if (condConst.booleanValue() == true) { // // x ^ // left.generateOptimizedBoolean( // currentScope, // codeStream, // falseLabel, // trueLabel, // valueRequired); // right.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // } else { // // x ^ // if ((bits & OnlyValueRequiredMASK) != 0) { // left.generateCode(currentScope, codeStream, valueRequired); // } else { // left.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // valueRequired); // } // right.generateOptimizedBoolean( // currentScope, // codeStream, // trueLabel, // falseLabel, // false); // } // return; // } // } // // default case // left.generateCode(currentScope, codeStream, valueRequired); // right.generateCode(currentScope, codeStream, valueRequired); // if (valueRequired) { // codeStream.ixor(); // if ((bits & OnlyValueRequiredMASK) == 0) { // if (falseLabel == null) { // if (trueLabel != null) { // // implicit falling through the FALSE case // codeStream.ifne(trueLabel); // } // } else { // // implicit falling through the TRUE case // if (trueLabel == null) { // codeStream.ifeq(falseLabel); // } else { // // no implicit fall through TRUE/FALSE --> should never occur // } // } // } // } // // reposition the endPC // codeStream.updateLastRecordedEndPC(codeStream.position); // } // // public void generateOptimizedStringBuffer( // BlockScope blockScope, // CodeStream codeStream, // int typeID) { // // /* In the case trying to make a string concatenation, there is no need to // create a new // * string buffer, thus use a lower-level API for code generation involving // only the // * appending of arguments to the existing StringBuffer // */ // // if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) // && ((bits & ReturnTypeIDMASK) == T_String)) { // if (constant != NotAConstant) { // codeStream.generateConstant(constant, implicitConversion); // codeStream.invokeStringBufferAppendForType(implicitConversion & 0xF); // } else { // int pc = codeStream.position; // left.generateOptimizedStringBuffer( // blockScope, // codeStream, // left.implicitConversion & 0xF); // codeStream.recordPositionsFrom(pc, left.sourceStart); // pc = codeStream.position; // right.generateOptimizedStringBuffer( // blockScope, // codeStream, // right.implicitConversion & 0xF); // codeStream.recordPositionsFrom(pc, right.sourceStart); // } // } else { // super.generateOptimizedStringBuffer(blockScope, codeStream, typeID); // } // } // // public void generateOptimizedStringBufferCreation( // BlockScope blockScope, // CodeStream codeStream, // int typeID) { // // /* In the case trying to make a string concatenation, there is no need to // create a new // * string buffer, thus use a lower-level API for code generation involving // only the // * appending of arguments to the existing StringBuffer // */ // // if ((((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) // && ((bits & ReturnTypeIDMASK) == T_String)) { // if (constant != NotAConstant) { // codeStream.newStringBuffer(); // new: java.lang.StringBuffer // codeStream.dup(); // codeStream.ldc(constant.stringValue()); // codeStream.invokeStringBufferStringConstructor(); // // invokespecial: java.lang.StringBuffer.(Ljava.lang.String;)V // } else { // int pc = codeStream.position; // left.generateOptimizedStringBufferCreation( // blockScope, // codeStream, // left.implicitConversion & 0xF); // codeStream.recordPositionsFrom(pc, left.sourceStart); // pc = codeStream.position; // right.generateOptimizedStringBuffer( // blockScope, // codeStream, // right.implicitConversion & 0xF); // codeStream.recordPositionsFrom(pc, right.sourceStart); // } // } else { // super.generateOptimizedStringBufferCreation(blockScope, codeStream, // typeID); // } // } // // public boolean isCompactableOperation() { // // return true; // } // // public void optimizedBooleanConstant(int leftId, int operator, int // rightId) { // // switch (operator) { // case AND : // if ((leftId != T_boolean) || (rightId != T_boolean)) // return; // case AND_AND : // Constant cst; // if ((cst = left.optimizedBooleanConstant()) != NotAConstant) { // if (cst.booleanValue() == false) { // left is equivalent to false // optimizedBooleanConstant = cst; // constant(false) // return; // } else { //left is equivalent to true // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) { // optimizedBooleanConstant = cst; // // the conditional result is equivalent to the right conditional value // } // return; // } // } // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) { // if (cst.booleanValue() == false) { // right is equivalent to false // optimizedBooleanConstant = cst; // constant(false) // } // } // return; // case OR : // if ((leftId != T_boolean) || (rightId != T_boolean)) // return; // case OR_OR : // if ((cst = left.optimizedBooleanConstant()) != NotAConstant) { // if (cst.booleanValue() == true) { // left is equivalent to true // optimizedBooleanConstant = cst; // constant(true) // return; // } else { //left is equivalent to false // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) { // optimizedBooleanConstant = cst; // } // return; // } // } // if ((cst = right.optimizedBooleanConstant()) != NotAConstant) { // if (cst.booleanValue() == true) { // right is equivalent to true // optimizedBooleanConstant = cst; // constant(true) // } // } // } // } public StringBuffer printExpressionNoParenthesis(int indent, StringBuffer output) { left.printExpression(indent, output).append(' ').append( operatorToString()).append(' '); return right.printExpression(0, output); } public TypeBinding resolveType(BlockScope scope) { // use the id of the type to navigate into the table TypeBinding leftTb = left.resolveType(scope); TypeBinding rightTb = right.resolveType(scope); if (leftTb == null || rightTb == null) { constant = Constant.NotAConstant; return null; } int leftId = leftTb.id; int rightId = rightTb.id; if (leftId > 15 || rightId > 15) { // must convert String + Object || // Object + String if (leftId == T_String) { rightId = T_Object; } else if (rightId == T_String) { leftId = T_Object; } else { constant = Constant.NotAConstant; scope.problemReporter().invalidOperator(this, leftTb, rightTb); return null; } } if (((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) { if (leftId == T_String && rightTb.isArrayType() && ((ArrayBinding) rightTb).elementsType(scope) == CharBinding) scope .problemReporter() .signalNoImplicitStringConversionForCharArrayExpression( right); else if (rightId == T_String && leftTb.isArrayType() && ((ArrayBinding) leftTb).elementsType(scope) == CharBinding) scope .problemReporter() .signalNoImplicitStringConversionForCharArrayExpression( left); } // the code is an int // (cast) left Op (cast) rigth --> result // 0000 0000 0000 0000 0000 // <<16 <<12 <<8 <<4 <<0 // Don't test for result = 0. If it is zero, some more work is done. // On the one hand when it is not zero (correct code) we avoid doing the // test int result = ResolveTypeTables[(bits & OperatorMASK) >> OperatorSHIFT][(leftId << 4) + rightId]; left.implicitConversion = result >>> 12; right.implicitConversion = (result >>> 4) & 0x000FF; bits |= result & 0xF; switch (result & 0xF) { // record the current ReturnTypeID // only switch on possible result type..... case T_boolean: this.resolvedType = BooleanBinding; break; case T_byte: this.resolvedType = ByteBinding; break; case T_char: this.resolvedType = CharBinding; break; case T_double: this.resolvedType = DoubleBinding; break; case T_float: this.resolvedType = FloatBinding; break; case T_int: this.resolvedType = IntBinding; break; case T_long: this.resolvedType = LongBinding; break; case T_String: this.resolvedType = scope.getJavaLangString(); break; default: // error........ constant = Constant.NotAConstant; scope.problemReporter().invalidOperator(this, leftTb, rightTb); return null; } // compute the constant when valid computeConstant(scope, leftId, rightId); return this.resolvedType; } public String toStringExpressionNoParenthesis() { return left.toStringExpression() + " " + //$NON-NLS-1$ operatorToString() + " " + //$NON-NLS-1$ right.toStringExpression(); } public void traverse(ASTVisitor visitor, BlockScope scope) { if (visitor.visit(this, scope)) { left.traverse(visitor, scope); right.traverse(visitor, scope); } visitor.endVisit(this, scope); } }