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
This commit is contained in:
Ilija Tovilo 2024-05-16 14:02:12 +02:00
parent 8094bd1b58
commit 62ebe822de
No known key found for this signature in database
GPG Key ID: A4F5D403F118200A
7 changed files with 38 additions and 2 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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()

View File

@ -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. */

View File

@ -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 { \

View File

@ -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);
}

View File

@ -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);
}