diff options
| author | Dmitry Stogov <dmitry@zend.com> | 2014-12-09 15:15:24 +0300 |
|---|---|---|
| committer | Dmitry Stogov <dmitry@zend.com> | 2014-12-09 15:15:24 +0300 |
| commit | 5b3a69c29f85fadb777337289c0e0f288a833e6a (patch) | |
| tree | 754f56147b65411922a4d2ae6419eb6e4467ef0d | |
| parent | f0f51da936da88c125324edfbdad3085dc802456 (diff) | |
| download | php-git-5b3a69c29f85fadb777337289c0e0f288a833e6a.tar.gz | |
Improved ASSIGN_<OP>, ASSIGN_DIM and UNSET_DIM
| -rw-r--r-- | Zend/zend_execute.c | 77 | ||||
| -rw-r--r-- | Zend/zend_vm_def.h | 114 | ||||
| -rw-r--r-- | Zend/zend_vm_execute.h | 1209 |
3 files changed, 693 insertions, 707 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 3127c39d10..283de41f7b 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -390,39 +390,43 @@ static zend_always_inline zval *_get_zval_ptr_cv_deref_BP_VAR_W(const zend_execu return ret; } -static inline zval *_get_zval_ptr(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC) +static zend_always_inline zval *_get_zval_ptr(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC) { - switch (op_type) { - case IS_CONST: - *should_free = NULL; - return node.zv; - case IS_TMP_VAR: + if (op_type & (IS_TMP_VAR|IS_VAR)) { + if (op_type == IS_TMP_VAR) { return _get_zval_ptr_tmp(node.var, execute_data, should_free); - case IS_VAR: + } else { + ZEND_ASSERT(op_type == IS_VAR); return _get_zval_ptr_var(node.var, execute_data, should_free); - case IS_CV: - default: + } + } else { + *should_free = NULL; + if (op_type == IS_CONST) { + return node.zv; + } else { ZEND_ASSERT(op_type == IS_CV); - *should_free = NULL; return _get_zval_ptr_cv(execute_data, node.var, type TSRMLS_CC); + } } } -static inline zval *_get_zval_ptr_deref(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC) +static zend_always_inline zval *_get_zval_ptr_deref(int op_type, znode_op node, const zend_execute_data *execute_data, zend_free_op *should_free, int type TSRMLS_DC) { - switch (op_type) { - case IS_CONST: - *should_free = NULL; - return node.zv; - case IS_TMP_VAR: + if (op_type & (IS_TMP_VAR|IS_VAR)) { + if (op_type == IS_TMP_VAR) { return _get_zval_ptr_tmp(node.var, execute_data, should_free); - case IS_VAR: + } else { + ZEND_ASSERT(op_type == IS_VAR); return _get_zval_ptr_var_deref(node.var, execute_data, should_free); - case IS_CV: - default: + } + } else { + *should_free = NULL; + if (op_type == IS_CONST) { + return node.zv; + } else { ZEND_ASSERT(op_type == IS_CV); - *should_free = NULL; return _get_zval_ptr_cv_deref(execute_data, node.var, type TSRMLS_CC); + } } } @@ -930,6 +934,39 @@ static zend_always_inline void zend_assign_to_object_dim(zval *retval, zval *obj } } +static void zend_binary_assign_op_obj_dim(zval *object, zval *property, zval *value, zval *retval, int (*binary_op)(zval *result, zval *op1, zval *op2 TSRMLS_DC)) +{ + zval *z; + zval rv; + + if (Z_OBJ_HT_P(object)->read_dimension && + (z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC)) != NULL) { + + if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { + zval rv; + zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC); + + if (Z_REFCOUNT_P(z) == 0) { + zend_objects_store_del(Z_OBJ_P(z) TSRMLS_CC); + } + ZVAL_COPY_VALUE(z, value); + } + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); + binary_op(z, z, value TSRMLS_CC); + Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC); + if (retval) { + ZVAL_COPY(retval, z); + } + zval_ptr_dtor(z); + } else { + zend_error(E_WARNING, "Attempt to assign property of non-object"); + if (retval) { + ZVAL_NULL(retval); + } + } +} + static void zend_assign_to_string_offset(zval *str, zend_long offset, zval *value, zval *result TSRMLS_DC) { zend_string *old_str; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index c0f6e40916..6028add427 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -347,7 +347,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR| } do { - 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 (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { @@ -360,8 +360,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR| } /* here we are sure we are dealing with an object */ - if (opline->extended_value == ZEND_ASSIGN_OBJ - && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { ZVAL_DEREF(zptr); @@ -372,19 +371,11 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR| ZVAL_COPY(EX_VAR(opline->result.var), zptr); } } else { - zval *z = NULL; + zval *z; zval rv; - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - if (Z_OBJ_HT_P(object)->read_property) { - z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); - } - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - if (Z_OBJ_HT_P(object)->read_dimension) { - z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC); - } - } - if (z) { + if (Z_OBJ_HT_P(object)->read_property && + (z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC)) != NULL) { if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { zval rv; zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC); @@ -394,14 +385,10 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMPVAR| } ZVAL_COPY_VALUE(z, value); } -//??? if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); binary_op(z, z, value TSRMLS_CC); - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - Z_OBJ_HT_P(object)->write_property(object, property, z, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC); - } + Z_OBJ_HT_P(object)->write_property(object, property, z, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), z); } @@ -434,44 +421,47 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_dim_helper, VAR|UNUSED|CV, CONST|TMPVAR| if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (OP1_TYPE != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) - if (OP1_TYPE == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (OP1_TYPE == IS_VAR && !OP1_FREE) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - ZEND_VM_DISPATCH_TO_HELPER_EX(zend_binary_assign_op_obj_helper, binary_op, binary_op); - } -#endif dim = GET_OP2_ZVAL_PTR(BP_VAR_R); - zend_fetch_dimension_address_RW(&rv, container, dim, OP2_TYPE TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (OP1_TYPE == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (OP1_TYPE != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if !defined(ZEND_VM_SPEC) || (OP2_TYPE != IS_UNUSED) + if (OP1_TYPE == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, OP2_TYPE TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); FREE_OP2(); FREE_OP(free_op_data1); @@ -793,12 +783,13 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMPVAR|C } ZVAL_COPY_VALUE(z, value); } - if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); incdec_op(z); - ZVAL_COPY_VALUE(retval, z); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, z); + } Z_OBJ_HT_P(object)->write_property(object, property, z, ((OP2_TYPE == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - SELECTIVE_PZVAL_LOCK(retval, opline); zval_ptr_dtor(z); } else { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); @@ -4486,15 +4477,15 @@ ZEND_VM_HANDLER(75, ZEND_UNSET_DIM, VAR|UNUSED|CV, CONST|TMPVAR|CV) if (OP1_TYPE == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); } - if (OP1_TYPE != IS_UNUSED) { - ZVAL_DEREF(container); - } - SEPARATE_ZVAL_NOREF(container); offset = GET_OP2_ZVAL_PTR(BP_VAR_R); +ZEND_VM_C_LABEL(unset_dim_again): if (OP1_TYPE != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - HashTable *ht = Z_ARRVAL_P(container); + HashTable *ht; + ZEND_VM_C_LABEL(offset_again): + SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); switch (Z_TYPE_P(offset)) { case IS_DOUBLE: hval = zend_dval_to_lval(Z_DVAL_P(offset)); @@ -4547,7 +4538,10 @@ ZEND_VM_C_LABEL(num_index_dim): //??? } Z_OBJ_HT_P(container)->unset_dimension(container, offset TSRMLS_CC); FREE_OP2(); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { + } else if (OP1_TYPE != IS_UNUSED && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + ZEND_VM_C_GOTO(unset_dim_again); + } else if (OP1_TYPE != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); ZEND_VM_CONTINUE(); /* bailed out before */ } else { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 4addf39d01..3b5c511d88 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -12138,7 +12138,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(int (*b } do { - 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 (IS_VAR != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { @@ -12151,8 +12151,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(int (*b } /* here we are sure we are dealing with an object */ - if (opline->extended_value == ZEND_ASSIGN_OBJ - && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { ZVAL_DEREF(zptr); @@ -12163,19 +12162,11 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(int (*b ZVAL_COPY(EX_VAR(opline->result.var), zptr); } } else { - zval *z = NULL; + zval *z; zval rv; - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - if (Z_OBJ_HT_P(object)->read_property) { - z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); - } - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - if (Z_OBJ_HT_P(object)->read_dimension) { - z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC); - } - } - if (z) { + if (Z_OBJ_HT_P(object)->read_property && + (z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC)) != NULL) { if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { zval rv; zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC); @@ -12185,14 +12176,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(int (*b } ZVAL_COPY_VALUE(z, value); } -//??? if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); binary_op(z, z, value TSRMLS_CC); - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC); - } + Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), z); } @@ -12225,44 +12212,47 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_CONST(int (*b if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (IS_VAR != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if 0 || (IS_CONST != IS_UNUSED) - if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_VAR == IS_VAR && !(free_op1 != NULL)) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } -#endif dim = opline->op2.zv; - zend_fetch_dimension_address_RW(&rv, container, dim, IS_CONST TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (IS_VAR != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if 0 || (IS_CONST != IS_UNUSED) + if (IS_VAR == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, IS_CONST TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); FREE_OP(free_op_data1); if (free_op1) {zval_ptr_dtor_nogc(free_op1);}; @@ -12582,12 +12572,13 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_CONST(incdec_t } ZVAL_COPY_VALUE(z, value); } - if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); incdec_op(z); - ZVAL_COPY_VALUE(retval, z); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, z); + } Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - SELECTIVE_PZVAL_LOCK(retval, opline); zval_ptr_dtor(z); } else { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); @@ -13442,15 +13433,15 @@ static int ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HAND if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); } - if (IS_VAR != IS_UNUSED) { - ZVAL_DEREF(container); - } - SEPARATE_ZVAL_NOREF(container); offset = opline->op2.zv; +unset_dim_again: if (IS_VAR != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - HashTable *ht = Z_ARRVAL_P(container); + HashTable *ht; + offset_again: + SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); switch (Z_TYPE_P(offset)) { case IS_DOUBLE: hval = zend_dval_to_lval(Z_DVAL_P(offset)); @@ -13503,7 +13494,10 @@ num_index_dim: //??? } Z_OBJ_HT_P(container)->unset_dimension(container, offset TSRMLS_CC); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { + } else if (IS_VAR != IS_UNUSED && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + goto unset_dim_again; + } else if (IS_VAR != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); ZEND_VM_CONTINUE(); /* bailed out before */ } else { @@ -14156,44 +14150,47 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_UNUSED(int (* if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (IS_VAR != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if 0 || (IS_UNUSED != IS_UNUSED) - if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_VAR == IS_VAR && !(free_op1 != NULL)) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } -#endif dim = NULL; - zend_fetch_dimension_address_RW(&rv, container, dim, IS_UNUSED TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (IS_VAR != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if 0 || (IS_UNUSED != IS_UNUSED) + if (IS_VAR == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, IS_UNUSED TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); FREE_OP(free_op_data1); if (free_op1) {zval_ptr_dtor_nogc(free_op1);}; @@ -15008,7 +15005,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CV(int (*bina } do { - 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 (IS_VAR != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { @@ -15021,8 +15018,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CV(int (*bina } /* here we are sure we are dealing with an object */ - if (opline->extended_value == ZEND_ASSIGN_OBJ - && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { ZVAL_DEREF(zptr); @@ -15033,19 +15029,11 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CV(int (*bina ZVAL_COPY(EX_VAR(opline->result.var), zptr); } } else { - zval *z = NULL; + zval *z; zval rv; - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - if (Z_OBJ_HT_P(object)->read_property) { - z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); - } - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - if (Z_OBJ_HT_P(object)->read_dimension) { - z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC); - } - } - if (z) { + if (Z_OBJ_HT_P(object)->read_property && + (z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC)) != NULL) { if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { zval rv; zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC); @@ -15055,14 +15043,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CV(int (*bina } ZVAL_COPY_VALUE(z, value); } -//??? if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); binary_op(z, z, value TSRMLS_CC); - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC); - } + Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), z); } @@ -15095,44 +15079,47 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_CV(int (*bina if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (IS_VAR != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if 0 || (IS_CV != IS_UNUSED) - if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_VAR == IS_VAR && !(free_op1 != NULL)) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_VAR_CV(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } -#endif dim = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - zend_fetch_dimension_address_RW(&rv, container, dim, IS_CV TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (IS_VAR != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if 0 || (IS_CV != IS_UNUSED) + if (IS_VAR == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, IS_CV TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); FREE_OP(free_op_data1); if (free_op1) {zval_ptr_dtor_nogc(free_op1);}; @@ -15452,12 +15439,13 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_CV(incdec_t in } ZVAL_COPY_VALUE(z, value); } - if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); incdec_op(z); - ZVAL_COPY_VALUE(retval, z); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, z); + } Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - SELECTIVE_PZVAL_LOCK(retval, opline); zval_ptr_dtor(z); } else { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); @@ -16278,15 +16266,15 @@ static int ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); } - if (IS_VAR != IS_UNUSED) { - ZVAL_DEREF(container); - } - SEPARATE_ZVAL_NOREF(container); offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); +unset_dim_again: if (IS_VAR != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - HashTable *ht = Z_ARRVAL_P(container); + HashTable *ht; + offset_again: + SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); switch (Z_TYPE_P(offset)) { case IS_DOUBLE: hval = zend_dval_to_lval(Z_DVAL_P(offset)); @@ -16339,7 +16327,10 @@ num_index_dim: //??? } Z_OBJ_HT_P(container)->unset_dimension(container, offset TSRMLS_CC); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { + } else if (IS_VAR != IS_UNUSED && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + goto unset_dim_again; + } else if (IS_VAR != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); ZEND_VM_CONTINUE(); /* bailed out before */ } else { @@ -16538,7 +16529,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_TMPVAR(int (* } do { - 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 (IS_VAR != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { @@ -16551,8 +16542,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_TMPVAR(int (* } /* here we are sure we are dealing with an object */ - if (opline->extended_value == ZEND_ASSIGN_OBJ - && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { ZVAL_DEREF(zptr); @@ -16563,19 +16553,11 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_TMPVAR(int (* ZVAL_COPY(EX_VAR(opline->result.var), zptr); } } else { - zval *z = NULL; + zval *z; zval rv; - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - if (Z_OBJ_HT_P(object)->read_property) { - z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); - } - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - if (Z_OBJ_HT_P(object)->read_dimension) { - z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC); - } - } - if (z) { + if (Z_OBJ_HT_P(object)->read_property && + (z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC)) != NULL) { if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { zval rv; zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC); @@ -16585,14 +16567,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_TMPVAR(int (* } ZVAL_COPY_VALUE(z, value); } -//??? if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); binary_op(z, z, value TSRMLS_CC); - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - Z_OBJ_HT_P(object)->write_property(object, property, z, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC); - } + Z_OBJ_HT_P(object)->write_property(object, property, z, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), z); } @@ -16625,44 +16603,47 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_VAR_TMPVAR(int (* if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (IS_VAR != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if 0 || ((IS_TMP_VAR|IS_VAR) != IS_UNUSED) - if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_VAR == IS_VAR && !(free_op1 != NULL)) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_VAR_TMPVAR(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } -#endif dim = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); - zend_fetch_dimension_address_RW(&rv, container, dim, (IS_TMP_VAR|IS_VAR) TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (IS_VAR == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (IS_VAR != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if 0 || ((IS_TMP_VAR|IS_VAR) != IS_UNUSED) + if (IS_VAR == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, (IS_TMP_VAR|IS_VAR) TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); zval_ptr_dtor_nogc(free_op2); FREE_OP(free_op_data1); @@ -16984,12 +16965,13 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_TMPVAR(incdec_ } ZVAL_COPY_VALUE(z, value); } - if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); incdec_op(z); - ZVAL_COPY_VALUE(retval, z); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, z); + } Z_OBJ_HT_P(object)->write_property(object, property, z, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - SELECTIVE_PZVAL_LOCK(retval, opline); zval_ptr_dtor(z); } else { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); @@ -17717,15 +17699,15 @@ static int ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_VAR_TMPVAR_HANDLER(ZEND_OPCODE_HAN if (IS_VAR == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); } - if (IS_VAR != IS_UNUSED) { - ZVAL_DEREF(container); - } - SEPARATE_ZVAL_NOREF(container); offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); +unset_dim_again: if (IS_VAR != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - HashTable *ht = Z_ARRVAL_P(container); + HashTable *ht; + offset_again: + SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); switch (Z_TYPE_P(offset)) { case IS_DOUBLE: hval = zend_dval_to_lval(Z_DVAL_P(offset)); @@ -17778,7 +17760,10 @@ num_index_dim: //??? } Z_OBJ_HT_P(container)->unset_dimension(container, offset TSRMLS_CC); zval_ptr_dtor_nogc(free_op2); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { + } else if (IS_VAR != IS_UNUSED && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + goto unset_dim_again; + } else if (IS_VAR != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); ZEND_VM_CONTINUE(); /* bailed out before */ } else { @@ -17943,7 +17928,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(int } do { - 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 (IS_UNUSED != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { @@ -17956,8 +17941,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(int } /* here we are sure we are dealing with an object */ - if (opline->extended_value == ZEND_ASSIGN_OBJ - && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { ZVAL_DEREF(zptr); @@ -17968,19 +17952,11 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(int ZVAL_COPY(EX_VAR(opline->result.var), zptr); } } else { - zval *z = NULL; + zval *z; zval rv; - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - if (Z_OBJ_HT_P(object)->read_property) { - z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); - } - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - if (Z_OBJ_HT_P(object)->read_dimension) { - z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC); - } - } - if (z) { + if (Z_OBJ_HT_P(object)->read_property && + (z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC)) != NULL) { if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { zval rv; zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC); @@ -17990,14 +17966,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(int } ZVAL_COPY_VALUE(z, value); } -//??? if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); binary_op(z, z, value TSRMLS_CC); - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC); - } + Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), z); } @@ -18029,44 +18001,47 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_CONST(int if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (IS_UNUSED != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if 0 || (IS_CONST != IS_UNUSED) - if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_UNUSED == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } -#endif dim = opline->op2.zv; - zend_fetch_dimension_address_RW(&rv, container, dim, IS_CONST TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (IS_UNUSED != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if 0 || (IS_CONST != IS_UNUSED) + if (IS_UNUSED == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, IS_CONST TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); FREE_OP(free_op_data1); @@ -18351,12 +18326,13 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_CONST(incde } ZVAL_COPY_VALUE(z, value); } - if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); incdec_op(z); - ZVAL_COPY_VALUE(retval, z); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, z); + } Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - SELECTIVE_PZVAL_LOCK(retval, opline); zval_ptr_dtor(z); } else { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); @@ -19013,15 +18989,15 @@ static int ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_H if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); } - if (IS_UNUSED != IS_UNUSED) { - ZVAL_DEREF(container); - } - SEPARATE_ZVAL_NOREF(container); offset = opline->op2.zv; +unset_dim_again: if (IS_UNUSED != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - HashTable *ht = Z_ARRVAL_P(container); + HashTable *ht; + offset_again: + SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); switch (Z_TYPE_P(offset)) { case IS_DOUBLE: hval = zend_dval_to_lval(Z_DVAL_P(offset)); @@ -19074,7 +19050,10 @@ num_index_dim: //??? } Z_OBJ_HT_P(container)->unset_dimension(container, offset TSRMLS_CC); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { + } else if (IS_UNUSED != IS_UNUSED && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + goto unset_dim_again; + } else if (IS_UNUSED != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); ZEND_VM_CONTINUE(); /* bailed out before */ } else { @@ -19683,44 +19662,47 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_UNUSED(int if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (IS_UNUSED != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if 0 || (IS_UNUSED != IS_UNUSED) - if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_UNUSED == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } -#endif dim = NULL; - zend_fetch_dimension_address_RW(&rv, container, dim, IS_UNUSED TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (IS_UNUSED != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if 0 || (IS_UNUSED != IS_UNUSED) + if (IS_UNUSED == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, IS_UNUSED TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); FREE_OP(free_op_data1); @@ -20125,7 +20107,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(int (*b } do { - 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 (IS_UNUSED != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { @@ -20138,8 +20120,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(int (*b } /* here we are sure we are dealing with an object */ - if (opline->extended_value == ZEND_ASSIGN_OBJ - && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { ZVAL_DEREF(zptr); @@ -20150,19 +20131,11 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(int (*b ZVAL_COPY(EX_VAR(opline->result.var), zptr); } } else { - zval *z = NULL; + zval *z; zval rv; - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - if (Z_OBJ_HT_P(object)->read_property) { - z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); - } - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - if (Z_OBJ_HT_P(object)->read_dimension) { - z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC); - } - } - if (z) { + if (Z_OBJ_HT_P(object)->read_property && + (z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC)) != NULL) { if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { zval rv; zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC); @@ -20172,14 +20145,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(int (*b } ZVAL_COPY_VALUE(z, value); } -//??? if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); binary_op(z, z, value TSRMLS_CC); - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC); - } + Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), z); } @@ -20211,44 +20180,47 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_CV(int (*b if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (IS_UNUSED != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if 0 || (IS_CV != IS_UNUSED) - if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_UNUSED == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } -#endif dim = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - zend_fetch_dimension_address_RW(&rv, container, dim, IS_CV TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (IS_UNUSED != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if 0 || (IS_CV != IS_UNUSED) + if (IS_UNUSED == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, IS_CV TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); FREE_OP(free_op_data1); @@ -20533,12 +20505,13 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_CV(incdec_t } ZVAL_COPY_VALUE(z, value); } - if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); incdec_op(z); - ZVAL_COPY_VALUE(retval, z); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, z); + } Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - SELECTIVE_PZVAL_LOCK(retval, opline); zval_ptr_dtor(z); } else { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); @@ -21099,15 +21072,15 @@ static int ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HAND if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); } - if (IS_UNUSED != IS_UNUSED) { - ZVAL_DEREF(container); - } - SEPARATE_ZVAL_NOREF(container); offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); +unset_dim_again: if (IS_UNUSED != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - HashTable *ht = Z_ARRVAL_P(container); + HashTable *ht; + offset_again: + SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); switch (Z_TYPE_P(offset)) { case IS_DOUBLE: hval = zend_dval_to_lval(Z_DVAL_P(offset)); @@ -21160,7 +21133,10 @@ num_index_dim: //??? } Z_OBJ_HT_P(container)->unset_dimension(container, offset TSRMLS_CC); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { + } else if (IS_UNUSED != IS_UNUSED && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + goto unset_dim_again; + } else if (IS_UNUSED != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); ZEND_VM_CONTINUE(); /* bailed out before */ } else { @@ -21509,7 +21485,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMPVAR(int } do { - 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 (IS_UNUSED != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { @@ -21522,8 +21498,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMPVAR(int } /* here we are sure we are dealing with an object */ - if (opline->extended_value == ZEND_ASSIGN_OBJ - && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { ZVAL_DEREF(zptr); @@ -21534,19 +21509,11 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMPVAR(int ZVAL_COPY(EX_VAR(opline->result.var), zptr); } } else { - zval *z = NULL; + zval *z; zval rv; - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - if (Z_OBJ_HT_P(object)->read_property) { - z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); - } - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - if (Z_OBJ_HT_P(object)->read_dimension) { - z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC); - } - } - if (z) { + if (Z_OBJ_HT_P(object)->read_property && + (z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC)) != NULL) { if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { zval rv; zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC); @@ -21556,14 +21523,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMPVAR(int } ZVAL_COPY_VALUE(z, value); } -//??? if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); binary_op(z, z, value TSRMLS_CC); - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - Z_OBJ_HT_P(object)->write_property(object, property, z, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC); - } + Z_OBJ_HT_P(object)->write_property(object, property, z, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), z); } @@ -21595,44 +21558,47 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_UNUSED_TMPVAR(int if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (IS_UNUSED != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if 0 || ((IS_TMP_VAR|IS_VAR) != IS_UNUSED) - if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_UNUSED == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMPVAR(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } -#endif dim = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); - zend_fetch_dimension_address_RW(&rv, container, dim, (IS_TMP_VAR|IS_VAR) TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (IS_UNUSED == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (IS_UNUSED != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if 0 || ((IS_TMP_VAR|IS_VAR) != IS_UNUSED) + if (IS_UNUSED == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, (IS_TMP_VAR|IS_VAR) TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); zval_ptr_dtor_nogc(free_op2); FREE_OP(free_op_data1); @@ -21918,12 +21884,13 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_TMPVAR(incd } ZVAL_COPY_VALUE(z, value); } - if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); incdec_op(z); - ZVAL_COPY_VALUE(retval, z); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, z); + } Z_OBJ_HT_P(object)->write_property(object, property, z, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - SELECTIVE_PZVAL_LOCK(retval, opline); zval_ptr_dtor(z); } else { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); @@ -22490,15 +22457,15 @@ static int ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_UNUSED_TMPVAR_HANDLER(ZEND_OPCODE_ if (IS_UNUSED == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); } - if (IS_UNUSED != IS_UNUSED) { - ZVAL_DEREF(container); - } - SEPARATE_ZVAL_NOREF(container); offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); +unset_dim_again: if (IS_UNUSED != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - HashTable *ht = Z_ARRVAL_P(container); + HashTable *ht; + offset_again: + SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); switch (Z_TYPE_P(offset)) { case IS_DOUBLE: hval = zend_dval_to_lval(Z_DVAL_P(offset)); @@ -22551,7 +22518,10 @@ num_index_dim: //??? } Z_OBJ_HT_P(container)->unset_dimension(container, offset TSRMLS_CC); zval_ptr_dtor_nogc(free_op2); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { + } else if (IS_UNUSED != IS_UNUSED && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + goto unset_dim_again; + } else if (IS_UNUSED != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); ZEND_VM_CONTINUE(); /* bailed out before */ } else { @@ -24486,7 +24456,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CONST(int (*bi } do { - 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 (IS_CV != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { @@ -24499,8 +24469,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CONST(int (*bi } /* here we are sure we are dealing with an object */ - if (opline->extended_value == ZEND_ASSIGN_OBJ - && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { ZVAL_DEREF(zptr); @@ -24511,19 +24480,11 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CONST(int (*bi ZVAL_COPY(EX_VAR(opline->result.var), zptr); } } else { - zval *z = NULL; + zval *z; zval rv; - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - if (Z_OBJ_HT_P(object)->read_property) { - z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); - } - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - if (Z_OBJ_HT_P(object)->read_dimension) { - z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC); - } - } - if (z) { + if (Z_OBJ_HT_P(object)->read_property && + (z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC)) != NULL) { if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { zval rv; zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC); @@ -24533,14 +24494,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CONST(int (*bi } ZVAL_COPY_VALUE(z, value); } -//??? if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); binary_op(z, z, value TSRMLS_CC); - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC); - } + Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), z); } @@ -24572,44 +24529,47 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_CONST(int (*bi if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (IS_CV != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if 0 || (IS_CONST != IS_UNUSED) - if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_CV == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_CV_CONST(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } -#endif dim = opline->op2.zv; - zend_fetch_dimension_address_RW(&rv, container, dim, IS_CONST TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (IS_CV != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if 0 || (IS_CONST != IS_UNUSED) + if (IS_CV == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, IS_CONST TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); FREE_OP(free_op_data1); @@ -24929,12 +24889,13 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_CONST(incdec_t } ZVAL_COPY_VALUE(z, value); } - if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); incdec_op(z); - ZVAL_COPY_VALUE(retval, z); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, z); + } Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CONST == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - SELECTIVE_PZVAL_LOCK(retval, opline); zval_ptr_dtor(z); } else { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); @@ -26050,15 +26011,15 @@ static int ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDL if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); } - if (IS_CV != IS_UNUSED) { - ZVAL_DEREF(container); - } - SEPARATE_ZVAL_NOREF(container); offset = opline->op2.zv; +unset_dim_again: if (IS_CV != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - HashTable *ht = Z_ARRVAL_P(container); + HashTable *ht; + offset_again: + SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); switch (Z_TYPE_P(offset)) { case IS_DOUBLE: hval = zend_dval_to_lval(Z_DVAL_P(offset)); @@ -26111,7 +26072,10 @@ num_index_dim: //??? } Z_OBJ_HT_P(container)->unset_dimension(container, offset TSRMLS_CC); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { + } else if (IS_CV != IS_UNUSED && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + goto unset_dim_again; + } else if (IS_CV != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); ZEND_VM_CONTINUE(); /* bailed out before */ } else { @@ -27438,44 +27402,47 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_UNUSED(int (*b if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (IS_CV != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if 0 || (IS_UNUSED != IS_UNUSED) - if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_CV == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } -#endif dim = NULL; - zend_fetch_dimension_address_RW(&rv, container, dim, IS_UNUSED TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (IS_CV != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if 0 || (IS_UNUSED != IS_UNUSED) + if (IS_CV == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, IS_UNUSED TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); FREE_OP(free_op_data1); @@ -28685,7 +28652,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CV(int (*binar } do { - 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 (IS_CV != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { @@ -28698,8 +28665,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CV(int (*binar } /* here we are sure we are dealing with an object */ - if (opline->extended_value == ZEND_ASSIGN_OBJ - && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { ZVAL_DEREF(zptr); @@ -28710,19 +28676,11 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CV(int (*binar ZVAL_COPY(EX_VAR(opline->result.var), zptr); } } else { - zval *z = NULL; + zval *z; zval rv; - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - if (Z_OBJ_HT_P(object)->read_property) { - z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); - } - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - if (Z_OBJ_HT_P(object)->read_dimension) { - z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC); - } - } - if (z) { + if (Z_OBJ_HT_P(object)->read_property && + (z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC)) != NULL) { if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { zval rv; zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC); @@ -28732,14 +28690,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CV(int (*binar } ZVAL_COPY_VALUE(z, value); } -//??? if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); binary_op(z, z, value TSRMLS_CC); - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC); - } + Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), z); } @@ -28771,44 +28725,47 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_CV(int (*binar if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (IS_CV != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if 0 || (IS_CV != IS_UNUSED) - if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_CV == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_CV_CV(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } -#endif dim = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); - zend_fetch_dimension_address_RW(&rv, container, dim, IS_CV TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (IS_CV != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if 0 || (IS_CV != IS_UNUSED) + if (IS_CV == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, IS_CV TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); FREE_OP(free_op_data1); @@ -29128,12 +29085,13 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_CV(incdec_t inc } ZVAL_COPY_VALUE(z, value); } - if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); incdec_op(z); - ZVAL_COPY_VALUE(retval, z); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, z); + } Z_OBJ_HT_P(object)->write_property(object, property, z, ((IS_CV == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - SELECTIVE_PZVAL_LOCK(retval, opline); zval_ptr_dtor(z); } else { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); @@ -30052,15 +30010,15 @@ static int ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); } - if (IS_CV != IS_UNUSED) { - ZVAL_DEREF(container); - } - SEPARATE_ZVAL_NOREF(container); offset = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var TSRMLS_CC); +unset_dim_again: if (IS_CV != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - HashTable *ht = Z_ARRVAL_P(container); + HashTable *ht; + offset_again: + SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); switch (Z_TYPE_P(offset)) { case IS_DOUBLE: hval = zend_dval_to_lval(Z_DVAL_P(offset)); @@ -30113,7 +30071,10 @@ num_index_dim: //??? } Z_OBJ_HT_P(container)->unset_dimension(container, offset TSRMLS_CC); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { + } else if (IS_CV != IS_UNUSED && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + goto unset_dim_again; + } else if (IS_CV != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); ZEND_VM_CONTINUE(); /* bailed out before */ } else { @@ -30726,7 +30687,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_TMPVAR(int (*b } do { - 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 (IS_CV != IS_UNUSED && UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) { if (UNEXPECTED(!make_real_object(&object TSRMLS_CC))) { @@ -30739,8 +30700,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_TMPVAR(int (*b } /* here we are sure we are dealing with an object */ - if (opline->extended_value == ZEND_ASSIGN_OBJ - && EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) + if (EXPECTED(Z_OBJ_HT_P(object)->get_property_ptr_ptr) && EXPECTED((zptr = Z_OBJ_HT_P(object)->get_property_ptr_ptr(object, property, BP_VAR_RW, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC)) != NULL)) { ZVAL_DEREF(zptr); @@ -30751,19 +30711,11 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_TMPVAR(int (*b ZVAL_COPY(EX_VAR(opline->result.var), zptr); } } else { - zval *z = NULL; + zval *z; zval rv; - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - if (Z_OBJ_HT_P(object)->read_property) { - z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC); - } - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - if (Z_OBJ_HT_P(object)->read_dimension) { - z = Z_OBJ_HT_P(object)->read_dimension(object, property, BP_VAR_R, &rv TSRMLS_CC); - } - } - if (z) { + if (Z_OBJ_HT_P(object)->read_property && + (z = Z_OBJ_HT_P(object)->read_property(object, property, BP_VAR_R, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL), &rv TSRMLS_CC)) != NULL) { if (Z_TYPE_P(z) == IS_OBJECT && Z_OBJ_HT_P(z)->get) { zval rv; zval *value = Z_OBJ_HT_P(z)->get(z, &rv TSRMLS_CC); @@ -30773,14 +30725,10 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_TMPVAR(int (*b } ZVAL_COPY_VALUE(z, value); } -//??? if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); binary_op(z, z, value TSRMLS_CC); - if (opline->extended_value == ZEND_ASSIGN_OBJ) { - Z_OBJ_HT_P(object)->write_property(object, property, z, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - } else /* if (opline->extended_value == ZEND_ASSIGN_DIM) */ { - Z_OBJ_HT_P(object)->write_dimension(object, property, z TSRMLS_CC); - } + Z_OBJ_HT_P(object)->write_property(object, property, z, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); if (RETURN_VALUE_USED(opline)) { ZVAL_COPY(EX_VAR(opline->result.var), z); } @@ -30812,44 +30760,47 @@ static int ZEND_FASTCALL zend_binary_assign_op_dim_helper_SPEC_CV_TMPVAR(int (*b if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot use string offset as an array"); } - if (IS_CV != IS_UNUSED) { - ZVAL_DEREF(container); - } - -#if 0 || ((IS_TMP_VAR|IS_VAR) != IS_UNUSED) - if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { - if (IS_CV == IS_VAR && !0) { - Z_ADDREF_P(container); /* undo the effect of get_obj_zval_ptr_ptr() */ - } - return zend_binary_assign_op_obj_helper_SPEC_CV_TMPVAR(binary_op, ZEND_OPCODE_HANDLER_ARGS_PASSTHRU); - } -#endif dim = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); - zend_fetch_dimension_address_RW(&rv, container, dim, (IS_TMP_VAR|IS_VAR) TSRMLS_CC); - value = get_zval_ptr_deref((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); - ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); - var_ptr = Z_INDIRECT(rv); + do { + if (IS_CV == IS_UNUSED || UNEXPECTED(Z_TYPE_P(container) != IS_ARRAY)) { + if (IS_CV != IS_UNUSED) { + ZVAL_DEREF(container); + } +#if 0 || ((IS_TMP_VAR|IS_VAR) != IS_UNUSED) + if (IS_CV == IS_UNUSED || EXPECTED(Z_TYPE_P(container) == IS_OBJECT)) { + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + zend_binary_assign_op_obj_dim(container, dim, value, UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, binary_op TSRMLS_CC); + break; + } +#endif + } - if (UNEXPECTED(var_ptr == NULL)) { - zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); - } + zend_fetch_dimension_address_RW(&rv, container, dim, (IS_TMP_VAR|IS_VAR) TSRMLS_CC); + value = get_zval_ptr((opline+1)->op1_type, (opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R); + ZEND_ASSERT(Z_TYPE(rv) == IS_INDIRECT); + var_ptr = Z_INDIRECT(rv); - if (UNEXPECTED(var_ptr == &EG(error_zval))) { - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_NULL(EX_VAR(opline->result.var)); + if (UNEXPECTED(var_ptr == NULL)) { + zend_error_noreturn(E_ERROR, "Cannot use assign-op operators with overloaded objects nor string offsets"); } - } else { - ZVAL_DEREF(var_ptr); - SEPARATE_ZVAL_NOREF(var_ptr); - binary_op(var_ptr, var_ptr, value TSRMLS_CC); + if (UNEXPECTED(var_ptr == &EG(error_zval))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_NULL(EX_VAR(opline->result.var)); + } + } else { + ZVAL_DEREF(var_ptr); + SEPARATE_ZVAL_NOREF(var_ptr); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + binary_op(var_ptr, var_ptr, value TSRMLS_CC); + + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), var_ptr); + } } - } + } while (0); zval_ptr_dtor_nogc(free_op2); FREE_OP(free_op_data1); @@ -31171,12 +31122,13 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_TMPVAR(incdec_t } ZVAL_COPY_VALUE(z, value); } - if (Z_REFCOUNTED_P(z)) Z_ADDREF_P(z); - SEPARATE_ZVAL_IF_NOT_REF(z); + ZVAL_DEREF(z); + SEPARATE_ZVAL_NOREF(z); incdec_op(z); - ZVAL_COPY_VALUE(retval, z); + if (RETURN_VALUE_USED(opline)) { + ZVAL_COPY(retval, z); + } Z_OBJ_HT_P(object)->write_property(object, property, z, (((IS_TMP_VAR|IS_VAR) == IS_CONST) ? (EX(run_time_cache) + Z_CACHE_SLOT_P(property)) : NULL) TSRMLS_CC); - SELECTIVE_PZVAL_LOCK(retval, opline); zval_ptr_dtor(z); } else { zend_error(E_WARNING, "Attempt to increment/decrement property of non-object"); @@ -32006,15 +31958,15 @@ static int ZEND_FASTCALL ZEND_UNSET_DIM_SPEC_CV_TMPVAR_HANDLER(ZEND_OPCODE_HAND if (IS_CV == IS_VAR && UNEXPECTED(container == NULL)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); } - if (IS_CV != IS_UNUSED) { - ZVAL_DEREF(container); - } - SEPARATE_ZVAL_NOREF(container); offset = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); +unset_dim_again: if (IS_CV != IS_UNUSED && EXPECTED(Z_TYPE_P(container) == IS_ARRAY)) { - HashTable *ht = Z_ARRVAL_P(container); + HashTable *ht; + offset_again: + SEPARATE_ARRAY(container); + ht = Z_ARRVAL_P(container); switch (Z_TYPE_P(offset)) { case IS_DOUBLE: hval = zend_dval_to_lval(Z_DVAL_P(offset)); @@ -32067,7 +32019,10 @@ num_index_dim: //??? } Z_OBJ_HT_P(container)->unset_dimension(container, offset TSRMLS_CC); zval_ptr_dtor_nogc(free_op2); - } else if (UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { + } else if (IS_CV != IS_UNUSED && Z_ISREF_P(container)) { + container = Z_REFVAL_P(container); + goto unset_dim_again; + } else if (IS_CV != IS_UNUSED && UNEXPECTED(Z_TYPE_P(container) == IS_STRING)) { zend_error_noreturn(E_ERROR, "Cannot unset string offsets"); ZEND_VM_CONTINUE(); /* bailed out before */ } else { |
