diff --git a/Zend/zend.c b/Zend/zend.c index a7d456876ad..ee9021c4142 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -26,6 +26,7 @@ #include "zend_list.h" #include "zend_API.h" #include "zend_exceptions.h" +#include "zend_objects_API.h" #include "zend_builtin_functions.h" #include "zend_ini.h" #include "zend_vm.h" @@ -531,6 +532,8 @@ static void executor_globals_ctor(zend_executor_globals *executor_globals) /* {{ #ifdef ZEND_WIN32 zend_get_windows_version_info(&executor_globals->windows_version_info); #endif + memset(&EG(proxy_call_func), 0, sizeof(zend_op_array)); + zend_init_proxy_call_func(&EG(proxy_call_func), &EG(proxy_call_op)); } /* }}} */ @@ -722,6 +725,7 @@ int zend_startup(zend_utility_functions *utility_functions, char **extensions) / #ifndef ZTS zend_init_rsrc_plist(); zend_init_exception_op(); + zend_init_proxy_call_func(&EG(proxy_call_func), &EG(proxy_call_op)); #endif zend_ini_startup(); diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c index 4cec5e6c01e..e3b90b3817a 100644 --- a/Zend/zend_builtin_functions.c +++ b/Zend/zend_builtin_functions.c @@ -1292,7 +1292,7 @@ ZEND_FUNCTION(method_exists) zend_string_release(lcname); zend_string_release(func->common.function_name); - efree(func); + zend_free_proxy_call_func(func); return; } zend_string_release(lcname); diff --git a/Zend/zend_globals.h b/Zend/zend_globals.h index afd668afb87..069316774cf 100644 --- a/Zend/zend_globals.h +++ b/Zend/zend_globals.h @@ -237,6 +237,9 @@ struct _zend_executor_globals { XPFPA_CW_DATATYPE saved_fpu_cw; #endif + zend_op_array proxy_call_func; + zend_op proxy_call_op; + void *reserved[ZEND_MAX_RESERVED_RESOURCES]; }; diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 86c66e84de3..9d968c38577 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -29,7 +29,6 @@ #include "zend_interfaces.h" #include "zend_closures.h" #include "zend_compile.h" -#include "zend_vm.h" #include "zend_hash.h" #define DEBUG_OBJECT_HANDLERS 0 @@ -1035,39 +1034,9 @@ ZEND_API int zend_check_protected(zend_class_entry *ce, zend_class_entry *scope) } /* }}} */ -static inline zend_op_array *zend_get_proxy_call_function(zend_class_entry *ce, zend_string *method_name, int is_static) /* {{{ */ { - zend_op_array *call_user_call = ecalloc(1, ZEND_MM_ALIGNED_SIZE(sizeof(zend_op_array)) + sizeof(zend_op)); - zend_function *fbc = is_static? ce->__callstatic : ce->__call; - - ZEND_ASSERT(fbc); - - call_user_call->type = ZEND_USER_FUNCTION; - call_user_call->scope = ce; - call_user_call->prototype = fbc; - call_user_call->fn_flags = ZEND_ACC_CALL_VIA_HANDLER | (is_static? (ZEND_ACC_STATIC | ZEND_ACC_PUBLIC) : 0); - call_user_call->this_var = -1; - call_user_call->filename = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.filename : STR_EMPTY_ALLOC(); - call_user_call->line_start = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_start : 0; - call_user_call->line_end = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_end : 0; - call_user_call->opcodes = (zend_op *)((char *)call_user_call + ZEND_MM_ALIGNED_SIZE(sizeof(zend_op_array))); - call_user_call->opcodes[0].opcode = ZEND_PROXY_CALL; - call_user_call->opcodes[0].op1_type = IS_UNUSED; - call_user_call->opcodes[0].op2_type = IS_UNUSED; - call_user_call->opcodes[0].result_type = IS_UNUSED; - ZEND_VM_SET_OPCODE_HANDLER(&call_user_call->opcodes[0]); - if (UNEXPECTED(strlen(method_name->val) != method_name->len)) { - call_user_call->function_name = zend_string_init(method_name->val, strlen(method_name->val), 0); - } else { - call_user_call->function_name = zend_string_copy(method_name); - } - - return call_user_call; -} -/* }}} */ - static inline union _zend_function *zend_get_user_call_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */ { - return (union _zend_function *)zend_get_proxy_call_function(ce, method_name, 0); + return (union _zend_function *)zend_get_proxy_call_func(ce, method_name, 0); } /* }}} */ @@ -1198,7 +1167,7 @@ ZEND_API void zend_std_callstatic_user_call(INTERNAL_FUNCTION_PARAMETERS) /* {{{ static inline union _zend_function *zend_get_user_callstatic_function(zend_class_entry *ce, zend_string *method_name) /* {{{ */ { - return (union _zend_function *)zend_get_proxy_call_function(ce, method_name, 1); + return (union _zend_function *)zend_get_proxy_call_func(ce, method_name, 1); } /* }}} */ diff --git a/Zend/zend_objects_API.c b/Zend/zend_objects_API.c index 92e36a5558e..e9d46fb38bb 100644 --- a/Zend/zend_objects_API.c +++ b/Zend/zend_objects_API.c @@ -22,6 +22,7 @@ #include "zend.h" #include "zend_globals.h" #include "zend_variables.h" +#include "zend_vm.h" #include "zend_API.h" #include "zend_objects_API.h" @@ -224,6 +225,57 @@ ZEND_API zend_object_handlers *zend_get_std_object_handlers(void) return &std_object_handlers; } +ZEND_API void zend_init_proxy_call_func(zend_op_array *func, zend_op *opline) +{ + func->type = ZEND_USER_FUNCTION; + + func->fn_flags = ZEND_ACC_CALL_VIA_HANDLER | ZEND_ACC_PUBLIC; + func->this_var = -1; + + opline->opcode = ZEND_PROXY_CALL; + opline->op1_type = IS_UNUSED; + opline->op2_type = IS_UNUSED; + opline->result_type = IS_UNUSED; + + ZEND_VM_SET_OPCODE_HANDLER(opline); + + func->opcodes = opline; +} + +ZEND_API zend_op_array *zend_get_proxy_call_func(zend_class_entry *ce, zend_string *method_name, int is_static) +{ + zend_op_array *func; + zend_function *fbc = is_static? ce->__callstatic : ce->__call; + + ZEND_ASSERT(fbc); + + if (EXPECTED(EG(proxy_call_func).function_name == NULL)) { + func = &EG(proxy_call_func); + } else { + func = ecalloc(1, ZEND_MM_ALIGNED_SIZE(sizeof(zend_op_array)) + sizeof(zend_op)); + zend_init_proxy_call_func(func, (zend_op *)((char *)func + ZEND_MM_ALIGNED_SIZE(sizeof(zend_op_array)))); + } + + if (is_static) { + func->fn_flags |= ZEND_ACC_STATIC; + } else { + func->fn_flags &= ~ZEND_ACC_STATIC; + } + + func->scope = ce; + func->prototype = fbc; + func->filename = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.filename : STR_EMPTY_ALLOC(); + func->line_start = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_start : 0; + func->line_end = (fbc->type == ZEND_USER_FUNCTION)? fbc->op_array.line_end : 0; + if (UNEXPECTED(strlen(method_name->val) != method_name->len)) { + func->function_name = zend_string_init(method_name->val, strlen(method_name->val), 0); + } else { + func->function_name = zend_string_copy(method_name); + } + + return func; +} + /* * Local variables: * tab-width: 4 diff --git a/Zend/zend_objects_API.h b/Zend/zend_objects_API.h index 5bc7d774bce..ce8b3dda2b5 100644 --- a/Zend/zend_objects_API.h +++ b/Zend/zend_objects_API.h @@ -70,8 +70,21 @@ ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects ZEND_API zend_object *zend_object_create_proxy(zval *object, zval *member); ZEND_API zend_object_handlers *zend_get_std_object_handlers(void); + +ZEND_API void zend_init_proxy_call_func(zend_op_array *func, zend_op *opline); + +ZEND_API zend_op_array *zend_get_proxy_call_func(zend_class_entry *ce, zend_string *method_name, int is_static); + END_EXTERN_C() +#define zend_free_proxy_call_func(func) do { \ + if (((zend_op_array *)func) == &EG(proxy_call_func)) { \ + ((zend_op_array *)func)->function_name = NULL; \ + } else { \ + efree(func); \ + } \ +} while (0) + static zend_always_inline void zend_object_release(zend_object *obj) { if (--GC_REFCOUNT(obj) == 0) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 2eee43468cc..90d8283131c 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6940,7 +6940,7 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) { zend_string_release(call->func->common.function_name); - efree(call->func); + zend_free_proxy_call_func(call->func); } EX(call) = call->prev_execute_data; @@ -7596,7 +7596,7 @@ ZEND_VM_HANDLER(158, ZEND_PROXY_CALL, ANY, ANY) i_init_func_execute_data(call, &call->func->op_array, ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0); - efree(fbc); + zend_free_proxy_call_func(fbc); ZEND_VM_ENTER(); } else { @@ -7618,7 +7618,7 @@ ZEND_VM_HANDLER(158, ZEND_PROXY_CALL, ANY, ANY) execute_data = EG(current_execute_data) = call->prev_execute_data; - efree(fbc); + zend_free_proxy_call_func(fbc); zend_vm_stack_free_args(call); zend_vm_stack_free_call_frame(call); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 006687576b6..96fc5be9073 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1554,7 +1554,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER( } if (call->func->common.fn_flags & ZEND_ACC_CALL_VIA_HANDLER) { zend_string_release(call->func->common.function_name); - efree(call->func); + zend_free_proxy_call_func(call->func); } EX(call) = call->prev_execute_data; @@ -1810,7 +1810,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PROXY_CALL_SPEC_HANDLER(ZEND_O i_init_func_execute_data(call, &call->func->op_array, ret, (fbc->common.fn_flags & ZEND_ACC_STATIC) == 0); - efree(fbc); + zend_free_proxy_call_func(fbc); ZEND_VM_ENTER(); } else { @@ -1832,7 +1832,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_PROXY_CALL_SPEC_HANDLER(ZEND_O execute_data = EG(current_execute_data) = call->prev_execute_data; - efree(fbc); + zend_free_proxy_call_func(fbc); zend_vm_stack_free_args(call); zend_vm_stack_free_call_frame(call); diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index da208f6c4b5..30a1d7b351d 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -2242,7 +2242,7 @@ ZEND_METHOD(reflection_parameter, __construct) if (fptr->type != ZEND_OVERLOADED_FUNCTION) { zend_string_release(fptr->common.function_name); } - efree(fptr); + zend_free_proxy_call_func(fptr); } if (is_closure) { zval_ptr_dtor(reference);