KT-12985 Do not create range instances for 'for' loop in CharSequence.indices
This commit is contained in:
@@ -656,6 +656,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
assert extensionReceiver != null : "Extension receiver should be non-null for optimizable 'Collection.indices' call";
|
assert extensionReceiver != null : "Extension receiver should be non-null for optimizable 'Collection.indices' call";
|
||||||
return new ForInCollectionIndicesRangeLoopGenerator(forExpression, extensionReceiver);
|
return new ForInCollectionIndicesRangeLoopGenerator(forExpression, extensionReceiver);
|
||||||
}
|
}
|
||||||
|
else if (RangeCodegenUtil.isCharSequenceIndices(loopRangeCallee)) {
|
||||||
|
ReceiverValue extensionReceiver = loopRangeCall.getExtensionReceiver();
|
||||||
|
assert extensionReceiver != null : "Extension receiver should be non-null for optimizable 'CharSequence.indices' call";
|
||||||
|
return new ForInCharSequenceIndicesRangeLoopGenerator(forExpression, extensionReceiver);
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -1198,7 +1203,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
|
|
||||||
StackValue receiver = generateReceiverValue(receiverValue, false);
|
StackValue receiver = generateReceiverValue(receiverValue, false);
|
||||||
Type receiverType = asmType(receiverValue.getType());
|
Type receiverType = asmType(receiverValue.getType());
|
||||||
receiver.put(receiverType, v); // NB receiverType is a collection or an array
|
receiver.put(receiverType, v);
|
||||||
getReceiverSizeAsInt();
|
getReceiverSizeAsInt();
|
||||||
v.iconst(1);
|
v.iconst(1);
|
||||||
v.sub(Type.INT_TYPE);
|
v.sub(Type.INT_TYPE);
|
||||||
@@ -1233,6 +1238,17 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class ForInCharSequenceIndicesRangeLoopGenerator extends ForInOptimizedIndicesLoopGenerator {
|
||||||
|
private ForInCharSequenceIndicesRangeLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ReceiverValue receiverValue) {
|
||||||
|
super(forExpression, receiverValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void getReceiverSizeAsInt() {
|
||||||
|
v.invokeinterface("java/lang/CharSequence", "length", "()I");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class ForInProgressionExpressionLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator {
|
private class ForInProgressionExpressionLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator {
|
||||||
private int incrementVar;
|
private int incrementVar;
|
||||||
private Type incrementType;
|
private Type incrementType;
|
||||||
|
|||||||
@@ -165,6 +165,17 @@ public class RangeCodegenUtil {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isCharSequenceIndices(@NotNull CallableDescriptor descriptor) {
|
||||||
|
if (!isTopLevelInPackage(descriptor, "indices", "kotlin.text")) return false;
|
||||||
|
|
||||||
|
ReceiverParameterDescriptor extensionReceiver = descriptor.getExtensionReceiverParameter();
|
||||||
|
if (extensionReceiver == null) return false;
|
||||||
|
KotlinType extensionReceiverType = extensionReceiver.getType();
|
||||||
|
if (!KotlinBuiltIns.isCharSequenceOrNullableCharSequence(extensionReceiverType)) return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean isTopLevelInPackage(@NotNull CallableDescriptor descriptor, @NotNull String name, @NotNull String packageName) {
|
private static boolean isTopLevelInPackage(@NotNull CallableDescriptor descriptor, @NotNull String name, @NotNull String packageName) {
|
||||||
if (!name.equals(descriptor.getName().asString())) return false;
|
if (!name.equals(descriptor.getName().asString())) return false;
|
||||||
|
|
||||||
|
|||||||
+16
@@ -0,0 +1,16 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun test(s: CharSequence): Int {
|
||||||
|
var result = 0
|
||||||
|
for (i in s.indices) {
|
||||||
|
result = result * 10 + (i + 1)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
val test = test("abcd")
|
||||||
|
if (test != 1234) return "Fail: $test"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
fun test(s: CharSequence): Int {
|
||||||
|
var result = 0
|
||||||
|
for (i in s.indices) {
|
||||||
|
result = result * 10 + (i + 1)
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// 0 iterator
|
||||||
|
// 0 getStart
|
||||||
|
// 0 getEnd
|
||||||
|
// 0 getFirst
|
||||||
|
// 0 getLast
|
||||||
@@ -10884,6 +10884,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInIndices"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/ranges/forInIndices"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInCharSequenceIndices.kt")
|
||||||
|
public void testForInCharSequenceIndices() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInIndices/forInCharSequenceIndices.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInCollectionImplicitReceiverIndices.kt")
|
@TestMetadata("forInCollectionImplicitReceiverIndices.kt")
|
||||||
public void testForInCollectionImplicitReceiverIndices() throws Exception {
|
public void testForInCollectionImplicitReceiverIndices() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInIndices/forInCollectionImplicitReceiverIndices.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/ranges/forInIndices/forInCollectionImplicitReceiverIndices.kt");
|
||||||
|
|||||||
@@ -909,6 +909,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
|
|||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/forLoop/forInIndices"), Pattern.compile("^(.+)\\.kt$"), true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/bytecodeText/forLoop/forInIndices"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("forInCharSequenceIndices.kt")
|
||||||
|
public void testForInCharSequenceIndices() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInIndices/forInCharSequenceIndices.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("forInCollectionImplicitReceiverIndices.kt")
|
@TestMetadata("forInCollectionImplicitReceiverIndices.kt")
|
||||||
public void testForInCollectionImplicitReceiverIndices() throws Exception {
|
public void testForInCollectionImplicitReceiverIndices() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInIndices/forInCollectionImplicitReceiverIndices.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInIndices/forInCollectionImplicitReceiverIndices.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user