Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 956f6fb49678a6f6b0116325be5b5357df948970
https://github.com/WebKit/WebKit/commit/956f6fb49678a6f6b0116325be5b5357df948970
Author: Sosuke Suzuki <[email protected]>
Date: 2026-09-04 (Fri, 04 Sep 2026)
Changed paths:
A JSTests/stress/regexp-interpreter-lookbehind-character-class-non-bmp.js
A
JSTests/stress/regexp-interpreter-lookbehind-fixed-count-non-bmp-character.js
A
JSTests/stress/regexp-interpreter-lookbehind-greedy-class-backtrack-non-bmp.js
A JSTests/stress/regexp-interpreter-lookbehind-surrogate-half.js
A JSTests/stress/regexp-interpreter-lookbehind.js
M Source/JavaScriptCore/yarr/YarrInterpreter.cpp
M Source/JavaScriptCore/yarr/YarrInterpreter.h
M Source/JavaScriptCore/yarr/YarrJIT.cpp
M Source/JavaScriptCore/yarr/YarrPattern.cpp
M Source/JavaScriptCore/yarr/YarrPattern.h
Log Message:
-----------
[YARR] Match lookbehinds in the interpreter from a copy of the disjunction in
match order
https://bugs.webkit.org/show_bug.cgi?id=322692
Reviewed by Daniel Liu.
This is the second step of the plan in 319067@main. The interpreter now
matches a lookbehind the way the JIT does: from a copy of its disjunction with
the terms in match order, so that only the input reading primitives know
about the direction.
Until now the interpreter handled the direction term by term: each matching
function had a Forward implementation and a separate Backward one. Those
Backward implementations each re-derived the surrogate pair rules, and the
ones that got them wrong are where the interpreter-only lookbehind bugs in /u
mode came from. With one set of primitives whose Backward form is the mirror
of the Forward one, the following are fixed without a case-by-case change, and
each gets its own test:
1. /(?<=[\u{1F600}a])b/u on "x😀b" returned null.
2. /(?<=\u{1F600}{2})x/u on "😀😀x" returned null.
3. /(?<=$.*)/su on "😁" matched at index 1, inside the surrogate pair.
4. /(?<=\uD83D)/u on "😀" matched at index 1.
The diff is large because most of it is deletion: every Backward
implementation and the Backward-specific bookkeeping in the bytecode compiler
are gone. The forward bytecode and the JIT's machine code are unchanged.
Tests: JSTests/stress/regexp-interpreter-lookbehind-character-class-non-bmp.js
JSTests/stress/regexp-interpreter-lookbehind-fixed-count-non-bmp-character.js
JSTests/stress/regexp-interpreter-lookbehind-greedy-class-backtrack-non-bmp.js
JSTests/stress/regexp-interpreter-lookbehind-surrogate-half.js
JSTests/stress/regexp-interpreter-lookbehind.js
* JSTests/stress/regexp-interpreter-lookbehind-character-class-non-bmp.js:
Added.
(shouldBe):
(stringify):
(shouldMatch):
*
JSTests/stress/regexp-interpreter-lookbehind-fixed-count-non-bmp-character.js:
Added.
(shouldBe):
(stringify):
(shouldMatch):
*
JSTests/stress/regexp-interpreter-lookbehind-greedy-class-backtrack-non-bmp.js:
Added.
(shouldBe):
(stringify):
(shouldMatch):
* JSTests/stress/regexp-interpreter-lookbehind-surrogate-half.js: Added.
(shouldBe):
(stringify):
(shouldMatch):
* JSTests/stress/regexp-interpreter-lookbehind.js: Added.
(shouldBe):
(stringify):
(shouldMatch):
* Source/JavaScriptCore/yarr/YarrInterpreter.cpp:
(JSC::Yarr::Interpreter::InputStream::characterIndex):
(JSC::Yarr::Interpreter::InputStream::readChecked):
(JSC::Yarr::Interpreter::InputStream::readCheckedDontAdvance):
(JSC::Yarr::Interpreter::InputStream::readSurrogatePairChecked):
(JSC::Yarr::Interpreter::InputStream::readCodePoint):
(JSC::Yarr::Interpreter::InputStream::reread):
(JSC::Yarr::Interpreter::InputStream::positionAt):
(JSC::Yarr::Interpreter::InputStream::checkInput):
(JSC::Yarr::Interpreter::InputStream::uncheckInput):
(JSC::Yarr::Interpreter::InputStream::uncheckCodePoint):
(JSC::Yarr::Interpreter::InputStream::isValidNegativeInputOffset):
(JSC::Yarr::Interpreter::checkCharacter):
(JSC::Yarr::Interpreter::checkSurrogatePair):
(JSC::Yarr::Interpreter::checkCasedCharacter):
(JSC::Yarr::Interpreter::checkCharacterClass):
(JSC::Yarr::Interpreter::checkCharacterClassDontAdvanceInputForNonBMP):
(JSC::Yarr::Interpreter::tryConsumeBackReference):
(JSC::Yarr::Interpreter::matchAssertionBOL):
(JSC::Yarr::Interpreter::matchAssertionEOL):
(JSC::Yarr::Interpreter::matchAssertionBOI):
(JSC::Yarr::Interpreter::matchAssertionEOI):
(JSC::Yarr::Interpreter::matchAssertionWordBoundary):
(JSC::Yarr::Interpreter::matchFixedCount):
(JSC::Yarr::Interpreter::matchGreedy):
(JSC::Yarr::Interpreter::backtrackNonGreedy):
(JSC::Yarr::Interpreter::backtrackPatternCharacter):
(JSC::Yarr::Interpreter::backtrackPatternCasedCharacter):
(JSC::Yarr::Interpreter::matchCharacterClass):
(JSC::Yarr::Interpreter::backtrackCharacterClass):
(JSC::Yarr::Interpreter::matchBackReference):
(JSC::Yarr::Interpreter::backtrackBackReference):
(JSC::Yarr::Interpreter::matchPatternCharacterFixed):
(JSC::Yarr::Interpreter::matchPatternCharacterGreedy):
(JSC::Yarr::Interpreter::matchPatternCasedCharacterFixed):
(JSC::Yarr::Interpreter::matchPatternCasedCharacterGreedy):
(JSC::Yarr::Interpreter::recordParenthesesMatch):
(JSC::Yarr::Interpreter::matchParenthesesOnceBegin):
(JSC::Yarr::Interpreter::matchParenthesesOnceEnd):
(JSC::Yarr::Interpreter::backtrackParenthesesOnceEnd):
(JSC::Yarr::Interpreter::matchParentheticalAssertionBegin):
(JSC::Yarr::Interpreter::backtrackParentheticalAssertionBegin):
(JSC::Yarr::Interpreter::matchDisjunction):
(JSC::Yarr::ByteCompiler::checkInput):
(JSC::Yarr::ByteCompiler::assertionBOL):
(JSC::Yarr::ByteCompiler::assertionEOL):
(JSC::Yarr::ByteCompiler::assertionBOI):
(JSC::Yarr::ByteCompiler::assertionEOI):
(JSC::Yarr::ByteCompiler::atomPatternCharacter):
(JSC::Yarr::ByteCompiler::atomCharacterClass):
(JSC::Yarr::ByteCompiler::atomParentheticalAssertionBegin):
(JSC::Yarr::ByteCompiler::atomParenthesesOnceEnd):
(JSC::Yarr::ByteCompiler::atomParenthesesTerminalEnd):
(JSC::Yarr::ByteCompiler::emitDisjunction):
(JSC::Yarr::ByteTermDumper::dumpTerm):
(JSC::Yarr::Interpreter::InputStream::rewind): Deleted.
(JSC::Yarr::Interpreter::InputStream::read): Deleted.
(JSC::Yarr::Interpreter::InputStream::readForCharacterDump): Deleted.
(JSC::Yarr::Interpreter::InputStream::tryReadBackward): Deleted.
(JSC::Yarr::Interpreter::InputStream::prev): Deleted.
(JSC::Yarr::Interpreter::InputStream::atStart): Deleted.
(JSC::Yarr::Interpreter::InputStream::tryUncheckInput): Deleted.
(JSC::Yarr::ByteCompiler::uncheckInput): Deleted.
(JSC::Yarr::ByteCompiler::haveCheckedInput): Deleted.
* Source/JavaScriptCore/yarr/YarrInterpreter.h:
(JSC::Yarr::ByteTerm::directed):
(JSC::Yarr::ByteTerm::ByteTerm):
(JSC::Yarr::ByteTerm::BOL):
(JSC::Yarr::ByteTerm::BOI):
(JSC::Yarr::ByteTerm::CheckInput):
(JSC::Yarr::ByteTerm::EOL):
(JSC::Yarr::ByteTerm::EOI):
(JSC::Yarr::ByteTerm::WordBoundary):
(JSC::Yarr::ByteTerm::BackReference):
(JSC::Yarr::ByteTerm::ParentheticalAssertionBegin):
(JSC::Yarr::ByteTerm::ParentheticalAssertionEnd):
(JSC::Yarr::ByteTerm::isCharacterType):
(JSC::Yarr::ByteTerm::isCasedCharacterType):
(JSC::Yarr::ByteTerm::isCharacterClass):
(JSC::Yarr::ByteTerm::isBackReference):
(JSC::Yarr::ByteTerm::parentMatchDirection):
(JSC::Yarr::ByteTerm::UncheckInput): Deleted.
(JSC::Yarr::ByteTerm::HaveCheckedInput): Deleted.
* Source/JavaScriptCore/yarr/YarrJIT.cpp:
* Source/JavaScriptCore/yarr/YarrPattern.cpp:
(JSC::Yarr::YarrPattern::copyDisjunctionInMatchOrder):
* Source/JavaScriptCore/yarr/YarrPattern.h:
Canonical link: https://commits.webkit.org/320492@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications