KT-933 Optimized iteration over progressions.
#KT-933 fixed
This commit is contained in:
@@ -56,6 +56,7 @@ 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.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
@@ -484,6 +485,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
return StackValue.none();
|
||||
}
|
||||
|
||||
if (RangeCodegenUtil.isProgression(loopRangeType)) {
|
||||
generateForLoop(new ForInProgressionExpressionLoopGenerator(forExpression));
|
||||
return StackValue.none();
|
||||
}
|
||||
|
||||
generateForLoop(new IteratorForLoopGenerator(forExpression));
|
||||
return StackValue.none();
|
||||
}
|
||||
@@ -939,6 +945,140 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
}
|
||||
|
||||
private class ForInProgressionExpressionLoopGenerator extends AbstractForLoopGenerator {
|
||||
private int endVar;
|
||||
private int incrementVar;
|
||||
private Type incrementType;
|
||||
|
||||
private ForInProgressionExpressionLoopGenerator(@NotNull JetForExpression forExpression) {
|
||||
super(forExpression);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeLoop() {
|
||||
super.beforeLoop();
|
||||
|
||||
endVar = createLoopTempVariable(asmElementType);
|
||||
incrementVar = createLoopTempVariable(asmElementType);
|
||||
|
||||
JetType loopRangeType = bindingContext.get(EXPRESSION_TYPE, forExpression.getLoopRange());
|
||||
assert loopRangeType != null;
|
||||
Type asmLoopRangeType = asmType(loopRangeType);
|
||||
|
||||
Collection<VariableDescriptor> incrementProp = loopRangeType.getMemberScope().getProperties(Name.identifier("increment"));
|
||||
assert incrementProp.size() == 1 : loopRangeType + " " + incrementProp.size();
|
||||
incrementType = asmType(incrementProp.iterator().next().getType());
|
||||
|
||||
gen(forExpression.getLoopRange(), asmLoopRangeType);
|
||||
v.dup();
|
||||
v.dup();
|
||||
|
||||
generateRangeOrProgressionProperty(asmLoopRangeType, "getStart", asmElementType, loopParameterVar);
|
||||
generateRangeOrProgressionProperty(asmLoopRangeType, "getEnd", asmElementType, endVar);
|
||||
generateRangeOrProgressionProperty(asmLoopRangeType, "getIncrement", incrementType, incrementVar);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void conditionAndJump(@NotNull Label loopExit) {
|
||||
v.load(loopParameterVar, asmElementType);
|
||||
v.load(incrementVar, asmElementType);
|
||||
|
||||
Label negativeIncrement = new Label();
|
||||
Label afterIf = new Label();
|
||||
|
||||
int sort = asmElementType.getSort();
|
||||
switch (sort) {
|
||||
case Type.INT:
|
||||
case Type.CHAR:
|
||||
case Type.BYTE:
|
||||
case Type.SHORT:
|
||||
v.ifle(negativeIncrement); // if increment < 0, jump
|
||||
|
||||
// increment > 0
|
||||
v.load(endVar, asmElementType);
|
||||
v.ificmpgt(loopExit);
|
||||
v.goTo(afterIf);
|
||||
|
||||
// increment < 0
|
||||
v.visitLabel(negativeIncrement);
|
||||
v.load(endVar, asmElementType);
|
||||
v.ificmplt(loopExit);
|
||||
v.visitLabel(afterIf);
|
||||
|
||||
break;
|
||||
|
||||
case Type.LONG:
|
||||
v.lconst(0L);
|
||||
v.lcmp();
|
||||
v.ifle(negativeIncrement); // if increment < 0, jump
|
||||
|
||||
// increment > 0
|
||||
v.load(endVar, asmElementType);
|
||||
v.lcmp();
|
||||
v.ifgt(loopExit);
|
||||
v.goTo(afterIf);
|
||||
|
||||
// increment < 0
|
||||
v.visitLabel(negativeIncrement);
|
||||
v.load(endVar, asmElementType);
|
||||
v.lcmp();
|
||||
v.iflt(loopExit);
|
||||
v.visitLabel(afterIf);
|
||||
|
||||
break;
|
||||
|
||||
case Type.DOUBLE:
|
||||
case Type.FLOAT:
|
||||
if (sort == Type.DOUBLE) {
|
||||
v.dconst(0.0);
|
||||
}
|
||||
else {
|
||||
v.fconst(0.0f);
|
||||
}
|
||||
v.cmpl(incrementType);
|
||||
v.ifle(negativeIncrement); // if increment < 0, jump
|
||||
|
||||
// increment > 0
|
||||
v.load(endVar, asmElementType);
|
||||
v.cmpg(asmElementType); // if loop parameter is NaN, exit from loop, as well
|
||||
v.ifgt(loopExit);
|
||||
v.goTo(afterIf);
|
||||
|
||||
// increment < 0
|
||||
v.visitLabel(negativeIncrement);
|
||||
v.load(endVar, asmElementType);
|
||||
v.cmpl(asmElementType); // if loop parameter is NaN, exit from loop, as well
|
||||
v.iflt(loopExit);
|
||||
v.visitLabel(afterIf);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Unexpected range element type: " + asmElementType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void assignToLoopParameter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void increment() {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
v.store(loopParameterVar, asmElementType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public StackValue visitBreakExpression(JetBreakExpression expression, StackValue receiver) {
|
||||
JetSimpleNameExpression labelElement = expression.getTargetLabel();
|
||||
|
||||
@@ -34,13 +34,17 @@ import static org.jetbrains.jet.codegen.AsmUtil.isPrimitiveNumberClassDescriptor
|
||||
|
||||
public class RangeCodegenUtil {
|
||||
private static final ImmutableMap<FqName, PrimitiveType> RANGE_TO_ELEMENT_TYPE;
|
||||
private static final ImmutableMap<FqName, PrimitiveType> PROGRESSION_TO_ELEMENT_TYPE;
|
||||
|
||||
static {
|
||||
ImmutableMap.Builder<FqName, PrimitiveType> rangeBuilder = ImmutableMap.builder();
|
||||
ImmutableMap.Builder<FqName, PrimitiveType> progressionBuilder = ImmutableMap.builder();
|
||||
for (PrimitiveType primitiveType : PrimitiveType.values()) {
|
||||
rangeBuilder.put(primitiveType.getRangeClassName(), primitiveType);
|
||||
progressionBuilder.put(primitiveType.getProgressionClassName(), primitiveType);
|
||||
}
|
||||
RANGE_TO_ELEMENT_TYPE = rangeBuilder.build();
|
||||
PROGRESSION_TO_ELEMENT_TYPE = progressionBuilder.build();
|
||||
}
|
||||
|
||||
private RangeCodegenUtil() {}
|
||||
@@ -49,6 +53,10 @@ public class RangeCodegenUtil {
|
||||
return !rangeType.isNullable() && getPrimitiveRangeElementType(rangeType) != null;
|
||||
}
|
||||
|
||||
public static boolean isProgression(JetType rangeType) {
|
||||
return !rangeType.isNullable() && getPrimitiveProgressionElementType(rangeType) != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static BinaryCall getRangeAsBinaryCall(@NotNull JetForExpression forExpression) {
|
||||
// We are looking for rangeTo() calls
|
||||
@@ -90,6 +98,17 @@ public class RangeCodegenUtil {
|
||||
return RANGE_TO_ELEMENT_TYPE.get(DescriptorUtils.getFQName(declarationDescriptor).toSafe());
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PrimitiveType getPrimitiveProgressionElementType(JetType rangeType) {
|
||||
ClassifierDescriptor declarationDescriptor = rangeType.getConstructor().getDeclarationDescriptor();
|
||||
assert declarationDescriptor != null;
|
||||
if (declarationDescriptor != KotlinBuiltIns.getInstance().getBuiltInsScope().getClassifier(declarationDescriptor.getName())) {
|
||||
// Must be a standard library class
|
||||
return null;
|
||||
}
|
||||
return PROGRESSION_TO_ELEMENT_TYPE.get(DescriptorUtils.getFQName(declarationDescriptor).toSafe());
|
||||
}
|
||||
|
||||
public static boolean isOptimizableRangeTo(CallableDescriptor rangeTo) {
|
||||
if ("rangeTo".equals(rangeTo.getName().getName())) {
|
||||
if (isPrimitiveNumberClassDescriptor(rangeTo.getContainingDeclaration())) {
|
||||
|
||||
Reference in New Issue
Block a user