fast_call_user_function
| From: | Sterling Hughes | Date: | Mon, 19 May 2003 17:00:50 +0000 |
| Subject: | fast_call_user_function | ||
| Groups: | php.internals | ||
| Request: | Send a blank email to internals+get-1736@lists.php.net to get a copy of this message | ||
Hi,
Attached is a patch which adds a new function
fast_call_user_function(). fast_call_user_function allows you to cache
the lookups of function calls, this way when you call the same function
repeatedly (as in usort() or any callback code), it doesn't need to be
looked up over and over and over and over and over again.
I've ported usort() and friends over to using fast_call_user_function()
and it resulted in around a 15% speedup. If no one objects I'm going to
commit this to Zend, and then make the necessary changes in the code (at
least in ext/standard).
-Sterling
--
"C makes it easy to shoot yourself in the foot; C++ makes it harder,
but when you do, it blows away your whole leg."
- Bjarne Stroustrup
? fast_call_user_function Index: zend_API.h =================================================================== RCS file: /repository/ZendEngine2/zend_API.h,v retrieving revision 1.138 diff -u -r1.138 zend_API.h --- zend_API.h 4 May 2003 22:49:31 -0000 1.138 +++ zend_API.h 19 May 2003 18:05:09 -0000 @@ -252,6 +252,7 @@ ZEND_API int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, int param_count, zval *params[] TSRMLS_DC); ZEND_API int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table TSRMLS_DC); +ZEND_API int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table, zend_function **function_pointer TSRMLS_DC); ZEND_API int zend_set_hash_symbol(zval *symbol, char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...); Index: zend_execute_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute_API.c,v retrieving revision 1.202 diff -u -r1.202 zend_execute_API.c --- zend_execute_API.c 12 May 2003 18:54:05 -0000 1.202 +++ zend_execute_API.c 19 May 2003 18:05:19 -0000 @@ -522,9 +522,15 @@ return ex_retval; } - int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table TSRMLS_DC) { + zend_function *function_pointer = NULL; + + return fast_call_user_function(function_table, object_pp, function_name, retval_ptr_ptr, param_count, params, no_separation, symbol_table, &function_pointer TSRMLS_CC); +} + +int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table, zend_function **function_pointer TSRMLS_DC) +{ int i; zval **original_return_value; HashTable *calling_symbol_table; @@ -549,70 +555,79 @@ EX(opline) = NULL; *retval_ptr_ptr = NULL; - if (function_name->type==IS_ARRAY) { /* assume array($obj, $name) couple */ - zval **tmp_object_ptr, **tmp_real_function_name; + /** + * Function name lookup code + * + */ + if (*function_pointer == NULL) { + if (function_name->type==IS_ARRAY) { /* assume array($obj, $name) couple */ + zval **tmp_object_ptr, **tmp_real_function_name; - if (zend_hash_index_find(function_name->value.ht, 0, (void **) &tmp_object_ptr)==FAILURE) { - return FAILURE; - } - if (zend_hash_index_find(function_name->value.ht, 1, (void **) &tmp_real_function_name)==FAILURE) { - return FAILURE; - } - function_name = *tmp_real_function_name; - SEPARATE_ZVAL_IF_NOT_REF(tmp_object_ptr); - object_pp = tmp_object_ptr; - (*object_pp)->is_ref = 1; - } - - if (object_pp && !*object_pp) { - object_pp = NULL; - } - - if (object_pp) { - /* TBI!! new object handlers */ - if (Z_TYPE_PP(object_pp) == IS_OBJECT) { - if (!IS_ZEND_STD_OBJECT(**object_pp)) { - zend_error(E_WARNING, "Cannot use call_user_function on objects without a class entry"); + if (zend_hash_index_find(function_name->value.ht, 0, (void **) &tmp_object_ptr)==FAILURE) { return FAILURE; } - - calling_scope = Z_OBJCE_PP(object_pp); - function_table = &calling_scope->function_table; - EX(object) = *object_pp; - } else if (Z_TYPE_PP(object_pp) == IS_STRING) { - zend_class_entry **ce; - char *lc_class; - int found; - - lc_class = estrndup(Z_STRVAL_PP(object_pp), Z_STRLEN_PP(object_pp)); - zend_str_tolower(lc_class, Z_STRLEN_PP(object_pp)); - found = zend_lookup_class(lc_class, Z_STRLEN_PP(object_pp), &ce TSRMLS_CC); - efree(lc_class); - if (found == FAILURE) + if (zend_hash_index_find(function_name->value.ht, 1, (void **) &tmp_real_function_name)==FAILURE) { return FAILURE; + } + function_name = *tmp_real_function_name; + SEPARATE_ZVAL_IF_NOT_REF(tmp_object_ptr); + object_pp = tmp_object_ptr; + (*object_pp)->is_ref = 1; + } - function_table = &(*ce)->function_table; - calling_scope = *ce; + if (object_pp && !*object_pp) { object_pp = NULL; - } else - return FAILURE; - } + } - if (function_name->type!=IS_STRING) { - return FAILURE; - } + if (object_pp) { + /* TBI!! new object handlers */ + if (Z_TYPE_PP(object_pp) == IS_OBJECT) { + if (!IS_ZEND_STD_OBJECT(**object_pp)) { + zend_error(E_WARNING, "Cannot use call_user_function on objects without a class entry"); + return FAILURE; + } + + calling_scope = Z_OBJCE_PP(object_pp); + function_table = &calling_scope->function_table; + EX(object) = *object_pp; + } else if (Z_TYPE_PP(object_pp) == IS_STRING) { + zend_class_entry **ce; + char *lc_class; + int found; + + lc_class = estrndup(Z_STRVAL_PP(object_pp), Z_STRLEN_PP(object_pp)); + zend_str_tolower(lc_class, Z_STRLEN_PP(object_pp)); + found = zend_lookup_class(lc_class, Z_STRLEN_PP(object_pp), &ce TSRMLS_CC); + efree(lc_class); + if (found == FAILURE) + return FAILURE; + + function_table = &(*ce)->function_table; + calling_scope = *ce; + object_pp = NULL; + } else + return FAILURE; + } - function_name_copy = *function_name; - zval_copy_ctor(&function_name_copy); - zend_str_tolower(function_name_copy.value.str.val, function_name_copy.value.str.len); + if (function_name->type!=IS_STRING) { + return FAILURE; + } - original_function_state_ptr = EG(function_state_ptr); - if (zend_hash_find(function_table, function_name_copy.value.str.val, function_name_copy.value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { + function_name_copy = *function_name; + zval_copy_ctor(&function_name_copy); + zend_str_tolower(function_name_copy.value.str.val, function_name_copy.value.str.len); + + original_function_state_ptr = EG(function_state_ptr); + if (zend_hash_find(function_table, function_name_copy.value.str.val, function_name_copy.value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { + zval_dtor(&function_name_copy); + return FAILURE; + } zval_dtor(&function_name_copy); - return FAILURE; + *function_pointer = EX(function_state).function; + } else { + EX(function_state).function = *function_pointer; } - zval_dtor(&function_name_copy); - + for (i=0; i<param_count; i++) { zval *param;
? fast_call_user_function Index: zend_API.h =================================================================== RCS file: /repository/ZendEngine2/zend_API.h,v retrieving revision 1.138 diff -u -r1.138 zend_API.h --- zend_API.h 4 May 2003 22:49:31 -0000 1.138 +++ zend_API.h 19 May 2003 18:05:09 -0000 @@ -252,6 +252,7 @@ ZEND_API int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, int param_count, zval *params[] TSRMLS_DC); ZEND_API int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table TSRMLS_DC); +ZEND_API int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table, zend_function **function_pointer TSRMLS_DC); ZEND_API int zend_set_hash_symbol(zval *symbol, char *name, int name_length, zend_bool is_ref, int num_symbol_tables, ...); Index: zend_execute_API.c =================================================================== RCS file: /repository/ZendEngine2/zend_execute_API.c,v retrieving revision 1.202 diff -u -r1.202 zend_execute_API.c --- zend_execute_API.c 12 May 2003 18:54:05 -0000 1.202 +++ zend_execute_API.c 19 May 2003 18:05:19 -0000 @@ -522,9 +522,15 @@ return ex_retval; } - int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table TSRMLS_DC) { + zend_function *function_pointer = NULL; + + return fast_call_user_function(function_table, object_pp, function_name, retval_ptr_ptr, param_count, params, no_separation, symbol_table, &function_pointer TSRMLS_CC); +} + +int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, int param_count, zval **params[], int no_separation, HashTable *symbol_table, zend_function **function_pointer TSRMLS_DC) +{ int i; zval **original_return_value; HashTable *calling_symbol_table; @@ -549,70 +555,79 @@ EX(opline) = NULL; *retval_ptr_ptr = NULL; - if (function_name->type==IS_ARRAY) { /* assume array($obj, $name) couple */ - zval **tmp_object_ptr, **tmp_real_function_name; + /** + * Function name lookup code + * + */ + if (*function_pointer == NULL) { + if (function_name->type==IS_ARRAY) { /* assume array($obj, $name) couple */ + zval **tmp_object_ptr, **tmp_real_function_name; - if (zend_hash_index_find(function_name->value.ht, 0, (void **) &tmp_object_ptr)==FAILURE) { - return FAILURE; - } - if (zend_hash_index_find(function_name->value.ht, 1, (void **) &tmp_real_function_name)==FAILURE) { - return FAILURE; - } - function_name = *tmp_real_function_name; - SEPARATE_ZVAL_IF_NOT_REF(tmp_object_ptr); - object_pp = tmp_object_ptr; - (*object_pp)->is_ref = 1; - } - - if (object_pp && !*object_pp) { - object_pp = NULL; - } - - if (object_pp) { - /* TBI!! new object handlers */ - if (Z_TYPE_PP(object_pp) == IS_OBJECT) { - if (!IS_ZEND_STD_OBJECT(**object_pp)) { - zend_error(E_WARNING, "Cannot use call_user_function on objects without a class entry"); + if (zend_hash_index_find(function_name->value.ht, 0, (void **) &tmp_object_ptr)==FAILURE) { return FAILURE; } - - calling_scope = Z_OBJCE_PP(object_pp); - function_table = &calling_scope->function_table; - EX(object) = *object_pp; - } else if (Z_TYPE_PP(object_pp) == IS_STRING) { - zend_class_entry **ce; - char *lc_class; - int found; - - lc_class = estrndup(Z_STRVAL_PP(object_pp), Z_STRLEN_PP(object_pp)); - zend_str_tolower(lc_class, Z_STRLEN_PP(object_pp)); - found = zend_lookup_class(lc_class, Z_STRLEN_PP(object_pp), &ce TSRMLS_CC); - efree(lc_class); - if (found == FAILURE) + if (zend_hash_index_find(function_name->value.ht, 1, (void **) &tmp_real_function_name)==FAILURE) { return FAILURE; + } + function_name = *tmp_real_function_name; + SEPARATE_ZVAL_IF_NOT_REF(tmp_object_ptr); + object_pp = tmp_object_ptr; + (*object_pp)->is_ref = 1; + } - function_table = &(*ce)->function_table; - calling_scope = *ce; + if (object_pp && !*object_pp) { object_pp = NULL; - } else - return FAILURE; - } + } - if (function_name->type!=IS_STRING) { - return FAILURE; - } + if (object_pp) { + /* TBI!! new object handlers */ + if (Z_TYPE_PP(object_pp) == IS_OBJECT) { + if (!IS_ZEND_STD_OBJECT(**object_pp)) { + zend_error(E_WARNING, "Cannot use call_user_function on objects without a class entry"); + return FAILURE; + } + + calling_scope = Z_OBJCE_PP(object_pp); + function_table = &calling_scope->function_table; + EX(object) = *object_pp; + } else if (Z_TYPE_PP(object_pp) == IS_STRING) { + zend_class_entry **ce; + char *lc_class; + int found; + + lc_class = estrndup(Z_STRVAL_PP(object_pp), Z_STRLEN_PP(object_pp)); + zend_str_tolower(lc_class, Z_STRLEN_PP(object_pp)); + found = zend_lookup_class(lc_class, Z_STRLEN_PP(object_pp), &ce TSRMLS_CC); + efree(lc_class); + if (found == FAILURE) + return FAILURE; + + function_table = &(*ce)->function_table; + calling_scope = *ce; + object_pp = NULL; + } else + return FAILURE; + } - function_name_copy = *function_name; - zval_copy_ctor(&function_name_copy); - zend_str_tolower(function_name_copy.value.str.val, function_name_copy.value.str.len); + if (function_name->type!=IS_STRING) { + return FAILURE; + } - original_function_state_ptr = EG(function_state_ptr); - if (zend_hash_find(function_table, function_name_copy.value.str.val, function_name_copy.value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { + function_name_copy = *function_name; + zval_copy_ctor(&function_name_copy); + zend_str_tolower(function_name_copy.value.str.val, function_name_copy.value.str.len); + + original_function_state_ptr = EG(function_state_ptr); + if (zend_hash_find(function_table, function_name_copy.value.str.val, function_name_copy.value.str.len+1, (void **) &EX(function_state).function)==FAILURE) { + zval_dtor(&function_name_copy); + return FAILURE; + } zval_dtor(&function_name_copy); - return FAILURE; + *function_pointer = EX(function_state).function; + } else { + EX(function_state).function = *function_pointer; } - zval_dtor(&function_name_copy); - + for (i=0; i<param_count; i++) { zval *param;