Skip to content

Commit dc807bc

Browse files
committed
Merge branch 'PHP-8.5'
* PHP-8.5: Fix JIT vm_interrupt (#21910)
2 parents ff1bb13 + c325e9b commit dc807bc

5 files changed

Lines changed: 86 additions & 13 deletions

File tree

ext/opcache/jit/zend_jit_ir.c

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10444,28 +10444,19 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen
1044410444
if (ZEND_OBSERVER_ENABLED && (!func || (func->common.fn_flags & (ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_GENERATOR)) == 0)) {
1044510445
ir_ref observer_handler;
1044610446
ir_ref rx = jit_FP(jit);
10447+
const zend_op *observer_opline = NULL;
1044710448
struct jit_observer_fcall_is_unobserved_data unobserved_data = jit_observer_fcall_is_unobserved_start(jit, func, &observer_handler, rx, func_ref);
1044810449
if (trace && (trace->op != ZEND_JIT_TRACE_END || trace->stop < ZEND_JIT_TRACE_STOP_INTERPRETER)) {
1044910450
ZEND_ASSERT(trace[1].op == ZEND_JIT_TRACE_VM || trace[1].op == ZEND_JIT_TRACE_END);
10450-
jit_SET_EX_OPLINE(jit, trace[1].opline);
10451+
observer_opline = trace[1].opline;
10452+
jit_SET_EX_OPLINE(jit, observer_opline);
1045110453
} else {
1045210454
// EX(opline) = opline
1045310455
ir_STORE(jit_EX(opline), jit_IP(jit));
1045410456
}
1045510457
jit_observer_fcall_begin(jit, rx, observer_handler);
1045610458

10457-
if (trace) {
10458-
int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM);
10459-
10460-
exit_addr = zend_jit_trace_get_exit_addr(exit_point);
10461-
if (!exit_addr) {
10462-
return 0;
10463-
}
10464-
} else {
10465-
exit_addr = NULL;
10466-
}
10467-
10468-
zend_jit_check_timeout(jit, NULL /* we're inside the called function */, exit_addr);
10459+
zend_jit_check_timeout(jit, observer_opline, NULL);
1046910460

1047010461
jit_observer_fcall_is_unobserved_end(jit, &unobserved_data);
1047110462
}

ext/zend_test/observer.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ static void observer_begin(zend_execute_data *execute_data)
7474
{
7575
assert_observer_opline(execute_data);
7676

77+
if (ZT_G(observer_set_vm_interrupt_on_begin)) {
78+
zend_atomic_bool_store_ex(&EG(vm_interrupt), true);
79+
}
80+
7781
if (!ZT_G(observer_show_output)) {
7882
return;
7983
}
@@ -142,6 +146,14 @@ static void observer_end(zend_execute_data *execute_data, zval *retval)
142146
}
143147
}
144148

149+
static void (*zend_test_prev_interrupt_function)(zend_execute_data *execute_data);
150+
static void zend_test_interrupt_function(zend_execute_data *execute_data)
151+
{
152+
if (zend_test_prev_interrupt_function) {
153+
zend_test_prev_interrupt_function(execute_data);
154+
}
155+
}
156+
145157
static void observer_show_init(zend_function *fbc)
146158
{
147159
if (fbc->common.function_name) {
@@ -381,6 +393,7 @@ PHP_INI_BEGIN()
381393
STD_PHP_INI_BOOLEAN("zend_test.observer.show_init_backtrace", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_init_backtrace, zend_zend_test_globals, zend_test_globals)
382394
STD_PHP_INI_BOOLEAN("zend_test.observer.show_opcode", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_opcode, zend_zend_test_globals, zend_test_globals)
383395
STD_PHP_INI_ENTRY("zend_test.observer.show_opcode_in_user_handler", "", PHP_INI_SYSTEM, OnUpdateString, observer_show_opcode_in_user_handler, zend_zend_test_globals, zend_test_globals)
396+
STD_PHP_INI_BOOLEAN("zend_test.observer.set_vm_interrupt_on_begin", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_set_vm_interrupt_on_begin, zend_zend_test_globals, zend_test_globals)
384397
STD_PHP_INI_BOOLEAN("zend_test.observer.fiber_init", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_fiber_init, zend_zend_test_globals, zend_test_globals)
385398
STD_PHP_INI_BOOLEAN("zend_test.observer.fiber_switch", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_fiber_switch, zend_zend_test_globals, zend_test_globals)
386399
STD_PHP_INI_BOOLEAN("zend_test.observer.fiber_destroy", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_fiber_destroy, zend_zend_test_globals, zend_test_globals)
@@ -418,10 +431,20 @@ void zend_test_observer_init(INIT_FUNC_ARGS)
418431
zend_test_prev_execute_internal = zend_execute_internal;
419432
zend_execute_internal = zend_test_execute_internal;
420433
}
434+
435+
if (ZT_G(observer_set_vm_interrupt_on_begin)) {
436+
zend_test_prev_interrupt_function = zend_interrupt_function;
437+
zend_interrupt_function = zend_test_interrupt_function;
438+
}
421439
}
422440

423441
void zend_test_observer_shutdown(SHUTDOWN_FUNC_ARGS)
424442
{
443+
if (zend_interrupt_function == zend_test_interrupt_function) {
444+
zend_interrupt_function = zend_test_prev_interrupt_function;
445+
zend_test_prev_interrupt_function = NULL;
446+
}
447+
425448
if (type != MODULE_TEMPORARY) {
426449
UNREGISTER_INI_ENTRIES();
427450
}

ext/zend_test/php_test.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
4141
int observer_show_init_backtrace;
4242
int observer_show_opcode;
4343
char *observer_show_opcode_in_user_handler;
44+
int observer_set_vm_interrupt_on_begin;
4445
int observer_nesting_depth;
4546
int observer_fiber_init;
4647
int observer_fiber_switch;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace ZendTestJitInterrupt;
4+
5+
function external_target(mixed $value): mixed
6+
{
7+
return $value;
8+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
--TEST--
2+
Observer: VM interrupt during tracing JIT user function call
3+
--EXTENSIONS--
4+
opcache
5+
zend_test
6+
--INI--
7+
opcache.enable=1
8+
opcache.enable_cli=1
9+
opcache.file_update_protection=0
10+
opcache.jit_buffer_size=64M
11+
opcache.jit=tracing
12+
opcache.jit_hot_loop=1
13+
opcache.jit_hot_func=1
14+
opcache.jit_hot_return=1
15+
opcache.jit_hot_side_exit=1
16+
opcache.jit_max_polymorphic_calls=0
17+
zend_test.observer.enabled=1
18+
zend_test.observer.show_output=0
19+
zend_test.observer.observe_function_names=ZendTestJitInterrupt\external_target
20+
zend_test.observer.set_vm_interrupt_on_begin=1
21+
--SKIPIF--
22+
<?php
23+
if (ini_get('opcache.jit') === false) die('skip JIT not available');
24+
?>
25+
--FILE--
26+
<?php
27+
namespace ZendTestJitInterrupt;
28+
29+
// Keep the callee in a separate file so the caller uses
30+
// INIT_NS_FCALL_BY_NAME/DO_FCALL_BY_NAME, not INIT_FCALL/DO_UCALL.
31+
require __DIR__ . '/observer_jit_vm_interrupt.inc';
32+
33+
function drive_probe(int $n): int
34+
{
35+
$sum = 0;
36+
for ($i = 0; $i < $n; $i++) {
37+
$sum += external_target($i);
38+
}
39+
return $sum;
40+
}
41+
42+
$total = 0;
43+
for ($round = 0; $round < 300; $round++) {
44+
$total += drive_probe(128);
45+
}
46+
47+
echo "total={$total}\n";
48+
?>
49+
--EXPECT--
50+
total=2438400

0 commit comments

Comments
 (0)