]> granicus.if.org Git - php/commitdiff
Improved reference counting
authorDmitry Stogov <dmitry@zend.com>
Thu, 2 Apr 2015 22:32:20 +0000 (01:32 +0300)
committerDmitry Stogov <dmitry@zend.com>
Thu, 2 Apr 2015 22:32:20 +0000 (01:32 +0300)
Zend/zend_execute.c
Zend/zend_execute.h
Zend/zend_object_handlers.c
Zend/zend_variables.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

index 424f4888e9b081092a8e9be53664d702aaac4890..063f9ed4276a6afa94d5caec531cdacf1b008ccb 100644 (file)
@@ -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);
index dce9e1c04011413a5bc2afdd9fb2c55ba74f0f58..408a7c5032742a116f2f2846835779c7e22441b2 100644 (file)
@@ -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;
 }
index 1ce666b71914619d82ae2ca6e5a651cd7d3e21b7..00fb17451ea616b247e343563bbaa342429d5fbd 100644 (file)
@@ -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;
                        }
                }
index 9ca31097c39fcc0e7ae03afb317ba6772f36d3ee..adb226123fc4a530bfc6b3403271e222cd4a4166 100644 (file)
@@ -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)
 {
index bd0ba8dd78049c596f7b63e0c97878bd755f6330..387edda41c2e4e0f56ee16cf5cf28d814ed8efba 100644 (file)
@@ -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);
index 145dfb6d0cedbcfe90891cc0a8f4c444bc13f265..554524271c0a424267ebfa925861c529dacff021 100644 (file)
@@ -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);