From 5521912b153ab6fd457ea4ce9ea3a7656f09b038 Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Wed, 7 May 2008 12:04:39 +0000 Subject: [PATCH] Use IS_CV for dirrent access to $this variable --- NEWS | 1 + Zend/zend_compile.c | 114 ++++++++++++++++++++++++------------ Zend/zend_compile.h | 7 ++- Zend/zend_execute_API.c | 13 ++-- Zend/zend_language_parser.y | 48 +++++++-------- Zend/zend_opcode.c | 2 +- Zend/zend_vm_def.h | 2 +- Zend/zend_vm_execute.h | 15 +++-- Zend/zend_vm_execute.skl | 13 ++-- 9 files changed, 134 insertions(+), 81 deletions(-) diff --git a/NEWS b/NEWS index ed5f8073b6..2b36bfe43d 100644 --- a/NEWS +++ b/NEWS @@ -109,6 +109,7 @@ PHP NEWS - Added native support for asinh(), acosh(), atanh(), log1p() and expm1() (Kalle) - Improved PHP runtime speed and memory usage: + . Use IS_CV for direct access to $this variable. (Dmitry) . Use ZEND_FREE() opcode instead of ZEND_SWITCH_FREE(IS_TMP_VAR). (Dmitry) . Lazy EG(active_symbol_table) initialization. (Dmitry) . Optimized ZEND_RETURN opcode to not allocate and copy return value if it is diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 8b3b15af4b..26e32c5dd3 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -562,12 +562,16 @@ void zend_do_assign(znode *result, znode *variable, znode *value TSRMLS_DC) } } - zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); + zend_do_end_variable_parse(variable, BP_VAR_W, 0 TSRMLS_CC); last_op_number = get_next_op_number(CG(active_op_array)); opline = get_next_op(CG(active_op_array) TSRMLS_CC); - if (variable->op_type == IS_VAR) { + if (variable->op_type == IS_CV) { + if (variable->u.var == CG(active_op_array)->this_var) { + zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); + } + } else if (variable->op_type == IS_VAR) { int n = 0; while (last_op_number - n > 0) { @@ -632,18 +636,24 @@ static inline zend_bool zend_is_function_or_method_call(znode *variable) void zend_do_assign_ref(znode *result, znode *lvar, znode *rvar TSRMLS_DC) { - int last_op_number = get_next_op_number(CG(active_op_array)); - zend_op *opline = get_next_op(CG(active_op_array) TSRMLS_CC); - - if (last_op_number > 0) { - zend_op *last_op = &CG(active_op_array)->opcodes[last_op_number-1]; + zend_op *opline; - if (lvar->op_type == IS_VAR && - opline_is_fetch_this(last_op TSRMLS_CC)) { - zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); - } - } + if (lvar->op_type == IS_CV) { + if (lvar->u.var == CG(active_op_array)->this_var) { + zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); + } + } else if (lvar->op_type == IS_VAR) { + int last_op_number = get_next_op_number(CG(active_op_array)); + + if (last_op_number > 0) { + opline = &CG(active_op_array)->opcodes[last_op_number-1]; + if (opline_is_fetch_this(opline TSRMLS_CC)) { + zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); + } + } + } + opline = get_next_op(CG(active_op_array) TSRMLS_CC); opline->opcode = ZEND_ASSIGN_REF; if (zend_is_function_or_method_call(rvar)) { opline->extended_value = ZEND_RETURNS_FUNCTION; @@ -897,11 +907,13 @@ void zend_do_begin_variable_parse(TSRMLS_D) } -void zend_do_end_variable_parse(int type, int arg_offset TSRMLS_DC) +void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS_DC) { zend_llist *fetch_list_ptr; zend_llist_element *le; - zend_op *opline, *opline_ptr=NULL; + zend_op *opline = NULL; + zend_op *opline_ptr; + zend_uint this_var = -1; zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); @@ -912,12 +924,36 @@ void zend_do_end_variable_parse(int type, int arg_offset TSRMLS_DC) if (le) { opline_ptr = (zend_op *)le->data; if (opline_is_fetch_this(opline_ptr TSRMLS_CC)) { - CG(active_op_array)->uses_this = 1; + /* convert to FETCH_?(this) into IS_CV */ + if (CG(active_op_array)->last == 0 || + CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode != ZEND_BEGIN_SILENCE) { + + this_var = opline_ptr->result.u.var; + if (CG(active_op_array)->this_var == -1) { + CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), Z_STRVAL(opline_ptr->op1.u.constant), Z_STRLEN(opline_ptr->op1.u.constant)); + } else { + efree(Z_STRVAL(opline_ptr->op1.u.constant)); + } + le = le->next; + if (variable->op_type == IS_VAR && + variable->u.var == this_var) { + variable->op_type = IS_CV; + variable->u.var = CG(active_op_array)->this_var; + } + } else if (CG(active_op_array)->this_var == -1) { + CG(active_op_array)->this_var = lookup_cv(CG(active_op_array), estrndup("this", sizeof("this")-1), sizeof("this")-1); + } } - while (1) { + while (le) { + opline_ptr = (zend_op *)le->data; opline = get_next_op(CG(active_op_array) TSRMLS_CC); memcpy(opline, opline_ptr, sizeof(zend_op)); + if (opline->op1.op_type == IS_VAR && + opline->op1.u.var == this_var) { + opline->op1.op_type = IS_CV; + opline->op1.u.var = CG(active_op_array)->this_var; + } switch (type) { case BP_VAR_R: if (opline->opcode == ZEND_FETCH_DIM_W && opline->op2.op_type == IS_UNUSED) { @@ -948,10 +984,8 @@ void zend_do_end_variable_parse(int type, int arg_offset TSRMLS_DC) break; } le = le->next; - if (le == NULL) break; - opline_ptr = (zend_op *)le->data; } - if (type == BP_VAR_W && arg_offset) { + if (opline && type == BP_VAR_W && arg_offset) { opline->extended_value = ZEND_FETCH_MAKE_REF; } } @@ -1348,7 +1382,12 @@ void zend_do_receive_arg(zend_uchar op, znode *var, znode *offset, znode *initia return; } - if (CG(active_op_array)->scope && + if (var->op_type == IS_CV && + var->u.var == CG(active_op_array)->this_var && + (CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) { + zend_error(E_COMPILE_ERROR, "Cannot re-assign $this"); + } else if (var->op_type == IS_VAR && + CG(active_op_array)->scope && ((CG(active_op_array)->fn_flags & ZEND_ACC_STATIC) == 0) && (Z_TYPE(varname->u.constant) == IS_STRING) && (Z_STRLEN(varname->u.constant) == sizeof("this")-1) && @@ -1455,7 +1494,7 @@ void zend_do_begin_method_call(znode *left_bracket TSRMLS_DC) int last_op_number; unsigned char *ptr = NULL; - zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); + zend_do_end_variable_parse(left_bracket, BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_variable_parse(TSRMLS_C); last_op_number = get_next_op_number(CG(active_op_array))-1; @@ -1977,17 +2016,17 @@ void zend_do_pass_param(znode *param, zend_uchar op, int offset TSRMLS_DC) if (original_op == ZEND_SEND_VAR) { switch (op) { case ZEND_SEND_VAR_NO_REF: - zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); + zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC); break; case ZEND_SEND_VAR: if (function_ptr) { - zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); + zend_do_end_variable_parse(param, BP_VAR_R, 0 TSRMLS_CC); } else { - zend_do_end_variable_parse(BP_VAR_FUNC_ARG, offset TSRMLS_CC); + zend_do_end_variable_parse(param, BP_VAR_FUNC_ARG, offset TSRMLS_CC); } break; case ZEND_SEND_REF: - zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); + zend_do_end_variable_parse(param, BP_VAR_W, 0 TSRMLS_CC); break; } } @@ -2066,9 +2105,9 @@ void zend_do_return(znode *expr, int do_end_vparse TSRMLS_DC) if (do_end_vparse) { if (CG(active_op_array)->return_reference && !zend_is_function_or_method_call(expr)) { - zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); + zend_do_end_variable_parse(expr, BP_VAR_W, 0 TSRMLS_CC); } else { - zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); + zend_do_end_variable_parse(expr, BP_VAR_R, 0 TSRMLS_CC); } } @@ -3491,15 +3530,16 @@ void zend_do_fetch_property(znode *result, znode *object, znode *property TSRMLS { zend_op opline; zend_llist *fetch_list_ptr; - zend_op *opline_ptr=NULL; zend_stack_top(&CG(bp_stack), (void **) &fetch_list_ptr); - if (fetch_list_ptr->count == 1) { - zend_llist_element *le; - - le = fetch_list_ptr->head; - opline_ptr = (zend_op *) le->data; + if (object->op_type == IS_CV) { + if (object->u.var == CG(active_op_array)->this_var) { + SET_UNUSED(*object); /* this means $this for objects */ + } + } else if (fetch_list_ptr->count == 1) { + zend_llist_element *le = fetch_list_ptr->head; + zend_op *opline_ptr = (zend_op *) le->data; if (opline_is_fetch_this(opline_ptr TSRMLS_CC)) { efree(Z_STRVAL(opline_ptr->op1.u.constant)); @@ -4124,7 +4164,7 @@ void zend_do_indirect_references(znode *result, znode *num_references, znode *va { int i; - zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); + zend_do_end_variable_parse(variable, BP_VAR_R, 0 TSRMLS_CC); for (i=1; iu.constant.value.lval; i++) { fetch_simple_variable_ex(result, variable, 0, ZEND_FETCH_R TSRMLS_CC); *variable = *result; @@ -4170,7 +4210,7 @@ void zend_do_isset_or_isempty(int type, znode *result, znode *variable TSRMLS_DC { zend_op *last_op; - zend_do_end_variable_parse(BP_VAR_IS, 0 TSRMLS_CC); + zend_do_end_variable_parse(variable, BP_VAR_IS, 0 TSRMLS_CC); zend_check_writable_variable(variable); @@ -4246,7 +4286,7 @@ void zend_do_foreach_begin(znode *foreach_token, znode *open_brackets_token, zno } /* save the location of FETCH_W instruction(s) */ open_brackets_token->u.opline_num = get_next_op_number(CG(active_op_array)); - zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); + zend_do_end_variable_parse(array, BP_VAR_W, 0 TSRMLS_CC); if (CG(active_op_array)->last > 0 && CG(active_op_array)->opcodes[CG(active_op_array)->last-1].opcode == ZEND_FETCH_OBJ_W) { /* Only lock the container if we are fetching from a real container and not $this */ @@ -4356,7 +4396,7 @@ void zend_do_foreach_cont(znode *foreach_token, znode *open_brackets_token, znod value_node = opline->result; if (assign_by_ref) { - zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); + zend_do_end_variable_parse(value, BP_VAR_W, 0 TSRMLS_CC); /* Mark FE_FETCH as IS_VAR as it holds the data directly as a value */ zend_do_assign_ref(NULL, value, &value_node TSRMLS_CC); } else { diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index e6340d9dde..dc2dff1a7f 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -197,6 +197,8 @@ struct _zend_op_array { unsigned char return_reference; /* END of common elements */ + zend_bool done_pass_two; + zend_uint *refcount; zend_op *opcodes; @@ -220,8 +222,7 @@ struct _zend_op_array { zend_op *start_op; int backpatch_count; - zend_bool done_pass_two; - zend_bool uses_this; + zend_uint this_var; char *filename; zend_uint line_start; @@ -396,7 +397,7 @@ void zend_do_pre_incdec(znode *result, znode *op1, zend_uchar op TSRMLS_DC); void zend_do_post_incdec(znode *result, znode *op1, zend_uchar op TSRMLS_DC); void zend_do_begin_variable_parse(TSRMLS_D); -void zend_do_end_variable_parse(int type, int arg_offset TSRMLS_DC); +void zend_do_end_variable_parse(znode *variable, int type, int arg_offset TSRMLS_DC); void zend_check_writable_variable(znode *variable); diff --git a/Zend/zend_execute_API.c b/Zend/zend_execute_API.c index c35d902ec5..929828654b 100644 --- a/Zend/zend_execute_API.c +++ b/Zend/zend_execute_API.c @@ -1811,12 +1811,13 @@ ZEND_API void zend_rebuild_symbol_table(TSRMLS_D) /* {{{ */ } if (EG(current_execute_data) && EG(current_execute_data)->op_array) { EG(current_execute_data)->symbol_table = EG(active_symbol_table); - if (EG(current_execute_data)->op_array->uses_this && EG(This)) { - Z_ADDREF_P(EG(This)); /* For $this pointer */ - if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), NULL)==FAILURE) { - Z_DELREF_P(EG(This)); - } - } + + if (EG(current_execute_data)->op_array->this_var != -1 && + !EG(current_execute_data)->CVs[EG(current_execute_data)->op_array->this_var] && + EG(This)) { + EG(current_execute_data)->CVs[EG(current_execute_data)->op_array->this_var] = (zval**)EG(current_execute_data)->CVs + EG(current_execute_data)->op_array->last_var + EG(current_execute_data)->op_array->this_var; + *EG(current_execute_data)->CVs[EG(current_execute_data)->op_array->this_var] = EG(This); + } for (i = 0; i < EG(current_execute_data)->op_array->last_var; i++) { if (EG(current_execute_data)->CVs[i]) { zend_hash_quick_update(EG(active_symbol_table), diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index 896e786f1c..fbe941937c 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -275,7 +275,7 @@ unset_variables: ; unset_variable: - variable { zend_do_end_variable_parse(BP_VAR_UNSET, 0 TSRMLS_CC); zend_do_unset(&$1 TSRMLS_CC); } + variable { zend_do_end_variable_parse(&$1, BP_VAR_UNSET, 0 TSRMLS_CC); zend_do_unset(&$1 TSRMLS_CC); } ; function_declaration_statement: @@ -567,21 +567,21 @@ non_empty_for_expr: 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(BP_VAR_W, 1 TSRMLS_CC); zend_do_end_variable_parse(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(BP_VAR_W, 0 TSRMLS_CC); zend_do_assign_ref(&$$, &$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); zend_do_assign_ref(&$$, &$1, &$3 TSRMLS_CC); } | 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_CLONE expr { zend_do_clone(&$$, &$2 TSRMLS_CC); } - | variable T_PLUS_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(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(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SUB, &$$, &$1, &$3 TSRMLS_CC); } - | variable T_MUL_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_MUL, &$$, &$1, &$3 TSRMLS_CC); } - | variable T_DIV_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_DIV, &$$, &$1, &$3 TSRMLS_CC); } - | variable T_CONCAT_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_CONCAT, &$$, &$1, &$3 TSRMLS_CC); } - | variable T_MOD_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_MOD, &$$, &$1, &$3 TSRMLS_CC); } - | variable T_AND_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_BW_AND, &$$, &$1, &$3 TSRMLS_CC); } - | variable T_OR_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_BW_OR, &$$, &$1, &$3 TSRMLS_CC); } - | variable T_XOR_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_BW_XOR, &$$, &$1, &$3 TSRMLS_CC); } - | variable T_SL_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SL, &$$, &$1, &$3 TSRMLS_CC); } - | variable T_SR_EQUAL expr { zend_check_writable_variable(&$1); zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); zend_do_binary_assign_op(ZEND_ASSIGN_SR, &$$, &$1, &$3 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); } + | variable T_MUL_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_MUL, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_DIV_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_DIV, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_CONCAT_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_CONCAT, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_MOD_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_MOD, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_AND_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_BW_AND, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_OR_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_BW_OR, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_XOR_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_BW_XOR, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_SL_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_SL, &$$, &$1, &$3 TSRMLS_CC); } + | variable T_SR_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_SR, &$$, &$1, &$3 TSRMLS_CC); } | rw_variable T_INC { zend_do_post_incdec(&$$, &$1, ZEND_POST_INC TSRMLS_CC); } | T_INC rw_variable { zend_do_pre_incdec(&$$, &$2, ZEND_PRE_INC TSRMLS_CC); } | rw_variable T_DEC { zend_do_post_incdec(&$$, &$1, ZEND_POST_DEC TSRMLS_CC); } @@ -647,16 +647,16 @@ function_call: | class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { $4.u.opline_num = zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call($4.u.opline_num?NULL:&$3, &$$, &$6, $4.u.opline_num, $4.u.opline_num TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | class_name T_PAAMAYIM_NEKUDOTAYIM variable_without_objects '(' { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + | 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, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} | variable_class_name T_PAAMAYIM_NEKUDOTAYIM T_STRING '(' { zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } function_call_parameter_list ')' { zend_do_end_function_call(NULL, &$$, &$6, 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(BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_class_member_function_call(&$1, &$3 TSRMLS_CC); } + | 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, &$$, &$6, 1, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} - | variable_without_objects '(' { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_begin_dynamic_function_call(&$1, 0 TSRMLS_CC); } + | 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, &$$, &$4, 0, 1 TSRMLS_CC); zend_do_extended_fcall_end(TSRMLS_C);} ; @@ -680,7 +680,7 @@ fully_qualified_class_name: class_name_reference: class_name { zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } - | dynamic_class_name_reference { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } + | dynamic_class_name_reference { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); zend_do_fetch_class(&$$, &$1 TSRMLS_CC); } ; @@ -779,17 +779,17 @@ expr: r_variable: - variable { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); $$ = $1; } + variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$ = $1; } ; w_variable: - variable { zend_do_end_variable_parse(BP_VAR_W, 0 TSRMLS_CC); $$ = $1; + variable { zend_do_end_variable_parse(&$1, BP_VAR_W, 0 TSRMLS_CC); $$ = $1; zend_check_writable_variable(&$1); } ; rw_variable: - variable { zend_do_end_variable_parse(BP_VAR_RW, 0 TSRMLS_CC); $$ = $1; + variable { zend_do_end_variable_parse(&$1, BP_VAR_RW, 0 TSRMLS_CC); $$ = $1; zend_check_writable_variable(&$1); } ; @@ -830,7 +830,7 @@ static_member: ; variable_class_name: - reference_variable { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); $$=$1;; } + reference_variable { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); $$=$1;; } ; base_variable_with_function_calls: @@ -865,7 +865,7 @@ dim_offset: object_property: object_dim_list { $$ = $1; } - | variable_without_objects { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); } { znode tmp_znode; zend_do_pop_object(&tmp_znode TSRMLS_CC); zend_do_fetch_property(&$$, &tmp_znode, &$1 TSRMLS_CC);} + | variable_without_objects { zend_do_end_variable_parse(&$1, BP_VAR_R, 0 TSRMLS_CC); } { znode tmp_znode; zend_do_pop_object(&tmp_znode TSRMLS_CC); zend_do_fetch_property(&$$, &tmp_znode, &$1 TSRMLS_CC);} ; object_dim_list: @@ -914,7 +914,7 @@ non_empty_array_pair_list: ; encaps_list: - encaps_list encaps_var { zend_do_end_variable_parse(BP_VAR_R, 0 TSRMLS_CC); zend_do_add_variable(&$$, &$1, &$2 TSRMLS_CC); } + encaps_list encaps_var { zend_do_end_variable_parse(&$2, BP_VAR_R, 0 TSRMLS_CC); zend_do_add_variable(&$$, &$1, &$2 TSRMLS_CC); } | encaps_list T_ENCAPSED_AND_WHITESPACE { zend_do_add_string(&$$, &$1, &$2 TSRMLS_CC); } | /* empty */ { zend_do_init_string(&$$ TSRMLS_CC); } diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 35e85cc16f..fbbccb3f0c 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -95,7 +95,7 @@ void init_op_array(zend_op_array *op_array, zend_uchar type, int initial_ops_siz op_array->return_reference = 0; op_array->done_pass_two = 0; - op_array->uses_this = 0; + op_array->this_var = -1; op_array->start_op = NULL; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 6d6761f8a6..734fccec74 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2390,7 +2390,7 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, ANY, CV) } else { zend_compiled_variable *cv = &CV_DEF_OF(opline->op2.u.var); zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, - &EG(exception), sizeof(zval *), NULL); + &EG(exception), sizeof(zval *), (void**)&EX(CVs)[opline->op2.u.var]); } EG(exception) = NULL; ZEND_VM_NEXT_OPCODE(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 839fc93f5a..d08b0adc66 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -69,10 +69,15 @@ ZEND_API void execute(zend_op_array *op_array TSRMLS_DC) ZEND_VM_SET_OPCODE(op_array->opcodes); } - if (op_array->uses_this && EG(This) && EG(active_symbol_table)) { - Z_ADDREF_P(EG(This)); /* For $this pointer */ - if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), NULL)==FAILURE) { - Z_DELREF_P(EG(This)); + if (op_array->this_var != -1 && EG(This)) { + Z_ADDREF_P(EG(This)); /* For $this pointer */ + if (!EG(active_symbol_table)) { + EX(CVs)[op_array->this_var] = (zval**)EX(CVs) + (op_array->last_var + op_array->this_var); + *EX(CVs)[op_array->this_var] = EG(This); + } else { + if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void**)&EX(CVs)[op_array->this_var])==FAILURE) { + Z_DELREF_P(EG(This)); + } } } @@ -1080,7 +1085,7 @@ static int ZEND_CATCH_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) } else { zend_compiled_variable *cv = &CV_DEF_OF(opline->op2.u.var); zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value, - &EG(exception), sizeof(zval *), NULL); + &EG(exception), sizeof(zval *), (void**)&EX(CVs)[opline->op2.u.var]); } EG(exception) = NULL; ZEND_VM_NEXT_OPCODE(); diff --git a/Zend/zend_vm_execute.skl b/Zend/zend_vm_execute.skl index 32e26aff56..b6e8d84d29 100644 --- a/Zend/zend_vm_execute.skl +++ b/Zend/zend_vm_execute.skl @@ -37,10 +37,15 @@ ZEND_API void {%EXECUTOR_NAME%}(zend_op_array *op_array TSRMLS_DC) ZEND_VM_SET_OPCODE(op_array->opcodes); } - if (op_array->uses_this && EG(This) && EG(active_symbol_table)) { - Z_ADDREF_P(EG(This)); /* For $this pointer */ - if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), NULL)==FAILURE) { - Z_DELREF_P(EG(This)); + if (op_array->this_var != -1 && EG(This)) { + Z_ADDREF_P(EG(This)); /* For $this pointer */ + if (!EG(active_symbol_table)) { + EX(CVs)[op_array->this_var] = (zval**)EX(CVs) + (op_array->last_var + op_array->this_var); + *EX(CVs)[op_array->this_var] = EG(This); + } else { + if (zend_hash_add(EG(active_symbol_table), "this", sizeof("this"), &EG(This), sizeof(zval *), (void**)&EX(CVs)[op_array->this_var])==FAILURE) { + Z_DELREF_P(EG(This)); + } } } -- 2.40.0