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";
|
||||
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;
|
||||
}
|
||||
@@ -1198,7 +1203,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
StackValue receiver = generateReceiverValue(receiverValue, false);
|
||||
Type receiverType = asmType(receiverValue.getType());
|
||||
receiver.put(receiverType, v); // NB receiverType is a collection or an array
|
||||
receiver.put(receiverType, v);
|
||||
getReceiverSizeAsInt();
|
||||
v.iconst(1);
|
||||
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 int incrementVar;
|
||||
private Type incrementType;
|
||||
|
||||
@@ -165,6 +165,17 @@ public class RangeCodegenUtil {
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testForInCollectionImplicitReceiverIndices() throws Exception {
|
||||
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);
|
||||
}
|
||||
|
||||
@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")
|
||||
public void testForInCollectionImplicitReceiverIndices() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/forLoop/forInIndices/forInCollectionImplicitReceiverIndices.kt");
|
||||
|
||||
Reference in New Issue
Block a user