From e0a40f46a185688b0c866d8fd081f35653a32e92 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 22 Jul 2024 19:21:19 +0200 Subject: [PATCH 1/8] Add API to exempt function from being JITed Signed-off-by: Bob Weinand --- ext/opcache/jit/zend_jit.h | 3 ++- ext/opcache/jit/zend_jit_trace.c | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/ext/opcache/jit/zend_jit.h b/ext/opcache/jit/zend_jit.h index 1e0176a4f4f55..0ce6c1a4409a2 100644 --- a/ext/opcache/jit/zend_jit.h +++ b/ext/opcache/jit/zend_jit.h @@ -162,7 +162,8 @@ void zend_jit_startup(void *jit_buffer, size_t size, bool reattached); void zend_jit_shutdown(void); void zend_jit_activate(void); void zend_jit_deactivate(void); -void zend_jit_status(zval *ret); +ZEND_EXT_API void zend_jit_status(zval *ret); +ZEND_EXT_API void zend_jit_blacklist_function(zend_op_array *op_array); void zend_jit_restart(void); #define ZREG_LOAD (1<<0) diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 82f360992607e..7cb625eb42c2c 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -7656,6 +7656,23 @@ static void zend_jit_blacklist_root_trace(const zend_op *opline, size_t offset) zend_shared_alloc_unlock(); } +ZEND_EXT_API void zend_jit_blacklist_function(zend_op_array *op_array) { + zend_jit_op_array_trace_extension *jit_extension = (zend_jit_op_array_trace_extension *)ZEND_FUNC_INFO(op_array); + if (!jit_extension) { + return; + } + + // First not-skipped op + zend_op *opline = op_array->opcodes; + if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) { + while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) { + opline++; + } + } + + zend_jit_blacklist_root_trace(opline, jit_extension->offset); +} + static bool zend_jit_trace_is_bad_root(const zend_op *opline, zend_jit_trace_stop stop, size_t offset) { const zend_op **cache_opline = JIT_G(bad_root_cache_opline); From d4fdaa69e7c831013b3ceb54909bc5d8c051bcb0 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 2 Sep 2024 13:37:37 +0200 Subject: [PATCH 2/8] Add check for blacklisted traces when calling functions Signed-off-by: Bob Weinand --- ext/opcache/jit/zend_jit_vm_helpers.c | 54 ++++++++++++++++++++------- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index d93e5fce94780..8d017912d8e02 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -521,16 +521,27 @@ static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend && (func->op_array.fn_flags & (ZEND_ACC_CLOSURE|ZEND_ACC_FAKE_CLOSURE))) { return -1; } - if (func->type == ZEND_USER_FUNCTION - && (func->op_array.fn_flags & ZEND_ACC_CLOSURE)) { + if (func->type == ZEND_USER_FUNCTION) { jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(&func->op_array); - if (UNEXPECTED(!jit_extension - || !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE) - || (func->op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE))) { + if (func->op_array.fn_flags & ZEND_ACC_CLOSURE) { + if (UNEXPECTED(!jit_extension + || !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE) + || (func->op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE))) { + return -1; + } + func = (zend_function*)jit_extension->op_array; + } + // First not-skipped op + zend_op *opline = func->op_array.opcodes; + if (!(func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) { + while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) { + opline++; + } + } + if (jit_extension && ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED) { return -1; } - func = (zend_function*)jit_extension->op_array; } if (is_megamorphic == ZEND_JIT_EXIT_POLYMORPHISM /* TODO: use more accurate check ??? */ @@ -986,6 +997,11 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, break; } + if (jit_extension && ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED) { + stop = ZEND_JIT_TRACE_STOP_BLACK_LIST; + break; + } + TRACE_RECORD(ZEND_JIT_TRACE_ENTER, EX(return_value) != NULL ? ZEND_JIT_TRACE_RETURN_VALUE_USED : 0, op_array); @@ -1100,17 +1116,29 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, stop = ZEND_JIT_TRACE_STOP_BAD_FUNC; break; } - if (func->type == ZEND_USER_FUNCTION - && (func->op_array.fn_flags & ZEND_ACC_CLOSURE)) { + if (func->type == ZEND_USER_FUNCTION) { jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(&func->op_array); - if (UNEXPECTED(!jit_extension) - || !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE) - || (func->op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE)) { - stop = ZEND_JIT_TRACE_STOP_INTERPRETER; + if (func->op_array.fn_flags & ZEND_ACC_CLOSURE) { + if (UNEXPECTED(!jit_extension + || !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE) + || (func->op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE))) { + stop = ZEND_JIT_TRACE_STOP_INTERPRETER; + break; + } + func = (zend_function*)jit_extension->op_array; + } + // First not-skipped op + zend_op *opline = func->op_array.opcodes; + if (!(func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) { + while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) { + opline++; + } + } + if (jit_extension && ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED) { + stop = ZEND_JIT_TRACE_STOP_BLACK_LIST; break; } - func = (zend_function*)jit_extension->op_array; } #ifndef HAVE_GCC_GLOBAL_REGS From 8e067ce951423ab76796b72bed1b18039502ffac Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 2 Sep 2024 19:56:39 +0200 Subject: [PATCH 3/8] Allow EG(vm_interrupt) in observer start handler to leave JIT Signed-off-by: Bob Weinand --- ext/opcache/jit/zend_jit_ir.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 133aa49cd2f56..832e410d1942b 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -10102,6 +10102,22 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen ir_STORE(jit_EX(opline), jit_IP(jit)); } jit_observer_fcall_begin(jit, rx, observer_handler); + + if (trace) { + int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); + + exit_addr = zend_jit_trace_get_exit_addr(exit_point); + if (!exit_addr) { + return 0; + } + } else { + exit_addr = NULL; + } + + if (!zend_jit_check_timeout(jit, NULL /* we're inside the called function */, exit_addr)) { + return 0; + } + jit_observer_fcall_is_unobserved_end(jit, &unobserved_data); } From e9bb4035811ebe5fa1f7a7f215e4b12c92747ee3 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 2 Sep 2024 21:47:15 +0200 Subject: [PATCH 4/8] Also reset hot handlers Signed-off-by: Bob Weinand --- ext/opcache/jit/zend_jit.c | 2 +- ext/opcache/jit/zend_jit_trace.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index e247b35f953d2..5657764926706 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -706,7 +706,7 @@ static bool zend_may_be_dynamic_property(zend_class_entry *ce, zend_string *memb # endif #endif -void zend_jit_status(zval *ret) +ZEND_EXT_API void zend_jit_status(zval *ret) { zval stats; array_init(&stats); diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 7cb625eb42c2c..41a7a773bde5b 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -7662,6 +7662,8 @@ ZEND_EXT_API void zend_jit_blacklist_function(zend_op_array *op_array) { return; } + zend_jit_stop_persistent_op_array(op_array); + // First not-skipped op zend_op *opline = op_array->opcodes; if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) { From 4349069b439568defa8123db5de47be44e9f5470 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 16 Sep 2024 19:03:50 +0200 Subject: [PATCH 5/8] Use ZEND_FUNC_JIT_ON_HOT_TRACE flag Signed-off-by: Bob Weinand --- ext/opcache/jit/zend_jit_trace.c | 17 +++++++---------- ext/opcache/jit/zend_jit_vm_helpers.c | 27 ++++++--------------------- ext/opcache/opcache.stub.php | 2 ++ ext/opcache/opcache_arginfo.h | 8 +++++++- ext/opcache/zend_accelerator_module.c | 16 ++++++++++++++++ 5 files changed, 38 insertions(+), 32 deletions(-) diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 41a7a773bde5b..400b0848ca145 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -7658,21 +7658,18 @@ static void zend_jit_blacklist_root_trace(const zend_op *opline, size_t offset) ZEND_EXT_API void zend_jit_blacklist_function(zend_op_array *op_array) { zend_jit_op_array_trace_extension *jit_extension = (zend_jit_op_array_trace_extension *)ZEND_FUNC_INFO(op_array); - if (!jit_extension) { + if (!jit_extension || !(jit_extension->func_info.flags & ZEND_JIT_ON_HOT_TRACE)) { return; } - zend_jit_stop_persistent_op_array(op_array); + zend_shared_alloc_lock(); + SHM_UNPROTECT(); - // First not-skipped op - zend_op *opline = op_array->opcodes; - if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) { - while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) { - opline++; - } - } + zend_jit_stop_persistent_op_array(op_array); + jit_extension->func_info.flags &= ~ZEND_FUNC_JIT_ON_HOT_TRACE; - zend_jit_blacklist_root_trace(opline, jit_extension->offset); + SHM_PROTECT(); + zend_shared_alloc_unlock(); } static bool zend_jit_trace_is_bad_root(const zend_op *opline, zend_jit_trace_stop stop, size_t offset) diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index 8d017912d8e02..30b9a53fd5427 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -524,24 +524,14 @@ static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend if (func->type == ZEND_USER_FUNCTION) { jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(&func->op_array); - if (func->op_array.fn_flags & ZEND_ACC_CLOSURE) { - if (UNEXPECTED(!jit_extension - || !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE) - || (func->op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE))) { - return -1; - } - func = (zend_function*)jit_extension->op_array; - } - // First not-skipped op - zend_op *opline = func->op_array.opcodes; - if (!(func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) { - while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) { - opline++; - } - } - if (jit_extension && ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED) { + if (UNEXPECTED(!jit_extension + || !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE) + || (func->op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE))) { return -1; } + if (func->op_array.fn_flags & ZEND_ACC_CLOSURE) { + func = (zend_function*)jit_extension->op_array; + } } if (is_megamorphic == ZEND_JIT_EXIT_POLYMORPHISM /* TODO: use more accurate check ??? */ @@ -997,11 +987,6 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, break; } - if (jit_extension && ZEND_OP_TRACE_INFO(opline, offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED) { - stop = ZEND_JIT_TRACE_STOP_BLACK_LIST; - break; - } - TRACE_RECORD(ZEND_JIT_TRACE_ENTER, EX(return_value) != NULL ? ZEND_JIT_TRACE_RETURN_VALUE_USED : 0, op_array); diff --git a/ext/opcache/opcache.stub.php b/ext/opcache/opcache.stub.php index 4eeb76f083bc5..526da238219a4 100644 --- a/ext/opcache/opcache.stub.php +++ b/ext/opcache/opcache.stub.php @@ -14,6 +14,8 @@ function opcache_compile_file(string $filename): bool {} function opcache_invalidate(string $filename, bool $force = false): bool {} +function opcache_jit_blacklist(Closure $closure): void {} + /** * @return array|false * @refcount 1 diff --git a/ext/opcache/opcache_arginfo.h b/ext/opcache/opcache_arginfo.h index b3e893fead62e..b4dc1f33a5fd8 100644 --- a/ext/opcache/opcache_arginfo.h +++ b/ext/opcache/opcache_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 81f337ea4ac5361ca4a0873fcd3b033beaf524c6 */ + * Stub hash: c416c231c5d1270b7e5961f84cc3ca3e29db4959 */ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_opcache_reset, 0, 0, _IS_BOOL, 0) ZEND_END_ARG_INFO() @@ -17,6 +17,10 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_opcache_invalidate, 0, 1, _IS_BO ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, force, _IS_BOOL, 0, "false") ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_opcache_jit_blacklist, 0, 1, IS_VOID, 0) + ZEND_ARG_OBJ_INFO(0, closure, Closure, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_opcache_get_configuration, 0, 0, MAY_BE_ARRAY|MAY_BE_FALSE) ZEND_END_ARG_INFO() @@ -26,6 +30,7 @@ ZEND_FUNCTION(opcache_reset); ZEND_FUNCTION(opcache_get_status); ZEND_FUNCTION(opcache_compile_file); ZEND_FUNCTION(opcache_invalidate); +ZEND_FUNCTION(opcache_jit_blacklist); ZEND_FUNCTION(opcache_get_configuration); ZEND_FUNCTION(opcache_is_script_cached); @@ -34,6 +39,7 @@ static const zend_function_entry ext_functions[] = { ZEND_FE(opcache_get_status, arginfo_opcache_get_status) ZEND_FE(opcache_compile_file, arginfo_opcache_compile_file) ZEND_FE(opcache_invalidate, arginfo_opcache_invalidate) + ZEND_FE(opcache_jit_blacklist, arginfo_opcache_jit_blacklist) ZEND_FE(opcache_get_configuration, arginfo_opcache_get_configuration) ZEND_FE(opcache_is_script_cached, arginfo_opcache_is_script_cached) ZEND_FE_END diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index cf1e86bb52442..3d358c9da7fa3 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -24,6 +24,7 @@ #include "php.h" #include "ZendAccelerator.h" #include "zend_API.h" +#include "zend_closures.h" #include "zend_shared_alloc.h" #include "zend_accelerator_blacklist.h" #include "php_ini.h" @@ -924,6 +925,21 @@ ZEND_FUNCTION(opcache_invalidate) } } +/* {{{ Prevents JIT on function. Call it before the first invocation of the given function. */ +ZEND_FUNCTION(opcache_jit_blacklist) +{ + zend_object *closure; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &closure, zend_ce_closure) == FAILURE) { + RETURN_THROWS(); + } + + const zend_function *func = zend_get_closure_method_def(closure); + if (ZEND_USER_CODE(func->type)) { + zend_jit_blacklist_function((zend_op_array *)&func->op_array); + } +} + ZEND_FUNCTION(opcache_compile_file) { zend_string *script_name; From 498f6aec37b98aaf5d12daa77ccddbd064f7fa78 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 16 Sep 2024 19:09:54 +0200 Subject: [PATCH 6/8] Fix after rebase Signed-off-by: Bob Weinand --- ext/opcache/jit/zend_jit_ir.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ext/opcache/jit/zend_jit_ir.c b/ext/opcache/jit/zend_jit_ir.c index 832e410d1942b..38ee5c409c322 100644 --- a/ext/opcache/jit/zend_jit_ir.c +++ b/ext/opcache/jit/zend_jit_ir.c @@ -10114,9 +10114,7 @@ static int zend_jit_do_fcall(zend_jit_ctx *jit, const zend_op *opline, const zen exit_addr = NULL; } - if (!zend_jit_check_timeout(jit, NULL /* we're inside the called function */, exit_addr)) { - return 0; - } + zend_jit_check_timeout(jit, NULL /* we're inside the called function */, exit_addr); jit_observer_fcall_is_unobserved_end(jit, &unobserved_data); } From 6e9081018e36b3ddeb41595733a2ec7e52610ed1 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Fri, 20 Sep 2024 13:59:29 +0200 Subject: [PATCH 7/8] Fixup remaining place in zend_jit_vm_helpers.c And add basic test for opcache_jit_blacklist. Signed-off-by: Bob Weinand --- ext/opcache/jit/zend_jit_trace.c | 4 ++- ext/opcache/jit/zend_jit_vm_helpers.c | 29 ++++++------------- .../tests/jit/opcache_jit_blacklist.phpt | 23 +++++++++++++++ ext/opcache/zend_accelerator_module.c | 4 +-- 4 files changed, 37 insertions(+), 23 deletions(-) create mode 100644 ext/opcache/tests/jit/opcache_jit_blacklist.phpt diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 400b0848ca145..379eb96174025 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -7658,16 +7658,18 @@ static void zend_jit_blacklist_root_trace(const zend_op *opline, size_t offset) ZEND_EXT_API void zend_jit_blacklist_function(zend_op_array *op_array) { zend_jit_op_array_trace_extension *jit_extension = (zend_jit_op_array_trace_extension *)ZEND_FUNC_INFO(op_array); - if (!jit_extension || !(jit_extension->func_info.flags & ZEND_JIT_ON_HOT_TRACE)) { + if (!jit_extension || !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE)) { return; } zend_shared_alloc_lock(); SHM_UNPROTECT(); + zend_jit_unprotect(); zend_jit_stop_persistent_op_array(op_array); jit_extension->func_info.flags &= ~ZEND_FUNC_JIT_ON_HOT_TRACE; + zend_jit_protect(); SHM_PROTECT(); zend_shared_alloc_unlock(); } diff --git a/ext/opcache/jit/zend_jit_vm_helpers.c b/ext/opcache/jit/zend_jit_vm_helpers.c index 30b9a53fd5427..2eeb43a4f754f 100644 --- a/ext/opcache/jit/zend_jit_vm_helpers.c +++ b/ext/opcache/jit/zend_jit_vm_helpers.c @@ -524,9 +524,9 @@ static int zend_jit_trace_record_fake_init_call_ex(zend_execute_data *call, zend if (func->type == ZEND_USER_FUNCTION) { jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(&func->op_array); - if (UNEXPECTED(!jit_extension - || !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE) - || (func->op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE))) { + if (UNEXPECTED(!jit_extension && (func->op_array.fn_flags & ZEND_ACC_CLOSURE)) + || (jit_extension && !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE)) + || (func->op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE)) { return -1; } if (func->op_array.fn_flags & ZEND_ACC_CLOSURE) { @@ -1104,26 +1104,15 @@ zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *ex, if (func->type == ZEND_USER_FUNCTION) { jit_extension = (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(&func->op_array); + if (UNEXPECTED(!jit_extension && (func->op_array.fn_flags & ZEND_ACC_CLOSURE)) + || (jit_extension && !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE)) + || (func->op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE)) { + stop = ZEND_JIT_TRACE_STOP_INTERPRETER; + break; + } if (func->op_array.fn_flags & ZEND_ACC_CLOSURE) { - if (UNEXPECTED(!jit_extension - || !(jit_extension->func_info.flags & ZEND_FUNC_JIT_ON_HOT_TRACE) - || (func->op_array.fn_flags & ZEND_ACC_FAKE_CLOSURE))) { - stop = ZEND_JIT_TRACE_STOP_INTERPRETER; - break; - } func = (zend_function*)jit_extension->op_array; } - // First not-skipped op - zend_op *opline = func->op_array.opcodes; - if (!(func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) { - while (opline->opcode == ZEND_RECV || opline->opcode == ZEND_RECV_INIT) { - opline++; - } - } - if (jit_extension && ZEND_OP_TRACE_INFO(opline, jit_extension->offset)->trace_flags & ZEND_JIT_TRACE_BLACKLISTED) { - stop = ZEND_JIT_TRACE_STOP_BLACK_LIST; - break; - } } #ifndef HAVE_GCC_GLOBAL_REGS diff --git a/ext/opcache/tests/jit/opcache_jit_blacklist.phpt b/ext/opcache/tests/jit/opcache_jit_blacklist.phpt new file mode 100644 index 0000000000000..33db720967555 --- /dev/null +++ b/ext/opcache/tests/jit/opcache_jit_blacklist.phpt @@ -0,0 +1,23 @@ +--TEST-- +Basic usage of opcache_jit_blacklist() +--INI-- +opcache.enable=1 +opcache.enable_cli=1 +opcache.file_update_protection=0 +opcache.protect_memory=1 +opcache.jit=tracing +--EXTENSIONS-- +opcache +--FILE-- + +--EXPECT-- +int(2) diff --git a/ext/opcache/zend_accelerator_module.c b/ext/opcache/zend_accelerator_module.c index 3d358c9da7fa3..359ba9418e289 100644 --- a/ext/opcache/zend_accelerator_module.c +++ b/ext/opcache/zend_accelerator_module.c @@ -928,13 +928,13 @@ ZEND_FUNCTION(opcache_invalidate) /* {{{ Prevents JIT on function. Call it before the first invocation of the given function. */ ZEND_FUNCTION(opcache_jit_blacklist) { - zend_object *closure; + zval *closure; if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &closure, zend_ce_closure) == FAILURE) { RETURN_THROWS(); } - const zend_function *func = zend_get_closure_method_def(closure); + const zend_function *func = zend_get_closure_method_def(Z_OBJ_P(closure)); if (ZEND_USER_CODE(func->type)) { zend_jit_blacklist_function((zend_op_array *)&func->op_array); } From ef5500f4e0e8c0c408d1eebb85d211efa661d036 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Tue, 24 Sep 2024 14:17:58 +0200 Subject: [PATCH 8/8] Add NEWS/UPGRADING entries --- NEWS | 1 + UPGRADING | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/NEWS b/NEWS index 145a1d9a5cb56..c819c21872475 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,7 @@ PHP NEWS - Opcache: . Fixed bug GH-15657 (Segmentation fault in dasm_x86.h). (nielsdos) + . Added opcache_jit_blacklist() function. (Bob) - PHPDBG: . Fixed bug GH-15901 (phpdbg: Assertion failure on i funcs). (cmb) diff --git a/UPGRADING b/UPGRADING index c046257074cd4..36ee66c1e085d 100644 --- a/UPGRADING +++ b/UPGRADING @@ -815,6 +815,10 @@ PHP 8.4 UPGRADE NOTES . Added mb_ucfirst and mb_lcfirst functions. RFC: https://wiki.php.net/rfc/mb_ucfirst +- OPCache: + . Added opcache_jit_blacklist function. It allows skipping the tracing JIT + execution of select functions. + - PCNTL: . Added pcntl_setns allowing a process to be reassociated with a namespace in order to share resources with other processes within this context.