diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index f25dc2e12ddd0..5b2d923d5101d 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -442,3 +442,13 @@ ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(zend_uchar opcode) { } return zend_vm_opcodes_flags[opcode]; } +ZEND_API zend_uchar zend_get_opcode_id(const char *name, size_t length) { + zend_uchar opcode; + for (opcode = 0; opcode < (sizeof(zend_vm_opcodes_names) / sizeof(zend_vm_opcodes_names[0])) - 1; opcode++) { + if (strncmp(zend_vm_opcodes_names[opcode], name, length) == 0) { + return opcode; + } + } + return ZEND_VM_LAST_OPCODE + 1; +} + diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index e7e40c8a853da..375adfbbfc290 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -79,6 +79,7 @@ BEGIN_EXTERN_C() ZEND_API const char* ZEND_FASTCALL zend_get_opcode_name(zend_uchar opcode); ZEND_API uint32_t ZEND_FASTCALL zend_get_opcode_flags(zend_uchar opcode); +ZEND_API zend_uchar zend_get_opcode_id(const char *name, size_t length); END_EXTERN_C() diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 4e8e089e501fe..70f62b796dd42 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -4234,11 +4234,19 @@ ZEND_EXT_API int zend_jit_check_support(void) } for (i = 0; i <= 256; i++) { - if (zend_get_user_opcode_handler(i) != NULL) { - zend_error(E_WARNING, "JIT is incompatible with third party extensions that setup user opcode handlers. JIT disabled."); - JIT_G(enabled) = 0; - JIT_G(on) = 0; - return FAILURE; + switch (i) { + /* JIT has no effect on these opcodes */ + case ZEND_BEGIN_SILENCE: + case ZEND_END_SILENCE: + case ZEND_EXIT: + break; + default: + if (zend_get_user_opcode_handler(i) != NULL) { + zend_error(E_WARNING, "JIT is incompatible with third party extensions that setup user opcode handlers. JIT disabled."); + JIT_G(enabled) = 0; + JIT_G(on) = 0; + return FAILURE; + } } } diff --git a/ext/opcache/tests/jit/ignored_opcodes.phpt b/ext/opcache/tests/jit/ignored_opcodes.phpt new file mode 100644 index 0000000000000..f98ae863ca57b --- /dev/null +++ b/ext/opcache/tests/jit/ignored_opcodes.phpt @@ -0,0 +1,32 @@ +--TEST-- +JIT: ignored opcodes +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.jit_buffer_size=1M +opcache.jit=function +;opcache.jit_debug=257 +zend_test.observer.enabled=1 +zend_test.observer.observe_all=1 +zend_test.observer.show_opcode_in_user_handler=ZEND_EXIT, ZEND_BEGIN_SILENCE, ZEND_END_SILENCE +--SKIPIF-- + + +--FILE-- + +--EXPECTF-- + + + + + + + diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 007634f97c343..6469f6f4a10e5 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -38,6 +38,7 @@ ZEND_BEGIN_MODULE_GLOBALS(zend_test) int observer_show_return_value; int observer_show_init_backtrace; int observer_show_opcode; + char *observer_show_opcode_in_user_handler; int observer_nesting_depth; int replace_zend_execute_ex; ZEND_END_MODULE_GLOBALS(zend_test) @@ -346,6 +347,7 @@ PHP_INI_BEGIN() 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) 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) STD_PHP_INI_BOOLEAN("zend_test.observer.show_opcode", "0", PHP_INI_SYSTEM, OnUpdateBool, observer_show_opcode, zend_zend_test_globals, zend_test_globals) + 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) 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) PHP_INI_END() @@ -357,6 +359,42 @@ static void custom_zend_execute_ex(zend_execute_data *execute_data) old_zend_execute_ex(execute_data); } +static int observer_show_opcode_in_user_handler(zend_execute_data *execute_data) +{ + if (ZT_G(observer_show_output)) { + php_printf("%*s\n", 2 * ZT_G(observer_nesting_depth), "", zend_get_opcode_name(EX(opline)->opcode)); + } + + return ZEND_USER_OPCODE_DISPATCH; +} + +static void observer_set_user_opcode_handler(const char *opcode_names, user_opcode_handler_t handler) +{ + const char *s = NULL, *e = opcode_names; + + while (1) { + if (*e == ' ' || *e == ',' || *e == '\0') { + if (s) { + zend_uchar opcode = zend_get_opcode_id(s, e - s); + if (opcode <= ZEND_VM_LAST_OPCODE) { + zend_set_user_opcode_handler(opcode, handler); + } else { + zend_error(E_WARNING, "Invalid opcode name %.*s", (int) (e - s), e); + } + s = NULL; + } + } else { + if (!s) { + s = e; + } + } + if (*e == '\0') { + break; + } + e++; + } +} + PHP_MINIT_FUNCTION(zend_test) { zend_test_interface = register_class__ZendTestInterface(); @@ -400,6 +438,10 @@ PHP_MINIT_FUNCTION(zend_test) zend_execute_ex = custom_zend_execute_ex; } + if (ZT_G(observer_enabled) && ZT_G(observer_show_opcode_in_user_handler)) { + observer_set_user_opcode_handler(ZT_G(observer_show_opcode_in_user_handler), observer_show_opcode_in_user_handler); + } + return SUCCESS; }