dmitry                                   Tue, 06 Jul 2010 11:40:17 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=301021

Log:
eliminated unnecessary iterations during request startup/shutdown

Changed paths:
    U   php/php-src/trunk/NEWS
    U   php/php-src/trunk/Zend/zend.c
    U   php/php-src/trunk/Zend/zend_API.c
    U   php/php-src/trunk/Zend/zend_API.h
    U   php/php-src/trunk/Zend/zend_compile.c
    U   php/php-src/trunk/Zend/zend_compile.h
    U   php/php-src/trunk/Zend/zend_execute_API.c
    U   php/php-src/trunk/Zend/zend_opcode.c

Modified: php/php-src/trunk/NEWS
===================================================================
--- php/php-src/trunk/NEWS	2010-07-06 11:37:19 UTC (rev 301020)
+++ php/php-src/trunk/NEWS	2010-07-06 11:40:17 UTC (rev 301021)
@@ -17,6 +17,7 @@
   . 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

Modified: php/php-src/trunk/Zend/zend.c
===================================================================
--- php/php-src/trunk/Zend/zend.c	2010-07-06 11:37:19 UTC (rev 301020)
+++ php/php-src/trunk/Zend/zend.c	2010-07-06 11:40:17 UTC (rev 301021)
@@ -761,7 +761,7 @@
 	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_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 @@
 }
 /* }}} */

-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) /* {{{ */
 {

Modified: php/php-src/trunk/Zend/zend_API.c
===================================================================
--- php/php-src/trunk/Zend/zend_API.c	2010-07-06 11:37:19 UTC (rev 301020)
+++ php/php-src/trunk/Zend/zend_API.c	2010-07-06 11:40:17 UTC (rev 301021)
@@ -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 @@
 }
 /* }}} */

+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 @@
 }
 /* }}} */

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

+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) /* {{{ */
 {

Modified: php/php-src/trunk/Zend/zend_API.h
===================================================================
--- php/php-src/trunk/Zend/zend_API.h	2010-07-06 11:37:19 UTC (rev 301020)
+++ php/php-src/trunk/Zend/zend_API.h	2010-07-06 11:40:17 UTC (rev 301021)
@@ -252,6 +252,7 @@
 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);

Modified: php/php-src/trunk/Zend/zend_compile.c
===================================================================
--- php/php-src/trunk/Zend/zend_compile.c	2010-07-06 11:37:19 UTC (rev 301020)
+++ php/php-src/trunk/Zend/zend_compile.c	2010-07-06 11:40:17 UTC (rev 301021)
@@ -3284,6 +3284,7 @@
 		/* 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 @@
 		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 @@
 		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);
 	}

Modified: php/php-src/trunk/Zend/zend_compile.h
===================================================================
--- php/php-src/trunk/Zend/zend_compile.h	2010-07-06 11:37:19 UTC (rev 301020)
+++ php/php-src/trunk/Zend/zend_compile.h	2010-07-06 11:40:17 UTC (rev 301021)
@@ -171,6 +171,10 @@
 #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 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);


Modified: php/php-src/trunk/Zend/zend_execute_API.c
===================================================================
--- php/php-src/trunk/Zend/zend_execute_API.c	2010-07-06 11:37:19 UTC (rev 301020)
+++ php/php-src/trunk/Zend/zend_execute_API.c	2010-07-06 11:40:17 UTC (rev 301021)
@@ -292,10 +292,12 @@
 		 * 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);


Modified: php/php-src/trunk/Zend/zend_opcode.c
===================================================================
--- php/php-src/trunk/Zend/zend_opcode.c	2010-07-06 11:37:19 UTC (rev 301020)
+++ php/php-src/trunk/Zend/zend_opcode.c	2010-07-06 11:40:17 UTC (rev 301021)
@@ -159,37 +159,66 @@
 	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;
+	/* 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 < (*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;
-				}
+		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;
 }

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to