JS_NewStringCopyUTF8N sometimes does two passes over the buffer - makes mozilla::IOUtils::JsBuffer::IntoString slow
Categories
(Core :: JavaScript Engine, task, P1)
Tracking
()
| Tracking | Status | |
|---|---|---|
| firefox153 | --- | fixed |
People
(Reporter: mstange, Assigned: mstange)
References
(Blocks 1 open bug)
Details
Attachments
(1 file)
Mayank shared this profile from Firefox startup with a 300MB session JSON file: https://share.firefox.dev/4dpVWVM
We can see IOUtils::JsBuffer::IntoString doing two passes over the input.
| Assignee | ||
Comment 1•4 months ago
|
||
InflateUTF8StringHelper used a hand-rolled byte-by-byte decoder that
walked the input twice: a counting pass to compute the output length and
a copy pass to emit the chars. Route the char16_t case through a new
InflateUTF8ToNewTwoByteCharsZ helper that allocates srclen + 1 char16_t
and runs a single SIMD pass via encoding_rs
(mozilla::ConvertUtf8toUtf16{,WithoutReplacement}). On invalid UTF-8 in
Throw mode, fall back to the slow validator just to preserve the precise
byte-offset error report. The Latin1 path is unchanged.
This speeds up IOUtils::JsBuffer::IntoString by around 2.5x, so it should
speed up session restore.
Before: https://share.firefox.dev/3POjZVq
After: https://share.firefox.dev/4o5j5AE
Updated•4 months ago
|
| Assignee | ||
Comment 2•4 months ago
|
||
Updated•4 months ago
|
| Assignee | ||
Comment 3•4 months ago
|
||
Comment 5•4 months ago
|
||
| bugherder | ||
Comment 6•4 months ago
|
||
can the same technique be used in StringBuilder::append (Utf8Unit*) ?
| Assignee | ||
Comment 7•4 months ago
|
||
Not sure - do you have a profile that spends time in it?
Comment 8•4 months ago
•
|
||
(In reply to Markus Stange [:mstange] from comment #7)
Not sure - do you have a profile that spends time in it?
I do not. Just for curiosity, I put your patch in chatgpt, and asked it where else can similar pattern be used.
This was the response:
StringBuilder::append(Utf8Unit*, size_t) is now the obvious next hotspot
The patch fixes the standalone TwoByteCharsZ path, but StringBuilder::append still does exactly what the old code did: it counts UTF-16 length first, grows the buffer, and then inflates again. That is still a full double walk over the remaining UTF-8 input. Reworking that call site to use the same “upper-bound allocate, convert once, maybe shrink” pattern is probably the highest-ROI follow-up because it sits on a general-purpose append path, not a niche API.
Updated•4 months ago
|
Description
•