From: Dmitry Stogov Date: Wed, 22 Apr 2015 18:46:13 +0000 (+0300) Subject: Use fast method to check if first arguments should be passed by reference (not tested... X-Git-Tag: PRE_PHP7_NSAPI_REMOVAL~179 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=15a5f61cf4ac1961c20b61ba58e19c64a653064c;p=php Use fast method to check if first arguments should be passed by reference (not tested onbig endian). --- diff --git a/Zend/zend_API.c b/Zend/zend_API.c index e6c8e56d86..dc51713807 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -2232,6 +2232,7 @@ ZEND_API int zend_register_functions(zend_class_entry *scope, const zend_functio internal_function->num_args = 0; internal_function->required_num_args = 0; } + zend_set_function_arg_flags((zend_function*)internal_function); if (ptr->flags & ZEND_ACC_ABSTRACT) { if (scope) { /* This is a class that must be abstract itself. Here we set the check info. */ diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index aeba6a9402..ff22e0ceb3 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -4108,6 +4108,31 @@ void zend_compile_stmt_list(zend_ast *ast) /* {{{ */ } /* }}} */ +ZEND_API int zend_set_function_arg_flags(zend_function *func) /* {{{ */ +{ + uint32_t i, n; + + func->common.arg_flags[0] = 0; + func->common.arg_flags[1] = 0; + func->common.arg_flags[2] = 0; + if (func->common.arg_info) { + n = MIN(func->common.num_args, MAX_ARG_FLAG_NUM); + i = 0; + while (i < n) { + ZEND_SET_ARG_FLAG(func, i + 1, func->common.arg_info[i].pass_by_reference); + i++; + } + if (func->common.fn_flags & ZEND_ACC_VARIADIC) { + uint32_t pass_by_reference = func->common.arg_info[i].pass_by_reference; + while (i < MAX_ARG_FLAG_NUM) { + ZEND_SET_ARG_FLAG(func, i + 1, pass_by_reference); + i++; + } + } + } +} +/* }}} */ + void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_method) /* {{{ */ { zend_ast_list *list = zend_ast_get_list(ast); @@ -4294,6 +4319,7 @@ void zend_compile_params(zend_ast *ast, zend_ast *return_type_ast, zend_bool is_ if (op_array->fn_flags & ZEND_ACC_VARIADIC) { op_array->num_args--; } + zend_set_function_arg_flags((zend_function*)op_array); } /* }}} */ diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 4b3d0a25b2..6ae1cd5f45 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -334,6 +334,7 @@ typedef struct _zend_internal_function_info { struct _zend_op_array { /* Common elements */ zend_uchar type; + zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string *function_name; zend_class_entry *scope; @@ -384,6 +385,7 @@ struct _zend_op_array { typedef struct _zend_internal_function { /* Common elements */ zend_uchar type; + zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string* function_name; zend_class_entry *scope; @@ -404,6 +406,7 @@ union _zend_function { struct { zend_uchar type; /* never used */ + zend_uchar arg_flags[3]; /* bitset of arg_info.pass_by_reference */ uint32_t fn_flags; zend_string *function_name; zend_class_entry *scope; @@ -776,6 +779,7 @@ ZEND_API void zend_activate_auto_globals(void); ZEND_API zend_bool zend_is_auto_global(zend_string *name); ZEND_API zend_bool zend_is_auto_global_str(char *name, size_t len); ZEND_API size_t zend_dirname(char *path, size_t len); +ZEND_API int zend_set_function_arg_flags(zend_function *func); int zendlex(zend_parser_stack_elem *elem); @@ -910,6 +914,32 @@ static zend_always_inline int zend_check_arg_send_type(const zend_function *zf, #define ARG_MAY_BE_SENT_BY_REF(zf, arg_num) \ zend_check_arg_send_type(zf, arg_num, ZEND_SEND_PREFER_REF) +/* Quick API to check firat 12 arguments */ +#define MAX_ARG_FLAG_NUM 12 + +#ifdef WORDS_BIGENDIAN +# define ZEND_SET_ARG_FLAG(zf, arg_num, mask) do { \ + *(uint32_t*)&(zf)->type |= ((mask) << ((arg_num) - 1) * 2); \ + } while (0) +# define ZEND_CHECK_ARG_FLAG(zf, arg_num, mask) \ + (((*((uint32_t*)&((zf)->type))) >> (((arg_num) - 1) * 2)) & (mask)) +#else +# define ZEND_SET_ARG_FLAG(zf, arg_num, mask) do { \ + *(uint32_t*)&(zf)->type |= (((mask) << 6) << (arg_num) * 2); \ + } while (0) +# define ZEND_CHECK_ARG_FLAG(zf, arg_num, mask) \ + (((*(uint32_t*)&(zf)->type) >> (((arg_num) + 3) * 2)) & (mask)) +#endif + +#define QUICK_ARG_MUST_BE_SENT_BY_REF(zf, arg_num) \ + ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_BY_REF) + +#define QUICK_ARG_SHOULD_BE_SENT_BY_REF(zf, arg_num) \ + ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) + +#define QUICK_ARG_MAY_BE_SENT_BY_REF(zf, arg_num) \ + ZEND_CHECK_ARG_FLAG(zf, arg_num, ZEND_SEND_PREFER_REF) + #define ZEND_RETURN_VAL 0 #define ZEND_RETURN_REF 1 diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index eb37d48522..ffeba914e6 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -72,6 +72,7 @@ static ZEND_FUNCTION(pass) static const zend_internal_function zend_pass_function = { ZEND_INTERNAL_FUNCTION, /* type */ + {0, 0, 0}, /* arg_flags */ 0, /* fn_flags */ NULL, /* name */ NULL, /* scope */ diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 679a104a59..a14f60080b 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -1007,6 +1007,9 @@ ZEND_API zend_function *zend_get_call_trampoline_func(zend_class_entry *ce, zend } func->type = ZEND_USER_FUNCTION; + func->arg_flags[0] = 0; + func->arg_flags[1] = 0; + func->arg_flags[2] = 0; func->fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE | ZEND_ACC_PUBLIC; if (is_static) { func->fn_flags |= ZEND_ACC_STATIC; diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 35c42fe4d7..8bdaded38f 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -51,6 +51,9 @@ static void op_array_alloc_ops(zend_op_array *op_array, uint32_t size) void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_size) { op_array->type = type; + op_array->arg_flags[0] = 0; + op_array->arg_flags[1] = 0; + op_array->arg_flags[2] = 0; op_array->refcount = (uint32_t *) emalloc(sizeof(uint32_t)); *op_array->refcount = 1; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 79b2f70133..16d3a23a16 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4085,7 +4085,12 @@ ZEND_VM_HANDLER(116, ZEND_SEND_VAL_EX, CONST|TMP, ANY) zval *value, *arg; zend_free_op free_op1; - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) { + if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + ZEND_VM_C_GOTO(send_val_by_ref); + } + } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { +ZEND_VM_C_LABEL(send_val_by_ref): SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num); FREE_UNFETCHED_OP1(); @@ -4225,7 +4230,12 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR_EX, VAR|CV, ANY) zval *varptr, *arg; zend_free_op free_op1; - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) { + if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + ZEND_VM_C_GOTO(send_var_by_ref); + } + } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { +ZEND_VM_C_LABEL(send_var_by_ref): ZEND_VM_DISPATCH_TO_HANDLER(ZEND_SEND_REF); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 27be74d6e1..0472feb379 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3215,7 +3215,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_CONST_HANDLER zval *value, *arg; - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) { + if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + goto send_val_by_ref; + } + } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { +send_val_by_ref: SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num); @@ -11466,7 +11471,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_TMP_HANDLER(Z zval *value, *arg; zend_free_op free_op1; - if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) { + if (QUICK_ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + goto send_val_by_ref; + } + } else if (ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { +send_val_by_ref: SAVE_OPLINE(); zend_error(E_EXCEPTION | E_ERROR, "Cannot pass parameter %d by reference", opline->op2.num); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); @@ -14703,7 +14713,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_VAR_HANDLER(Z zval *varptr, *arg; zend_free_op free_op1; - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) { + if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + goto send_var_by_ref; + } + } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { +send_var_by_ref: return ZEND_SEND_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } @@ -28441,7 +28456,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_CV_HANDLER(ZE zval *varptr, *arg; - if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + if (EXPECTED(opline->op2.num <= MAX_ARG_FLAG_NUM)) { + if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { + goto send_var_by_ref; + } + } else if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, opline->op2.num)) { +send_var_by_ref: return ZEND_SEND_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); } diff --git a/ext/com_dotnet/com_handlers.c b/ext/com_dotnet/com_handlers.c index 66983d1b34..ec5c70defa 100644 --- a/ext/com_dotnet/com_handlers.c +++ b/ext/com_dotnet/com_handlers.c @@ -279,6 +279,7 @@ static union _zend_function *com_method_get(zend_object **object_ptr, zend_strin f.fn_flags = ZEND_ACC_CALL_VIA_HANDLER; f.function_name = zend_string_copy(name); f.handler = PHP_FN(com_method_handler); + zend_set_function_arg_flags((zend_function*)&f); fptr = &f; diff --git a/ext/pdo/pdo_dbh.c b/ext/pdo/pdo_dbh.c index 9029e4a8ea..8189473524 100644 --- a/ext/pdo/pdo_dbh.c +++ b/ext/pdo/pdo_dbh.c @@ -1319,6 +1319,7 @@ int pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind) ifunc->num_args = 0; ifunc->required_num_args = 0; } + zend_set_function_arg_flags((zend_function*)ifunc); namelen = strlen(funcs->fname); lc_name = emalloc(namelen+1); zend_str_tolower_copy(lc_name, funcs->fname, namelen); diff --git a/ext/soap/soap.c b/ext/soap/soap.c index 883e0ac541..120274b272 100644 --- a/ext/soap/soap.c +++ b/ext/soap/soap.c @@ -668,6 +668,7 @@ PHP_MINIT_FUNCTION(soap) fe.prototype = NULL; fe.num_args = 2; fe.arg_info = NULL; + zend_set_function_arg_flags((zend_function*)&fe); INIT_OVERLOADED_CLASS_ENTRY(ce, PHP_SOAP_CLIENT_CLASSNAME, soap_client_functions, (zend_function *)&fe, NULL, NULL);