KT-6916: do not create Progression instances in for-in-downTo loops

This commit is contained in:
Dmitry Petrov
2016-07-01 12:26:20 +03:00
parent e187f799d9
commit bf4f26318e
10 changed files with 183 additions and 10 deletions
@@ -635,12 +635,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
if (RangeCodegenUtil.isOptimizableRangeTo(loopRangeCallee)) {
ReceiverValue from = loopRangeCall.getDispatchReceiver();
assert from != null : "Dispatch receiver should be non-null for optimizable 'rangeTo' call";
List<ResolvedValueArgument> valueArgumentsByIndex = loopRangeCall.getValueArgumentsByIndex();
assert valueArgumentsByIndex != null : "Value arguments should be non-null for optimizable 'rangeTo' call";
KtExpression to = valueArgumentsByIndex.get(0).getArguments().get(0).getArgumentExpression();
assert to != null : "1st value argument should be non-null for optimizable 'rangeTo' call";
KtExpression to = getSingleArgumentExpression(loopRangeCall);
assert to != null : "Optimizable 'rangeTo' call should have a single expression argument";
return new ForInRangeLiteralLoopGenerator(forExpression, from, to);
}
else if (RangeCodegenUtil.isOptimizableDownTo(loopRangeCallee)) {
ReceiverValue from = loopRangeCall.getExtensionReceiver();
assert from != null : "Extension receiver should be non-null for optimizable 'downTo' call";
KtExpression to = getSingleArgumentExpression(loopRangeCall);
assert to != null : "Optimizable 'downTo' call should have a single expression argument";
return new ForInDownToProgressionLoopGenerator(forExpression, from, to);
}
else if (RangeCodegenUtil.isArrayOrPrimitiveArrayIndices(loopRangeCallee)) {
ReceiverValue extensionReceiver = loopRangeCall.getExtensionReceiver();
assert extensionReceiver != null : "Extension receiver should be non-null for optimizable 'Array.indices' call";
@@ -655,6 +660,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
return null;
}
@Nullable
private static KtExpression getSingleArgumentExpression(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
List<ResolvedValueArgument> resolvedValueArguments = resolvedCall.getValueArgumentsByIndex();
if (resolvedValueArguments == null) return null;
if (resolvedValueArguments.size() != 1) return null;
List<ValueArgument> valueArguments = resolvedValueArguments.get(0).getArguments();
if (valueArguments.size() != 1) return null;
return valueArguments.get(0).getArgumentExpression();
}
private OwnerKind contextKind() {
return context.getContextKind();
}
@@ -1044,8 +1059,16 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
private abstract class AbstractForInRangeLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator {
private AbstractForInRangeLoopGenerator(@NotNull KtForExpression forExpression) {
private final int step;
private AbstractForInRangeLoopGenerator(@NotNull KtForExpression forExpression, int step) {
super(forExpression);
this.step = step;
assert step == 1 || step == -1 : "'step' should be either 1 or -1: " + step;
}
private AbstractForInRangeLoopGenerator(@NotNull KtForExpression forExpression) {
this(forExpression, 1);
}
@Override
@@ -1063,10 +1086,20 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
v.load(endVar, asmElementType);
if (asmElementType.getSort() == Type.LONG) {
v.lcmp();
v.ifgt(loopExit);
if (step > 0) {
v.ifgt(loopExit);
}
else {
v.iflt(loopExit);
}
}
else {
v.ificmpgt(loopExit);
if (step > 0) {
v.ificmpgt(loopExit);
}
else {
v.ificmplt(loopExit);
}
}
}
@@ -1079,12 +1112,12 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
checkPostCondition(loopExit);
if (loopParameterType == Type.INT_TYPE) {
v.iinc(loopParameterVar, 1);
v.iinc(loopParameterVar, step);
}
else {
StackValue loopParameter = loopParameter();
loopParameter.put(asmElementType, v);
genIncrement(asmElementType, 1, v);
genIncrement(asmElementType, step, v);
loopParameter.store(StackValue.onStack(asmElementType), v);
}
}
@@ -1111,6 +1144,27 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
}
}
private class ForInDownToProgressionLoopGenerator extends AbstractForInRangeLoopGenerator {
private final ReceiverValue from;
private final KtExpression to;
private ForInDownToProgressionLoopGenerator(
@NotNull KtForExpression forExpression,
@NotNull ReceiverValue from,
@NotNull KtExpression to
) {
super(forExpression, -1);
this.from = from;
this.to = to;
}
@Override
protected void storeRangeStartAndEnd() {
loopParameter().store(generateReceiverValue(from, false), v);
StackValue.local(endVar, asmElementType).store(gen(to), v);
}
}
private class ForInRangeInstanceLoopGenerator extends AbstractForInRangeLoopGenerator {
private ForInRangeInstanceLoopGenerator(@NotNull KtForExpression forExpression) {
super(forExpression);
@@ -132,6 +132,17 @@ public class RangeCodegenUtil {
return false;
}
public static boolean isOptimizableDownTo(@NotNull CallableDescriptor descriptor) {
if (!isTopLevelInPackage(descriptor, "downTo", "kotlin.ranges")) return false;
ReceiverParameterDescriptor extensionReceiver = descriptor.getExtensionReceiverParameter();
if (extensionReceiver == null) return false;
ClassifierDescriptor extensionReceiverClassifier = extensionReceiver.getType().getConstructor().getDeclarationDescriptor();
if (!isPrimitiveNumberClassDescriptor(extensionReceiverClassifier)) return false;
return true;
}
public static boolean isArrayOrPrimitiveArrayIndices(@NotNull CallableDescriptor descriptor) {
if (!isTopLevelInPackage(descriptor, "indices", "kotlin.collections")) return false;