From 1a1178a685a0a366d7b435af635cbcc6f2850ab4 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Tue, 6 Jul 2010 11:40:17 +0000 Subject: [PATCH] eliminated unnecessary iterations during request startup/shutdown --- NEWS | 1 + Zend/zend.c | 34 +------- Zend/zend_API.c | 166 ++++++++++++++++++++++++++++++++++++++-- Zend/zend_API.h | 1 + Zend/zend_compile.c | 7 ++ Zend/zend_compile.h | 7 ++ Zend/zend_execute_API.c | 4 +- Zend/zend_opcode.c | 71 ++++++++++++----- 8 files changed, 229 insertions(+), 62 deletions(-) diff --git a/NEWS b/NEWS index c0662a5a31..da0fe6290b 100644 --- a/NEWS +++ b/NEWS @@ -17,6 +17,7 @@ PHP NEWS . optimized access to static properties using executor specialization. A constant class name may be used as a direct operand of ZEND_FETCH_* instruction without previous ZEND_FETCH_CLASS. + . eliminated unnecessary iterations during request startup/shutdown - Added concept of interned strings. All strings constants known at compile time are allocated in a single copy and never changed. (Dmitry) - Added an optimization which saves memory and emalloc/efree calls for empty diff --git a/Zend/zend.c b/Zend/zend.c index 64a75511f4..cdf6dacfbd 100644 --- a/Zend/zend.c +++ b/Zend/zend.c @@ -761,7 +761,7 @@ void zend_shutdown(TSRMLS_D) /* {{{ */ zend_shutdown_timeout_thread(); #endif zend_destroy_rsrc_list(&EG(persistent_list) TSRMLS_CC); - zend_hash_graceful_reverse_destroy(&module_registry); + zend_destroy_modules(); zend_hash_destroy(GLOBAL_FUNCTION_TABLE); zend_hash_destroy(GLOBAL_CLASS_TABLE); @@ -859,22 +859,6 @@ void zend_activate(TSRMLS_D) /* {{{ */ } /* }}} */ -void zend_activate_modules(TSRMLS_D) /* {{{ */ -{ - zend_hash_apply(&module_registry, (apply_func_t) module_registry_request_startup TSRMLS_CC); -} -/* }}} */ - -void zend_deactivate_modules(TSRMLS_D) /* {{{ */ -{ - EG(opline_ptr) = NULL; /* we're no longer executing anything */ - - zend_try { - zend_hash_reverse_apply(&module_registry, (apply_func_t) module_registry_cleanup TSRMLS_CC); - } zend_end_try(); -} -/* }}} */ - void zend_call_destructors(TSRMLS_D) /* {{{ */ { zend_try { @@ -928,22 +912,6 @@ void zend_deactivate(TSRMLS_D) /* {{{ */ } /* }}} */ -static int exec_done_cb(zend_module_entry *module TSRMLS_DC) /* {{{ */ -{ - if (module->post_deactivate_func) { - module->post_deactivate_func(); - } - return 0; -} -/* }}} */ - -void zend_post_deactivate_modules(TSRMLS_D) /* {{{ */ -{ - zend_hash_apply(&module_registry, (apply_func_t) exec_done_cb TSRMLS_CC); - zend_hash_reverse_apply(&module_registry, (apply_func_t) module_registry_unload_temp TSRMLS_CC); -} -/* }}} */ - BEGIN_EXTERN_C() ZEND_API void zend_message_dispatcher(long message, void *data TSRMLS_DC) /* {{{ */ { diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 37bb653e3b..db4febed01 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -36,6 +36,12 @@ static int module_count=0; ZEND_API HashTable module_registry; +static zend_module_entry **module_request_startup_handlers; +static zend_module_entry **module_request_shutdown_handlers; +static zend_module_entry **module_post_deactivate_handlers; + +static zend_class_entry **class_cleanup_handlers; + /* this function doesn't check for too many parameters */ ZEND_API int zend_get_parameters(int ht, int param_count, ...) /* {{{ */ { @@ -1679,14 +1685,101 @@ try_again: } /* }}} */ +static void zend_collect_module_handlers(void) /* {{{ */ +{ + HashPosition pos; + zend_module_entry *module; + int startup_count = 0; + int shutdown_count = 0; + int post_deactivate_count = 0; + zend_class_entry **pce; + int class_count = 0; + + /* Collect extensions with request startup/shutdown handlers */ + for (zend_hash_internal_pointer_reset_ex(&module_registry, &pos); + zend_hash_get_current_data_ex(&module_registry, (void *) &module, &pos) == SUCCESS; + zend_hash_move_forward_ex(&module_registry, &pos)) { + if (module->request_startup_func) { + startup_count++; + } + if (module->request_shutdown_func) { + shutdown_count++; + } + if (module->post_deactivate_func) { + post_deactivate_count++; + } + } + module_request_startup_handlers = (zend_module_entry**)malloc( + sizeof(zend_module_entry*) * + (startup_count + 1 + + shutdown_count + 1 + + post_deactivate_count + 1)); + module_request_startup_handlers[startup_count] = NULL; + module_request_shutdown_handlers = module_request_startup_handlers + startup_count + 1; + module_request_shutdown_handlers[shutdown_count] = NULL; + module_post_deactivate_handlers = module_request_shutdown_handlers + shutdown_count + 1; + module_post_deactivate_handlers[post_deactivate_count] = NULL; + startup_count = 0; + + for (zend_hash_internal_pointer_reset_ex(&module_registry, &pos); + zend_hash_get_current_data_ex(&module_registry, (void *) &module, &pos) == SUCCESS; + zend_hash_move_forward_ex(&module_registry, &pos)) { + if (module->request_startup_func) { + module_request_startup_handlers[startup_count++] = module; + } + if (module->request_shutdown_func) { + module_request_shutdown_handlers[--shutdown_count] = module; + } + if (module->post_deactivate_func) { + module_post_deactivate_handlers[--post_deactivate_count] = module; + } + } + + /* Collect internal classes with static members */ + for (zend_hash_internal_pointer_reset_ex(CG(class_table), &pos); + zend_hash_get_current_data_ex(CG(class_table), (void *) &pce, &pos) == SUCCESS; + zend_hash_move_forward_ex(CG(class_table), &pos)) { + if ((*pce)->type == ZEND_INTERNAL_CLASS && + (*pce)->default_static_members_count > 0) { + class_count++; + } + } + + class_cleanup_handlers = (zend_class_entry**)malloc( + sizeof(zend_class_entry*) * + (class_count + 1)); + class_cleanup_handlers[class_count] = NULL; + + if (class_count) { + for (zend_hash_internal_pointer_reset_ex(CG(class_table), &pos); + zend_hash_get_current_data_ex(CG(class_table), (void *) &pce, &pos) == SUCCESS; + zend_hash_move_forward_ex(CG(class_table), &pos)) { + if ((*pce)->type == ZEND_INTERNAL_CLASS && + (*pce)->default_static_members_count > 0) { + class_cleanup_handlers[--class_count] = *pce; + } + } + } +} +/* }}} */ + ZEND_API int zend_startup_modules(TSRMLS_D) /* {{{ */ { zend_hash_sort(&module_registry, zend_sort_modules, NULL, 0 TSRMLS_CC); zend_hash_apply(&module_registry, (apply_func_t)zend_startup_module_ex TSRMLS_CC); + zend_collect_module_handlers(); return SUCCESS; } /* }}} */ +ZEND_API void zend_destroy_modules(void) /* {{{ */ +{ + free(class_cleanup_handlers); + free(module_request_startup_handlers); + zend_hash_graceful_reverse_destroy(&module_registry); +} +/* }}} */ + ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module TSRMLS_DC) /* {{{ */ { int name_len; @@ -2147,19 +2240,19 @@ void module_destructor(zend_module_entry *module) /* {{{ */ } /* }}} */ -/* call request startup for all modules */ -int module_registry_request_startup(zend_module_entry *module TSRMLS_DC) /* {{{ */ +void zend_activate_modules(TSRMLS_D) /* {{{ */ { - if (module->request_startup_func) { -#if 0 - zend_printf("%s: Request startup\n", module->name); -#endif + zend_module_entry **p = module_request_startup_handlers; + + while (*p) { + zend_module_entry *module = *p; + if (module->request_startup_func(module->type, module->module_number TSRMLS_CC)==FAILURE) { zend_error(E_WARNING, "request_startup() for %s module failed", module->name); exit(1); } + p++; } - return 0; } /* }}} */ @@ -2176,12 +2269,71 @@ int module_registry_cleanup(zend_module_entry *module TSRMLS_DC) /* {{{ */ } /* }}} */ +void zend_deactivate_modules(TSRMLS_D) /* {{{ */ +{ + EG(opline_ptr) = NULL; /* we're no longer executing anything */ + + zend_try { + if (EG(full_tables_cleanup)) { + zend_hash_reverse_apply(&module_registry, (apply_func_t) module_registry_cleanup TSRMLS_CC); + } else { + zend_module_entry **p = module_request_shutdown_handlers; + + while (*p) { + zend_module_entry *module = *p; + + module->request_shutdown_func(module->type, module->module_number TSRMLS_CC); + p++; + } + } + } zend_end_try(); +} +/* }}} */ + +ZEND_API void zend_cleanup_internal_classes(TSRMLS_D) /* {{{ */ +{ + zend_class_entry **p = class_cleanup_handlers; + + while (*p) { + zend_cleanup_internal_class_data(*p TSRMLS_CC); + p++; + } +} +/* }}} */ + int module_registry_unload_temp(const zend_module_entry *module TSRMLS_DC) /* {{{ */ { return (module->type == MODULE_TEMPORARY) ? ZEND_HASH_APPLY_REMOVE : ZEND_HASH_APPLY_STOP; } /* }}} */ +static int exec_done_cb(zend_module_entry *module TSRMLS_DC) /* {{{ */ +{ + if (module->post_deactivate_func) { + module->post_deactivate_func(); + } + return 0; +} +/* }}} */ + +void zend_post_deactivate_modules(TSRMLS_D) /* {{{ */ +{ + if (EG(full_tables_cleanup)) { + zend_hash_apply(&module_registry, (apply_func_t) exec_done_cb TSRMLS_CC); + zend_hash_reverse_apply(&module_registry, (apply_func_t) module_registry_unload_temp TSRMLS_CC); + } else { + zend_module_entry **p = module_post_deactivate_handlers; + + while (*p) { + zend_module_entry *module = *p; + + module->post_deactivate_func(); + p++; + } + } +} +/* }}} */ + /* return the next free module number */ int zend_next_free_module(void) /* {{{ */ { diff --git a/Zend/zend_API.h b/Zend/zend_API.h index 9c7fbb3301..5e5a4eab14 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -252,6 +252,7 @@ ZEND_API zend_module_entry* zend_register_internal_module(zend_module_entry *mod ZEND_API zend_module_entry* zend_register_module_ex(zend_module_entry *module TSRMLS_DC); ZEND_API int zend_startup_module_ex(zend_module_entry *module TSRMLS_DC); ZEND_API int zend_startup_modules(TSRMLS_D); +ZEND_API void zend_destroy_modules(void); ZEND_API void zend_check_magic_method_implementation(const zend_class_entry *ce, const zend_function *fptr, int error_type TSRMLS_DC); ZEND_API zend_class_entry *zend_register_internal_class(zend_class_entry *class_entry TSRMLS_DC); diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index fd00d0088a..c70a8a589d 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3284,6 +3284,7 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent /* The verification will be done in runtime by ZEND_VERIFY_ABSTRACT_CLASS */ zend_verify_abstract_class(ce TSRMLS_CC); } + ce->ce_flags |= parent_ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS; } /* }}} */ @@ -3599,6 +3600,9 @@ static int zend_traits_merge_functions_to_class(zend_function *fn TSRMLS_DC, int if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) { ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS; } + if (fn->op_array.static_variables) { + ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS; + } fn_copy = *fn; zend_traits_duplicate_function(&fn_copy, estrdup(fn->common.function_name) TSRMLS_CC); @@ -5379,6 +5383,9 @@ void zend_do_fetch_static_variable(znode *varname, const znode *static_assignmen INIT_ZVAL(*tmp); } if (!CG(active_op_array)->static_variables) { + if (CG(active_op_array)->scope) { + CG(active_op_array)->scope->ce_flags |= ZEND_HAS_STATIC_IN_METHODS; + } ALLOC_HASHTABLE(CG(active_op_array)->static_variables); zend_hash_init(CG(active_op_array)->static_variables, 2, NULL, ZVAL_PTR_DTOR, 0); } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index e1a30c5926..9147426698 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -171,6 +171,10 @@ typedef struct _zend_try_catch_element { #define ZEND_ACC_IMPLEMENT_INTERFACES 0x80000 #define ZEND_ACC_IMPLEMENT_TRAITS 0x400000 +/* user class has methods with static variables */ +#define ZEND_HAS_STATIC_IN_METHODS 0x800000 + + #define ZEND_ACC_CLOSURE 0x100000 /* function flag for internal user call handlers __call, __callstatic */ @@ -610,6 +614,9 @@ ZEND_API void init_op_array(zend_op_array *op_array, zend_uchar type, int initia ZEND_API void destroy_op_array(zend_op_array *op_array TSRMLS_DC); ZEND_API void zend_destroy_file_handle(zend_file_handle *file_handle TSRMLS_DC); ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC); +ZEND_API int zend_cleanup_user_class_data(zend_class_entry **pce TSRMLS_DC); +ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC); +ZEND_API void zend_cleanup_internal_classes(TSRMLS_C); ZEND_API int zend_cleanup_function_data(zend_function *function TSRMLS_DC); ZEND_API int zend_cleanup_function_data_full(zend_function *function TSRMLS_DC); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index 91e1b6aec8..18dc4dfd9a 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -292,10 +292,12 @@ void shutdown_executor(TSRMLS_D) /* {{{ */ * not contain objects and thus are not probelmatic */ if (EG(full_tables_cleanup)) { zend_hash_apply(EG(function_table), (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC); + zend_hash_apply(EG(class_table), (apply_func_t) zend_cleanup_class_data TSRMLS_CC); } else { zend_hash_reverse_apply(EG(function_table), (apply_func_t) zend_cleanup_function_data TSRMLS_CC); + zend_hash_reverse_apply(EG(class_table), (apply_func_t) zend_cleanup_user_class_data TSRMLS_CC); + zend_cleanup_internal_classes(TSRMLS_C); } - zend_hash_apply(EG(class_table), (apply_func_t) zend_cleanup_class_data TSRMLS_CC); zend_vm_stack_destroy(TSRMLS_C); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 08f0e69406..a1e70ef8fc 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -159,37 +159,66 @@ ZEND_API int zend_cleanup_function_data_full(zend_function *function TSRMLS_DC) return 0; } -ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC) +static inline void cleanup_user_class_data(zend_class_entry *ce TSRMLS_DC) { - if ((*pce)->type == ZEND_USER_CLASS) { - /* Clean all parts that can contain run-time data */ - /* Note that only run-time accessed data need to be cleaned up, pre-defined data can - not contain objects and thus are not probelmatic */ - zend_hash_apply(&(*pce)->function_table, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC); - if ((*pce)->static_members_table) { - int i; - - for (i = 0; i < (*pce)->default_static_members_count; i++) { - if ((*pce)->static_members_table[i]) { - zval_ptr_dtor(&(*pce)->static_members_table[i]); - (*pce)->static_members_table[i] = NULL; - } + /* Clean all parts that can contain run-time data */ + /* Note that only run-time accessed data need to be cleaned up, pre-defined data can + not contain objects and thus are not probelmatic */ + if (ce->ce_flags & ZEND_HAS_STATIC_IN_METHODS) { + zend_hash_apply(&ce->function_table, (apply_func_t) zend_cleanup_function_data_full TSRMLS_CC); + } + if (ce->static_members_table) { + int i; + + for (i = 0; i < ce->default_static_members_count; i++) { + if (ce->static_members_table[i]) { + zval_ptr_dtor(&ce->static_members_table[i]); + ce->static_members_table[i] = NULL; } - (*pce)->static_members_table = NULL; } - } else if (CE_STATIC_MEMBERS(*pce)) { + ce->static_members_table = NULL; + } +} + +static inline void cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC) +{ + if (CE_STATIC_MEMBERS(ce)) { int i; - for (i = 0; i < (*pce)->default_static_members_count; i++) { - zval_ptr_dtor(&CE_STATIC_MEMBERS(*pce)[i]); + for (i = 0; i < ce->default_static_members_count; i++) { + zval_ptr_dtor(&CE_STATIC_MEMBERS(ce)[i]); } - efree(CE_STATIC_MEMBERS(*pce)); + efree(CE_STATIC_MEMBERS(ce)); #ifdef ZTS - CG(static_members_table)[(zend_intptr_t)((*pce)->static_members_table)] = NULL; + CG(static_members_table)[(zend_intptr_t)((ce->static_members_table)] = NULL; #else - (*pce)->static_members_table = NULL; + ce->static_members_table = NULL; #endif } +} + +ZEND_API void zend_cleanup_internal_class_data(zend_class_entry *ce TSRMLS_DC) +{ + cleanup_internal_class_data(ce TSRMLS_CC); +} + +ZEND_API int zend_cleanup_user_class_data(zend_class_entry **pce TSRMLS_DC) +{ + if ((*pce)->type == ZEND_USER_CLASS) { + cleanup_user_class_data(*pce TSRMLS_CC); + return ZEND_HASH_APPLY_KEEP; + } else { + return ZEND_HASH_APPLY_STOP; + } +} + +ZEND_API int zend_cleanup_class_data(zend_class_entry **pce TSRMLS_DC) +{ + if ((*pce)->type == ZEND_USER_CLASS) { + cleanup_user_class_data(*pce TSRMLS_CC); + } else { + cleanup_internal_class_data(*pce TSRMLS_CC); + } return 0; } -- 2.49.0