From 62ebe822de465b6ed7cb2ebe349caf98ebc31639 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Thu, 16 May 2024 14:02:12 +0200 Subject: [PATCH] Separate internal and user function extension handles This allows us to skip zend_init_internal_run_time_cache() when opcache is enabled. This function can be quite expensive. Closes GH-14252 --- UPGRADING.INTERNALS | 5 +++++ Zend/zend_extensions.c | 19 ++++++++++++++++++- Zend/zend_extensions.h | 2 ++ Zend/zend_observer.c | 8 +++++++- Zend/zend_observer.h | 2 ++ Zend/zend_vm_def.h | 2 ++ Zend/zend_vm_execute.h | 2 ++ 7 files changed, 38 insertions(+), 2 deletions(-) diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS index 63cc0e2a21e..8f62015f733 100644 --- a/UPGRADING.INTERNALS +++ b/UPGRADING.INTERNALS @@ -81,6 +81,11 @@ PHP 8.4 INTERNALS UPGRADE NOTES got each a new parameter returning an observer which must be called, if the removal happened during observer execution. +* zend_get_internal_function_extension_handle[s]() must now be used over + zend_get_op_array_extension_handle[s]() when registering run_time_cache slots + for internal functions. If you need a cache slot for both internal and user + functions, you may obtain a slot for each through the corresponding function. + ======================== 2. Build system changes diff --git a/Zend/zend_extensions.c b/Zend/zend_extensions.c index c0c6dc81962..fe5e4fb9a7f 100644 --- a/Zend/zend_extensions.c +++ b/Zend/zend_extensions.c @@ -23,6 +23,7 @@ ZEND_API zend_llist zend_extensions; ZEND_API uint32_t zend_extension_flags = 0; ZEND_API int zend_op_array_extension_handles = 0; +ZEND_API int zend_internal_function_extension_handles = 0; static int last_resource_number; zend_result zend_load_extension(const char *path) @@ -207,6 +208,7 @@ void zend_startup_extensions_mechanism(void) /* Startup extensions mechanism */ zend_llist_init(&zend_extensions, sizeof(zend_extension), (void (*)(void *)) zend_extension_dtor, 1); zend_op_array_extension_handles = 0; + zend_internal_function_extension_handles = 0; last_resource_number = 0; } @@ -301,8 +303,23 @@ ZEND_API int zend_get_op_array_extension_handles(const char *module_name, int ha return handle; } +ZEND_API int zend_get_internal_function_extension_handle(const char *module_name) +{ + int handle = zend_internal_function_extension_handles++; + zend_add_system_entropy(module_name, "zend_get_internal_function_extension_handle", &zend_internal_function_extension_handles, sizeof(int)); + return handle; +} + +ZEND_API int zend_get_internal_function_extension_handles(const char *module_name, int handles) +{ + int handle = zend_internal_function_extension_handles; + zend_internal_function_extension_handles += handles; + zend_add_system_entropy(module_name, "zend_get_internal_function_extension_handle", &zend_internal_function_extension_handles, sizeof(int)); + return handle; +} + ZEND_API size_t zend_internal_run_time_cache_reserved_size(void) { - return zend_op_array_extension_handles * sizeof(void *); + return zend_internal_function_extension_handles * sizeof(void *); } ZEND_API void zend_init_internal_run_time_cache(void) { diff --git a/Zend/zend_extensions.h b/Zend/zend_extensions.h index 1ef2d978196..908c90e7d04 100644 --- a/Zend/zend_extensions.h +++ b/Zend/zend_extensions.h @@ -116,6 +116,8 @@ extern ZEND_API int zend_op_array_extension_handles; ZEND_API int zend_get_resource_handle(const char *module_name); ZEND_API int zend_get_op_array_extension_handle(const char *module_name); ZEND_API int zend_get_op_array_extension_handles(const char *module_name, int handles); +ZEND_API int zend_get_internal_function_extension_handle(const char *module_name); +ZEND_API int zend_get_internal_function_extension_handles(const char *module_name, int handles); ZEND_API void zend_extension_dispatch_message(int message, void *arg); END_EXTERN_C() diff --git a/Zend/zend_observer.c b/Zend/zend_observer.c index 1ef244f7baf..d8a67b1f059 100644 --- a/Zend/zend_observer.c +++ b/Zend/zend_observer.c @@ -24,7 +24,8 @@ #include "zend_vm.h" #define ZEND_OBSERVER_DATA(function) \ - ZEND_OP_ARRAY_EXTENSION((&(function)->common), zend_observer_fcall_op_array_extension) + ZEND_OP_ARRAY_EXTENSION((&(function)->common), ZEND_USER_CODE((function)->type) \ + ? zend_observer_fcall_op_array_extension : zend_observer_fcall_internal_function_extension) #define ZEND_OBSERVER_NOT_OBSERVED ((void *) 2) @@ -40,6 +41,7 @@ zend_llist zend_observer_fiber_switch; zend_llist zend_observer_fiber_destroy; int zend_observer_fcall_op_array_extension; +int zend_observer_fcall_internal_function_extension; bool zend_observer_errors_observed; bool zend_observer_function_declared_observed; bool zend_observer_class_linked_observed; @@ -64,6 +66,7 @@ ZEND_API void zend_observer_startup(void) zend_llist_init(&zend_observer_fiber_destroy, sizeof(zend_observer_fiber_destroy_handler), NULL, 1); zend_observer_fcall_op_array_extension = -1; + zend_observer_fcall_internal_function_extension = -1; } ZEND_API void zend_observer_post_startup(void) @@ -74,6 +77,9 @@ ZEND_API void zend_observer_post_startup(void) zend_observer_fcall_op_array_extension = zend_get_op_array_extension_handles("Zend Observer", (int) zend_observers_fcall_list.count * 2); + zend_observer_fcall_internal_function_extension = + zend_get_internal_function_extension_handles("Zend Observer", (int) zend_observers_fcall_list.count * 2); + /* ZEND_CALL_TRAMPOLINE has SPEC(OBSERVER) but zend_init_call_trampoline_op() * is called before any extensions have registered as an observer. So we * adjust the offset to the observed handler when we know we need to observe. */ diff --git a/Zend/zend_observer.h b/Zend/zend_observer.h index 1b6cac19449..092445811dd 100644 --- a/Zend/zend_observer.h +++ b/Zend/zend_observer.h @@ -27,10 +27,12 @@ BEGIN_EXTERN_C() extern ZEND_API int zend_observer_fcall_op_array_extension; +extern ZEND_API int zend_observer_fcall_internal_function_extension; extern ZEND_API bool zend_observer_errors_observed; extern ZEND_API bool zend_observer_function_declared_observed; extern ZEND_API bool zend_observer_class_linked_observed; +/* Omit zend_observer_fcall_internal_function_extension check, they are set at the same time. */ #define ZEND_OBSERVER_ENABLED (zend_observer_fcall_op_array_extension != -1) #define ZEND_OBSERVER_FCALL_BEGIN(execute_data) do { \ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 14293928fd2..9824a94e90b 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -8019,6 +8019,8 @@ ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_ca } /* Uncaught exception */ + + /* Don't use ZEND_OBSERVER_ENABLED because it gets replaced by zend_vm_gen.php. */ if (zend_observer_fcall_op_array_extension != -1) { zend_observer_fcall_end(execute_data, NULL); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index ac7c71fb5df..6ca5a757f78 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3199,6 +3199,8 @@ static zend_never_inline ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_dispatch_try } /* Uncaught exception */ + + /* Don't use 0 because it gets replaced by zend_vm_gen.php. */ if (zend_observer_fcall_op_array_extension != -1) { zend_observer_fcall_end(execute_data, NULL); }