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:
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user