From 6203a250f7b8c36be3ced49acd6558a4871d433f Mon Sep 17 00:00:00 2001 From: Andi Gutmans Date: Fri, 4 Jan 2002 08:05:21 +0000 Subject: [PATCH] - Separate other kinds of function calls too. - Significantly improve performance of function calls by moving lowercasing - the function name to compile-time when possible. --- Zend/zend_compile.c | 18 ++-- Zend/zend_compile.h | 3 + Zend/zend_execute.c | 210 ++++++++++++++++++++++++++++---------------- 3 files changed, 150 insertions(+), 81 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index df80201335..3cbb04f513 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -693,7 +693,13 @@ void zend_do_add_variable(znode *result, znode *op1, znode *op2 TSRMLS_DC) *result = opline->result; } - +static void zend_lowercase_znode_if_const(znode *z) +{ + if (z->op_type == IS_CONST) { + zend_str_tolower(z->u.constant.value.str.val, z->u.constant.value.str.len); + } +} + void zend_do_free(znode *op1 TSRMLS_DC) { if (op1->op_type==IS_TMP_VAR) { @@ -909,8 +915,9 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) zend_do_extended_fcall_begin(TSRMLS_C); return; } - last_op->opcode = ZEND_INIT_FCALL_BY_NAME; - last_op->extended_value = ZEND_MEMBER_FUNC_CALL; + last_op->opcode = ZEND_INIT_METHOD_CALL; + zend_lowercase_znode_if_const(&last_op->op2); + // last_op->extended_value = ZEND_MEMBER_FUNC_CALL; left_bracket->u.constant.value.lval = ZEND_INIT_FCALL_BY_NAME; /*opline = get_next_op(CG(active_op_array) TSRMLS_CC); @@ -1011,10 +1018,11 @@ void zend_do_begin_class_member_function_call(znode *class_name, znode *function unsigned char *ptr = NULL; zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - opline->opcode = ZEND_INIT_FCALL_BY_NAME; + opline->opcode = ZEND_INIT_STATIC_METHOD_CALL; opline->op1 = *class_name; + zend_lowercase_znode_if_const(function_name); opline->op2 = *function_name; - opline->extended_value = ZEND_MEMBER_FUNC_CALL; + //opline->extended_value = ZEND_MEMBER_FUNC_CALL; zend_stack_push(&CG(function_call_stack), (void *) &ptr, sizeof(zend_function *)); } diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index a9f69d9c2f..7d91ba6c4e 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -546,6 +546,9 @@ int zendlex(znode *zendlval TSRMLS_DC); #define ZEND_CLONE 111 #define ZEND_INIT_CTOR_CALL 112 +#define ZEND_INIT_METHOD_CALL 113 +#define ZEND_INIT_STATIC_METHOD_CALL 114 + /* end of block */ diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 15202bd6e6..6d0acd6282 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1563,11 +1563,134 @@ binary_assign_op_addr: { EX(calling_namespace) = Z_OBJCE_P(EX(object).ptr); NEXT_OPCODE(); } - case ZEND_INIT_FCALL_BY_NAME: { + case ZEND_INIT_METHOD_CALL: + { zval *function_name; zend_function *function; HashTable *active_function_table; zval tmp; + zend_bool is_const; + char *function_name_strval; + int function_name_strlen; + + zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object).ptr); + + is_const = (EX(opline)->op2.op_type == IS_CONST); + + if (is_const) { + function_name_strval = EX(opline)->op2.u.constant.value.str.val; + function_name_strlen = EX(opline)->op2.u.constant.value.str.len; + } else { + function_name = get_zval_ptr(&EX(opline)->op2, EX(Ts), &EG(free_op2), BP_VAR_R); + + tmp = *function_name; + zval_copy_ctor(&tmp); + convert_to_string(&tmp); + function_name = &tmp; + zend_str_tolower(tmp.value.str.val, tmp.value.str.len); + + function_name_strval = tmp.value.str.val; + function_name_strlen = tmp.value.str.len; + } + + EX(calling_namespace) = EG(namespace); + + EX(object).ptr = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R); + + /* Nuked overloaded method code. This will be redone differently */ + + if (EX(object).ptr && EX(object).ptr->type == IS_OBJECT) { + active_function_table = &Z_OBJCE_P(EX(object).ptr)->function_table; + } else { + zend_error(E_ERROR, "Call to a member function on a non-object"); + } + if (!PZVAL_IS_REF(EX(object).ptr)) { + EX(object).ptr->refcount++; /* For $this pointer */ + } else { + zval *this_ptr; + ALLOC_ZVAL(this_ptr); + *this_ptr = *EX(object).ptr; + INIT_PZVAL(this_ptr); + zval_copy_ctor(this_ptr); + EX(object).ptr = this_ptr; + } + + EX(calling_namespace) = Z_OBJCE_P(EX(object).ptr); + + if (zend_hash_find(active_function_table, function_name_strval, function_name_strlen+1, (void **) &function)==FAILURE) { + zend_error(E_ERROR, "Call to undefined function: %s()", function_name_strval); + } + + if (!is_const) { + zval_dtor(&tmp); + FREE_OP(EX(Ts), &EX(opline)->op2, EG(free_op2)); + } + + EX(fbc) = function; + NEXT_OPCODE(); + } + case ZEND_INIT_STATIC_METHOD_CALL: + { + zval *function_name; + zend_function *function; + zval tmp; + zval **object_ptr_ptr; + zend_class_entry *ce; + zend_bool is_const; + char *function_name_strval; + int function_name_strlen; + + zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object).ptr); + + is_const = (EX(opline)->op2.op_type == IS_CONST); + + if (is_const) { + function_name_strval = EX(opline)->op2.u.constant.value.str.val; + function_name_strlen = EX(opline)->op2.u.constant.value.str.len; + } else { + function_name = get_zval_ptr(&EX(opline)->op2, EX(Ts), &EG(free_op2), BP_VAR_R); + + tmp = *function_name; + zval_copy_ctor(&tmp); + convert_to_string(&tmp); + function_name = &tmp; + zend_str_tolower(tmp.value.str.val, tmp.value.str.len); + + function_name_strval = tmp.value.str.val; + function_name_strlen = tmp.value.str.len; + } + + EX(calling_namespace) = EG(namespace); + + if (zend_hash_find(EG(active_symbol_table), "this", sizeof("this"), (void **) &object_ptr_ptr)==FAILURE) { + EX(object).ptr=NULL; + } else { + /* We assume that "this" is already is_ref and pointing to the object. + If it isn't then tough */ + EX(object).ptr = *object_ptr_ptr; + EX(object).ptr->refcount++; /* For this pointer */ + } + ce = EX(Ts)[EX(opline)->op1.u.var].EA.class_entry; + + EX(calling_namespace) = ce; + + if (zend_hash_find(&ce->function_table, function_name_strval, function_name_strlen+1, (void **) &function)==FAILURE) { + zend_error(E_ERROR, "Call to undefined function: %s()", function_name_strval); + } + + if (!is_const) { + zval_dtor(&tmp); + } + + EX(fbc) = function; + + NEXT_OPCODE(); + } + case ZEND_INIT_FCALL_BY_NAME: + { + zval *function_name; + zend_function *function; + zval tmp; zend_ptr_stack_n_push(&EG(arg_types_stack), 2, EX(fbc), EX(object).ptr); @@ -1581,90 +1704,25 @@ binary_assign_op_addr: { EX(calling_namespace) = EG(namespace); - if (EX(opline)->op1.op_type != IS_UNUSED) { - if (EX(opline)->op1 .op_type==IS_CONST) { /* used for class::function() */ - zval **object_ptr_ptr; - - if (zend_hash_find(EG(active_symbol_table), "this", sizeof("this"), (void **) &object_ptr_ptr)==FAILURE) { - EX(object).ptr=NULL; - } else { - /* We assume that "this" is already is_ref and pointing to the object. - If it isn't then tough */ - EX(object).ptr = *object_ptr_ptr; - EX(object).ptr->refcount++; /* For this pointer */ - } - - { - zend_class_entry *ce = EX(Ts)[EX(opline)->op1.u.var].EA.class_entry; - active_function_table = &ce->function_table; - EX(calling_namespace) = ce; - } - } else { /* used for member function calls */ - EX(object).ptr = get_zval_ptr(&EX(opline)->op1, EX(Ts), &EG(free_op1), BP_VAR_R); - - if ((!EX(object).ptr && EX(Ts)[EX(opline)->op1.u.var].EA.type==IS_OVERLOADED_OBJECT) - || ((EX(object).ptr && EX(object).ptr->type==IS_OBJECT) && Z_OBJCE_P(EX(object).ptr)->handle_function_call)) { /* overloaded function call */ - zend_overloaded_element overloaded_element; - - overloaded_element.element = *function_name; - overloaded_element.type = OE_IS_METHOD; - - if (EX(object).ptr) { - EX(Ts)[EX(opline)->op1.u.var].EA.data.overloaded_element.object = EX(object).ptr; - EX(Ts)[EX(opline)->op1.u.var].EA.data.overloaded_element.type = BP_VAR_NA; - EX(Ts)[EX(opline)->op1.u.var].EA.data.overloaded_element.elements_list = (zend_llist *) emalloc(sizeof(zend_llist)); - zend_llist_init(EX(Ts)[EX(opline)->op1.u.var].EA.data.overloaded_element.elements_list, sizeof(zend_overloaded_element), NULL, 0); - } - zend_llist_add_element(EX(Ts)[EX(opline)->op1.u.var].EA.data.overloaded_element.elements_list, &overloaded_element); - EX(fbc) = (zend_function *) emalloc(sizeof(zend_function)); - EX(fbc)->type = ZEND_OVERLOADED_FUNCTION; - EX(fbc)->common.arg_types = NULL; - EX(fbc)->overloaded_function.var = EX(opline)->op1.u.var; - goto overloaded_function_call_cont; - } + EX(object).ptr = NULL; - if (EX(object).ptr && EX(object).ptr->type == IS_OBJECT) { - active_function_table = &Z_OBJCE_P(EX(object).ptr)->function_table; - } else { - zend_error(E_ERROR, "Call to a member function on a non-object"); - } - if (!PZVAL_IS_REF(EX(object).ptr)) { - EX(object).ptr->refcount++; /* For $this pointer */ - } else { - zval *this_ptr; - ALLOC_ZVAL(this_ptr); - *this_ptr = *EX(object).ptr; - INIT_PZVAL(this_ptr); - zval_copy_ctor(this_ptr); - EX(object).ptr = this_ptr; + do { + if (EG(namespace)) { + if (zend_hash_find(&EG(namespace)->function_table, function_name->value.str.val, function_name->value.str.len+1, (void **) &function) == SUCCESS) { + break; } - //active_function_table = &Z_OBJCE_P(EX(object).ptr)->function_table; - EX(calling_namespace) = Z_OBJCE_P(EX(object).ptr); } - if (zend_hash_find(active_function_table, function_name->value.str.val, function_name->value.str.len+1, (void **) &function)==FAILURE) { + if (zend_hash_find(EG(function_table), function_name->value.str.val, function_name->value.str.len+1, (void **) &function)==FAILURE) { zend_error(E_ERROR, "Call to undefined function: %s()", function_name->value.str.val); } - } else { /* function pointer */ - EX(object).ptr = NULL; - do { - if (EG(namespace)) { - if (zend_hash_find(&EG(namespace)->function_table, function_name->value.str.val, function_name->value.str.len+1, (void **) &function) == SUCCESS) { - break; - } - } - if (zend_hash_find(EG(function_table), function_name->value.str.val, function_name->value.str.len+1, (void **) &function)==FAILURE) { - zend_error(E_ERROR, "Call to undefined function: %s()", function_name->value.str.val); - } - EX(calling_namespace) = NULL; - } while (0); - } + EX(calling_namespace) = NULL; + } while (0); zval_dtor(&tmp); EX(fbc) = function; -overloaded_function_call_cont: - FREE_OP(EX(Ts), &EX(opline)->op2, EG(free_op2)); + + NEXT_OPCODE(); } - NEXT_OPCODE(); case ZEND_DO_FCALL_BY_NAME: EX(function_state).function = EX(fbc); goto do_fcall_common; -- 2.40.0