/* * The APIs with an extra argument is used whenever there are two references to the same variable which * are optimized in one access: e.g "a = a + 1" optimized into "a++". */ public void generateCompoundAssignment( BlockScope currentScope, MethodBinding writeAccessor, Expression expression, int operator, int assignmentImplicitConversion, boolean valueRequired) { switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.FIELD: // assigning to a field break; case Binding.LOCAL: // assigning to a local variable (cannot assign to outer local) LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; // using incr bytecode if possible Constant assignConstant; switch (localBinding.type.id) { case T_JavaLangString: return; case T_int: assignConstant = expression.constant; if (localBinding.resolvedPosition == -1) { if (valueRequired) { /* * restart code gen because we either: * - need the value * - the constant can have potential side-effect */ localBinding.useFlag = LocalVariableBinding.USED; throw new AbortMethod(null, null); } else if (assignConstant == Constant.NotAConstant) { // we only need to generate the value of the expression's constant if it is not a // constant expression expression.generateCode(currentScope, false); } return; } if ((assignConstant != Constant.NotAConstant) && (assignConstant.typeID() != TypeIds.T_float) // only for integral types && (assignConstant.typeID() != TypeIds.T_double)) { // TODO (philippe) is this test needed ? switch (operator) { case PLUS: int increment = assignConstant.intValue(); if (increment != (short) increment) break; // not representable as a 16-bits value return; case MINUS: increment = -assignConstant.intValue(); if (increment != (short) increment) break; // not representable as a 16-bits value return; } } // $FALL-THROUGH$ default: if (localBinding.resolvedPosition == -1) { assignConstant = expression.constant; if (valueRequired) { /* * restart code gen because we either: * - need the value * - the constant can have potential side-effect */ localBinding.useFlag = LocalVariableBinding.USED; throw new AbortMethod(null, null); } else if (assignConstant == Constant.NotAConstant) { // we only need to generate the value of the expression's constant if it is not a // constant expression expression.generateCode(currentScope, false); } return; } } } switch ((this.implicitConversion & TypeIds.IMPLICIT_CONVERSION_MASK) >> 4) { case T_JavaLangString: case T_JavaLangObject: case T_undefined: // we enter here if the single name reference is a field of type java.lang.String or if the // type of the // operation is java.lang.Object // For example: o = o + ""; // where the compiled type of o is java.lang.Object. // no need for generic cast on previous #getfield since using Object string buffer methods. break; default: // promote the array reference to the suitable operation type // generate the increment value (will by itself be promoted to the operation value) if (expression != IntLiteral.One) { // prefix operation expression.generateCode(currentScope, true); } } // store the result back into the variable switch (this.bits & ASTNode.RestrictiveFlagMASK) { case Binding.FIELD: // assigning to a field FieldBinding codegenField = ((FieldBinding) this.binding).original(); fieldStore( currentScope, codegenField, writeAccessor, this.actualReceiverType, true /* implicit this*/, valueRequired); // no need for generic cast as value got dupped return; case Binding.LOCAL: // assigning to a local variable LocalVariableBinding localBinding = (LocalVariableBinding) this.binding; if (valueRequired) { switch (localBinding.type.id) { case TypeIds.T_long: case TypeIds.T_double: break; default: break; } } } }