Repository navigation
AOT: tier-2 preg_capture compile fixes (defer user init, ?? isset IR) — WIP runtime - #18176
Conversation
… IR (#16075) Defer user-script Context init when the source uses preg_* so nested preg helper JIT links on a full-init module (~5s) instead of OOM/hanging under minimal user bodies. Coerce PregJitHelper capture HashTable returns for LLVM verify, route isset/?? boxed array offsets through HashTableHelper::readHashtableFromValueBox, and replace full-init superglobal refresh with the user-script native emitter after the defer path restores PHP_COMPILER_AOT_USER_SCRIPT. Remaining: standalone binary still segfaults at c:main_before_php on preg execute; phpc build can still hang with CACHE=0 on large link. Repro: php test/repro/preg_match_aot_minimal.php Co-authored-by: Cursor <cursoragent@cursor.com>
#16075) Clear VmActiveContextInitLlvm pending/scheduled statics when deferring user-script init for preg prelink so thin __init__ emission is not skipped across Context resets. Add maintainer repro scripts for minimal preg_match and capture/coalesce AOT paths. Execute still segfaults after c:main_before_php — runtime init/helper mismatch remains open on #16075 / PR #18176. Co-authored-by: Cursor <cursoragent@cursor.com>
Continuation (worker lane B)Commit: 55c66c5 — reset Verification (Docker)./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && vendor/bin/phpunit --filter IssetHelperRuntimeShrinkTest'
# OK (3 tests)
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh
WORK=$(mktemp -d)
echo "<?php preg_match(\"/x/\", \"x\"); echo \"ok\n\";" > "$WORK/preg.php"
./phpc build -o "$WORK/out" "$WORK/preg.php"
"$WORK/out"; echo exit=$?'
# build OK (~23s); execute: phpc: fatal signal (segfault) after c:main_before_php; exit=139
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && php test/repro/preg_match_aot_minimal.php'
# compile+link OK; execute segfault (same)
./script/docker-exec.sh -- bash -lc './script/check-aot-build-smoke.sh'
# tier 1 OK; tier-2 preg_capture still broken (report-only)Blocker (not merge-ready)AOT binary links but segfaults at first Not merging until execute repro is green. |
After temporary full-init Context creation for preg nested JIT, restore ensureMinimalUserStandaloneBodies once PHP_COMPILER_AOT_USER_SCRIPT is re-enabled so compileToFile sees thin standalone stubs. Execute still segfaults at c:main_before_php when internal_43 calls __compiler_preg_match → PregJitHelper::matchArgv (IR verified); next step is runtime init vs nested-helper ABI mismatch after defer. Co-authored-by: Cursor <cursoragent@cursor.com>
Align PregMatchRuntime nested JIT with JitVmHelperLink — ensure VmActiveContextJitHelper::resolve lowering before compiling PregJitHelper. Execute segfault in vmpregnative.pregmatch remains open on PR #18176. Co-authored-by: Cursor <cursoragent@cursor.com>
- Fix array_splice.php JitIntdiv import (same-namespace JitIntdiv) - CloneWithJitHelper: avoid array_splice in nested clone-with path - VmPregEngine: foreach max-key scan + manual reverse (skip array_keys/reverse builtins) - PregMatchRuntime: clarify VmPregNative-only nested compile intent Root cause for execute segfault: VmPregPure::pregMatch lowers to ExternalMethod null stub when VmPregNative is nested-compiled without VmPregPure IR. Full VmPregEngine nested compile still blocked (BoundVariable). Next: register real vmpregpure::pregmatch proxy or complete VmPregEngine JIT lowering. Co-authored-by: Cursor <cursoragent@cursor.com>
#16075) Replace VmPregEngine compile/match throws with abortCompile/limitErrorCode flags so nested JIT can lower the engine without try/catch. Add VmPregUtf8 (UTF-8 subset without VM frame deps) for VmPregPure. Partial BoundVariable SCOPE_OBJECT → $this in JIT Context. Execute still segfaults: nested file compile lacks $this for instance methods; VmPregPure remains ExternalMethod stub until engine bundle compiles. Co-authored-by: Cursor <cursoragent@cursor.com>
Move modifier checks into helper methods so nested JIT no longer lowers match-on-string-offset after an e-modifier guard (structGep crash). Compile and link for tier-2 preg_capture now succeed; execute still needs VmPregPure nested lowering or real vmpregpure proxies. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Maintainer triage 2026-07-12: compile/link green per PR notes; execute still segfaults — not merge-ready. Re-run blocked on AOT execute red gate. |
|
claim: cursor-agent-lane-c — continuing PR #18176 execute segfault (VmPregPure nested JIT) |
…mpile (#18176) - Resolve BoundVariable before generic `this` name check in JIT Context - Handle SCOPE_OBJECT and by-ref BoundVariable operands in nested compile - Seed implicitThisArgument from LLVM param 0 when argVars omitted on-demand - Broaden instanceMethodUsesThis for file-scope nested class methods (#16075) - Fix VmPregEngine match/default arms: use $this->abortCompile() not broken $engine closure Execute still segfaults: VmPregPure remains external stub until VmPregEngine nested JIT completes. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Worker lane C — continuation (2026-07-12) Pushed aa464d0 on PR #18176 toward nested VmPregEngine compile for AOT execute. Root cause (narrowed)
This commit
Verification./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && vendor/bin/phpunit --filter "VmPregPatternNestedJitTest|IssetHelperRuntimeShrinkTest"'
# OK (4 tests)
./script/docker-exec.sh -- bash -lc 'source script/php-env.sh && php test/repro/preg_match_aot_minimal.php'
# compile+link OK; execute still segfault (exit 139)Next step (not merge-ready)Ensure on-demand instance method compile always registers |
* AOT: tier-2 preg_capture compile path — defer user init, fix ?? isset IR (#16075) Defer user-script Context init when the source uses preg_* so nested preg helper JIT links on a full-init module (~5s) instead of OOM/hanging under minimal user bodies. Coerce PregJitHelper capture HashTable returns for LLVM verify, route isset/?? boxed array offsets through HashTableHelper::readHashtableFromValueBox, and replace full-init superglobal refresh with the user-script native emitter after the defer path restores PHP_COMPILER_AOT_USER_SCRIPT. Remaining: standalone binary still segfaults at c:main_before_php on preg execute; phpc build can still hang with CACHE=0 on large link. Repro: php test/repro/preg_match_aot_minimal.php Co-authored-by: Cursor <cursoragent@cursor.com> * AOT: reset VmActiveContextInit state on preg defer + add repro scripts (#16075) Clear VmActiveContextInitLlvm pending/scheduled statics when deferring user-script init for preg prelink so thin __init__ emission is not skipped across Context resets. Add maintainer repro scripts for minimal preg_match and capture/coalesce AOT paths. Execute still segfaults after c:main_before_php — runtime init/helper mismatch remains open on #16075 / PR #18176. Co-authored-by: Cursor <cursoragent@cursor.com> * AOT: retrofit user-script bodies after preg prelink defer (#16075) After temporary full-init Context creation for preg nested JIT, restore ensureMinimalUserStandaloneBodies once PHP_COMPILER_AOT_USER_SCRIPT is re-enabled so compileToFile sees thin standalone stubs. Execute still segfaults at c:main_before_php when internal_43 calls __compiler_preg_match → PregJitHelper::matchArgv (IR verified); next step is runtime init vs nested-helper ABI mismatch after defer. Co-authored-by: Cursor <cursoragent@cursor.com> * AOT: register NestedVmActiveContext during preg helper compile (#16075) Align PregMatchRuntime nested JIT with JitVmHelperLink — ensure VmActiveContextJitHelper::resolve lowering before compiling PregJitHelper. Execute segfault in vmpregnative.pregmatch remains open on PR #18176. Co-authored-by: Cursor <cursoragent@cursor.com> * AOT: prep preg nested-JIT chain + document VmPregPure stub gap (#16075) - Fix array_splice.php JitIntdiv import (same-namespace JitIntdiv) - CloneWithJitHelper: avoid array_splice in nested clone-with path - VmPregEngine: foreach max-key scan + manual reverse (skip array_keys/reverse builtins) - PregMatchRuntime: clarify VmPregNative-only nested compile intent Root cause for execute segfault: VmPregPure::pregMatch lowers to ExternalMethod null stub when VmPregNative is nested-compiled without VmPregPure IR. Full VmPregEngine nested compile still blocked (BoundVariable). Next: register real vmpregpure::pregmatch proxy or complete VmPregEngine JIT lowering. Co-authored-by: Cursor <cursoragent@cursor.com> * AOT preg: exception-free VmPregEngine + VmPregUtf8 for nested JIT path (#16075) Replace VmPregEngine compile/match throws with abortCompile/limitErrorCode flags so nested JIT can lower the engine without try/catch. Add VmPregUtf8 (UTF-8 subset without VM frame deps) for VmPregPure. Partial BoundVariable SCOPE_OBJECT → $this in JIT Context. Execute still segfaults: nested file compile lacks $this for instance methods; VmPregPure remains ExternalMethod stub until engine bundle compiles. Co-authored-by: Cursor <cursoragent@cursor.com> * AOT: fix VmPregPattern nested-JIT compile segfault (#16075) Move modifier checks into helper methods so nested JIT no longer lowers match-on-string-offset after an e-modifier guard (structGep crash). Compile and link for tier-2 preg_capture now succeed; execute still needs VmPregPure nested lowering or real vmpregpure proxies. Co-authored-by: Cursor <cursoragent@cursor.com> * AOT preg: JIT $this/BoundVariable fixes toward nested VmPregEngine compile (#18176) - Resolve BoundVariable before generic `this` name check in JIT Context - Handle SCOPE_OBJECT and by-ref BoundVariable operands in nested compile - Seed implicitThisArgument from LLVM param 0 when argVars omitted on-demand - Broaden instanceMethodUsesThis for file-scope nested class methods (#16075) - Fix VmPregEngine match/default arms: use $this->abortCompile() not broken $engine closure Execute still segfaults: VmPregPure remains external stub until VmPregEngine nested JIT completes. Co-authored-by: Cursor <cursoragent@cursor.com> * Stdlib: trigger_error() enum error_level TypeError (#9086) Route VM/JIT error_level parsing through VmMath/JitIntdiv guards so enum case operands raise Zend-aligned TypeError instead of LogicException. Co-authored-by: Cursor <cursoragent@cursor.com> --------- Co-authored-by: PurHur <PurHur@users.noreply.github.com> Co-authored-by: Cursor <cursoragent@cursor.com>
BoundVariable SCOPE_OBJECT in queued nested instance methods can miss argVars when nested compiles clobber jitFunctionRootBlock. Derive $this from activeFunction when LLVM param 0 is __object__*; remove duplicate BoundVariable handler branch in getVariableFromOp. Next: VmPregEngine nested compile still hits RuntimeIndirectInstanceMethodCall on $engine->applyOptions(); AOT execute segfaults until VmPregPure is linked. Co-authored-by: Cursor <cursoragent@cursor.com>
…bug (#16075) Replace match() default arms that called abortCompile() with if/elseif chains and inlined compile-abort state — nested JIT mis-bound the scrutinee (string) as $this on match default instance calls (RuntimeIndirectInstanceMethodCall). Document remaining blocker: full VmPregEngine nested compile still needs $this binding fix in applyInlineModifier property stores before VmPregPure can link for AOT execute. Co-authored-by: Cursor <cursoragent@cursor.com>
|
Update 2026-07-12: VmPregEngine match-default IR fix pushed ( |
Add PregJitHelper::matchArgvTrivialUnanchored for delimiter-wrapped literals without metacharacters so nested JIT can match /x/-style patterns without calling VmPregPure external stubs once helper ABI is fixed. Execute still segfaults entering nested PregJitHelper from user main (ABI blocker unchanged); VM + compile/link tests green. Co-authored-by: Cursor <cursoragent@cursor.com>
Root cause for false-positive defer: source regex matched preg_* in string literals and triggered full context reset, producing execute segfaults on scripts that never call preg. Gate defer/prelink on Block literal FUNCCALL names instead. After preg prelink on temporary full-init Context, wire user-script refresh prerequisites via ensureDeferredEmitPrerequisites (no nested Multipart JIT). Use JitNestedHelperCoerce::callHelper in preg i64 bridges. Execute still segfaults entering user main when preg is actually called; next: nested PregJitHelper ABI or native LLVM trivial-match bridge. Co-authored-by: Cursor <cursoragent@cursor.com>
Reconcile PR #18176 with master's PregMatchUserScriptLlvm stub path (#18311). Drop the broken user-init defer pass that segfaulted at c:main_before_php; keep Block::containsPregPrelinkBuiltinCalls CFG literal gate (no false-positive defer on string literals containing "preg_match"). Verification: - php test/repro/preg_match_aot_minimal.php → ok - phpunit --filter PregPrelinkDeferRuntimeTest|PregJitTrivialMatchTest|... → 9/9 - make bootstrap-selfhost-vm-driver-execute-probe → OK Co-authored-by: Cursor <cursoragent@cursor.com>
Summary
Block::containsPregPrelinkBuiltinCalls()replaces source-regex detection — string literals containingpreg_matchno longer trigger false-positive prelink.PregMatchUserScriptLlvmstub path (AOT preg: user-script LLVM stubs fix preg_match execute (#16075) #18311); dropped broken user-init defer pass that segfaulted atc:main_before_php.matchArgvTrivialUnanchored, preg bridge ABI hygiene, repro scripts.Verification
Note
Full nested
PregJitHelperexecute ABI for real regex matching remains future work on #16075 epic step 3; user-script AOT uses thin LLVM stubs (returns 1 forpreg_match) per #18311 until tier-2 execute is complete.Closes #16075 (partial — CFG gate + execute no-segfault; full preg semantics WIP)