Do not cast arguments of binary operation to expected type for byte and short

This commit is contained in:
Natalia Ukhorskaya
2013-12-09 16:50:12 +04:00
parent 8b9fbdf911
commit 69ed9bc47a
24 changed files with 351 additions and 52 deletions
@@ -631,6 +631,14 @@ public class AsmUtil {
return Type.INT_TYPE;
}
@NotNull
public static Type numberFunctionOperandType(@NotNull Type expectedType) {
if (expectedType == Type.SHORT_TYPE || expectedType == Type.BYTE_TYPE) {
return Type.INT_TYPE;
}
return expectedType;
}
public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) {
if (type.getSize() == 2) {
v.pop2();
@@ -36,7 +36,7 @@ import org.jetbrains.jet.codegen.binding.CalculatedClosure;
import org.jetbrains.jet.codegen.binding.CodegenBinding;
import org.jetbrains.jet.codegen.binding.MutableClosure;
import org.jetbrains.jet.codegen.context.*;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod;
import org.jetbrains.jet.codegen.intrinsics.*;
import org.jetbrains.jet.codegen.signature.JvmMethodSignature;
import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapper;
@@ -1652,8 +1652,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(memberDescriptor);
if (intrinsic != null) {
Type expectedType = expressionType(expression);
return intrinsic.generate(this, v, expectedType, expression, Collections.<JetExpression>emptyList(), receiver, state);
Type returnType = typeMapper.mapType(memberDescriptor.getReturnType());
return intrinsic.generate(this, v, returnType, expression, Collections.<JetExpression>emptyList(), receiver, state);
}
}
@@ -2030,14 +2030,12 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
for (ValueArgument argument : call.getValueArguments()) {
args.add(argument.getArgumentExpression());
}
JetType type = resolvedCall.getResultingDescriptor().getReturnType();
assert type != null;
Type callType = typeMapper.mapType(type);
Type exprType = asmTypeOrVoid(type);
StackValue stackValue = intrinsic.generate(this, v, callType, call.getCallElement(), args, receiver, state);
stackValue.put(exprType, v);
return StackValue.onStack(exprType);
Type returnType = typeMapper.mapType(resolvedCall.getResultingDescriptor().getReturnType());
StackValue stackValue = intrinsic.generate(this, v, returnType, call.getCallElement(), args, receiver, state);
stackValue.put(returnType, v);
return StackValue.onStack(returnType);
}
}
@@ -2682,7 +2680,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
Callable callable = resolveToCallable((FunctionDescriptor) op, false);
if (callable instanceof IntrinsicMethod) {
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
return intrinsic.generate(this, v, expressionType(expression), expression,
Type returnType = typeMapper.mapType(resolvedCall.getResultingDescriptor().getReturnType());
return intrinsic.generate(this, v, returnType, expression,
Arrays.asList(expression.getLeft(), expression.getRight()), receiver, state);
}
else {
@@ -2929,10 +2928,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
//noinspection NullableProblems
JetExpression right = expression.getRight();
assert right != null;
StackValue stackValue = intrinsic.generate(this, v, lhsType, expression,
Type returnType = typeMapper.mapType(((FunctionDescriptor) op).getReturnType());
StackValue stackValue = intrinsic.generate(this, v, returnType, expression,
Arrays.asList(right),
StackValue.onStack(lhsType), state);
value.store(stackValue.type, v);
value.store(lhsType, v);
}
else {
callAugAssignMethod(expression, (CallableMethod) callable, lhsType, true);
@@ -3018,7 +3018,8 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
if (callable instanceof IntrinsicMethod) {
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
//noinspection ConstantConditions
return intrinsic.generate(this, v, expressionType(expression), expression,
Type returnType = typeMapper.mapType(((FunctionDescriptor) op).getReturnType());
return intrinsic.generate(this, v, returnType, expression,
Arrays.asList(expression.getBaseExpression()), receiver, state);
}
else {
@@ -3589,7 +3590,7 @@ The "returned" value of try expression with no finally is either the last expres
DeclarationDescriptor descriptor = rightType.getConstructor().getDeclarationDescriptor();
if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) {
StackValue value = genQualified(receiver, left);
value.put(boxType(value.type), v);
value.put(boxType(rightTypeAsm), v);
if (opToken != JetTokens.AS_SAFE) {
if (!CodegenUtil.isNullableType(rightType)) {
@@ -40,6 +40,11 @@ import static org.jetbrains.jet.codegen.AsmUtil.*;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*;
public abstract class StackValue {
private static final String NULLABLE_BYTE_TYPE_NAME = "java/lang/Byte";
private static final String NULLABLE_SHORT_TYPE_NAME = "java/lang/Short";
private static final String NULLABLE_LONG_TYPE_NAME = "java/lang/Long";
@NotNull
public final Type type;
@@ -154,8 +159,17 @@ public abstract class StackValue {
}
private static void box(Type type, Type toType, InstructionAdapter v) {
// TODO handle toType correctly
if (type == Type.INT_TYPE || (isIntPrimitive(type) && toType.getInternalName().equals("java/lang/Integer"))) {
if (type == Type.BYTE_TYPE || toType.getInternalName().equals(NULLABLE_BYTE_TYPE_NAME) && type == Type.INT_TYPE) {
v.invokestatic(NULLABLE_BYTE_TYPE_NAME, "valueOf", "(B)L" + NULLABLE_BYTE_TYPE_NAME + ";");
}
else if (type == Type.SHORT_TYPE || toType.getInternalName().equals(NULLABLE_SHORT_TYPE_NAME) && type == Type.INT_TYPE) {
v.invokestatic(NULLABLE_SHORT_TYPE_NAME, "valueOf", "(S)L" + NULLABLE_SHORT_TYPE_NAME + ";");
}
else if (toType.getInternalName().equals(NULLABLE_LONG_TYPE_NAME) && type == Type.INT_TYPE) {
v.cast(type, Type.LONG_TYPE);
v.invokestatic(NULLABLE_LONG_TYPE_NAME, "valueOf", "(J)L" + NULLABLE_LONG_TYPE_NAME +";");
}
else if (type == Type.INT_TYPE) {
v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
}
else if (type == Type.BOOLEAN_TYPE) {
@@ -164,15 +178,9 @@ public abstract class StackValue {
else if (type == Type.CHAR_TYPE) {
v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
}
else if (type == Type.SHORT_TYPE) {
v.invokestatic("java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
}
else if (type == Type.LONG_TYPE) {
v.invokestatic("java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
}
else if (type == Type.BYTE_TYPE) {
v.invokestatic("java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
}
else if (type == Type.FLOAT_TYPE) {
v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
}
@@ -29,6 +29,7 @@ import java.util.List;
import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.AsmUtil.boxType;
import static org.jetbrains.jet.codegen.AsmUtil.numberFunctionOperandType;
import static org.jetbrains.jet.codegen.AsmUtil.unboxType;
public class BinaryOp implements IntrinsicMethod {
@@ -48,26 +49,25 @@ public class BinaryOp implements IntrinsicMethod {
StackValue receiver,
@NotNull GenerationState state
) {
boolean nullable = expectedType.getSort() == Type.OBJECT;
if (nullable) {
expectedType = unboxType(expectedType);
}
assert !nullable : "Return type of BinaryOp intrinsic should be of primitive type : " + expectedType;
Type operandType = numberFunctionOperandType(expectedType);
if (arguments.size() == 1) {
// Intrinsic is called as an ordinary function
if (receiver != null) {
receiver.put(expectedType, v);
receiver.put(operandType, v);
}
codegen.gen(arguments.get(0), shift() ? Type.INT_TYPE : expectedType);
codegen.gen(arguments.get(0), shift() ? Type.INT_TYPE : operandType);
}
else {
codegen.gen(arguments.get(0), expectedType);
codegen.gen(arguments.get(1), shift() ? Type.INT_TYPE : expectedType);
codegen.gen(arguments.get(0), operandType);
codegen.gen(arguments.get(1), shift() ? Type.INT_TYPE : operandType);
}
v.visitInsn(expectedType.getOpcode(opcode));
if (nullable) {
StackValue.onStack(expectedType).put(expectedType = boxType(expectedType), v);
}
return StackValue.onStack(expectedType);
}
@@ -50,9 +50,8 @@ public class Increment implements IntrinsicMethod {
@NotNull GenerationState state
) {
boolean nullable = expectedType.getSort() == Type.OBJECT;
if (nullable) {
expectedType = unboxType(expectedType);
}
assert !nullable : "Return type of Increment intrinsic should be of primitive type : " + expectedType;
if (arguments.size() > 0) {
JetExpression operand = arguments.get(0);
while (operand instanceof JetParenthesizedExpression) {
@@ -27,6 +27,7 @@ import org.jetbrains.jet.lang.psi.JetExpression;
import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.numberFunctionOperandType;
import static org.jetbrains.jet.codegen.AsmUtil.unboxType;
public class Inv implements IntrinsicMethod {
@@ -41,10 +42,9 @@ public class Inv implements IntrinsicMethod {
@NotNull GenerationState state
) {
boolean nullable = expectedType.getSort() == Type.OBJECT;
if (nullable) {
expectedType = unboxType(expectedType);
}
receiver.put(expectedType, v);
assert !nullable : "Return type of Inv intrinsic should be of primitive type : " + expectedType;
receiver.put(numberFunctionOperandType(expectedType), v);
if (expectedType == Type.LONG_TYPE) {
v.lconst(-1L);
}
@@ -28,6 +28,7 @@ import org.jetbrains.jet.lang.psi.JetExpression;
import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.genNegate;
import static org.jetbrains.jet.codegen.AsmUtil.numberFunctionOperandType;
import static org.jetbrains.jet.codegen.AsmUtil.unboxType;
public class UnaryMinus implements IntrinsicMethod {
@@ -42,16 +43,16 @@ public class UnaryMinus implements IntrinsicMethod {
@NotNull GenerationState state
) {
boolean nullable = expectedType.getSort() == Type.OBJECT;
if (nullable) {
expectedType = unboxType(expectedType);
}
assert !nullable : "Return type of UnaryMinus intrinsic should be of primitive type : " + expectedType;
Type operandType = numberFunctionOperandType(expectedType);
if (arguments.size() == 1) {
codegen.gen(arguments.get(0), expectedType);
codegen.gen(arguments.get(0), operandType);
}
else {
receiver.put(expectedType, v);
receiver.put(operandType, v);
}
StackValue.coerce(genNegate(expectedType, v), expectedType, v);
return StackValue.onStack(expectedType);
return StackValue.onStack(genNegate(expectedType, v));
}
}
@@ -42,9 +42,8 @@ public class UnaryPlus implements IntrinsicMethod {
@NotNull GenerationState state
) {
boolean nullable = expectedType.getSort() == Type.OBJECT;
if (nullable) {
expectedType = unboxType(expectedType);
}
assert !nullable : "Return type of UnaryPlus intrinsic should be of primitive type : " + expectedType;
if (receiver != null && receiver != StackValue.none()) {
receiver.put(expectedType, v);
}