Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: f4f06bc1151fe9f14da9f05774162f39351ed537
      
https://github.com/WebKit/WebKit/commit/f4f06bc1151fe9f14da9f05774162f39351ed537
  Author: Sosuke Suzuki <[email protected]>
  Date:   2026-08-12 (Wed, 12 Aug 2026)

  Changed paths:
    A JSTests/microbenchmarks/regexp-lookbehind-fixed.js
    A JSTests/microbenchmarks/regexp-lookbehind-negative-alternation.js
    A JSTests/microbenchmarks/regexp-lookbehind-replace.js
    A JSTests/microbenchmarks/regexp-lookbehind-variable.js
    A JSTests/stress/regexp-lookbehind-jit-alternatives.js
    A JSTests/stress/regexp-lookbehind-jit-captures.js
    A JSTests/stress/regexp-lookbehind-jit-hot-loop.js
    A JSTests/stress/regexp-lookbehind-jit-large-offset.js
    A JSTests/stress/regexp-lookbehind-jit.js
    M Source/JavaScriptCore/runtime/RegExp.cpp
    M Source/JavaScriptCore/yarr/YarrJIT.cpp

  Log Message:
  -----------
  [YARR] Compile lookbehinds
in the JIT
https://bugs.webkit.org/show_bug.cgi?id=321496

Reviewed by Daniel Liu.

A pattern containing a lookbehind never reached YarrJIT: RegExp::compile did 
not call
jitCompile for it and YarrGenerator::compile bailed out on 
m_containsLookbehinds, so a single
lookbehind sent the whole pattern, including everything around it, to the 
interpreter.

A lookbehind matches its disjunction backward, ending at the current position, 
which is the
same as matching the reversed sequence of its terms while consuming input 
downward. This patch
makes opCompileParentheticalAssertion compile a Backward assertion from a copy 
of its
disjunction in which each alternative has its terms reversed and its input 
positions reassigned
the way setupAlternativeOffsets() does (reverseDisjunctionForBackward), so the 
existing op
compilation, code generation and backtracking are reused as they are. The 
YarrPattern is left
untouched for the interpreter fallback.

The ops compiled from it are marked
Backward, and only the primitives that touch the index
register look at the direction: index is the start of the input consumed so 
far, so claiming
input subtracts and checks index >= 0, the character `offset` before index is 
read from
input[index + offset - 1], the end of input is index == 0, greedy terms consume 
with index -= 1
and give back with index += 1, a capture stores its end when the parenthesis 
begins and its
start when it ends, and ^ $ \b test the start / end of input and read the 
surrounding
characters through canBeAtStartOfInput() and friends. The machine code 
generated for Forward
ops is unchanged.

Unicode patterns with a lookbehind, and lookbehinds containing a backreference, 
a lookahead,
or a quantified parenthesis still fall back to the interpreter, and Backward 
ops do not combine
adjacent characters into a wider load yet.

Follow-up patches are planned to (1) JIT the remaining lookbehind shapes above 
and optimize
Backward ops further, (2) make the
interpreter match lookbehinds from a reversed disjunction
in the same way instead of its own backward bookkeeping, and then (3) have 
YarrPatternConstructor
build the disjunction of a lookbehind in reversed form from the start, so that 
both tiers share
one representation and this copy goes away.

                                                Baseline                  
Patched

regexp-lookbehind-variable                  167.9369+-2.1830     ^     
34.5673+-0.2600        ^ definitely 4.8583x faster
regexp-lookbehind-negative-alternation      470.5741+-1.4593     ^     
48.5470+-0.2605        ^ definitely 9.6932x faster
regexp-lookbehind-fixed                     233.4527+-4.8987     ^     
44.8282+-0.4900        ^ definitely 5.2077x faster
regexp-lookbehind-replace                   651.3264+-5.8342     ^     
61.1449+-1.7254        ^ definitely 10.6522x faster
regexp-exec                                  14.5383+-0.1674     ?     
14.6957+-0.2200        ? might be 1.0108x
slower

Tests: JSTests/microbenchmarks/regexp-lookbehind-fixed.js
       JSTests/microbenchmarks/regexp-lookbehind-negative-alternation.js
       JSTests/microbenchmarks/regexp-lookbehind-replace.js
       JSTests/microbenchmarks/regexp-lookbehind-variable.js
       JSTests/stress/regexp-lookbehind-jit-alternatives.js
       JSTests/stress/regexp-lookbehind-jit-captures.js
       JSTests/stress/regexp-lookbehind-jit-hot-loop.js
       JSTests/stress/regexp-lookbehind-jit-large-offset.js
       JSTests/stress/regexp-lookbehind-jit.js

* JSTests/microbenchmarks/regexp-lookbehind-fixed.js: Added.
* JSTests/microbenchmarks/regexp-lookbehind-negative-alternation.js: Added.
* JSTests/microbenchmarks/regexp-lookbehind-replace.js: Added.
* JSTests/microbenchmarks/regexp-lookbehind-variable.js: Added.
* JSTests/stress/regexp-lookbehind-jit-alternatives.js: Added.
(shouldBe):
(matchOf):
(shouldBe.matchOf):
(shouldBe.matchOf.b):
*
JSTests/stress/regexp-lookbehind-jit-captures.js: Added.
(shouldBe):
(matchOf):
(shouldBe.matchOf.a):
* JSTests/stress/regexp-lookbehind-jit-hot-loop.js: Added.
(shouldBe):
(execConstant):
(testVarying):
(replaceAll):
(searchSticky):
* JSTests/stress/regexp-lookbehind-jit-large-offset.js: Added.
(shouldBe):
(matchOf):
* JSTests/stress/regexp-lookbehind-jit.js: Added.
(shouldBe):
(matchOf):
(shouldBe.matchOf):
(string_appeared_here.string_appeared_here.repeat):
* Source/JavaScriptCore/runtime/RegExp.cpp:
(JSC::RegExp::compile):
(JSC::RegExp::compileMatchOnly):
* Source/JavaScriptCore/yarr/YarrJIT.cpp:
(JSC::Yarr::dumpCompileFailure):

Canonical link: 
https://flagged.apple.com:443/proxy?t2=DW7d4H4Dq5&o=aHR0cHM6Ly9jb21taXRzLndlYmtpdC5vcmcvMzE5MDY3QG1haW4=&emid=d45ee5ac-40a8-4d5b-ac3a-f07ff9dea825&c=11



To unsubscribe from these emails, change your notification settings at 
https://github.com/WebKit/WebKit/settings/notifications

Reply via email to