Skip to content

Commit fc64a7b

Browse files
committed
Ignore some opcodes in JIT check
Some user opcode handler actually gets called when JIT is used, so do not disable JIT even if these user opcode handlers were registered, just ignore them. ZEND_EXIT can help Swoole to detect exit/die operation and exit from the current coroutine and record exit_status correctly. ZEND_*_SILENCE can help Swoole to switch EG(error_reporting) to keep the right behavior when using the error control operator. So we ignore ZEND_EXIT, ZEND_BEGIN_SILENCE, ZEND_END_SILENCE in JIT check here. Closes GH-6640.
1 parent cb8f39f commit fc64a7b

File tree

3 files changed

+87
-5
lines changed

3 files changed

+87
-5
lines changed

ext/opcache/jit/zend_jit.c

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4234,11 +4234,19 @@ ZEND_EXT_API int zend_jit_check_support(void)
42344234
}
42354235

42364236
for (i = 0; i <= 256; i++) {
4237-
if (zend_get_user_opcode_handler(i) != NULL) {
4238-
zend_error(E_WARNING, "JIT is incompatible with third party extensions that setup user opcode handlers. JIT disabled.");
4239-
JIT_G(enabled) = 0;
4240-
JIT_G(on) = 0;
4241-
return FAILURE;
4237+
switch (i) {
4238+
/* JIT has no effect on these opcodes */
4239+
case ZEND_BEGIN_SILENCE:
4240+
case ZEND_END_SILENCE:
4241+
case ZEND_EXIT:
4242+
break;
4243+
default:
4244+
if (zend_get_user_opcode_handler(i) != NULL) {
4245+
zend_error(E_WARNING, "JIT is incompatible with third party extensions that setup user opcode handlers. JIT disabled.");
4246+
JIT_G(enabled) = 0;
4247+
JIT_G(on) = 0;
4248+
return FAILURE;
4249+
}
42424250
}
42434251
}
42444252

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
--TEST--
2+
JIT: ignored opcodes
3+
--INI--
4+
opcache.enable=1
5+
opcache.enable_cli=1
6+
opcache.file_update_protection=0
7+
opcache.jit_buffer_size=1M
8+
opcache.jit=function
9+
;opcache.jit_debug=257
10+
zend_test.observer.enabled=1
11+
zend_test.observer.observe_all=1
12+
zend_test.observer.show_opcode_in_user_handler=ZEND_EXIT, ZEND_BEGIN_SILENCE, ZEND_END_SILENCE
13+
--SKIPIF--
14+
<?php require_once('skipif.inc'); ?>
15+
<?php if (!extension_loaded('zend_test')) die('skip: zend_test extension required'); ?>
16+
--FILE--
17+
<?php
18+
function test(): int
19+
{
20+
return 0;
21+
}
22+
23+
exit(@test());
24+
?>
25+
--EXPECTF--
26+
<!-- init '%s' -->
27+
<file '%s'>
28+
<!-- opcode: 'ZEND_BEGIN_SILENCE' in user handler -->
29+
<!-- opcode: 'ZEND_END_SILENCE' in user handler -->
30+
<!-- opcode: 'ZEND_EXIT' in user handler -->
31+
<!-- Exception: UnwindExit -->
32+
</file '%s'>

ext/zend_test/test.c

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test)
3838
int observer_show_return_value;
3939
int observer_show_init_backtrace;
4040
int observer_show_opcode;
41+
char *observer_show_opcode_in_user_handler;
4142
int observer_nesting_depth;
4243
int replace_zend_execute_ex;
4344
ZEND_END_MODULE_GLOBALS(zend_test)
@@ -346,6 +347,7 @@ PHP_INI_BEGIN()
346347
STD_PHP_INI_BOOLEAN("zend_test.observer.show_return_value", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_return_value, zend_zend_test_globals, zend_test_globals)
347348
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)
348349
STD_PHP_INI_BOOLEAN("zend_test.observer.show_opcode", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_opcode, zend_zend_test_globals, zend_test_globals)
350+
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)
349351
STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals)
350352
PHP_INI_END()
351353

@@ -357,6 +359,42 @@ static void custom_zend_execute_ex(zend_execute_data *execute_data)
357359
old_zend_execute_ex(execute_data);
358360
}
359361

362+
static int observer_show_opcode_in_user_handler(zend_execute_data *execute_data)
363+
{
364+
if (ZT_G(observer_show_output)) {
365+
php_printf("%*s<!-- opcode: '%s' in user handler -->\n", 2 * ZT_G(observer_nesting_depth), "", zend_get_opcode_name(EX(opline)->opcode));
366+
}
367+
368+
return ZEND_USER_OPCODE_DISPATCH;
369+
}
370+
371+
static void observer_set_user_opcode_handler(const char *opcode_names, user_opcode_handler_t handler)
372+
{
373+
const char *s = NULL, *e = opcode_names;
374+
375+
while (1) {
376+
if (*e == ' ' || *e == ',' || *e == '\0') {
377+
if (s) {
378+
zend_uchar opcode = zend_get_opcode_id(s, e - s);
379+
if (opcode <= ZEND_VM_LAST_OPCODE) {
380+
zend_set_user_opcode_handler(opcode, handler);
381+
} else {
382+
zend_error(E_WARNING, "Invalid opcode name %.*s", (int) (e - s), e);
383+
}
384+
s = NULL;
385+
}
386+
} else {
387+
if (!s) {
388+
s = e;
389+
}
390+
}
391+
if (*e == '\0') {
392+
break;
393+
}
394+
e++;
395+
}
396+
}
397+
360398
PHP_MINIT_FUNCTION(zend_test)
361399
{
362400
zend_test_interface = register_class__ZendTestInterface();
@@ -400,6 +438,10 @@ PHP_MINIT_FUNCTION(zend_test)
400438
zend_execute_ex = custom_zend_execute_ex;
401439
}
402440

441+
if (ZT_G(observer_enabled) && ZT_G(observer_show_opcode_in_user_handler)) {
442+
observer_set_user_opcode_handler(ZT_G(observer_show_opcode_in_user_handler), observer_show_opcode_in_user_handler);
443+
}
444+
403445
return SUCCESS;
404446
}
405447

0 commit comments

Comments
 (0)