Don't use 'iinc' instruction on byte/short/char variables

Android run-time verifier complains when there's any possibility that a
byte/short/char local variable could contain a value not fitting into the
type's limits.
This commit is contained in:
Alexander Udalov
2013-06-25 18:11:17 +04:00
parent db41329e67
commit 356c32893b
5 changed files with 112 additions and 82 deletions
@@ -433,25 +433,23 @@ public class AsmUtil {
}
}
public static Type genIncrement(Type expectedType, int myDelta, InstructionAdapter v) {
public static void genIncrement(Type expectedType, int myDelta, InstructionAdapter v) {
if (expectedType == Type.LONG_TYPE) {
//noinspection UnnecessaryBoxing
v.lconst(myDelta);
}
else if (expectedType == Type.FLOAT_TYPE) {
//noinspection UnnecessaryBoxing
v.fconst(myDelta);
}
else if (expectedType == Type.DOUBLE_TYPE) {
//noinspection UnnecessaryBoxing
v.dconst(myDelta);
}
else {
v.iconst(myDelta);
expectedType = Type.INT_TYPE;
v.add(Type.INT_TYPE);
StackValue.coerce(Type.INT_TYPE, expectedType, v);
return;
}
v.add(expectedType);
return expectedType;
}
public static Type genNegate(Type expectedType, InstructionAdapter v) {
@@ -3057,89 +3057,92 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
v.mark(ok);
return StackValue.onStack(base.type);
}
DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
if (op instanceof FunctionDescriptor) {
Type asmType = expressionType(expression);
DeclarationDescriptor cls = op.getContainingDeclaration();
if (op.getName().asString().equals("inc") || op.getName().asString().equals("dec")) {
if (isPrimitiveNumberClassDescriptor(cls)) {
receiver.put(receiver.type, v);
JetExpression operand = expression.getBaseExpression();
if (operand instanceof JetReferenceExpression) {
int index = indexOfLocal((JetReferenceExpression) operand);
if (index >= 0 && isIntPrimitive(asmType)) {
int increment = op.getName().asString().equals("inc") ? 1 : -1;
return StackValue.postIncrement(index, increment);
}
}
gen(operand, asmType); // old value
generateIncrement(op, asmType, operand, receiver); // increment in-place
return StackValue.onStack(asmType); // old value
}
else {
ResolvedCall<? extends CallableDescriptor> resolvedCall =
bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
assert resolvedCall != null;
if (!(op instanceof FunctionDescriptor)) {
throw new UnsupportedOperationException("Don't know how to generate this postfix expression: " + op);
}
Callable callable = resolveToCallable((FunctionDescriptor) op, false);
Type asmType = expressionType(expression);
DeclarationDescriptor cls = op.getContainingDeclaration();
StackValue value = gen(expression.getBaseExpression());
value.dupReceiver(v);
int increment;
if (op.getName().asString().equals("inc")) {
increment = 1;
}
else if (op.getName().asString().equals("dec")) {
increment = -1;
}
else {
throw new UnsupportedOperationException("Unsupported postfix operation: " + op);
}
Type type = expressionType(expression.getBaseExpression());
value.put(type, v);
switch (value.receiverSize()) {
case 0:
dup(v, type);
break;
case 1:
if (type.getSize() == 2) {
v.dup2X1();
}
else {
v.dupX1();
}
break;
case 2:
if (type.getSize() == 2) {
v.dup2X2();
}
else {
v.dupX2();
}
break;
case -1:
throw new UnsupportedOperationException();
}
CallableMethod callableMethod = (CallableMethod) callable;
callableMethod.invokeWithNotNullAssertion(v, state, resolvedCall);
value.store(callableMethod.getReturnType(), v);
return StackValue.onStack(type);
if (isPrimitiveNumberClassDescriptor(cls)) {
receiver.put(receiver.type, v);
JetExpression operand = expression.getBaseExpression();
if (operand instanceof JetReferenceExpression && asmType == Type.INT_TYPE) {
int index = indexOfLocal((JetReferenceExpression) operand);
if (index >= 0) {
return StackValue.postIncrement(index, increment);
}
}
gen(operand, asmType); // old value
generateIncrement(increment, asmType, operand, receiver); // increment in-place
return StackValue.onStack(asmType); // old value
}
else {
ResolvedCall<? extends CallableDescriptor> resolvedCall =
bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
assert resolvedCall != null;
Callable callable = resolveToCallable((FunctionDescriptor) op, false);
StackValue value = gen(expression.getBaseExpression());
value.dupReceiver(v);
Type type = expressionType(expression.getBaseExpression());
value.put(type, v);
switch (value.receiverSize()) {
case 0:
dup(v, type);
break;
case 1:
if (type.getSize() == 2) {
v.dup2X1();
}
else {
v.dupX1();
}
break;
case 2:
if (type.getSize() == 2) {
v.dup2X2();
}
else {
v.dupX2();
}
break;
case -1:
throw new UnsupportedOperationException();
}
CallableMethod callableMethod = (CallableMethod) callable;
callableMethod.invokeWithNotNullAssertion(v, state, resolvedCall);
value.store(callableMethod.getReturnType(), v);
return StackValue.onStack(type);
}
throw new UnsupportedOperationException("Don't know how to generate this postfix expression");
}
private void generateIncrement(DeclarationDescriptor op, Type asmType, JetExpression operand, StackValue receiver) {
int increment = op.getName().asString().equals("inc") ? 1 : -1;
if (operand instanceof JetReferenceExpression) {
int index = indexOfLocal((JetReferenceExpression) operand);
if (index >= 0 && isIntPrimitive(asmType)) {
v.iinc(index, increment);
return;
}
}
private void generateIncrement(int increment, Type asmType, JetExpression operand, StackValue receiver) {
StackValue value = genQualified(receiver, operand);
value.dupReceiver(v);
value.put(asmType, v);
asmType = genIncrement(asmType, increment, v);
genIncrement(asmType, increment, v);
value.store(asmType, v);
}
@@ -29,7 +29,8 @@ import org.jetbrains.jet.lang.psi.JetReferenceExpression;
import java.util.List;
import static org.jetbrains.jet.codegen.AsmUtil.*;
import static org.jetbrains.jet.codegen.AsmUtil.genIncrement;
import static org.jetbrains.jet.codegen.AsmUtil.unboxType;
public class Increment implements IntrinsicMethod {
private final int myDelta;
@@ -57,9 +58,9 @@ public class Increment implements IntrinsicMethod {
while (operand instanceof JetParenthesizedExpression) {
operand = ((JetParenthesizedExpression) operand).getExpression();
}
if (operand instanceof JetReferenceExpression) {
if (operand instanceof JetReferenceExpression && expectedType == Type.INT_TYPE) {
int index = codegen.indexOfLocal((JetReferenceExpression) operand);
if (index >= 0 && isIntPrimitive(expectedType)) {
if (index >= 0) {
return StackValue.preIncrement(index, myDelta);
}
}
@@ -68,12 +69,13 @@ public class Increment implements IntrinsicMethod {
value.dupReceiver(v);
value.put(expectedType, v);
value.store(genIncrement(expectedType, myDelta, v), v);
genIncrement(expectedType, myDelta, v);
value.store(expectedType, v);
value.put(expectedType, v);
}
else {
receiver.put(expectedType, v);
StackValue.coerce(genIncrement(expectedType, myDelta, v), expectedType, v);
genIncrement(expectedType, myDelta, v);
}
return StackValue.onStack(expectedType);
}
@@ -0,0 +1,22 @@
fun byteArg(b: Byte) {}
fun charArg(c: Char) {}
fun shortArg(s: Short) {}
fun box(): String {
var b = 42.toByte()
b++
++b
byteArg(b)
var c = 'x'
c++
++c
charArg(c)
var s = 239.toShort()
s++
++s
shortArg(s)
return "OK"
}
@@ -3339,6 +3339,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest("compiler/testData/codegen/box/primitiveTypes/ea35963.kt");
}
@TestMetadata("incrementByteCharShort.kt")
public void testIncrementByteCharShort() throws Exception {
doTest("compiler/testData/codegen/box/primitiveTypes/incrementByteCharShort.kt");
}
@TestMetadata("intLiteralIsNotNull.kt")
public void testIntLiteralIsNotNull() throws Exception {
doTest("compiler/testData/codegen/box/primitiveTypes/intLiteralIsNotNull.kt");