Support only integer primitive ranges and progressions in optimized for loop codegen.

Do not call getProgressionFinalElement, use new progression properties 'first' and 'last' instead.
This commit is contained in:
Ilya Gorbunov
2015-11-13 05:29:55 +03:00
parent 5d4e72ed7f
commit 96f301fdec
6 changed files with 44 additions and 113 deletions
@@ -743,6 +743,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
// This method consumes range/progression from stack // This method consumes range/progression from stack
// The result is stored to local variable // The result is stored to local variable
protected void generateRangeOrProgressionProperty(Type loopRangeType, String getterName, Type elementType, int varToStore) { protected void generateRangeOrProgressionProperty(Type loopRangeType, String getterName, Type elementType, int varToStore) {
v.invokevirtual(loopRangeType.getInternalName(), getterName, "()" + elementType.getDescriptor(), false);
v.store(varToStore, elementType);
}
protected void generateRangeOrProgressionBoxedProperty(Type loopRangeType, String getterName, Type elementType, int varToStore) {
Type boxedType = boxType(elementType); Type boxedType = boxType(elementType);
v.invokevirtual(loopRangeType.getInternalName(), getterName, "()" + boxedType.getDescriptor(), false); v.invokevirtual(loopRangeType.getInternalName(), getterName, "()" + boxedType.getDescriptor(), false);
StackValue.coerce(boxedType, elementType, v); StackValue.coerce(boxedType, elementType, v);
@@ -901,10 +906,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
private abstract class AbstractForInProgressionOrRangeLoopGenerator extends AbstractForLoopGenerator { private abstract class AbstractForInProgressionOrRangeLoopGenerator extends AbstractForLoopGenerator {
protected int endVar; protected int endVar;
// For integer progressions instead of comparing loopParameterVar with endVar at the beginning of an iteration we check whether
// loopParameterVar == finalVar at the end of the iteration (and also if there should be any iterations at all, before the loop)
protected final boolean isIntegerProgression;
private AbstractForInProgressionOrRangeLoopGenerator(@NotNull KtForExpression forExpression) { private AbstractForInProgressionOrRangeLoopGenerator(@NotNull KtForExpression forExpression) {
super(forExpression); super(forExpression);
@@ -914,12 +915,6 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
case Type.SHORT: case Type.SHORT:
case Type.CHAR: case Type.CHAR:
case Type.LONG: case Type.LONG:
isIntegerProgression = true;
break;
case Type.DOUBLE:
case Type.FLOAT:
isIntegerProgression = false;
break; break;
default: default:
@@ -934,17 +929,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
endVar = createLoopTempVariable(asmElementType); endVar = createLoopTempVariable(asmElementType);
} }
// Index of the local variable holding the actual last value of the loop parameter.
// For ranges it equals end, for progressions it's a function of start, end and increment
protected abstract int getFinalVar();
protected void checkPostCondition(@NotNull Label loopExit) { protected void checkPostCondition(@NotNull Label loopExit) {
int finalVar = getFinalVar(); assert endVar != -1 :
assert isIntegerProgression && finalVar != -1 : "endVar must be allocated, endVar = " + endVar;
"Post-condition should be checked only in case of integer progressions, finalVar = " + finalVar;
v.load(loopParameterVar, asmElementType); v.load(loopParameterVar, asmElementType);
v.load(finalVar, asmElementType); v.load(endVar, asmElementType);
if (asmElementType.getSort() == Type.LONG) { if (asmElementType.getSort() == Type.LONG) {
v.lcmp(); v.lcmp();
v.ifeq(loopExit); v.ifeq(loopExit);
@@ -953,6 +943,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
v.ificmpeq(loopExit); v.ificmpeq(loopExit);
} }
} }
@Override
public void checkPreCondition(@NotNull Label loopExit) {
}
} }
private abstract class AbstractForInRangeLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator { private abstract class AbstractForInRangeLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator {
@@ -969,25 +963,8 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
protected abstract void storeRangeStartAndEnd(); protected abstract void storeRangeStartAndEnd();
@Override
protected int getFinalVar() {
return endVar;
}
@Override
public void checkPreCondition(@NotNull Label loopExit) {
if (isIntegerProgression) return;
v.load(loopParameterVar, asmElementType);
v.load(endVar, asmElementType);
v.cmpg(asmElementType);
v.ifgt(loopExit);
}
@Override @Override
public void checkEmptyLoop(@NotNull Label loopExit) { public void checkEmptyLoop(@NotNull Label loopExit) {
if (!isIntegerProgression) return;
v.load(loopParameterVar, asmElementType); v.load(loopParameterVar, asmElementType);
v.load(endVar, asmElementType); v.load(endVar, asmElementType);
@@ -1006,9 +983,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
@Override @Override
protected void increment(@NotNull Label loopExit) { protected void increment(@NotNull Label loopExit) {
if (isIntegerProgression) { checkPostCondition(loopExit);
checkPostCondition(loopExit);
}
if (asmElementType == Type.INT_TYPE) { if (asmElementType == Type.INT_TYPE) {
v.iinc(loopParameterVar, 1); v.iinc(loopParameterVar, 1);
@@ -1055,8 +1030,9 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
gen(forExpression.getLoopRange(), asmLoopRangeType); gen(forExpression.getLoopRange(), asmLoopRangeType);
v.dup(); v.dup();
generateRangeOrProgressionProperty(asmLoopRangeType, "getStart", asmElementType, loopParameterVar); // ranges inherit first and last from corresponding progressions
generateRangeOrProgressionProperty(asmLoopRangeType, "getEnd", asmElementType, endVar); generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterVar);
generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, endVar);
} }
} }
@@ -1064,17 +1040,10 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
private int incrementVar; private int incrementVar;
private Type incrementType; private Type incrementType;
private int finalVar;
private ForInProgressionExpressionLoopGenerator(@NotNull KtForExpression forExpression) { private ForInProgressionExpressionLoopGenerator(@NotNull KtForExpression forExpression) {
super(forExpression); super(forExpression);
} }
@Override
protected int getFinalVar() {
return finalVar;
}
@Override @Override
public void beforeLoop() { public void beforeLoop() {
super.beforeLoop(); super.beforeLoop();
@@ -1094,66 +1063,13 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
v.dup(); v.dup();
v.dup(); v.dup();
generateRangeOrProgressionProperty(asmLoopRangeType, "getStart", asmElementType, loopParameterVar); generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterVar);
generateRangeOrProgressionProperty(asmLoopRangeType, "getEnd", asmElementType, endVar); generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, endVar);
generateRangeOrProgressionProperty(asmLoopRangeType, "getIncrement", incrementType, incrementVar); generateRangeOrProgressionBoxedProperty(asmLoopRangeType, "getIncrement", incrementType, incrementVar);
storeFinalVar();
}
private void storeFinalVar() {
if (!isIntegerProgression) {
finalVar = -1;
return;
}
v.load(loopParameterVar, asmElementType);
v.load(endVar, asmElementType);
v.load(incrementVar, incrementType);
Type methodParamType = asmElementType.getSort() == Type.LONG ? Type.LONG_TYPE : Type.INT_TYPE;
v.invokestatic("kotlin/internal/ProgressionUtilKt", "getProgressionFinalElement",
Type.getMethodDescriptor(methodParamType, methodParamType, methodParamType, methodParamType), false);
finalVar = createLoopTempVariable(asmElementType);
v.store(finalVar, asmElementType);
}
@Override
public void checkPreCondition(@NotNull Label loopExit) {
if (isIntegerProgression) return;
v.load(loopParameterVar, asmElementType);
v.load(endVar, asmElementType);
v.load(incrementVar, incrementType);
Label negativeIncrement = new Label();
Label afterIf = new Label();
if (incrementType.getSort() == Type.DOUBLE) {
v.dconst(0.0);
}
else {
v.fconst(0.0f);
}
v.cmpl(incrementType);
v.ifle(negativeIncrement); // if increment < 0, jump
// increment > 0
v.cmpg(asmElementType); // if loop parameter is NaN, exit from loop, as well
v.ifgt(loopExit);
v.goTo(afterIf);
// increment < 0
v.mark(negativeIncrement);
v.cmpl(asmElementType); // if loop parameter is NaN, exit from loop, as well
v.iflt(loopExit);
v.mark(afterIf);
} }
@Override @Override
public void checkEmptyLoop(@NotNull Label loopExit) { public void checkEmptyLoop(@NotNull Label loopExit) {
if (!isIntegerProgression) return;
v.load(loopParameterVar, asmElementType); v.load(loopParameterVar, asmElementType);
v.load(endVar, asmElementType); v.load(endVar, asmElementType);
@@ -1198,9 +1114,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
@Override @Override
protected void increment(@NotNull Label loopExit) { protected void increment(@NotNull Label loopExit) {
if (isIntegerProgression) { checkPostCondition(loopExit);
checkPostCondition(loopExit);
}
v.load(loopParameterVar, asmElementType); v.load(loopParameterVar, asmElementType);
v.load(incrementVar, asmElementType); v.load(incrementVar, asmElementType);
@@ -38,10 +38,21 @@ public class RangeCodegenUtil {
private static final ImmutableMap<FqName, PrimitiveType> RANGE_TO_ELEMENT_TYPE; private static final ImmutableMap<FqName, PrimitiveType> RANGE_TO_ELEMENT_TYPE;
private static final ImmutableMap<FqName, PrimitiveType> PROGRESSION_TO_ELEMENT_TYPE; private static final ImmutableMap<FqName, PrimitiveType> PROGRESSION_TO_ELEMENT_TYPE;
private static PrimitiveType[] supportedRangeTypes() {
return new PrimitiveType[] {
PrimitiveType.CHAR,
PrimitiveType.INT,
PrimitiveType.LONG,
// deprecated:
PrimitiveType.BYTE,
PrimitiveType.SHORT,
};
}
static { static {
ImmutableMap.Builder<FqName, PrimitiveType> rangeBuilder = ImmutableMap.builder(); ImmutableMap.Builder<FqName, PrimitiveType> rangeBuilder = ImmutableMap.builder();
ImmutableMap.Builder<FqName, PrimitiveType> progressionBuilder = ImmutableMap.builder(); ImmutableMap.Builder<FqName, PrimitiveType> progressionBuilder = ImmutableMap.builder();
for (PrimitiveType primitiveType : PrimitiveType.values()) { for (PrimitiveType primitiveType : supportedRangeTypes()) {
FqName rangeClassFqName = BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier(primitiveType.getTypeName() + "Range")); FqName rangeClassFqName = BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier(primitiveType.getTypeName() + "Range"));
FqName progressionClassFqName = BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier(primitiveType.getTypeName() + "Progression")); FqName progressionClassFqName = BUILT_INS_PACKAGE_FQ_NAME.child(Name.identifier(primitiveType.getTypeName() + "Progression"));
rangeBuilder.put(rangeClassFqName, primitiveType); rangeBuilder.put(rangeClassFqName, primitiveType);
@@ -5,4 +5,6 @@ fun f() {
// 0 iterator // 0 iterator
// 0 getStart // 0 getStart
// 0 getEnd // 0 getEnd
// 0 getFirst
// 0 getLast
@@ -5,4 +5,6 @@ fun f(a: Int, b: Int) {
// 0 iterator // 0 iterator
// 0 getStart // 0 getStart
// 0 getEnd // 0 getEnd
// 0 getFirst
// 0 getLast
@@ -6,6 +6,6 @@ fun f() {
} }
// 0 iterator // 0 iterator
// 2 getStart // 2 getFirst
// 2 getEnd // 2 getLast
// 2 getIncrement // 2 getIncrement
@@ -4,5 +4,7 @@ fun f(r: IntRange) {
} }
// 0 iterator // 0 iterator
// 1 getStart // 0 getStart
// 1 getEnd // 0 getEnd
// 1 getFirst
// 1 getLast