From 11581d8b097eabb6be4da062321d45ddad17f691 Mon Sep 17 00:00:00 2001 From: twosee Date: Thu, 1 Apr 2021 00:12:44 +0800 Subject: [PATCH 1/3] Add zend_get_opcode_id() to get opcode id from name --- Zend/zend_vm_opcodes.c | 10 ++++++++++ Zend/zend_vm_opcodes.h | 1 + 2 files changed, 11 insertions(+) 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() From 1828f21e9e1a115e0de07de6f14e27acd6b67143 Mon Sep 17 00:00:00 2001 From: twosee Date: Thu, 1 Apr 2021 00:14:46 +0800 Subject: [PATCH 2/3] Ignore ZEND_EXIT, ZEND_BEGIN_SILENCE, ZEND_END_SILENCE 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. --- ext/opcache/jit/zend_jit.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) 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; + } } } From a2a8411a5252dfbdada3670402d0d9c9ca4e817e Mon Sep 17 00:00:00 2001 From: twosee Date: Thu, 1 Apr 2021 00:16:00 +0800 Subject: [PATCH 3/3] Add ignored opcodes test for JIT --- ext/opcache/tests/jit/ignored_opcodes.phpt | 32 +++++++++++++++++ ext/zend_test/test.c | 42 ++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 ext/opcache/tests/jit/ignored_opcodes.phpt 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; }