Skip to content

Commit db2b0a8

Browse files
committed
Improve performance of string __mul__
1 parent 5df57d7 commit db2b0a8

File tree

1 file changed

+38
-10
lines changed
  • graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str

1 file changed

+38
-10
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/str/StringBuiltins.java

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
import java.nio.charset.IllegalCharsetNameException;
5858
import java.nio.charset.StandardCharsets;
5959
import java.nio.charset.UnsupportedCharsetException;
60+
import java.util.Arrays;
6061
import java.util.List;
6162

6263
import org.graalvm.nativeimage.ImageInfo;
@@ -1438,18 +1439,32 @@ private Object encodeString(String self, String encoding, String errors) {
14381439
@TypeSystemReference(PythonArithmeticTypes.class)
14391440
abstract static class MulNode extends PythonBinaryBuiltinNode {
14401441

1441-
@Specialization
1442+
@Specialization(guards = "right <= 0")
1443+
String doEmptyStringInt(@SuppressWarnings("unused") Object left, @SuppressWarnings("unused") int right) {
1444+
return "";
1445+
}
1446+
1447+
@Specialization(guards = {"left.length() == 0", "right > 0"})
1448+
String doEmptyStringInt(String left, @SuppressWarnings("unused") int right) {
1449+
return left;
1450+
}
1451+
1452+
@Specialization(guards = {"left.length() == 1", "right > 0"})
1453+
String doCharInt(String left, int right) {
1454+
char[] result = new char[right];
1455+
Arrays.fill(result, left.charAt(0));
1456+
return new String(result);
1457+
}
1458+
1459+
@Specialization(guards = {"left.length() > 1", "right > 0"})
14421460
String doStringInt(String left, int right) {
1443-
if (right <= 0) {
1444-
return "";
1445-
}
14461461
return repeatString(left, right);
14471462
}
14481463

14491464
@Specialization(limit = "1")
14501465
String doStringLong(String left, long right,
14511466
@Exclusive @CachedLibrary("right") PythonObjectLibrary lib) {
1452-
return doStringInt(left, lib.asSize(right));
1467+
return doStringIntGeneric(left, lib.asSize(right));
14531468
}
14541469

14551470
@Specialization
@@ -1464,7 +1479,7 @@ String doStringObject(VirtualFrame frame, String left, Object right,
14641479
} else {
14651480
repeat = lib.asSize(right);
14661481
}
1467-
return doStringInt(left, repeat);
1482+
return doStringIntGeneric(left, repeat);
14681483
} catch (PException e) {
14691484
e.expect(PythonBuiltinClassType.OverflowError, typeErrorProfile);
14701485
throw raise(MemoryError);
@@ -1481,14 +1496,27 @@ Object doGeneric(VirtualFrame frame, Object self, Object times,
14811496
return doStringObject(frame, selfStr, times, hasFrame, lib, typeErrorProfile);
14821497
}
14831498

1499+
public String doStringIntGeneric(String left, int right) {
1500+
if (right <= 0) {
1501+
return "";
1502+
}
1503+
return repeatString(left, right);
1504+
}
1505+
14841506
@TruffleBoundary
14851507
private String repeatString(String left, int times) {
14861508
try {
1487-
StringBuilder str = new StringBuilder(Math.multiplyExact(left.length(), times));
1488-
for (int i = 0; i < times; i++) {
1489-
str.append(left);
1509+
int total = Math.multiplyExact(left.length(), times);
1510+
char[] result = new char[total];
1511+
left.getChars(0, left.length(), result, 0);
1512+
int done = left.length();
1513+
while (done < total) {
1514+
int todo = total - done;
1515+
int len = Math.min(done, todo);
1516+
System.arraycopy(result, 0, result, done, len);
1517+
done += len;
14901518
}
1491-
return str.toString();
1519+
return new String(result);
14921520
} catch (OutOfMemoryError | ArithmeticException e) {
14931521
throw raise(MemoryError);
14941522
}

0 commit comments

Comments
 (0)