summaryrefslogtreecommitdiff
path: root/Zend
diff options
context:
space:
mode:
authorZeev Suraski <zeev@php.net>2003-08-05 10:24:40 +0000
committerZeev Suraski <zeev@php.net>2003-08-05 10:24:40 +0000
commit92b4013e8d6fb3a92f958e9c01abf824bbdb4aaa (patch)
tree85e2d271c92ef8bd6dcc50944327933e3391d781 /Zend
parent97c2522128815964b450aed41ef095d6d9ccc8aa (diff)
downloadphp-git-92b4013e8d6fb3a92f958e9c01abf824bbdb4aaa.tar.gz
Try to put an end to the endless number of call_user_function variants.
zend_call_function() now takes a structure that should contain all of the necessary information. If further information is necessary in the future, then we'll be able to add it without having to introduce a new function. As for caching - the 2nd, optional argument is a struct that can hold all of the information that's necessary to invoke the function, including its handler, scope and object it operates on (if any). Note that you may only use a cache if the arguments you provide to zend_call_function() are identical to the ones of the last call, except for the argument and return value information. The recently introduced fast_call_user_function() was removed I fixed most of the places that used fast_call_user_function() to use caching but there are still some that need to be fixed (XML and reflection)
Diffstat (limited to 'Zend')
-rw-r--r--Zend/zend_API.h26
-rw-r--r--Zend/zend_execute_API.c179
-rw-r--r--Zend/zend_reflection_api.c69
3 files changed, 172 insertions, 102 deletions
diff --git a/Zend/zend_API.h b/Zend/zend_API.h
index 5a3abe20c4..41fd8ab32b 100644
--- a/Zend/zend_API.h
+++ b/Zend/zend_API.h
@@ -265,9 +265,33 @@ ZEND_API int add_property_zval_ex(zval *arg, char *key, uint key_len, zval *valu
#define add_property_stringl(__arg, __key, __str, __length, __duplicate) add_property_stringl_ex(__arg, __key, strlen(__key)+1, __str, __length, __duplicate TSRMLS_CC)
#define add_property_zval(__arg, __key, __value) add_property_zval_ex(__arg, __key, strlen(__key)+1, __value TSRMLS_CC)
+
ZEND_API int call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval *retval_ptr, zend_uint 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, zend_uint 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, zend_uint param_count, zval **params[], int no_separation, HashTable *symbol_table, zend_function **function_pointer TSRMLS_DC);
+
+typedef struct _zend_fcall_info {
+ size_t size;
+ HashTable *function_table;
+ zval *function_name;
+ HashTable *symbol_table;
+ zval **retval_ptr_ptr;
+ zend_uint param_count;
+ zval ***params;
+ zval **object_pp;
+ zend_bool no_separation;
+} zend_fcall_info;
+
+typedef struct _zend_fcall_info_cache {
+ zend_bool initialized;
+ zend_function *function_handler;
+ zend_class_entry *calling_scope;
+ zval **object_pp;
+} zend_fcall_info_cache;
+
+ZEND_API extern zend_fcall_info_cache empty_fcall_info_cache;
+
+ZEND_API int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TSRMLS_DC);
+
ZEND_API int zend_set_hash_symbol(zval *symbol, char *name, int name_length,
zend_bool is_ref, int num_symbol_tables, ...);
diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c
index 05688f86b1..18b3388ab8 100644
--- a/Zend/zend_execute_API.c
+++ b/Zend/zend_execute_API.c
@@ -40,6 +40,8 @@ ZEND_API void (*zend_execute_internal)(zend_execute_data *execute_data_ptr, int
#ifdef ZEND_WIN32
#include <process.h>
/* true global */
+ZEND_API zend_fcall_info_cache empty_fcall_info_cache = { NULL, NULL, NULL, 0 };
+
static WNDCLASS wc;
static HWND timeout_window;
static HANDLE timeout_thread_event;
@@ -481,13 +483,23 @@ int call_user_function(HashTable *function_table, zval **object_pp, zval *functi
int call_user_function_ex(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, zend_uint 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);
+ zend_fcall_info fci;
+
+ fci.size = sizeof(fci);
+ fci.function_table = function_table;
+ fci.object_pp = object_pp;
+ fci.function_name = function_name;
+ fci.retval_ptr_ptr = retval_ptr_ptr;
+ fci.param_count = param_count;
+ fci.params = params;
+ fci.no_separation = (zend_bool) no_separation;
+ fci.symbol_table = symbol_table;
+
+ return zend_call_function(&fci, NULL TSRMLS_CC);
}
-int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *function_name, zval **retval_ptr_ptr, zend_uint param_count, zval **params[], int no_separation, HashTable *symbol_table, zend_function **function_pointer TSRMLS_DC)
+int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache TSRMLS_DC)
{
zend_uint i;
zval **original_return_value;
@@ -507,55 +519,63 @@ int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *f
zval *params_array;
int call_via_handler = 0;
+ switch (fci->size) {
+ case sizeof(zend_fcall_info):
+ break; /* nothing to do currently */
+ default:
+ zend_error(E_ERROR, "Corrupted fcall_info provided to zend_call_function()");
+ break;
+ }
+
/* Initialize execute_data */
EX(fbc) = NULL;
EX(object) = NULL;
EX(Ts) = NULL;
EX(op_array) = NULL;
EX(opline) = NULL;
- *retval_ptr_ptr = NULL;
+ *fci->retval_ptr_ptr = NULL;
- if (function_name->type==IS_ARRAY) { /* assume array($obj, $name) couple */
- zval **tmp_object_ptr, **tmp_real_function_name;
+ if (!fci_cache || !fci_cache->initialized) {
+ if (fci->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(fci->function_name->value.ht, 0, (void **) &tmp_object_ptr)==FAILURE) {
+ return FAILURE;
+ }
+ if (zend_hash_index_find(fci->function_name->value.ht, 1, (void **) &tmp_real_function_name)==FAILURE) {
+ return FAILURE;
+ }
+ fci->function_name = *tmp_real_function_name;
+ SEPARATE_ZVAL_IF_NOT_REF(tmp_object_ptr);
+ fci->object_pp = tmp_object_ptr;
+ (*fci->object_pp)->is_ref = 1;
}
- if (zend_hash_index_find(function_name->value.ht, 1, (void **) &tmp_real_function_name)==FAILURE) {
- return FAILURE;
+
+ if (fci->object_pp && !*fci->object_pp) {
+ fci->object_pp = NULL;
}
- 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 (fci->object_pp) {
+ /* TBI!! new object handlers */
+ if (Z_TYPE_PP(fci->object_pp) == IS_OBJECT) {
+ if (!IS_ZEND_STD_OBJECT(**fci->object_pp)) {
+ zend_error(E_WARNING, "Cannot use call_user_function on objects without a class entry");
+ 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(fci->object_pp);
+ fci->function_table = &calling_scope->function_table;
+ EX(object) = *fci->object_pp;
}
-
- calling_scope = Z_OBJCE_PP(object_pp);
- function_table = &calling_scope->function_table;
- EX(object) = *object_pp;
}
- }
- if (*function_pointer == NULL) {
- if (object_pp) {
- if (Z_TYPE_PP(object_pp) == IS_STRING) {
+ if (fci->object_pp) {
+ if (Z_TYPE_PP(fci->object_pp) == IS_STRING) {
zend_class_entry **ce;
char *lc_class;
int found = FAILURE;
- lc_class = zend_str_tolower_dup(Z_STRVAL_PP(object_pp), Z_STRLEN_PP(object_pp));
+ lc_class = zend_str_tolower_dup(Z_STRVAL_PP(fci->object_pp), Z_STRLEN_PP(fci->object_pp));
if (EG(active_op_array) && strcmp(lc_class, "self") == 0) {
ce = &(EG(active_op_array)->scope);
found = (*ce != NULL?SUCCESS:FAILURE);
@@ -563,32 +583,32 @@ int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *f
ce = &(EG(active_op_array)->scope->parent);
found = (*ce != NULL?SUCCESS:FAILURE);
} else {
- found = zend_lookup_class(lc_class, Z_STRLEN_PP(object_pp), &ce TSRMLS_CC);
+ found = zend_lookup_class(lc_class, Z_STRLEN_PP(fci->object_pp), &ce TSRMLS_CC);
}
efree(lc_class);
if (found == FAILURE)
return FAILURE;
- function_table = &(*ce)->function_table;
+ fci->function_table = &(*ce)->function_table;
calling_scope = *ce;
- object_pp = NULL;
+ fci->object_pp = NULL;
}
- if (function_table == NULL) {
+ if (fci->function_table == NULL) {
return FAILURE;
}
}
- if (function_name->type!=IS_STRING) {
+ if (fci->function_name->type!=IS_STRING) {
return FAILURE;
}
- function_name_lc = zend_str_tolower_dup(function_name->value.str.val, function_name->value.str.len);
+ function_name_lc = zend_str_tolower_dup(fci->function_name->value.str.val, fci->function_name->value.str.len);
original_function_state_ptr = EG(function_state_ptr);
- if (zend_hash_find(function_table, function_name_lc, function_name->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) {
+ if (zend_hash_find(fci->function_table, function_name_lc, fci->function_name->value.str.len+1, (void **) &EX(function_state).function)==FAILURE) {
/* try calling __call */
- if(calling_scope && calling_scope->__call) {
+ if (calling_scope && calling_scope->__call) {
EX(function_state).function = calling_scope->__call;
/* prepare params */
ALLOC_INIT_ZVAL(method_name);
@@ -603,55 +623,62 @@ int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *f
}
}
efree(function_name_lc);
- *function_pointer = EX(function_state).function;
+ EX(function_state).function;
+ if (fci_cache) {
+ fci_cache->function_handler = EX(function_state).function;
+ fci_cache->object_pp = fci->object_pp;
+ fci_cache->calling_scope = calling_scope;
+ fci_cache->initialized = 1;
+ }
} else {
- EX(function_state).function = *function_pointer;
- calling_scope= EX(function_state).function->common.scope;
+ EX(function_state).function = fci_cache->function_handler;
+ calling_scope = fci_cache->calling_scope;
+ fci->object_pp = fci_cache->object_pp;
}
- for (i=0; i<param_count; i++) {
+ for (i=0; i<fci->param_count; i++) {
zval *param;
if (ARG_SHOULD_BE_SENT_BY_REF(EX(function_state).function, i+1)
- && !PZVAL_IS_REF(*params[i])) {
- if ((*params[i])->refcount>1) {
+ && !PZVAL_IS_REF(*fci->params[i])) {
+ if ((*fci->params[i])->refcount>1) {
zval *new_zval;
- if (no_separation) {
+ if (fci->no_separation) {
return FAILURE;
}
ALLOC_ZVAL(new_zval);
- *new_zval = **params[i];
+ *new_zval = **fci->params[i];
zval_copy_ctor(new_zval);
new_zval->refcount = 1;
- (*params[i])->refcount--;
- *params[i] = new_zval;
+ (*fci->params[i])->refcount--;
+ *fci->params[i] = new_zval;
}
- (*params[i])->refcount++;
- (*params[i])->is_ref = 1;
- param = *params[i];
- } else if (*params[i] != &EG(uninitialized_zval)) {
- (*params[i])->refcount++;
- param = *params[i];
+ (*fci->params[i])->refcount++;
+ (*fci->params[i])->is_ref = 1;
+ param = *fci->params[i];
+ } else if (*fci->params[i] != &EG(uninitialized_zval)) {
+ (*fci->params[i])->refcount++;
+ param = *fci->params[i];
} else {
ALLOC_ZVAL(param);
- *param = **(params[i]);
+ *param = **(fci->params[i]);
INIT_PZVAL(param);
}
- if(call_via_handler) {
+ if (call_via_handler) {
add_next_index_zval(params_array, param);
} else {
zend_ptr_stack_push(&EG(argument_stack), param);
}
}
- if(call_via_handler) {
+ if (call_via_handler) {
zend_ptr_stack_push(&EG(argument_stack), method_name);
zend_ptr_stack_push(&EG(argument_stack), params_array);
- param_count = 2;
+ fci->param_count = 2;
}
- zend_ptr_stack_n_push(&EG(argument_stack), 2, (void *) (long) param_count, NULL);
+ zend_ptr_stack_n_push(&EG(argument_stack), 2, (void *) (long) fci->param_count, NULL);
EG(function_state_ptr) = &EX(function_state);
@@ -660,8 +687,8 @@ int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *f
current_this = EG(This);
- if (object_pp) {
- EG(This) = *object_pp;
+ if (fci->object_pp) {
+ EG(This) = *fci->object_pp;
if (!PZVAL_IS_REF(EG(This))) {
EG(This)->refcount++; /* For $this pointer */
@@ -683,8 +710,8 @@ int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *f
if (EX(function_state).function->type == ZEND_USER_FUNCTION) {
calling_symbol_table = EG(active_symbol_table);
- if (symbol_table) {
- EG(active_symbol_table) = symbol_table;
+ if (fci->symbol_table) {
+ EG(active_symbol_table) = fci->symbol_table;
} else {
ALLOC_HASHTABLE(EG(active_symbol_table));
zend_hash_init(EG(active_symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0);
@@ -692,7 +719,7 @@ int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *f
original_return_value = EG(return_value_ptr_ptr);
original_op_array = EG(active_op_array);
- EG(return_value_ptr_ptr) = retval_ptr_ptr;
+ EG(return_value_ptr_ptr) = fci->retval_ptr_ptr;
EG(active_op_array) = (zend_op_array *) EX(function_state).function;
original_opline_ptr = EG(opline_ptr);
orig_free_op1 = EG(free_op1);
@@ -700,7 +727,7 @@ int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *f
orig_unary_op = EG(unary_op);
orig_binary_op = EG(binary_op);
zend_execute(EG(active_op_array) TSRMLS_CC);
- if (!symbol_table) {
+ if (!fci->symbol_table) {
zend_hash_destroy(EG(active_symbol_table));
FREE_HASHTABLE(EG(active_symbol_table));
}
@@ -713,12 +740,12 @@ int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *f
EG(unary_op) = orig_unary_op;
EG(binary_op) = orig_binary_op;
} else {
- ALLOC_INIT_ZVAL(*retval_ptr_ptr);
- ((zend_internal_function *) EX(function_state).function)->handler(param_count, *retval_ptr_ptr, (object_pp?*object_pp:NULL), 1 TSRMLS_CC);
- INIT_PZVAL(*retval_ptr_ptr);
+ ALLOC_INIT_ZVAL(*fci->retval_ptr_ptr);
+ ((zend_internal_function *) EX(function_state).function)->handler(fci->param_count, *fci->retval_ptr_ptr, (fci->object_pp?*fci->object_pp:NULL), 1 TSRMLS_CC);
+ INIT_PZVAL(*fci->retval_ptr_ptr);
}
zend_ptr_stack_clear_multiple(TSRMLS_C);
- if(call_via_handler) {
+ if (call_via_handler) {
zval_ptr_dtor(&method_name);
zval_ptr_dtor(&params_array);
}
@@ -729,11 +756,11 @@ int fast_call_user_function(HashTable *function_table, zval **object_pp, zval *f
}
EG(scope) = current_scope;
EG(This) = current_this;
- EG(current_execute_data) = EX(prev_execute_data); \
-
- return SUCCESS;
+ EG(current_execute_data) = EX(prev_execute_data);
+ return SUCCESS;
}
+
ZEND_API int zend_lookup_class(char *name, int name_length, zend_class_entry ***ce TSRMLS_DC)
{
zval **args[1];
diff --git a/Zend/zend_reflection_api.c b/Zend/zend_reflection_api.c
index 648144b957..2a9a4e5292 100644
--- a/Zend/zend_reflection_api.c
+++ b/Zend/zend_reflection_api.c
@@ -249,7 +249,8 @@ static void _class_string(string *str, zend_class_entry *ce, char *indent TSRMLS
}
if (ce->num_interfaces) {
- int i;
+ zend_uint i;
+
string_printf(str, " implements %s", ce->interfaces[0]->name);
for (i = 1; i < ce->num_interfaces; ++i) {
string_printf(str, ", %s", ce->interfaces[i]->name);
@@ -337,7 +338,7 @@ static void _class_string(string *str, zend_class_entry *ce, char *indent TSRMLS
static void _function_parameter_string(string *str, zend_function *fptr, char* indent TSRMLS_DC)
{
- int i;
+ zend_uint i;
struct _zend_arg_info *arg_info = fptr->common.arg_info;
if (!arg_info) return;
@@ -757,6 +758,7 @@ ZEND_FUNCTION(reflection_function_invoke)
zval *fname;
int result;
int argc = ZEND_NUM_ARGS();
+ zend_fcall_info fci;
METHOD_NOTSTATIC;
GET_REFLECTION_OBJECT_PTR(fptr);
@@ -774,15 +776,18 @@ ZEND_FUNCTION(reflection_function_invoke)
*/
MAKE_STD_ZVAL(fname);
ZVAL_NULL(fname);
- result = fast_call_user_function(
- EG(function_table), NULL, fname,
- &retval_ptr,
- argc,
- params,
- 1,
- NULL,
- &fptr TSRMLS_CC
- );
+
+ fci.size = sizeof(fci);
+ fci.function_table = EG(function_table);
+ fci.function_name = fname;
+ fci.symbol_table = NULL;
+ fci.object_pp = NULL;
+ fci.retval_ptr_ptr = &retval_ptr;
+ fci.param_count = argc;
+ fci.no_separation = 1;
+ /*fci.function_handler_cache = &fptr;*/
+
+ result = zend_call_function(&fci, NULL TSRMLS_CC);
zval_ptr_dtor(&fname);
efree(params);
@@ -983,6 +988,7 @@ ZEND_FUNCTION(reflection_method_invoke)
zval *fname;
int argc = ZEND_NUM_ARGS();
int result;
+ zend_fcall_info fci;
METHOD_NOTSTATIC;
@@ -1032,17 +1038,19 @@ ZEND_FUNCTION(reflection_method_invoke)
*/
MAKE_STD_ZVAL(fname);
ZVAL_NULL(fname);
- result = fast_call_user_function(
- EG(function_table),
- object_pp,
- fname,
- &retval_ptr,
- argc - 1,
- params+ 1,
- 1,
- NULL,
- &mptr TSRMLS_CC
- );
+
+ fci.size = sizeof(fci);
+ fci.function_table = EG(function_table);
+ fci.function_name = fname;
+ fci.symbol_table = NULL;
+ fci.object_pp = object_pp;
+ fci.retval_ptr_ptr = &retval_ptr;
+ fci.param_count = argc-1;
+ fci.params = params+1;
+ fci.no_separation = 1;
+ /*fci.function_handler_cache = &mptr;*/
+
+ result = zend_call_function(&fci, NULL TSRMLS_CC);
zval_ptr_dtor(&fname);
efree(params);
@@ -1611,6 +1619,7 @@ ZEND_FUNCTION(reflection_class_newinstance)
if (ce->constructor) {
zval ***params;
zval *fname;
+ zend_fcall_info fci;
params = safe_emalloc(sizeof(zval **), argc, 0);
if (zend_get_parameters_array_ex(argc, params) == FAILURE) {
@@ -1625,9 +1634,19 @@ ZEND_FUNCTION(reflection_class_newinstance)
*/
MAKE_STD_ZVAL(fname);
ZVAL_NULL(fname);
- if (fast_call_user_function(EG(function_table), &return_value, fname,
- &retval_ptr, argc, params,
- 1, NULL, &ce->constructor TSRMLS_CC) == FAILURE) {
+
+ fci.size = sizeof(fci);
+ fci.function_table = EG(function_table);
+ fci.function_name = fname;
+ fci.symbol_table = NULL;
+ fci.object_pp = &return_value;
+ fci.retval_ptr_ptr = &retval_ptr;
+ fci.param_count = argc;
+ fci.params = params;
+ fci.no_separation = 1;
+ /*fci.function_handler_cache = &ce->constructor;*/
+
+ if (zend_call_function(&fci, NULL TSRMLS_CC) == FAILURE) {
efree(params);
zval_ptr_dtor(&fname);
zend_error(E_WARNING, "Invokation of %s's constructor failed\n", ce->name);