[php-src] PR #24651: Tracing JIT: keep the SEND_VAL type guard after assigning to a reference
| From: | waroad | Date: | Sat, 24 Oct 2026 15:42:54 +0000 |
| Subject: | [php-src] PR #24651: Tracing JIT: keep the SEND_VAL type guard after assigning to a reference | ||
| Groups: | php.git-pulls | ||
| Request: | Send a blank email to git-pulls+get-39823@lists.php.net to get a copy of this message | ||
Pull Request: https://github.com/php/php-src/pull/24651
Author: waroad
@ndossche here is the patch I offered in the issue, as you asked.
With
opcache.jit=tracing, a trace like sink($x = $y + 2) can be recorded
while $x is a reference to an untyped property, then run while $x is a
reference to a typed float (or string) property. When that happens,
sink() receives an int holding the raw bits of the converted value:
int(4617315517961601024) instead of float(5), and for a
string property an unrelated int (int(1097804056) in my run) instead of
string(1) "5".
When an ASSIGN result goes straight into the following SEND_VAL, the
tracing JIT fuses the two. The result is written directly into the callee's argument slot, the
SEND_VAL is skipped, and the callee's parameter takes the type recorded for the
SEND_VAL operand. That type was never checked. It's fine when the result is a copy
of the guarded op2, but the typed reference helper can coerce the value, so the recorded type may be
wrong. The fix stops fusing in that case: when op1 is a guarded reference (ref_addr is
set), the result goes to its own slot as usual, and SEND_VAL checks its type and
side-exits if it doesn't match. The reference branch also had a second copy of the result
address / send-fusion code, which the shared code right after it already does. I removed that copy
so there is only one place to apply the condition.
The new test ext/opcache/tests/jit/gh24436.phpt runs the same call site with untyped,
typed float and typed string property references. It fails without the
patch and passes with it, both with run-tests' defaults and with CI's tracing JIT options.
The reproducer from the issue, run with the command line given there, also prints
int(4617315517961601024) before the patch and float(5) after.
ext/opcache/tests passes in both tracing and function JIT modes. I based this on
PHP-8.4 since that's the branch I reproduced and tested on.
Fixes #24436.
Found with an LLM-based testing tool; I wrote this fix with help from Claude and reviewed it myself.