. 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
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);
}
/* }}} */
-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 {
}
/* }}} */
-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) /* {{{ */
{
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, ...) /* {{{ */
{
}
/* }}} */
+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;
}
/* }}} */
-/* 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;
}
/* }}} */
}
/* }}} */
+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) /* {{{ */
{
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);
/* 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;
}
/* }}} */
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);
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);
}
#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 */
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);
* 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);
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;
}