From 2eae18794945db6c8e2540525b10a59759e0ade9 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 26 Feb 2014 00:14:50 +0100 Subject: [PATCH] Store arg_num in fcall entry Instead of storing the argument number in the znode of the parameter list, store it in fcall->arg_num. This mainly cleans up the parameter parsing code, which previously had to duplicate all rules (this becomes more excessive as more features are added, e.g. named params would already require a minimum of 14 rules...) --- Zend/zend_compile.c | 38 +++++++++++++++++----------------- Zend/zend_compile.h | 9 ++++---- Zend/zend_language_parser.y | 41 +++++++++++++++++++------------------ 3 files changed, 45 insertions(+), 43 deletions(-) diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 76a38d2818..d53cb96cd0 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2552,20 +2552,19 @@ int zend_do_begin_class_member_function_call(znode *class_name, znode *method_na } /* }}} */ -void zend_do_end_function_call(znode *function_name, znode *result, const znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC) /* {{{ */ +void zend_do_end_function_call(znode *function_name, znode *result, int is_method, int is_dynamic_fcall TSRMLS_DC) /* {{{ */ { zend_op *opline; + zend_function_call_entry *fcall; + zend_stack_top(&CG(function_call_stack), (void **) &fcall); if (is_method && function_name && function_name->op_type == IS_UNUSED) { /* clone */ - if (Z_LVAL(argument_list->u.constant) != 0) { + if (fcall->arg_num != 0) { zend_error(E_WARNING, "Clone method does not require arguments"); } opline = &CG(active_op_array)->opcodes[Z_LVAL(function_name->u.constant)]; } else { - zend_function_call_entry *fcall; - zend_stack_top(&CG(function_call_stack), (void **) &fcall); - opline = get_next_op(CG(active_op_array) TSRMLS_CC); if (fcall->fbc) { opline->opcode = ZEND_DO_FCALL; @@ -2592,18 +2591,17 @@ void zend_do_end_function_call(znode *function_name, znode *result, const znode opline->result.var = get_temporary_variable(CG(active_op_array)); opline->result_type = IS_VAR; GET_NODE(result, opline->result); - - zend_stack_del_top(&CG(function_call_stack)); - opline->extended_value = Z_LVAL(argument_list->u.constant); + opline->extended_value = fcall->arg_num; if (CG(context).used_stack + 1 > CG(active_op_array)->used_stack) { CG(active_op_array)->used_stack = CG(context).used_stack + 1; } - CG(context).used_stack -= Z_LVAL(argument_list->u.constant); + CG(context).used_stack -= fcall->arg_num; + zend_stack_del_top(&CG(function_call_stack)); } /* }}} */ -void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{{ */ +void zend_do_pass_param(znode *param, zend_uchar op TSRMLS_DC) /* {{{ */ { zend_op *opline; int original_op = op; @@ -2614,12 +2612,13 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ zend_stack_top(&CG(function_call_stack), (void **) &fcall); function_ptr = fcall->fbc; + fcall->arg_num++; if (original_op == ZEND_SEND_REF) { if (function_ptr && function_ptr->common.function_name && function_ptr->common.type == ZEND_USER_FUNCTION && - !ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { + !ARG_SHOULD_BE_SENT_BY_REF(function_ptr, fcall->arg_num)) { zend_error_noreturn(E_COMPILE_ERROR, "Call-time pass-by-reference has been removed; " "If you would like to pass argument by reference, modify the declaration of %s().", @@ -2631,7 +2630,7 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ } if (function_ptr) { - if (ARG_MAY_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { + if (ARG_MAY_BE_SENT_BY_REF(function_ptr, fcall->arg_num)) { if (op == ZEND_SEND_VAR && param->op_type & (IS_VAR|IS_CV)) { send_by_reference = ZEND_ARG_SEND_BY_REF; if (zend_is_function_or_method_call(param)) { @@ -2642,7 +2641,7 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ } else { op = ZEND_SEND_VAL; } - } else if (ARG_SHOULD_BE_SENT_BY_REF(function_ptr, (zend_uint) offset)) { + } else if (ARG_SHOULD_BE_SENT_BY_REF(function_ptr, fcall->arg_num)) { send_by_reference = ZEND_ARG_SEND_BY_REF; } } @@ -2677,7 +2676,7 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ if (function_ptr) { zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC); } else { - zend_do_end_variable_parse(param, BP_VAR_FUNC_ARG, offset TSRMLS_CC); + zend_do_end_variable_parse(param, BP_VAR_FUNC_ARG, fcall->arg_num TSRMLS_CC); } break; case ZEND_SEND_REF: @@ -2703,7 +2702,7 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ } opline->opcode = op; SET_NODE(opline->op1, param); - opline->op2.opline_num = offset; + opline->op2.opline_num = fcall->arg_num; SET_UNUSED(opline->op2); if (++CG(context).used_stack > CG(active_op_array)->used_stack) { @@ -2712,12 +2711,13 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) /* {{ } /* }}} */ -void zend_do_unpack_params(znode *params, int offset TSRMLS_DC) /* {{{ */ +void zend_do_unpack_params(znode *params TSRMLS_DC) /* {{{ */ { zend_op *opline; zend_function_call_entry *fcall; zend_stack_top(&CG(function_call_stack), (void **) &fcall); + if (fcall->fbc) { /* If argument unpacking is used argument numbers and sending modes can no longer be * computed at compile time, thus we need access to EX(call). In order to have it we @@ -2741,7 +2741,7 @@ void zend_do_unpack_params(znode *params, int offset TSRMLS_DC) /* {{{ */ opline->opcode = ZEND_SEND_UNPACK; SET_NODE(opline->op1, params); SET_UNUSED(opline->op2); - opline->op2.num = (zend_uint) offset; + opline->op2.num = fcall->arg_num; } /* }}} */ @@ -5599,11 +5599,11 @@ void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC) /* } /* }}} */ -void zend_do_end_new_object(znode *result, const znode *new_token, const znode *argument_list TSRMLS_DC) /* {{{ */ +void zend_do_end_new_object(znode *result, const znode *new_token TSRMLS_DC) /* {{{ */ { znode ctor_result; - zend_do_end_function_call(NULL, &ctor_result, argument_list, 1, 0 TSRMLS_CC); + zend_do_end_function_call(NULL, &ctor_result, 1, 0 TSRMLS_CC); zend_do_free(&ctor_result TSRMLS_CC); CG(active_op_array)->opcodes[new_token->u.op.opline_num].op2.opline_num = get_next_op_number(CG(active_op_array)); diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 0ea3be4f11..270c085d03 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -365,6 +365,7 @@ typedef struct _zend_function_state { typedef struct _zend_function_call_entry { zend_function *fbc; + zend_uint arg_num; } zend_function_call_entry; typedef struct _zend_switch_entry { @@ -521,7 +522,7 @@ void zend_do_begin_dynamic_function_call(znode *function_name, int prefix_len TS void zend_do_fetch_class(znode *result, znode *class_name TSRMLS_DC); void zend_do_build_full_name(znode *result, znode *prefix, znode *name, int is_class_member TSRMLS_DC); int zend_do_begin_class_member_function_call(znode *class_name, znode *method_name TSRMLS_DC); -void zend_do_end_function_call(znode *function_name, znode *result, const znode *argument_list, int is_method, int is_dynamic_fcall TSRMLS_DC); +void zend_do_end_function_call(znode *function_name, znode *result, int is_method, int is_dynamic_fcall TSRMLS_DC); void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC); void zend_do_yield(znode *result, znode *value, const znode *key, zend_bool is_variable TSRMLS_DC); void zend_do_handle_exception(TSRMLS_D); @@ -557,8 +558,8 @@ ZEND_API void zend_do_inheritance(zend_class_entry *ce, zend_class_entry *parent void zend_do_early_binding(TSRMLS_D); ZEND_API void zend_do_delayed_early_binding(const zend_op_array *op_array TSRMLS_DC); -void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC); -void zend_do_unpack_params(znode *params, int offset TSRMLS_DC); +void zend_do_pass_param(znode *param, zend_uchar op TSRMLS_DC); +void zend_do_unpack_params(znode *params TSRMLS_DC); void zend_do_boolean_or_begin(znode *expr1, znode *op_token TSRMLS_DC); @@ -588,7 +589,7 @@ void zend_do_pop_object(znode *object TSRMLS_DC); void zend_do_begin_new_object(znode *new_token, znode *class_type TSRMLS_DC); -void zend_do_end_new_object(znode *result, const znode *new_token, const znode *argument_list TSRMLS_DC); +void zend_do_end_new_object(znode *result, const znode *new_token TSRMLS_DC); void zend_do_fetch_constant(znode *result, znode *constant_container, znode *constant_name, int mode, zend_bool check_namespace TSRMLS_DC); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 5d3f73beaf..d3844540cf 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -580,19 +580,20 @@ optional_class_type: function_call_parameter_list: '(' ')' { Z_LVAL($$.u.constant) = 0; } | '(' non_empty_function_call_parameter_list ')' { $$ = $2; } - | '(' yield_expr ')' { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$2, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } + | '(' yield_expr ')' { zend_do_pass_param(&$2, ZEND_SEND_VAL TSRMLS_CC); } ; non_empty_function_call_parameter_list: - expr_without_variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } - | variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$1, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); } - | '&' w_variable { Z_LVAL($$.u.constant) = 1; zend_do_pass_param(&$2, ZEND_SEND_REF, Z_LVAL($$.u.constant) TSRMLS_CC); } - | T_ELLIPSIS expr { Z_LVAL($$.u.constant) = 0; zend_do_unpack_params(&$2, Z_LVAL($$.u.constant) TSRMLS_CC); } - | non_empty_function_call_parameter_list ',' expr_without_variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAL, Z_LVAL($$.u.constant) TSRMLS_CC); } - | non_empty_function_call_parameter_list ',' variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$3, ZEND_SEND_VAR, Z_LVAL($$.u.constant) TSRMLS_CC); } - | non_empty_function_call_parameter_list ',' '&' w_variable { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant)+1; zend_do_pass_param(&$4, ZEND_SEND_REF, Z_LVAL($$.u.constant) TSRMLS_CC); } - | non_empty_function_call_parameter_list ',' T_ELLIPSIS expr { Z_LVAL($$.u.constant)=Z_LVAL($1.u.constant); zend_do_unpack_params(&$4, Z_LVAL($$.u.constant) TSRMLS_CC); } + function_call_parameter + | non_empty_function_call_parameter_list ',' function_call_parameter +; + +function_call_parameter: + expr_without_variable { zend_do_pass_param(&$1, ZEND_SEND_VAL TSRMLS_CC); } + | variable { zend_do_pass_param(&$1, ZEND_SEND_VAR TSRMLS_CC); } + | '&' w_variable { zend_do_pass_param(&$2, ZEND_SEND_REF TSRMLS_CC); } + | T_ELLIPSIS expr { zend_do_unpack_params(&$2 TSRMLS_CC); } ; global_var_list: @@ -769,14 +770,14 @@ instance_call: ; new_expr: - T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + T_NEW class_name_reference { zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$1, &$2 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$$, &$1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} ; expr_without_variable: T_LIST '(' { zend_do_list_init(TSRMLS_C); } assignment_list ')' '=' expr { zend_do_list_end(&$$, &$7 TSRMLS_CC); } | variable '=' expr { zend_check_writable_variable(&$1); zend_do_assign(&$$, &$1, &$3 TSRMLS_CC); } | variable '=' '&' variable { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$4, BP_VAR_W, 1 TSRMLS_CC); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$1, &$4 TSRMLS_CC); } - | variable '=' '&' T_NEW class_name_reference { zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated"); zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4, &$7 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $3.EA = ZEND_PARSED_NEW; zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); } + | variable '=' '&' T_NEW class_name_reference { zend_error(E_DEPRECATED, "Assigning the return value of new by reference is deprecated"); zend_check_writable_variable(&$1); zend_do_extended_fcall_begin(TSRMLS_C); zend_do_begin_new_object(&$4, &$5 TSRMLS_CC); } ctor_arguments { zend_do_end_new_object(&$3, &$4 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $3.EA = ZEND_PARSED_NEW; zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); } | T_CLONE expr { zend_do_clone(&$$, &$2 TSRMLS_CC); } | variable T_PLUS_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_ADD, &$$, &$1, &$3 TSRMLS_CC); } | variable T_MINUS_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SUB, &$$, &$1, &$3 TSRMLS_CC); } @@ -890,21 +891,21 @@ lexical_var_list: function_call: namespace_name { $$.u.op.opline_num = zend_do_begin_function_call(&$1, 1 TSRMLS_CC); } - function_call_parameter_list { zend_do_end_function_call(&$1, &$$, &$3, 0, $2.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } + function_call_parameter_list { zend_do_end_function_call(&$1, &$$, 0, $2.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } | T_NAMESPACE T_NS_SEPARATOR namespace_name { $1.op_type = IS_CONST; ZVAL_EMPTY_STRING(&$1.u.constant); zend_do_build_namespace_name(&$1, &$1, &$3 TSRMLS_CC); $$.u.op.opline_num = zend_do_begin_function_call(&$1, 0 TSRMLS_CC); } - function_call_parameter_list { zend_do_end_function_call(&$1, &$$, &$5, 0, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } + function_call_parameter_list { zend_do_end_function_call(&$1, &$$, 0, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } | T_NS_SEPARATOR namespace_name { $$.u.op.opline_num = zend_do_begin_function_call(&$2, 0 TSRMLS_CC); } - function_call_parameter_list { zend_do_end_function_call(&$2, &$$, &$4, 0, $3.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } + function_call_parameter_list { zend_do_end_function_call(&$2, &$$, 0, $3.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } | class_name T_PAAMAYIM_NEKUDOTAYIM variable_name { $$.u.op.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } - function_call_parameter_list { zend_do_end_function_call($4.u.op.opline_num?NULL:&$3, &$$, &$5, $4.u.op.opline_num, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + function_call_parameter_list { zend_do_end_function_call($4.u.op.opline_num?NULL:&$3, &$$, $4.u.op.opline_num, $4.u.op.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { zend_do_end_variable_parse(&$3, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } - function_call_parameter_list { zend_do_end_function_call(NULL, &$$, &$5, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + function_call_parameter_list { zend_do_end_function_call(NULL, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_name { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } - function_call_parameter_list { zend_do_end_function_call(NULL, &$$, &$5, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + function_call_parameter_list { zend_do_end_function_call(NULL, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | variable_class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects { zend_do_end_variable_parse(&$3, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } - function_call_parameter_list { zend_do_end_function_call(NULL, &$$, &$5, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + function_call_parameter_list { zend_do_end_function_call(NULL, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | variable_without_objects { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); } - function_call_parameter_list { zend_do_end_function_call(&$1, &$$, &$3, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} + function_call_parameter_list { zend_do_end_function_call(&$1, &$$, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} ; class_name: @@ -1117,7 +1118,7 @@ array_method_dereference: method: { zend_do_pop_object(&$$ TSRMLS_CC); zend_do_begin_method_call(&$$ TSRMLS_CC); } - function_call_parameter_list { zend_do_end_function_call(&$1, &$$, &$2, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } + function_call_parameter_list { zend_do_end_function_call(&$1, &$$, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C); } ; method_or_not: -- 2.40.0