Fix loops over progressions near to MAX_VALUE/MIN_VALUE

#KT-492 Fixed

For Byte, Char and Short ranges, promote the type of the loop parameter to int
to avoid overflows. For Int and Long ranges at the end of the loop over a
progression we now check if the new (incremented) value of the loop parameter
is greater than the old value iff increment > 0
This commit is contained in:
Alexander Udalov
2013-06-18 19:41:38 +04:00
parent 33d6347876
commit ee80e0b8ca
25 changed files with 1148 additions and 36 deletions
@@ -47,9 +47,7 @@ import java.util.Set;
import static org.jetbrains.asm4.Opcodes.*;
import static org.jetbrains.jet.codegen.CodegenUtil.*;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isClassObject;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumEntry;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isKindOf;
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*;
import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.JAVA_STRING_TYPE;
public class AsmUtil {
@@ -642,4 +640,22 @@ public class AsmUtil {
return Type.INT_TYPE;
}
public static void pop(@NotNull InstructionAdapter v, @NotNull Type type) {
if (type.getSize() == 2) {
v.pop2();
}
else {
v.pop();
}
}
public static void dup(@NotNull InstructionAdapter v, @NotNull Type type) {
if (type.getSize() == 2) {
v.dup2();
}
else {
v.dup();
}
}
}
@@ -1108,20 +1108,69 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
@Override
protected void increment(@NotNull Label loopExit) {
v.load(loopParameterVar, asmElementType);
v.load(incrementVar, asmElementType);
v.add(asmElementType);
int sort = asmElementType.getSort();
if (sort == Type.CHAR || sort == Type.BYTE || sort == Type.SHORT) {
StackValue.coerce(Type.INT_TYPE, asmElementType, v);
if (sort == Type.INT || sort == Type.LONG) {
checkNewLoopParameterValue(loopExit);
}
v.store(loopParameterVar, asmElementType);
}
// Checks that (increment > 0) == (new value of loop parameter > old value of loop parameter).
// Old value should be stored in loopParameterVar, new value should be on top of the stack
private void checkNewLoopParameterValue(@NotNull Label loopExit) {
Label negativeIncrement = new Label();
Label afterIf = new Label();
Label popAndExit = new Label();
dup(v, asmElementType);
v.load(loopParameterVar, asmElementType);
v.load(incrementVar, asmElementType);
if (asmElementType.getSort() == Type.LONG) {
v.lconst(0L);
v.lcmp();
v.ifle(negativeIncrement);
// increment > 0
v.lcmp();
v.iflt(popAndExit);
v.goTo(afterIf);
// increment < 0
v.mark(negativeIncrement);
v.lcmp();
v.ifgt(popAndExit);
v.goTo(afterIf);
}
else {
v.ifle(negativeIncrement);
// increment > 0
v.ificmplt(popAndExit);
v.goTo(afterIf);
// increment < 0
v.mark(negativeIncrement);
v.ificmpgt(popAndExit);
v.goTo(afterIf);
}
// Pop the new value of loop parameter from the stack and exit the loop
v.mark(popAndExit);
pop(v, asmElementType);
v.goTo(loopExit);
v.mark(afterIf);
}
}
@Override
public StackValue visitBreakExpression(JetBreakExpression expression, StackValue receiver) {
JetSimpleNameExpression labelElement = expression.getTargetLabel();
@@ -3059,12 +3108,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
switch (value.receiverSize()) {
case 0:
if (type.getSize() == 2) {
v.dup2();
}
else {
v.dup();
}
dup(v, type);
break;
case 1:
@@ -30,7 +30,6 @@ import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
import org.jetbrains.jet.lang.resolve.java.JvmClassName;
import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
@@ -211,15 +210,6 @@ public abstract class StackValue {
}
}
private static void pop(Type type, InstructionAdapter v) {
if (type.getSize() == 1) {
v.pop();
}
else {
v.pop2();
}
}
protected void coerceTo(Type toType, InstructionAdapter v) {
coerce(this.type, toType, v);
}
@@ -232,7 +222,7 @@ public abstract class StackValue {
if (toType.equals(fromType)) return;
if (toType.getSort() == Type.VOID) {
pop(fromType, v);
pop(v, fromType);
}
else if (fromType.getSort() == Type.VOID) {
if (toType.equals(JET_UNIT_TYPE) || toType.equals(OBJECT_TYPE)) {
@@ -246,7 +236,7 @@ public abstract class StackValue {
}
}
else if (toType.equals(JET_UNIT_TYPE)) {
pop(fromType, v);
pop(v, fromType);
putUnitInstance(v);
}
else if (toType.getSort() == Type.ARRAY) {
@@ -646,7 +636,7 @@ public abstract class StackValue {
method.invokeWithNotNullAssertion(v, state, resolvedSetCall);
Type returnType = asmMethod.getReturnType();
if (returnType != Type.VOID_TYPE) {
pop(returnType, v);
pop(v, returnType);
}
}
else {