X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=repo%2Forg.ibex.tool%2Fsrc%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2Fast%2FBinaryExpression.java;fp=repo%2Forg.ibex.tool%2Fsrc%2Forg%2Feclipse%2Fjdt%2Finternal%2Fcompiler%2Fast%2FBinaryExpression.java;h=b5804d03d186504d5ac124348ede5b5c1e1d74d3;hb=6f0cd02d46e011bd5599e1b7fefc6159cb811135;hp=0000000000000000000000000000000000000000;hpb=622d0e5a4b1b35b6918a516a79a0cc22272a919e;p=org.ibex.tool.git diff --git a/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java b/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java new file mode 100644 index 0000000..b5804d0 --- /dev/null +++ b/repo/org.ibex.tool/src/org/eclipse/jdt/internal/compiler/ast/BinaryExpression.java @@ -0,0 +1,1761 @@ +/******************************************************************************* + * Copyright (c) 2000, 2004 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 org.eclipse.jdt.internal.compiler.ast; + +import org.eclipse.jdt.internal.compiler.ASTVisitor; +import org.eclipse.jdt.internal.compiler.impl.*; +import org.eclipse.jdt.internal.compiler.codegen.*; +import org.eclipse.jdt.internal.compiler.flow.*; +import org.eclipse.jdt.internal.compiler.lookup.*; + +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); + Label internalTrueLabel = new Label(codeStream); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + falseLabel, + false); + internalTrueLabel.place(); + 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 & + Label internalTrueLabel = new Label(codeStream); + left.generateOptimizedBoolean( + currentScope, + codeStream, + internalTrueLabel, + falseLabel, + false); + internalTrueLabel.place(); + 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); + Label internalFalseLabel = new Label(codeStream); + right.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + internalFalseLabel, + false); + internalFalseLabel.place(); + 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 | + Label internalFalseLabel = new Label(codeStream); + left.generateOptimizedBoolean( + currentScope, + codeStream, + trueLabel, + internalFalseLabel, + false); + internalFalseLabel.place(); + 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) { + + boolean leftIsCast, rightIsCast; + if ((leftIsCast = left instanceof CastExpression) == true) left.bits |= IgnoreNeedForCastCheckMASK; // will check later on + TypeBinding leftType = left.resolveType(scope); + + if ((rightIsCast = right instanceof CastExpression) == true) right.bits |= IgnoreNeedForCastCheckMASK; // will check later on + TypeBinding rightType = right.resolveType(scope); + + // use the id of the type to navigate into the table + if (leftType == null || rightType == null) { + constant = Constant.NotAConstant; + return null; + } + int leftTypeId = leftType.id; + int rightTypeId = rightType.id; + if (leftTypeId > 15 + || rightTypeId > 15) { // must convert String + Object || Object + String + if (leftTypeId == T_String) { + rightTypeId = T_Object; + } else if (rightTypeId == T_String) { + leftTypeId = T_Object; + } else { + constant = Constant.NotAConstant; + scope.problemReporter().invalidOperator(this, leftType, rightType); + return null; + } + } + if (((bits & OperatorMASK) >> OperatorSHIFT) == PLUS) { + if (leftTypeId == T_String + && rightType.isArrayType() + && ((ArrayBinding) rightType).elementsType(scope) == CharBinding) { + scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(right); + } else if (rightTypeId == T_String + && leftType.isArrayType() + && ((ArrayBinding) leftType).elementsType(scope) == CharBinding) { + scope.problemReporter().signalNoImplicitStringConversionForCharArrayExpression(left); + } + } + + // the code is an int + // (cast) left Op (cast) right --> 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 operator = (bits & OperatorMASK) >> OperatorSHIFT; + int operatorSignature = OperatorSignatures[operator][(leftTypeId << 4) + rightTypeId]; + left.implicitConversion = operatorSignature >>> 12; + right.implicitConversion = (operatorSignature >>> 4) & 0x000FF; + + bits |= operatorSignature & 0xF; + switch (operatorSignature & 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, leftType, rightType); + return null; + } + + // check need for operand cast + if (leftIsCast || rightIsCast) { + CastExpression.checkNeedForArgumentCasts(scope, operator, operatorSignature, left, leftTypeId, leftIsCast, right, rightTypeId, rightIsCast); + } + // compute the constant when valid + computeConstant(scope, leftTypeId, rightTypeId); + return this.resolvedType; + } + + public void traverse(ASTVisitor visitor, BlockScope scope) { + + if (visitor.visit(this, scope)) { + left.traverse(visitor, scope); + right.traverse(visitor, scope); + } + visitor.endVisit(this, scope); + } +}