codeStream.invoke(Opcodes.OPC_invokestatic, this.syntheticAccessors[SingleNameReference.READ], null /* default declaringClass */);
}
}
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 :
codeStream.generateStringConcatenationAppend(currentScope, this, expression);
if (valueRequired) {
codeStream.dup();
}
codeStream.store(localBinding, false);
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(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, 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, codeStream, 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
codeStream.iinc(localBinding.resolvedPosition, increment);
if (valueRequired) {
codeStream.load(localBinding);
}
return;
case MINUS :
increment = -assignConstant.intValue();
if (increment != (short) increment) break; // not representable as a 16-bits value
codeStream.iinc(localBinding.resolvedPosition, increment);
if (valueRequired) {
codeStream.load(localBinding);
}
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(CodeStream.RESTART_CODE_GEN_FOR_UNUSED_LOCALS_MODE, 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, codeStream, false);
}
return;
}
codeStream.load(localBinding);
}
}
// perform the actual compound operation
int operationTypeID;
switch(operationTypeID = (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.
codeStream.generateStringConcatenationAppend(currentScope, null, expression);
// 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
if (this.genericCast != null)
codeStream.checkcast(this.genericCast);
codeStream.generateImplicitConversion(this.implicitConversion);
// generate the increment value (will by itself be promoted to the operation value)
if (expression == IntLiteral.One){ // prefix operation
codeStream.generateConstant(expression.constant, this.implicitConversion);
} else {
expression.generateCode(currentScope, codeStream, true);
}
// perform the operation
codeStream.sendOperator(operator, operationTypeID);
// cast the value back to the array reference type
codeStream.generateImplicitConversion(assignmentImplicitConversion);
}
// 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, codeStream, 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 :
codeStream.dup2();