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

Reply via email to