From adcf0c6052761350695da211b337edff12c6e63c Mon Sep 17 00:00:00 2001 From: Dmitry Stogov Date: Fri, 3 Apr 2015 01:32:20 +0300 Subject: [PATCH] Improved reference counting --- Zend/zend_execute.c | 21 +- Zend/zend_execute.h | 25 +- Zend/zend_object_handlers.c | 2 +- Zend/zend_variables.h | 6 +- Zend/zend_vm_def.h | 140 ++++--- Zend/zend_vm_execute.h | 776 ++++++++++++++++++++++++------------ 6 files changed, 648 insertions(+), 322 deletions(-) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 424f4888e9..063f9ed427 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -971,7 +971,7 @@ static inline int zend_verify_missing_return_type(zend_function *zf) static zend_always_inline void zend_assign_to_object(zval *retval, zval *object, uint32_t object_op_type, zval *property_name, uint32_t property_op_type, int value_type, znode_op value_op, const zend_execute_data *execute_data, void **cache_slot) { zend_free_op free_value; - zval *value = get_zval_ptr_deref(value_type, value_op, execute_data, &free_value, BP_VAR_R); + zval *value = get_zval_ptr(value_type, value_op, execute_data, &free_value, BP_VAR_R); zval tmp; if (object_op_type != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { @@ -1033,9 +1033,6 @@ fast_assign: if (retval && !EG(exception)) { ZVAL_COPY(retval, value); } - if (value_type == IS_VAR) { - FREE_OP(free_value); - } return; } } else { @@ -1057,9 +1054,11 @@ fast_assign: zval_copy_ctor_func(&tmp); value = &tmp; } - } else if (value_type != IS_TMP_VAR && - Z_REFCOUNTED_P(value)) { - Z_ADDREF_P(value); + } else if (value_type != IS_TMP_VAR) { + ZVAL_DEREF(value); + if (Z_REFCOUNTED_P(value)) { + Z_ADDREF_P(value); + } } zend_hash_add_new(zobj->properties, Z_STR_P(property_name), value); if (retval && !EG(exception)) { @@ -1089,9 +1088,11 @@ fast_assign: zval_copy_ctor_func(&tmp); value = &tmp; } - } else if (value_type != IS_TMP_VAR && - Z_REFCOUNTED_P(value)) { - Z_ADDREF_P(value); + } else if (value_type != IS_TMP_VAR) { + ZVAL_DEREF(value); + if (Z_REFCOUNTED_P(value)) { + Z_ADDREF_P(value); + } } Z_OBJ_HT_P(object)->write_property(object, property_name, value, cache_slot); diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index dce9e1c040..408a7c5032 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -55,6 +55,13 @@ ZEND_API void zend_verify_internal_return_error(const zend_function *zf, const c static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value, zend_uchar value_type) { + zend_refcounted *ref = NULL; + + if ((value_type & (IS_VAR|IS_CV)) && Z_ISREF_P(value)) { + ref = Z_COUNTED_P(value); + value = Z_REFVAL_P(value); + } + do { if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) { zend_refcounted *garbage; @@ -81,12 +88,18 @@ static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval if (UNEXPECTED(Z_OPT_COPYABLE_P(variable_ptr))) { zval_copy_ctor_func(variable_ptr); } - } else if (value_type != IS_TMP_VAR) { + } else if (value_type == IS_CV) { if (UNEXPECTED(Z_OPT_REFCOUNTED_P(variable_ptr))) { Z_ADDREF_P(variable_ptr); } + } else if (/* value_type == IS_VAR && */ UNEXPECTED(ref)) { + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(variable_ptr)) { + Z_ADDREF_P(variable_ptr); + } } - _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + zval_dtor_func_for_ptr(garbage); return variable_ptr; } else { /* we need to split */ /* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */ @@ -104,10 +117,16 @@ static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval if (UNEXPECTED(Z_OPT_COPYABLE_P(variable_ptr))) { zval_copy_ctor_func(variable_ptr); } - } else if (value_type != IS_TMP_VAR) { + } else if (value_type == IS_CV) { if (UNEXPECTED(Z_OPT_REFCOUNTED_P(variable_ptr))) { Z_ADDREF_P(variable_ptr); } + } else if (/* value_type == IS_VAR && */ UNEXPECTED(ref)) { + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(variable_ptr)) { + Z_ADDREF_P(variable_ptr); + } } return variable_ptr; } diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 1ce666b719..00fb17451e 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -625,7 +625,7 @@ ZEND_API void zend_std_write_property(zval *object, zval *member, zval *value, v } else if (EXPECTED(zobj->properties != NULL)) { if ((variable_ptr = zend_hash_find(zobj->properties, Z_STR_P(member))) != NULL) { found: - zend_assign_to_variable(variable_ptr, value, (IS_VAR|IS_TMP_VAR)); + zend_assign_to_variable(variable_ptr, value, IS_CV); goto exit; } } diff --git a/Zend/zend_variables.h b/Zend/zend_variables.h index 9ca31097c3..adb226123f 100644 --- a/Zend/zend_variables.h +++ b/Zend/zend_variables.h @@ -31,9 +31,9 @@ ZEND_API void ZEND_FASTCALL _zval_dtor_func(zend_refcounted *p ZEND_FILE_LINE_DC ZEND_API void ZEND_FASTCALL _zval_dtor_func_for_ptr(zend_refcounted *p ZEND_FILE_LINE_DC); ZEND_API void ZEND_FASTCALL _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC); -#define zval_dtor_func(p) _zval_dtor_func(zv ZEND_FILE_LINE_CC) -#define zval_dtor_func_for_ptr(p) _zval_dtor_func_for_ptr(zv ZEND_FILE_LINE_CC) -#define zval_copy_ctor_func(zv) _zval_copy_ctor_func(zv ZEND_FILE_LINE_CC) +#define zval_dtor_func(zv) _zval_dtor_func(zv ZEND_FILE_LINE_CC) +#define zval_dtor_func_for_ptr(zv) _zval_dtor_func_for_ptr(zv ZEND_FILE_LINE_CC) +#define zval_copy_ctor_func(zv) _zval_copy_ctor_func(zv ZEND_FILE_LINE_CC) static zend_always_inline void _zval_dtor(zval *zvalue ZEND_FILE_LINE_DC) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index bd0ba8dd78..387edda41c 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2184,17 +2184,14 @@ ZEND_VM_C_LABEL(try_assign_dim_array): variable_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(object_ptr), dim, OP2_TYPE, BP_VAR_W); FREE_OP2(); } - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); - if ((opline+1)->op1_type == IS_VAR) { - FREE_OP(free_op_data1); - } + value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -2263,27 +2260,23 @@ ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV) zval *variable_ptr; SAVE_OPLINE(); - value = GET_OP2_ZVAL_PTR_DEREF(BP_VAR_R); + value = GET_OP2_ZVAL_PTR(BP_VAR_R); variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); if (OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (OP2_TYPE == IS_TMP_VAR) { - FREE_OP2(); - } + FREE_OP2(); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, OP2_TYPE); + value = zend_assign_to_variable(variable_ptr, value, OP2_TYPE); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } FREE_OP1_VAR_PTR(); + /* zend_assign_to_variable() always takes care of op2, never free it! */ } - /* zend_assign_to_variable() always takes care of op2, never free it! */ - FREE_OP2_IF_VAR(); - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -3788,13 +3781,22 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY) zval_copy_ctor_func(EX(return_value)); } } - } else if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && Z_ISREF_P(retval_ptr)) { - ZVAL_COPY(EX(return_value), Z_REFVAL_P(retval_ptr)); - FREE_OP1_IF_VAR(); - } else { - ZVAL_COPY_VALUE(EX(return_value), retval_ptr); - if (OP1_TYPE == IS_CV) { - if (Z_OPT_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr); + } else if (OP1_TYPE == IS_CV) { + ZVAL_DEREF(retval_ptr); + ZVAL_COPY(EX(return_value), retval_ptr); + } else /* if (OP1_TYPE == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(retval_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(retval_ptr); + + retval_ptr = Z_REFVAL_P(retval_ptr); + ZVAL_COPY_VALUE(EX(return_value), retval_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(retval_ptr)) { + Z_ADDREF_P(retval_ptr); + } + } else { + ZVAL_COPY_VALUE(EX(return_value), retval_ptr); } } } @@ -3884,13 +3886,22 @@ ZEND_VM_HANDLER(161, ZEND_GENERATOR_RETURN, CONST|TMP|VAR|CV, ANY) zval_copy_ctor_func(&generator->retval); } } - } else if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && Z_ISREF_P(retval)) { - ZVAL_COPY(&generator->retval, Z_REFVAL_P(retval)); - FREE_OP1_IF_VAR(); - } else { + } else if (OP1_TYPE == IS_CV) { + ZVAL_DEREF(retval); ZVAL_COPY_VALUE(&generator->retval, retval); - if (OP1_TYPE == IS_CV) { - if (Z_OPT_REFCOUNTED_P(retval)) Z_ADDREF_P(retval); + } else /* if (OP1_TYPE == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(retval))) { + zend_refcounted *ref = Z_COUNTED_P(retval); + + retval = Z_REFVAL_P(retval); + ZVAL_COPY_VALUE(&generator->retval, retval); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(retval)) { + Z_ADDREF_P(retval); + } + } else { + ZVAL_COPY_VALUE(&generator->retval, retval); } } @@ -4037,19 +4048,31 @@ ZEND_VM_HANDLER(117, ZEND_SEND_VAR, VAR|CV, ANY) USE_OPLINE zval *varptr, *arg; zend_free_op free_op1; + zend_refcounted *ref; SAVE_OPLINE(); varptr = GET_OP1_ZVAL_PTR(BP_VAR_R); arg = ZEND_CALL_VAR(EX(call), opline->result.var); - if (Z_ISREF_P(varptr)) { - ZVAL_COPY(arg, Z_REFVAL_P(varptr)); - FREE_OP1(); - } else { - ZVAL_COPY_VALUE(arg, varptr); - if (OP1_TYPE == IS_CV) { - if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); + + if (OP1_TYPE == IS_CV) { + ZVAL_DEREF(varptr); + ZVAL_COPY(arg, varptr); + } else /* if (OP1_TYPE == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(varptr))) { + zend_refcounted *ref = Z_COUNTED_P(varptr); + + varptr = Z_REFVAL_P(varptr); + ZVAL_COPY_VALUE(arg, varptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } else { + ZVAL_COPY_VALUE(arg, varptr); } } + ZEND_VM_NEXT_OPCODE(); } @@ -4140,15 +4163,26 @@ ZEND_VM_HANDLER(66, ZEND_SEND_VAR_EX, VAR|CV, ANY) SAVE_OPLINE(); varptr = GET_OP1_ZVAL_PTR(BP_VAR_R); arg = ZEND_CALL_VAR(EX(call), opline->result.var); - if (Z_ISREF_P(varptr)) { - ZVAL_COPY(arg, Z_REFVAL_P(varptr)); - FREE_OP1(); - } else { - ZVAL_COPY_VALUE(arg, varptr); - if (OP1_TYPE == IS_CV) { - if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); + + if (OP1_TYPE == IS_CV) { + ZVAL_DEREF(varptr); + ZVAL_COPY(arg, varptr); + } else /* if (OP1_TYPE == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(varptr))) { + zend_refcounted *ref = Z_COUNTED_P(varptr); + + varptr = Z_REFVAL_P(varptr); + ZVAL_COPY_VALUE(arg, varptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } else { + ZVAL_COPY_VALUE(arg, varptr); } } + ZEND_VM_NEXT_OPCODE(); } @@ -5008,12 +5042,24 @@ ZEND_VM_HANDLER(72, ZEND_ADD_ARRAY_ELEMENT, CONST|TMP|VAR|CV, CONST|TMPVAR|UNUSE ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((OP1_TYPE == IS_CV || OP1_TYPE == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); - FREE_OP1_IF_VAR(); - } else if (OP1_TYPE == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + } else if (OP1_TYPE == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (OP1_TYPE == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); + + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -5349,7 +5395,7 @@ ZEND_VM_HANDLER(74, ZEND_UNSET_VAR, CONST|TMPVAR|CV, UNUSED|CONST|VAR) if (!--GC_REFCOUNT(garbage)) { ZVAL_UNDEF(var); - _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + zval_dtor_func_for_ptr(garbage); } else { GC_ZVAL_CHECK_POSSIBLE_ROOT(var); ZVAL_UNDEF(var); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 145dfb6d0c..554524271c 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2848,13 +2848,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_SPEC_CONST_HANDLER(ZEND zval_copy_ctor_func(EX(return_value)); } } - } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(retval_ptr)) { - ZVAL_COPY(EX(return_value), Z_REFVAL_P(retval_ptr)); + } else if (IS_CONST == IS_CV) { + ZVAL_DEREF(retval_ptr); + ZVAL_COPY(EX(return_value), retval_ptr); + } else /* if (IS_CONST == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(retval_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(retval_ptr); - } else { - ZVAL_COPY_VALUE(EX(return_value), retval_ptr); - if (IS_CONST == IS_CV) { - if (Z_OPT_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr); + retval_ptr = Z_REFVAL_P(retval_ptr); + ZVAL_COPY_VALUE(EX(return_value), retval_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(retval_ptr)) { + Z_ADDREF_P(retval_ptr); + } + } else { + ZVAL_COPY_VALUE(EX(return_value), retval_ptr); } } } @@ -2943,13 +2952,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_CONST_HA zval_copy_ctor_func(&generator->retval); } } - } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(retval)) { - ZVAL_COPY(&generator->retval, Z_REFVAL_P(retval)); - - } else { + } else if (IS_CONST == IS_CV) { + ZVAL_DEREF(retval); ZVAL_COPY_VALUE(&generator->retval, retval); - if (IS_CONST == IS_CV) { - if (Z_OPT_REFCOUNTED_P(retval)) Z_ADDREF_P(retval); + } else /* if (IS_CONST == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(retval))) { + zend_refcounted *ref = Z_COUNTED_P(retval); + + retval = Z_REFVAL_P(retval); + ZVAL_COPY_VALUE(&generator->retval, retval); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(retval)) { + Z_ADDREF_P(retval); + } + } else { + ZVAL_COPY_VALUE(&generator->retval, retval); } } @@ -5377,12 +5395,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_C ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); + } else if (IS_CONST == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_CONST == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); - } else if (IS_CONST == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -5488,7 +5518,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_CONST_HAN if (!--GC_REFCOUNT(garbage)) { ZVAL_UNDEF(var); - _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + zval_dtor_func_for_ptr(garbage); } else { GC_ZVAL_CHECK_POSSIBLE_ROOT(var); ZVAL_UNDEF(var); @@ -6413,7 +6443,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_VAR_HANDL if (!--GC_REFCOUNT(garbage)) { ZVAL_UNDEF(var); - _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + zval_dtor_func_for_ptr(garbage); } else { GC_ZVAL_CHECK_POSSIBLE_ROOT(var); ZVAL_UNDEF(var); @@ -7148,12 +7178,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_U ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); + } else if (IS_CONST == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_CONST == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); - } else if (IS_CONST == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -7259,7 +7301,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CONST_UNUSED_HA if (!--GC_REFCOUNT(garbage)) { ZVAL_UNDEF(var); - _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + zval_dtor_func_for_ptr(garbage); } else { GC_ZVAL_CHECK_POSSIBLE_ROOT(var); ZVAL_UNDEF(var); @@ -8774,12 +8816,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_C ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); + } else if (IS_CONST == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_CONST == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); - } else if (IS_CONST == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -10302,12 +10356,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_T ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_CONST == IS_CV || IS_CONST == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); + } else if (IS_CONST == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_CONST == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); - } else if (IS_CONST == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -10601,13 +10667,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_O zval_copy_ctor_func(EX(return_value)); } } - } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(retval_ptr)) { - ZVAL_COPY(EX(return_value), Z_REFVAL_P(retval_ptr)); + } else if (IS_TMP_VAR == IS_CV) { + ZVAL_DEREF(retval_ptr); + ZVAL_COPY(EX(return_value), retval_ptr); + } else /* if (IS_TMP_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(retval_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(retval_ptr); - } else { - ZVAL_COPY_VALUE(EX(return_value), retval_ptr); - if (IS_TMP_VAR == IS_CV) { - if (Z_OPT_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr); + retval_ptr = Z_REFVAL_P(retval_ptr); + ZVAL_COPY_VALUE(EX(return_value), retval_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(retval_ptr)) { + Z_ADDREF_P(retval_ptr); + } + } else { + ZVAL_COPY_VALUE(EX(return_value), retval_ptr); } } } @@ -10696,13 +10771,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_TMP_HAND zval_copy_ctor_func(&generator->retval); } } - } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(retval)) { - ZVAL_COPY(&generator->retval, Z_REFVAL_P(retval)); - - } else { + } else if (IS_TMP_VAR == IS_CV) { + ZVAL_DEREF(retval); ZVAL_COPY_VALUE(&generator->retval, retval); - if (IS_TMP_VAR == IS_CV) { - if (Z_OPT_REFCOUNTED_P(retval)) Z_ADDREF_P(retval); + } else /* if (IS_TMP_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(retval))) { + zend_refcounted *ref = Z_COUNTED_P(retval); + + retval = Z_REFVAL_P(retval); + ZVAL_COPY_VALUE(&generator->retval, retval); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(retval)) { + Z_ADDREF_P(retval); + } + } else { + ZVAL_COPY_VALUE(&generator->retval, retval); } } @@ -11596,12 +11680,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CON ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); + } else if (IS_TMP_VAR == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_TMP_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); - } else if (IS_TMP_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -12287,12 +12383,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_UNU ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); + } else if (IS_TMP_VAR == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_TMP_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); - } else if (IS_TMP_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -12797,12 +12905,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_CV_ ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); + } else if (IS_TMP_VAR == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_TMP_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); - } else if (IS_TMP_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -13277,12 +13397,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_TMP_TMP ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_TMP_VAR == IS_CV || IS_TMP_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); + } else if (IS_TMP_VAR == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_TMP_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); - } else if (IS_TMP_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -13567,13 +13699,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_O zval_copy_ctor_func(EX(return_value)); } } - } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(retval_ptr)) { - ZVAL_COPY(EX(return_value), Z_REFVAL_P(retval_ptr)); - zval_ptr_dtor_nogc(free_op1); - } else { - ZVAL_COPY_VALUE(EX(return_value), retval_ptr); - if (IS_VAR == IS_CV) { - if (Z_OPT_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr); + } else if (IS_VAR == IS_CV) { + ZVAL_DEREF(retval_ptr); + ZVAL_COPY(EX(return_value), retval_ptr); + } else /* if (IS_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(retval_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(retval_ptr); + + retval_ptr = Z_REFVAL_P(retval_ptr); + ZVAL_COPY_VALUE(EX(return_value), retval_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(retval_ptr)) { + Z_ADDREF_P(retval_ptr); + } + } else { + ZVAL_COPY_VALUE(EX(return_value), retval_ptr); } } } @@ -13663,13 +13804,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_VAR_HAND zval_copy_ctor_func(&generator->retval); } } - } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(retval)) { - ZVAL_COPY(&generator->retval, Z_REFVAL_P(retval)); - zval_ptr_dtor_nogc(free_op1); - } else { + } else if (IS_VAR == IS_CV) { + ZVAL_DEREF(retval); ZVAL_COPY_VALUE(&generator->retval, retval); - if (IS_VAR == IS_CV) { - if (Z_OPT_REFCOUNTED_P(retval)) Z_ADDREF_P(retval); + } else /* if (IS_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(retval))) { + zend_refcounted *ref = Z_COUNTED_P(retval); + + retval = Z_REFVAL_P(retval); + ZVAL_COPY_VALUE(&generator->retval, retval); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(retval)) { + Z_ADDREF_P(retval); + } + } else { + ZVAL_COPY_VALUE(&generator->retval, retval); } } @@ -13722,19 +13872,31 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_SPEC_VAR_HANDLER(ZEND USE_OPLINE zval *varptr, *arg; zend_free_op free_op1; + zend_refcounted *ref; SAVE_OPLINE(); varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); arg = ZEND_CALL_VAR(EX(call), opline->result.var); - if (Z_ISREF_P(varptr)) { - ZVAL_COPY(arg, Z_REFVAL_P(varptr)); - zval_ptr_dtor_nogc(free_op1); - } else { - ZVAL_COPY_VALUE(arg, varptr); - if (IS_VAR == IS_CV) { - if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); + + if (IS_VAR == IS_CV) { + ZVAL_DEREF(varptr); + ZVAL_COPY(arg, varptr); + } else /* if (IS_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(varptr))) { + zend_refcounted *ref = Z_COUNTED_P(varptr); + + varptr = Z_REFVAL_P(varptr); + ZVAL_COPY_VALUE(arg, varptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } else { + ZVAL_COPY_VALUE(arg, varptr); } } + ZEND_VM_NEXT_OPCODE(); } @@ -13825,15 +13987,26 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_VAR_HANDLER(Z SAVE_OPLINE(); varptr = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); arg = ZEND_CALL_VAR(EX(call), opline->result.var); - if (Z_ISREF_P(varptr)) { - ZVAL_COPY(arg, Z_REFVAL_P(varptr)); - zval_ptr_dtor_nogc(free_op1); - } else { - ZVAL_COPY_VALUE(arg, varptr); - if (IS_VAR == IS_CV) { - if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); + + if (IS_VAR == IS_CV) { + ZVAL_DEREF(varptr); + ZVAL_COPY(arg, varptr); + } else /* if (IS_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(varptr))) { + zend_refcounted *ref = Z_COUNTED_P(varptr); + + varptr = Z_REFVAL_P(varptr); + ZVAL_COPY_VALUE(arg, varptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } else { + ZVAL_COPY_VALUE(arg, varptr); } } + ZEND_VM_NEXT_OPCODE(); } @@ -15886,17 +16059,14 @@ try_assign_dim_array: variable_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(object_ptr), dim, IS_CONST, BP_VAR_W); } - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); - if ((opline+1)->op1_type == IS_VAR) { - FREE_OP(free_op_data1); - } + value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -15969,22 +16139,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CONST_HANDLER( variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1); if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (IS_CONST == IS_TMP_VAR) { - } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, IS_CONST); + value = zend_assign_to_variable(variable_ptr, value, IS_CONST); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } if (free_op1) {zval_ptr_dtor_nogc(free_op1);}; + /* zend_assign_to_variable() always takes care of op2, never free it! */ } - /* zend_assign_to_variable() always takes care of op2, never free it! */ - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -16246,12 +16413,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CON ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); - zval_ptr_dtor_nogc(free_op1); - } else if (IS_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + } else if (IS_VAR == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); + + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -16661,22 +16840,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_TMP_HANDLER(ZE variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1); if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (IS_TMP_VAR == IS_TMP_VAR) { - zval_ptr_dtor_nogc(free_op2); - } + zval_ptr_dtor_nogc(free_op2); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR); + value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } if (free_op1) {zval_ptr_dtor_nogc(free_op1);}; + /* zend_assign_to_variable() always takes care of op2, never free it! */ } - /* zend_assign_to_variable() always takes care of op2, never free it! */ - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -16859,27 +17035,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_VAR_HANDLER(ZE zval *variable_ptr; SAVE_OPLINE(); - value = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2); + value = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1); if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (IS_VAR == IS_TMP_VAR) { - zval_ptr_dtor_nogc(free_op2); - } + zval_ptr_dtor_nogc(free_op2); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, IS_VAR); + value = zend_assign_to_variable(variable_ptr, value, IS_VAR); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } if (free_op1) {zval_ptr_dtor_nogc(free_op1);}; + /* zend_assign_to_variable() always takes care of op2, never free it! */ } - /* zend_assign_to_variable() always takes care of op2, never free it! */ - zval_ptr_dtor_nogc(free_op2); - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -17511,17 +17683,14 @@ try_assign_dim_array: variable_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(object_ptr), dim, IS_UNUSED, BP_VAR_W); } - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); - if ((opline+1)->op1_type == IS_VAR) { - FREE_OP(free_op_data1); - } + value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -17788,12 +17957,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_UNU ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); - zval_ptr_dtor_nogc(free_op1); - } else if (IS_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + } else if (IS_VAR == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); + + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -19097,17 +19278,14 @@ try_assign_dim_array: variable_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(object_ptr), dim, IS_CV, BP_VAR_W); } - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); - if ((opline+1)->op1_type == IS_VAR) { - FREE_OP(free_op_data1); - } + value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -19176,26 +19354,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CV_HANDLER(ZEN zval *variable_ptr; SAVE_OPLINE(); - value = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var); + value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1); if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (IS_CV == IS_TMP_VAR) { - } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, IS_CV); + value = zend_assign_to_variable(variable_ptr, value, IS_CV); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } if (free_op1) {zval_ptr_dtor_nogc(free_op1);}; + /* zend_assign_to_variable() always takes care of op2, never free it! */ } - /* zend_assign_to_variable() always takes care of op2, never free it! */ - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -19420,12 +19595,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_CV_ ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); - zval_ptr_dtor_nogc(free_op1); - } else if (IS_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + } else if (IS_VAR == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); + + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -20825,17 +21012,14 @@ try_assign_dim_array: variable_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(object_ptr), dim, (IS_TMP_VAR|IS_VAR), BP_VAR_W); zval_ptr_dtor_nogc(free_op2); } - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); - if ((opline+1)->op1_type == IS_VAR) { - FREE_OP(free_op_data1); - } + value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -21053,12 +21237,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_VAR_TMP ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_VAR == IS_CV || IS_VAR == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); - zval_ptr_dtor_nogc(free_op1); - } else if (IS_VAR == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + } else if (IS_VAR == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_VAR == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); + + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -27099,13 +27295,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OP zval_copy_ctor_func(EX(return_value)); } } - } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(retval_ptr)) { - ZVAL_COPY(EX(return_value), Z_REFVAL_P(retval_ptr)); + } else if (IS_CV == IS_CV) { + ZVAL_DEREF(retval_ptr); + ZVAL_COPY(EX(return_value), retval_ptr); + } else /* if (IS_CV == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(retval_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(retval_ptr); - } else { - ZVAL_COPY_VALUE(EX(return_value), retval_ptr); - if (IS_CV == IS_CV) { - if (Z_OPT_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr); + retval_ptr = Z_REFVAL_P(retval_ptr); + ZVAL_COPY_VALUE(EX(return_value), retval_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(retval_ptr)) { + Z_ADDREF_P(retval_ptr); + } + } else { + ZVAL_COPY_VALUE(EX(return_value), retval_ptr); } } } @@ -27194,13 +27399,22 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_GENERATOR_RETURN_SPEC_CV_HANDL zval_copy_ctor_func(&generator->retval); } } - } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(retval)) { - ZVAL_COPY(&generator->retval, Z_REFVAL_P(retval)); - - } else { + } else if (IS_CV == IS_CV) { + ZVAL_DEREF(retval); ZVAL_COPY_VALUE(&generator->retval, retval); - if (IS_CV == IS_CV) { - if (Z_OPT_REFCOUNTED_P(retval)) Z_ADDREF_P(retval); + } else /* if (IS_CV == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(retval))) { + zend_refcounted *ref = Z_COUNTED_P(retval); + + retval = Z_REFVAL_P(retval); + ZVAL_COPY_VALUE(&generator->retval, retval); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(retval)) { + Z_ADDREF_P(retval); + } + } else { + ZVAL_COPY_VALUE(&generator->retval, retval); } } @@ -27253,19 +27467,31 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_SPEC_CV_HANDLER(ZEND_ USE_OPLINE zval *varptr, *arg; + zend_refcounted *ref; SAVE_OPLINE(); varptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var); arg = ZEND_CALL_VAR(EX(call), opline->result.var); - if (Z_ISREF_P(varptr)) { - ZVAL_COPY(arg, Z_REFVAL_P(varptr)); - } else { - ZVAL_COPY_VALUE(arg, varptr); - if (IS_CV == IS_CV) { - if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); + if (IS_CV == IS_CV) { + ZVAL_DEREF(varptr); + ZVAL_COPY(arg, varptr); + } else /* if (IS_CV == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(varptr))) { + zend_refcounted *ref = Z_COUNTED_P(varptr); + + varptr = Z_REFVAL_P(varptr); + ZVAL_COPY_VALUE(arg, varptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } else { + ZVAL_COPY_VALUE(arg, varptr); } } + ZEND_VM_NEXT_OPCODE(); } @@ -27355,15 +27581,26 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_CV_HANDLER(ZE SAVE_OPLINE(); varptr = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var); arg = ZEND_CALL_VAR(EX(call), opline->result.var); - if (Z_ISREF_P(varptr)) { - ZVAL_COPY(arg, Z_REFVAL_P(varptr)); - } else { - ZVAL_COPY_VALUE(arg, varptr); - if (IS_CV == IS_CV) { - if (Z_OPT_REFCOUNTED_P(arg)) Z_ADDREF_P(arg); + if (IS_CV == IS_CV) { + ZVAL_DEREF(varptr); + ZVAL_COPY(arg, varptr); + } else /* if (IS_CV == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(varptr))) { + zend_refcounted *ref = Z_COUNTED_P(varptr); + + varptr = Z_REFVAL_P(varptr); + ZVAL_COPY_VALUE(arg, varptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(arg)) { + Z_ADDREF_P(arg); + } + } else { + ZVAL_COPY_VALUE(arg, varptr); } } + ZEND_VM_NEXT_OPCODE(); } @@ -30161,17 +30398,14 @@ try_assign_dim_array: variable_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(object_ptr), dim, IS_CONST, BP_VAR_W); } - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); - if ((opline+1)->op1_type == IS_VAR) { - FREE_OP(free_op_data1); - } + value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -30244,22 +30478,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CONST_HANDLER(Z variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var); if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (IS_CONST == IS_TMP_VAR) { - } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, IS_CONST); + value = zend_assign_to_variable(variable_ptr, value, IS_CONST); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + /* zend_assign_to_variable() always takes care of op2, never free it! */ } - /* zend_assign_to_variable() always takes care of op2, never free it! */ - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -30492,12 +30723,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CONS ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); + } else if (IS_CV == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_CV == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); - } else if (IS_CV == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -30603,7 +30846,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_CONST_HANDLE if (!--GC_REFCOUNT(garbage)) { ZVAL_UNDEF(var); - _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + zval_dtor_func_for_ptr(garbage); } else { GC_ZVAL_CHECK_POSSIBLE_ROOT(var); ZVAL_UNDEF(var); @@ -31371,22 +31614,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_TMP_HANDLER(ZEN variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var); if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (IS_TMP_VAR == IS_TMP_VAR) { - zval_ptr_dtor_nogc(free_op2); - } + zval_ptr_dtor_nogc(free_op2); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR); + value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + /* zend_assign_to_variable() always takes care of op2, never free it! */ } - /* zend_assign_to_variable() always takes care of op2, never free it! */ - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -31752,27 +31992,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_VAR_HANDLER(ZEN zval *variable_ptr; SAVE_OPLINE(); - value = _get_zval_ptr_var_deref(opline->op2.var, execute_data, &free_op2); + value = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var); if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (IS_VAR == IS_TMP_VAR) { - zval_ptr_dtor_nogc(free_op2); - } + zval_ptr_dtor_nogc(free_op2); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, IS_VAR); + value = zend_assign_to_variable(variable_ptr, value, IS_VAR); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + /* zend_assign_to_variable() always takes care of op2, never free it! */ } - /* zend_assign_to_variable() always takes care of op2, never free it! */ - zval_ptr_dtor_nogc(free_op2); - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -31858,7 +32094,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_VAR_HANDLER( if (!--GC_REFCOUNT(garbage)) { ZVAL_UNDEF(var); - _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + zval_dtor_func_for_ptr(garbage); } else { GC_ZVAL_CHECK_POSSIBLE_ROOT(var); ZVAL_UNDEF(var); @@ -32810,17 +33046,14 @@ try_assign_dim_array: variable_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(object_ptr), dim, IS_UNUSED, BP_VAR_W); } - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); - if ((opline+1)->op1_type == IS_VAR) { - FREE_OP(free_op_data1); - } + value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -32959,12 +33192,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_UNUS ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); + } else if (IS_CV == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_CV == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); - } else if (IS_CV == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -33070,7 +33315,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_CV_UNUSED_HANDL if (!--GC_REFCOUNT(garbage)) { ZVAL_UNDEF(var); - _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + zval_dtor_func_for_ptr(garbage); } else { GC_ZVAL_CHECK_POSSIBLE_ROOT(var); ZVAL_UNDEF(var); @@ -35063,17 +35308,14 @@ try_assign_dim_array: variable_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(object_ptr), dim, IS_CV, BP_VAR_W); } - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); - if ((opline+1)->op1_type == IS_VAR) { - FREE_OP(free_op_data1); - } + value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -35142,26 +35384,23 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CV_HANDLER(ZEND zval *variable_ptr; SAVE_OPLINE(); - value = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op2.var); + value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var); variable_ptr = _get_zval_ptr_cv_undef_BP_VAR_W(execute_data, opline->op1.var); if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) { - if (IS_CV == IS_TMP_VAR) { - } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, IS_CV); + value = zend_assign_to_variable(variable_ptr, value, IS_CV); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + /* zend_assign_to_variable() always takes care of op2, never free it! */ } - /* zend_assign_to_variable() always takes care of op2, never free it! */ - CHECK_EXCEPTION(); ZEND_VM_NEXT_OPCODE(); } @@ -35456,12 +35695,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_CV_H ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); + } else if (IS_CV == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_CV == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); - } else if (IS_CV == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -37679,17 +37930,14 @@ try_assign_dim_array: variable_ptr = zend_fetch_dimension_address_inner(Z_ARRVAL_P(object_ptr), dim, (IS_TMP_VAR|IS_VAR), BP_VAR_W); zval_ptr_dtor_nogc(free_op2); } - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); if (UNEXPECTED(variable_ptr == &EG(error_zval))) { FREE_OP(free_op_data1); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_NULL(EX_VAR(opline->result.var)); } } else { - value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); - if ((opline+1)->op1_type == IS_VAR) { - FREE_OP(free_op_data1); - } + value = zend_assign_to_variable(variable_ptr, value, (opline+1)->op1_type); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -37979,12 +38227,24 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CV_TMPV ZVAL_DUP(&new_expr, expr_ptr); expr_ptr = &new_expr; } - } else if ((IS_CV == IS_CV || IS_CV == IS_VAR) && Z_ISREF_P(expr_ptr)) { - expr_ptr = Z_REFVAL_P(expr_ptr); - if (Z_REFCOUNTED_P(expr_ptr)) Z_ADDREF_P(expr_ptr); + } else if (IS_CV == IS_CV) { + ZVAL_DEREF(expr_ptr); + if (Z_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } else /* if (IS_CV == IS_VAR) */ { + if (UNEXPECTED(Z_ISREF_P(expr_ptr))) { + zend_refcounted *ref = Z_COUNTED_P(expr_ptr); - } else if (IS_CV == IS_CV && Z_REFCOUNTED_P(expr_ptr)) { - Z_ADDREF_P(expr_ptr); + expr_ptr = Z_REFVAL_P(expr_ptr); + if (UNEXPECTED(--GC_REFCOUNT(ref) == 0)) { + ZVAL_COPY_VALUE(&new_expr, expr_ptr); + expr_ptr = &new_expr; + efree_size(ref, sizeof(zend_reference)); + } else if (Z_OPT_REFCOUNTED_P(expr_ptr)) { + Z_ADDREF_P(expr_ptr); + } + } } } @@ -40031,7 +40291,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMPVAR_CONST_HA if (!--GC_REFCOUNT(garbage)) { ZVAL_UNDEF(var); - _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + zval_dtor_func_for_ptr(garbage); } else { GC_ZVAL_CHECK_POSSIBLE_ROOT(var); ZVAL_UNDEF(var); @@ -40626,7 +40886,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMPVAR_VAR_HAND if (!--GC_REFCOUNT(garbage)) { ZVAL_UNDEF(var); - _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + zval_dtor_func_for_ptr(garbage); } else { GC_ZVAL_CHECK_POSSIBLE_ROOT(var); ZVAL_UNDEF(var); @@ -41036,7 +41296,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_VAR_SPEC_TMPVAR_UNUSED_H if (!--GC_REFCOUNT(garbage)) { ZVAL_UNDEF(var); - _zval_dtor_func_for_ptr(garbage ZEND_FILE_LINE_CC); + zval_dtor_func_for_ptr(garbage); } else { GC_ZVAL_CHECK_POSSIBLE_ROOT(var); ZVAL_UNDEF(var); -- 2.40.0