Repository navigation
Description
A long EReg match keeps its thread inside the managed execution zone for the entire PCRE2 call. A collection requested by another thread cannot start until matching returns. This adds the remaining match time to a process-wide GC pause, even when the collector itself has very little work.
Reproduced on Windows x64, Haxe 4.3.7, MSVC 19.44.35213, default GC, libhxcpp 920fa85. PCRE JIT was not enabled.
The subject contains only ASCII a characters and the expression is ^[a-z]+$. This is a successful linear match. A second Haxe thread waits 5 ms, records a timestamp, calls cpp.vm.Gc.run(true), and records completion. The control uses the same retained subject and expression but calls Sys.sleep(0.3) instead of matching. Full collection precedes each trial, and expression creation is outside the matching timer. Seven samples per size, alternating match/control order:
| Subject | Median match duration | Median collection request duration during match | Median collection request duration during sleep |
|---|---|---|---|
| 32 MiB | 19.0928 ms | 13.7827 ms | 0.0857 ms |
| 64 MiB | 39.3879 ms | 33.6590 ms | 0.0843 ms |
| 128 MiB | 73.3406 ms | 68.0030 ms | 0.0853 ms |
The collection request starts roughly 5 ms after matching begins and completes just after matching ends. The last two columns include the collection itself, not just the wait for the matching thread. These are large-subject measurements intended to isolate scheduling behavior, not typical request sizes or an application throughput estimate.
pcredata::run in src/hx/libs/regexp/RegExp.cpp calls both pcre2_match_8 and pcre2_match_16 directly, including the JIT fallback, without entering a GC-free zone or providing safepoints during matching. While the collector waits for that thread, other allocating workers can also stop at the collection handshake.
Investigate allowing collections during native matching, entirely within libhxcpp. Simply wrapping the current calls in a GC-free zone is insufficient: PCRE holds a pointer into the subject, which must remain valid under moving GC, and the owning expression, match data and cached UTF-16 subject must stay alive. Account for copying or pinning costs, keep match positions and captures unchanged, and include the interpreter and optional JIT paths. The performance benefit is reduced interference between independent workers, not faster PCRE execution.
A local conventional regression, test/regression/RegexpConcurrentCollection, checks ASCII and UTF-16 matches, captures and positions while another thread repeatedly forces collections. It passes with default GC and HXCPP_GC_MOVING. It provides correctness coverage for a future change; it deliberately has no timing assertion and does not currently fail. The timing probe above is separate. No runtime implementation changes were made.
Keep the timing workload in performance coverage so a future implementation can compare collection latency and match throughput together. No compiler or stdlib change is needed.
Activity
Match long regular expression spans in a GC-free zone