Repository navigation
Fix DFA anchor bugs; native split for over-JIT patterns; Laurikari anchor caching - #153
Conversation
…tails Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 96e865d725
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
A long greedy search can return a truncated match on the call that saturates the Laurikari cache. Repeating the same call returns the full span because subsequent searches switch to the JDK half.
🤖 Bits Code Review · Commit 96e865d
What does this PR do?
Fixes anchor bugs in the DFA bytecode generators. Patterns with ALLOW_JDK_FALLBACK whose generated method exceeds the JIT size limit now route to a native search engine instead of the plain JDK fallback. Also speeds up the Laurikari (tagged DFA) engine for patterns with end anchors and
\b.DFA anchor fixes (codegen)
DFASwitchBytecodeGeneratorignoredDFATransition.entryGuard(mid-pattern^,$,\Z) at every transition site. Itsmatches()also had a\Zspecial case that accepted before a trailing\n. Examples that diverged from the JDK:x{1,25}\Zon"x\n",x{1,25}\n^b,x{1,25}$\nb.[start, end).findFromempty-at-end skipped start-state assertions, andfindMatchEndhad no assertion or accept checks.PatternAnalyzer/FallbackPatternDetectorrouting fixes for shapes the DFA cannot represent. For example,(?:$b?|\r)on"\r\n"gave[0,1)on DFA_UNROLLED; the JDK gives[0,0).SubsetConstructorend-guard fix, the DFA_SWITCH_WITH_GROUPS accept check, andDFAUnrolledgroup-action ordering.Over-JIT-limit split (runtime)
RuntimeCompiler.overJitNativenow tries, in order:OverJitSplitMatcher: the find family goes to a freshLaurikariDfaMatcher, and the whole-input family goes to a shared JDK half.(?i), because the JDK half folds Unicode case and Laurikari folds ASCII only.JavaRegexFallbackMatcher(pattern)constructor, so it does not log the "Falling back" warning.Laurikari performance
LaurikariDFACachecaches anchor-dependent transitions under a lookahead class (10 classes). The class encodes the next character and the distance to the region end. Before this change, transitions into anchor-sensitive states were never cached.LaurikariDfaMatchercaches the start state of a find from position 0 per lookahead class. Before, it rebuilt the start closure on every call.Motivation
A differential fuzz against the JDK found the DFA anchor bugs. On 6k fuzzed patterns (seed 0xBEEF), the JDK divergences fell from 53 to 0 on DFA_SWITCH, from 225 to 0 on DFA_UNROLLED and from 11 to 0 on DFA_SWITCH_WITH_GROUPS. The review of these fixes found patterns whose generated method is over the JIT limit and that fell back to the JDK, for example
[^a]{3,30}b+(?:\n{2}\n{1,25}\n$)\d{1,25}. The over-JIT split gives the find family of such patterns a native engine.Related Issue(s)
Independent of #150. Rebased on #152 (structural cache keys); the split cache is keyed by
CompilationKeylike the other caches.Change Type
Checklist
./gradlew build)Performance Impact
JMH on x86,
-f 3, ops/ms, new benchmarkOverJitLimitRerouteBenchmark. Its five patterns are realistic over-JIT-limit shapes.-gc truethe difference goes away (FindLong 15.71 → 16.53), so it comes from heap layout, not from the code.Additional Notes
./gradlew test): reggie-runtime 3699 (31 skipped), reggie-codegen 529, reggie-processor 259; 0 failures../gradlew buildwas not run as a separate step.(?!(a))[ab]{1,25}is not changed. The JDK'sfind()keeps a stale group from a failed attempt; Reggie gives -1, the same as JDKfind(1)and the PCRE answer.🤖 Generated with Claude Code