[php-src] Issue #24386: JIT: ir_gcm_schedule_late assertion "Early placement doesn't dominate the late" with tracing JIT
| From: | waroad | Date: | Sat, 17 Oct 2026 19:17:46 +0000 |
| Subject: | [php-src] Issue #24386: JIT: ir_gcm_schedule_late assertion "Early placement doesn't dominate the late" with tracing JIT | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-253012@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/24386
Author: waroad
With the tracing JIT and low hot thresholds, a by-ref
foreach over an array argument
plus a function using global and static, called from a hot loop, hits an
assertion in ir_gcm_schedule_late() when the trace is compiled.
```php
<?php
function arrays($a) {
foreach ($a as &$v) $v += 1;
}
function counter($n) {
global $g;
static $total = 0;
$g += $n;
$total += $n;
}
for ($i = 0; $i < 100; $i++) {
arrays([4]);
counter(2);
}
```
```
php -n -d opcache.enable_cli=1 -d opcache.file_update_protection=0 -d opcache.jit_buffer_size=64M -d
opcache.protect_memory=1 -d opcache.jit=tracing -d opcache.jit_hot_func=2 -d opcache.jit_hot_loop=2
-d opcache.jit_hot_return=2 -d opcache.jit_hot_side_exit=2 input.php
```
```
php: ext/opcache/jit/ir/ir_gcm.c:579: ir_gcm_schedule_late: Assertion `ir_gcm_dominates(ctx,
ctx->cfg_map[ref], lca) && "Early placement doesn't dominate the
late"' failed.
```
I expected the script to run and exit normally, as it does on the release build and with
opcache.jit=0.
It reproduces at 5ccc56b1e43f (latest upstream when checked). It is assertion-only: the build with
assertions enabled aborts (rc 134, SIGABRT), the release build exits 0 with correct output. The same
assertion was reported in #17190 (closed); I did not check whether it is the same cause.
opcache.jit=1252, 1253 and 0153 with the same thresholds also
fail; jit=function does not. With the default hot thresholds the loop never gets hot
and nothing fails.
Looks like the trace IR built in zend_jit_trace.c/zend_jit_ir.c has a
value used in a block that its early-scheduled block does not dominate, which
ir_gcm_schedule_late() then catches. I did not find the exact node. It still fails with
PR #24298 (Update IR) applied. PR #18392 (JIT: Don't reuse IP register for EX(call)) may be
related; not tested here, its diff does not apply on the latest commit.
Found with an LLM-based testing tool; I used Claude to reduce it and look for the cause.