mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Fit JIT variable not stored before YIELD
JIT doesn't recognize that variables may be used after returning from a trace due to YIELD, so some effects may never be stored to memory. YIELD ops terminate trace recordings with ZEND_JIT_TRACE_STOP_RETURN, and are handled mostly like RETURN. Here I change zend_jit_trace_execute() so that YIELD terminates recordings with ZEND_JIT_TRACE_STOP_INTERPRETER instead, to ensure that we recognize that variables may be used after returning from the trace due to YIELD. Fixes GH-19493 Closes GH-19515
This commit is contained in:
3
NEWS
3
NEWS
@@ -6,6 +6,9 @@ PHP NEWS
|
||||
. Fixed bug GH-18850 (Repeated inclusion of file with __halt_compiler()
|
||||
triggers "Constant already defined" warning). (ilutov)
|
||||
|
||||
- Opcache:
|
||||
. Fixed bug GH-19493 (JIT variable not stored before YIELD). (Arnaud)
|
||||
|
||||
- OpenSSL:
|
||||
. Fixed bug GH-19245 (Success error message on TLS stream accept failure).
|
||||
(Jakub Zelenka)
|
||||
|
||||
@@ -937,11 +937,18 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef HAVE_GCC_GLOBAL_REGS
|
||||
const zend_op *prev_opline = opline;
|
||||
#endif
|
||||
handler = (zend_vm_opcode_handler_t)ZEND_OP_TRACE_INFO(opline, offset)->call_handler;
|
||||
#ifdef HAVE_GCC_GLOBAL_REGS
|
||||
handler();
|
||||
if (UNEXPECTED(opline == zend_jit_halt_op)) {
|
||||
stop = ZEND_JIT_TRACE_STOP_RETURN;
|
||||
if (prev_opline->opcode == ZEND_YIELD || prev_opline->opcode == ZEND_YIELD_FROM) {
|
||||
stop = ZEND_JIT_TRACE_STOP_INTERPRETER;
|
||||
} else {
|
||||
stop = ZEND_JIT_TRACE_STOP_RETURN;
|
||||
}
|
||||
opline = NULL;
|
||||
halt = ZEND_JIT_TRACE_HALT;
|
||||
break;
|
||||
@@ -951,7 +958,11 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex,
|
||||
rc = handler(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU);
|
||||
if (rc != 0) {
|
||||
if (rc < 0) {
|
||||
stop = ZEND_JIT_TRACE_STOP_RETURN;
|
||||
if (opline->opcode == ZEND_YIELD || opline->opcode == ZEND_YIELD_FROM) {
|
||||
stop = ZEND_JIT_TRACE_STOP_INTERPRETER;
|
||||
} else {
|
||||
stop = ZEND_JIT_TRACE_STOP_RETURN;
|
||||
}
|
||||
opline = NULL;
|
||||
halt = ZEND_JIT_TRACE_HALT;
|
||||
break;
|
||||
|
||||
24
ext/opcache/tests/jit/gh19493-001.phpt
Normal file
24
ext/opcache/tests/jit/gh19493-001.phpt
Normal file
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
GH-19493 001: Var not stored before YIELD
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function f() {
|
||||
$offset = 0;
|
||||
yield true;
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$offset++;
|
||||
if ($offset === 99) {
|
||||
break;
|
||||
}
|
||||
yield true;
|
||||
}
|
||||
return $offset;
|
||||
}
|
||||
$gen = f();
|
||||
foreach ($gen as $v) {}
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(99)
|
||||
24
ext/opcache/tests/jit/gh19493-002.phpt
Normal file
24
ext/opcache/tests/jit/gh19493-002.phpt
Normal file
@@ -0,0 +1,24 @@
|
||||
--TEST--
|
||||
GH-19493 002: Var not stored before YIELD_FROM
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function f() {
|
||||
$offset = 0;
|
||||
yield from [true];
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$offset++;
|
||||
if ($offset === 99) {
|
||||
break;
|
||||
}
|
||||
yield from [true];
|
||||
}
|
||||
return $offset;
|
||||
}
|
||||
$gen = f();
|
||||
foreach ($gen as $v) {}
|
||||
var_dump($gen->getReturn());
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
int(99)
|
||||
Reference in New Issue
Block a user