Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 54916608d7d648c662f4524d57000ec33b0eb431
https://github.com/WebKit/WebKit/commit/54916608d7d648c662f4524d57000ec33b0eb431
Author: Sosuke Suzuki <[email protected]>
Date: 2026-07-29 (Wed, 29 Jul 2026)
Changed paths:
A JSTests/stress/regexp-unicode-nonbmp-advance-latch-bug.js
A JSTests/stress/temporal-hebrew-day-constrain.js
M Source/JavaScriptCore/yarr/YarrJIT.cpp
Log Message:
-----------
[YARR] Fix non-BMP advance latch and simplify `tryReadUnicodeCharImpl`
https://bugs.webkit.org/show_bug.cgi?id=308288
Reviewed by Yusuke Suzuki.
For /u patterns, YARR JIT uses firstCharacterAdditionalReadSize (the advance
latch)
to move the match start past both units of a surrogate pair when a match attempt
fails. The latch was set as a side effect of every non-BMP character read, so a
read
anywhere in the pattern could corrupt it, e.g. /.x/u.exec("a\u{10000}x")
returned null
because the U+10000 read at position 1 latched the register while the start
character
'a' is BMP. Several workarounds (word boundary and backreference read guards,
latch
resets at alternative reentry, and after wide character compares) papered over
individual instances of this.
This change makes the latch a function of the match start position alone:
1. initAdvanceLatch() sets the latch iff the code units at the match start form
a
complete surrogate pair (a lone lead advances by one code unit, like
AdvanceStringIndex). It is emitted where an alternative is entered as the
first one
attempted at a start position: right before the alternative body after any
start-position prefilter (Boyer-Moore lookahead / SIMD searches move the
index),
and on the path that enters a shorter alternative directly when longer ones
no
longer fit.
2. tryReadUnicodeCharImpl no longer touches the latch, so
TryReadUnicodeCharGenFirstNonBMPOptimization, its second slow-path thunk,
and all of
the workarounds above are removed.
3. Skipping the trail surrogate position is only unobservable when every
alternative
consumes at least one character, since a character read at that position
yields
errorCodePoint. A zero minimum-size alternative (e.g. /aa|\B/u) can match
there, so
the optimization now also requires m_body->m_minimumSize; this fixes
/a?\B|q/u.exec("X\u{1F600}Z") returning null instead of the empty match at 2.
Test: JSTests/stress/regexp-unicode-nonbmp-advance-latch-bug.js
* JSTests/stress/regexp-unicode-nonbmp-advance-latch-bug.js: Added.
(shouldBe):
(shouldBeMatch):
* JSTests/stress/temporal-hebrew-day-constrain.js: Added.
(shouldBe):
(shouldBe.byCode.toString):
(shouldBe.byOrdinal.toString):
(Temporal.PlainDate.from):
* Source/JavaScriptCore/yarr/YarrJIT.cpp:
(JSC::Yarr::tryReadUnicodeCharImpl):
(JSC::Yarr::tryReadUnicodeCharSlowImpl):
(JSC::Yarr::tryReadUnicodeCharSlowThunkGenerator):
(JSC::Yarr::tryReadUnicodeCharIncForNonBMPSlowThunkGenerator): Deleted.
Canonical link: https://commits.webkit.org/318209@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications