Skip to content

Commit 1fcc374

Browse files
authored
fix: Fix wrong reallocations in String#replaceAll + refactoring (#1564)
1 parent bdee862 commit 1fcc374

File tree

6 files changed

+2220
-2037
lines changed

6 files changed

+2220
-2037
lines changed

std/assembly/string.ts

+38-36
Original file line numberDiff line numberDiff line change
@@ -360,53 +360,54 @@ import { Array } from "./array";
360360
}
361361

362362
replaceAll(search: String, replacement: String): String {
363-
var len: usize = this.length;
364-
var slen: usize = search.length;
365-
if (len <= slen) {
366-
return len < slen ? this : select<String>(replacement, this, search == this);
367-
}
368-
var rlen: usize = replacement.length;
369-
if (!slen) {
370-
if (!rlen) return this;
363+
var thisLen: usize = this.length;
364+
var searchLen: usize = search.length;
365+
if (thisLen <= searchLen) {
366+
return thisLen < searchLen
367+
? this
368+
: select<String>(replacement, this, search == this);
369+
}
370+
var replaceLen: usize = replacement.length;
371+
if (!searchLen) {
372+
if (!replaceLen) return this;
371373
// Special case: 'abc'.replaceAll('', '-') -> '-a-b-c-'
372-
let out = __new((len + (len + 1) * rlen) << 1, idof<String>());
373-
memory.copy(out, changetype<usize>(replacement), rlen << 1);
374-
let offset = rlen;
375-
for (let i: usize = 0; i < len; ++i) {
374+
let out = __new((thisLen + (thisLen + 1) * replaceLen) << 1, idof<String>());
375+
memory.copy(out, changetype<usize>(replacement), replaceLen << 1);
376+
let offset = replaceLen;
377+
for (let i: usize = 0; i < thisLen; ++i) {
376378
store<u16>(
377379
changetype<usize>(out) + (offset++ << 1),
378380
load<u16>(changetype<usize>(this) + (i << 1))
379381
);
380382
memory.copy(
381383
out + (offset << 1),
382384
changetype<usize>(replacement),
383-
rlen << 1
385+
replaceLen << 1
384386
);
385-
offset += rlen;
387+
offset += replaceLen;
386388
}
387389
return changetype<String>(out);
388390
}
389391
var prev: isize = 0, next: isize = 0;
390-
if (slen == rlen) {
392+
if (searchLen == replaceLen) {
391393
// Fast path when search and replacement have same length
392-
let size = len << 1;
393-
let out = __new(size, idof<String>());
394-
memory.copy(out, changetype<usize>(this), size);
394+
let outSize = thisLen << 1;
395+
let out = __new(outSize, idof<String>());
396+
memory.copy(out, changetype<usize>(this), outSize);
395397
while (~(next = <isize>this.indexOf(search, <i32>prev))) {
396-
memory.copy(out + (next << 1), changetype<usize>(replacement), rlen << 1);
397-
prev = next + slen;
398+
memory.copy(out + (next << 1), changetype<usize>(replacement), replaceLen << 1);
399+
prev = next + searchLen;
398400
}
399401
return changetype<String>(out);
400402
}
401-
var out: usize = 0, offset: usize = 0, resLen = len;
403+
var out: usize = 0, offset: usize = 0, outSize = thisLen;
402404
while (~(next = <isize>this.indexOf(search, <i32>prev))) {
403-
if (!out) out = __new(len << 1, idof<String>());
404-
if (offset > resLen) {
405-
let newLength = resLen << 1;
406-
out = __renew(out, newLength << 1);
407-
resLen = newLength;
408-
}
405+
if (!out) out = __new(thisLen << 1, idof<String>());
409406
let chunk = next - prev;
407+
if (offset + chunk + replaceLen > outSize) {
408+
outSize <<= 1;
409+
out = __renew(out, outSize << 1);
410+
}
410411
memory.copy(
411412
out + (offset << 1),
412413
changetype<usize>(this) + (prev << 1),
@@ -416,18 +417,17 @@ import { Array } from "./array";
416417
memory.copy(
417418
out + (offset << 1),
418419
changetype<usize>(replacement),
419-
rlen << 1
420+
replaceLen << 1
420421
);
421-
offset += rlen;
422-
prev = next + slen;
422+
offset += replaceLen;
423+
prev = next + searchLen;
423424
}
424425
if (offset) {
425-
if (offset > resLen) {
426-
let newLength = resLen << 1;
427-
out = __renew(out, newLength << 1);
428-
resLen = newLength;
426+
let rest = thisLen - prev;
427+
if (offset + rest > outSize) {
428+
outSize <<= 1;
429+
out = __renew(out, outSize << 1);
429430
}
430-
let rest = len - prev;
431431
if (rest) {
432432
memory.copy(
433433
out + (offset << 1),
@@ -436,7 +436,9 @@ import { Array } from "./array";
436436
);
437437
}
438438
rest += offset;
439-
if (resLen > rest) out = __renew(out, rest << 1);
439+
if (outSize > rest) {
440+
out = __renew(out, rest << 1);
441+
}
440442
return changetype<String>(out);
441443
}
442444
return this;

tests/compiler/std/string-encoding.optimized.wat

+1-1
Original file line numberDiff line numberDiff line change
@@ -2591,7 +2591,7 @@
25912591
if
25922592
i32.const 0
25932593
i32.const 1504
2594-
i32.const 738
2594+
i32.const 740
25952595
i32.const 7
25962596
call $~lib/builtins/abort
25972597
unreachable

tests/compiler/std/string-encoding.untouched.wat

+1-1
Original file line numberDiff line numberDiff line change
@@ -4388,7 +4388,7 @@
43884388
if
43894389
i32.const 0
43904390
i32.const 480
4391-
i32.const 738
4391+
i32.const 740
43924392
i32.const 7
43934393
call $~lib/builtins/abort
43944394
unreachable

0 commit comments

Comments
 (0)