Closed Bug 2043732 Opened 4 months ago Closed 4 months ago

JS_NewStringCopyUTF8N sometimes does two passes over the buffer - makes mozilla::IOUtils::JsBuffer::IntoString slow

Categories

(Core :: JavaScript Engine, task, P1)

task

Tracking

()

RESOLVED FIXED
153 Branch
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.

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

Assignee: nobody → mstange.moz
Status: NEW → ASSIGNED
Blocks: 1803803
Severity: -- → N/A
Priority: -- → P1
Status: ASSIGNED → RESOLVED
Closed: 4 months ago
Resolution: --- → FIXED
Target Milestone: --- → 153 Branch

can the same technique be used in StringBuilder::append (Utf8Unit*) ?

Not sure - do you have a profile that spends time in it?

(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.

QA Whiteboard: [qa-triage-done-c154/b153]
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: