Files
ladybird/Libraries/LibJS/Runtime/Array.cpp
Aliaksandr Kalenik 1f46651af5 LibJS: Reuse cached UTF-16 in Array.prototype.sort's string comparator
CompareArrayElements was calling ToString(x) +
PrimitiveString::create(vm, ...) on every comparison, producing a
fresh PrimitiveString that wrapped the original's AK::String but
carried no cached UTF-16. The subsequent IsLessThan then hit
PrimitiveString::utf16_string_view() on that fresh object, which
re-ran simdutf UTF-8 validation + UTF-8 -> UTF-16 conversion for
both sides on every one of the N log N comparisons.

When x and y are already String Values, ToString(x) and
ToPrimitive(x, Number) are the identity per spec, so we can drop
the IsLessThan detour entirely and compare their Utf16Views
directly. The original PrimitiveString caches its UTF-16 on first
access, so subsequent comparisons against the same element hit
the cache; Utf16View::operator<=> additionally gives us a memcmp
fast path when both sides ended up with short-ASCII UTF-16 storage.

Microbenchmark:
```js
function makeStrings(n) {
    let seed = 1234567;
    const rand = () => {
        seed = (seed * 1103515245 + 12345) & 0x7fffffff;
        return seed;
    };
    const out = new Array(n);
    for (let i = 0; i < n; i++)
        out[i] = "item_" + rand().toString(36)
            + "_" + rand().toString(36);
    return out;
}
const base = makeStrings(100000);
const arr = base.slice();
arr.sort();
```

```
n       before  after   speedup
1k      0.70ms  0.30ms  2.3x
10k     8.33ms  3.33ms  2.5x
50k    49.33ms 17.33ms  2.8x
100k  118.00ms 45.00ms  2.6x
```
2026-04-22 19:12:54 +02:00

19 KiB