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