]> granicus.if.org Git - php/commitdiff
Various VM optimizations
authorDmitry Stogov <dmitry@zend.com>
Thu, 3 Apr 2014 22:52:53 +0000 (02:52 +0400)
committerDmitry Stogov <dmitry@zend.com>
Thu, 3 Apr 2014 22:52:53 +0000 (02:52 +0400)
Zend/zend.h
Zend/zend_API.c
Zend/zend_API.h
Zend/zend_execute.c
Zend/zend_gc.h
Zend/zend_types.h
Zend/zend_variables.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/standard/array.c

index d8c14f0a0769bb524d5f7aec534a1727d8dc2fa9..71b80c3e797181a51fb40689263082b33cbf824d 100644 (file)
@@ -661,7 +661,7 @@ END_EXTERN_C()
                zval *__z1 = (z);                                                               \
                zval *__z2 = (v);                                                               \
                ZVAL_COPY_VALUE(__z1, __z2);                                    \
-               if (Z_REFCOUNTED_P(__z1)) {                                             \
+               if (Z_OPT_REFCOUNTED_P(__z1)) {                                 \
                        Z_ADDREF_P(__z1);                                                       \
                }                                                                                               \
        } while (0)
@@ -671,7 +671,7 @@ END_EXTERN_C()
                zval *__z1 = (z);                                                               \
                zval *__z2 = (v);                                                               \
                ZVAL_COPY_VALUE(__z1, __z2);                                    \
-               zval_copy_ctor(__z1);                                                   \
+               zval_opt_copy_ctor(__z1);                                               \
        } while (0)
 
 #define ZVAL_DEREF(z) do {                                                             \
@@ -698,7 +698,7 @@ END_EXTERN_C()
                zval *__z2 = (v);                                                               \
                ZVAL_DEREF(__z2);                                                               \
                ZVAL_COPY_VALUE(__z1, __z2);                                    \
-               zval_copy_ctor(__z1);                                                   \
+               zval_opt_copy_ctor(__z1);                                               \
        } while (0)
 
 #define ZVAL_UNREF(z) do {                                                             \
@@ -718,66 +718,69 @@ END_EXTERN_C()
                Z_UNSET_ISREF_P(z);                                                             \
        } while (0)
 
-#define SEPARATE_ZVAL(zv) do {                                                                                 \
-               zval *_zv = (zv);                                                                                               \
-               if (Z_REFCOUNTED_P(_zv)) {                                                                              \
-                       if (Z_REFCOUNT_P(_zv) > 1) {                                                            \
-                               if (Z_ISREF_P(_zv)) {                                                                   \
-                                       Z_DELREF_P(_zv);                                                                        \
-                                       ZVAL_DUP(_zv, Z_REFVAL_P(_zv));                                         \
-                               } else if (Z_TYPE_FLAGS_P(_zv) & IS_TYPE_COPYABLE) {    \
-                                       Z_DELREF_P(_zv);                                                                        \
-                                       zval_copy_ctor_func(_zv);                                                       \
-                               }                                                                                                               \
-                       }                                                                                                                       \
-               }                                                                                                                               \
+#define SEPARATE_ZVAL(zv) do {                                                 \
+               zval *_zv = (zv);                                                               \
+               if (Z_REFCOUNTED_P(_zv)) {                                              \
+                       if (Z_REFCOUNT_P(_zv) > 1) {                            \
+                               if (Z_ISREF_P(_zv)) {                                   \
+                                       Z_DELREF_P(_zv);                                        \
+                                       ZVAL_DUP(_zv, Z_REFVAL_P(_zv));         \
+                               } else if (Z_COPYABLE_P(_zv)) {                 \
+                                       Z_DELREF_P(_zv);                                        \
+                                       zval_copy_ctor_func(_zv);                       \
+                               }                                                                               \
+                       }                                                                                       \
+               }                                                                                               \
        } while (0)
 
-#define SEPARATE_ZVAL_IF_NOT_REF(zv) do {                                                              \
-               zval *_zv = (zv);                                                                                               \
-               if (!Z_ISREF_P(_zv) &&                                                                                  \
-                   (Z_TYPE_FLAGS_P(_zv) & IS_TYPE_COPYABLE) &&                                 \
-                   Z_REFCOUNT_P(_zv) > 1) {                                                                    \
-                       Z_DELREF_P(_zv);                                                                                        \
-                       zval_copy_ctor_func(_zv);                                                                       \
-               }                                                                                                                       \
+#define SEPARATE_ZVAL_IF_NOT_REF(zv) do {                              \
+               zval *_zv = (zv);                                                               \
+               if (!Z_ISREF_P(_zv) &&                                                  \
+                   Z_COPYABLE_P(_zv) &&                                                \
+                   Z_REFCOUNT_P(_zv) > 1) {                                    \
+                       Z_DELREF_P(_zv);                                                        \
+                       zval_copy_ctor_func(_zv);                                       \
+               }                                                                                       \
        } while (0)
 
-#define SEPARATE_ZVAL_IF_REF(zv) do {                                                                  \
-               zval *__zv = (zv);                                                                                              \
-               if (Z_ISREF_P(__zv)) {                                                                                  \
-                       if (Z_REFCOUNT_P(__zv) == 1) {                                                          \
-                               ZVAL_UNREF(__zv);                                                                               \
-                       } else {                                                                                                        \
-                               Z_DELREF_P(__zv);                                                                               \
-                               ZVAL_DUP(__zv, Z_REFVAL_P(__zv));                                               \
-                       }                                                                                                                       \
-               }                                                                                                                               \
+#define SEPARATE_ZVAL_IF_REF(zv) do {                                  \
+               zval *__zv = (zv);                                                              \
+               if (Z_ISREF_P(__zv)) {                                                  \
+                       if (Z_REFCOUNT_P(__zv) == 1) {                          \
+                               ZVAL_UNREF(__zv);                                               \
+                       } else {                                                                        \
+                               Z_DELREF_P(__zv);                                               \
+                               ZVAL_DUP(__zv, Z_REFVAL_P(__zv));               \
+                       }                                                                                       \
+               }                                                                                               \
        } while (0)
 
-#define SEPARATE_ZVAL_TO_MAKE_IS_REF(zv) do {                                                  \
-               zval *__zv = (zv);                                                                                              \
-               if (!Z_ISREF_P(__zv)) {                                                                                 \
-                   if (!(Z_TYPE_FLAGS_P(__zv) & IS_TYPE_COPYABLE) ||                   \
-                           Z_REFCOUNT_P(__zv) == 1) {                                                          \
-                               ZVAL_NEW_REF(__zv, __zv);                                                               \
-                       } else {                                                                                                        \
-                               Z_DELREF_P(__zv);                                                                               \
-                               ZVAL_NEW_REF(__zv, __zv);                                                               \
-                               zval_copy_ctor_func(Z_REFVAL_P(__zv));                                  \
-                       }                                                                                                                       \
-               }                                                                                                                               \
+#define SEPARATE_ZVAL_TO_MAKE_IS_REF(zv) do {                  \
+               zval *__zv = (zv);                                                              \
+               if (!Z_ISREF_P(__zv)) {                                                 \
+                   if (!Z_COPYABLE_P(__zv) ||                                  \
+                           Z_REFCOUNT_P(__zv) == 1) {                          \
+                               ZVAL_NEW_REF(__zv, __zv);                               \
+                       } else {                                                                        \
+                               Z_DELREF_P(__zv);                                               \
+                               ZVAL_NEW_REF(__zv, __zv);                               \
+                               zval_copy_ctor_func(Z_REFVAL_P(__zv));  \
+                       }                                                                                       \
+               }                                                                                               \
        } while (0)
 
+
+// TODO: remove ???
 #define COPY_PZVAL_TO_ZVAL(zv, pzv)                    \
        ZVAL_COPY_VALUE(&(zv), (pzv));                  \
-       if (Z_REFCOUNTED_P(pzv)) {                              \
+       if (Z_OPT_REFCOUNTED_P(pzv)) {                  \
                if (Z_REFCOUNT_P(pzv)>1) {                      \
                        zval_copy_ctor(&(zv));                  \
                        Z_DELREF_P((pzv));                              \
                }                                                                       \
        }                                                                               \
 
+// TODO: remove ???
 #define REPLACE_ZVAL_VALUE(ppzv_dest, pzv_src, copy) { \
        int is_ref, refcount;                                           \
                                                                                                \
@@ -787,7 +790,7 @@ END_EXTERN_C()
        zval_dtor(*ppzv_dest);                                          \
        ZVAL_COPY_VALUE(*ppzv_dest, pzv_src);           \
        if (copy) {                                 \
-               zval_copy_ctor(*ppzv_dest);                             \
+               zval_opt_copy_ctor(*ppzv_dest);                 \
     }                                              \
        Z_SET_ISREF_TO_PP(ppzv_dest, is_ref);           \
        Z_SET_REFCOUNT_PP(ppzv_dest, refcount);         \
index 4c100a55d4caa1e6056f533414d0e308b57abbeb..36995787dfd1f7bd5dad916fba4344144c7b9a55 100644 (file)
@@ -3844,7 +3844,7 @@ ZEND_API int zend_update_static_property(zend_class_entry *scope, const char *na
                                zval_dtor(property);
                                ZVAL_COPY_VALUE(property, value);
                                if (Z_REFCOUNT_P(value) > 0) {
-                                       zval_copy_ctor(property);
+                                       zval_opt_copy_ctor(property);
                                }
                        } else {
                                zval garbage;
index a8bb4f3ff0447bc76ae2624bc8be30d921e2c66c..01ab9892e248e553b2f703080950ac07427d3bc3 100644 (file)
@@ -583,7 +583,7 @@ END_EXTERN_C()
                                Z_REFVAL_P(__zv));                              \
                }                                                                               \
                if (copy) {                                                             \
-                       zval_copy_ctor(__z);                            \
+                       zval_opt_copy_ctor(__z);                        \
            }                                                                           \
                if (dtor) {                                                             \
                        if (!copy) {                                            \
index c4d2297a08d45abb3517362a4ca1a5c76fdb90e0..5c32ef0705500c55a0caf9c07a231a677c36cbd8 100644 (file)
@@ -64,40 +64,13 @@ static void zend_extension_fcall_end_handler(const zend_extension *extension, ze
 
 #define TEMP_VAR_STACK_LIMIT 2000
 
-static zend_always_inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free, int unref TSRMLS_DC)
+static zend_always_inline void zend_pzval_unlock_func(zval *z, zend_free_op *should_free)
 {
        should_free->var = NULL;
-       if (Z_REFCOUNTED_P(z)) {
-               if (!Z_DELREF_P(z)) {
-                       Z_SET_REFCOUNT_P(z, 1);
-//???                  Z_UNSET_ISREF_P(z);
-//???                  if (Z_ISREF_P(z)) {
-//???                          zend_reference *ref = Z_REF_P(z);
-//???                          ZVAL_COPY_VALUE(z, &ref->val);
-//???                          efree(ref);
-//???                  }
-                       should_free->var = z;
-/*             should_free->is_var = 1; */
-//???          } else {
-//???                  if (unref && Z_ISREF_P(z) && Z_REFCOUNT_P(z) == 1) {
-//???                  Z_UNSET_ISREF_P(z);
-//???                          if (Z_ISREF_P(z)) {
-//???                                  zend_reference *ref = Z_REF_P(z);
-//???                                  ZVAL_COPY_VALUE(z, &ref->val);
-//???                                  efree(ref);
-//???                          }
-//???                  }
-               }
-       }
-}
-
-static zend_always_inline void zend_pzval_unlock_free_func(zval *z TSRMLS_DC)
-{
-       if (Z_REFCOUNTED_P(z)) {
-               if (!Z_DELREF_P(z)) {
-                       ZEND_ASSERT(z != &EG(uninitialized_zval));
-                       zval_dtor(z);
-               }
+       if (Z_REFCOUNTED_P(z) && !Z_DELREF_P(z)) {
+               Z_SET_REFCOUNT_P(z, 1);
+               should_free->var = z;
+               /* should_free->is_var = 1; */
        }
 }
 
@@ -105,9 +78,7 @@ static zend_always_inline void zend_pzval_unlock_free_func(zval *z TSRMLS_DC)
 #define zval_ptr_dtor(zv) i_zval_ptr_dtor(zv ZEND_FILE_LINE_CC TSRMLS_CC)
 #define zval_ptr_dtor_nogc(zv) i_zval_ptr_dtor_nogc(zv ZEND_FILE_LINE_CC TSRMLS_CC)
 
-#define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f, 1 TSRMLS_CC)
-#define PZVAL_UNLOCK_EX(z, f, u) zend_pzval_unlock_func(z, f, u TSRMLS_CC)
-#define PZVAL_UNLOCK_FREE(z) zend_pzval_unlock_free_func(z TSRMLS_CC)
+#define PZVAL_UNLOCK(z, f) zend_pzval_unlock_func(z, f)
 #define PZVAL_LOCK(z) if (Z_REFCOUNTED_P(z)) Z_ADDREF_P((z))
 #define SELECTIVE_PZVAL_LOCK(pzv, opline)      if (RETURN_VALUE_USED(opline)) { PZVAL_LOCK(pzv); }
 
@@ -183,9 +154,6 @@ static zend_always_inline zval *_get_zval_ptr_var(zend_uint var, const zend_exec
 {
        zval *ret = EX_VAR(var);
 
-       if (UNEXPECTED(Z_TYPE_P(ret) == IS_INDIRECT)) {
-               ret = Z_INDIRECT_P(ret);
-       }
        should_free->var = ret;
        return ret;
 }
@@ -194,9 +162,6 @@ static zend_always_inline zval *_get_zval_ptr_var_deref(zend_uint var, const zen
 {
        zval *ret = EX_VAR(var);
 
-       if (UNEXPECTED(Z_TYPE_P(ret) == IS_INDIRECT)) {
-               ret = Z_INDIRECT_P(ret);
-       }
        should_free->var = ret;
        ZVAL_DEREF(ret);
        return ret;
@@ -462,22 +427,6 @@ static zend_always_inline zval *_get_zval_ptr_ptr_var(zend_uint var, const zend_
        return ret;
 }
 
-//???
-#if 0
-static zend_always_inline zval *_get_zval_ptr_var_fast(zend_uint var, const zend_execute_data *execute_data, zend_free_op *should_free TSRMLS_DC)
-{
-       zval* ptr = EX_VAR(var);
-
-       if (EXPECTED(Z_TYPE_P(ptr) != IS_STR_OFFSET)) {
-               should_free->var = ptr;
-       } else {
-               /* string offset */
-               should_free->var = Z_STR_OFFSET_P(EX_VAR(var))->str;
-       }
-       return ptr;
-}
-#endif
-
 static zend_always_inline zval *_get_obj_zval_ptr_unused(TSRMLS_D)
 {
        if (EXPECTED(Z_OBJ(EG(This)) != NULL)) {
@@ -514,22 +463,25 @@ static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *v
 }
 
 /* this should modify object only if it's empty */
-static inline void make_real_object(zval *object_ptr TSRMLS_DC)
+static inline zval* make_real_object(zval *object_ptr TSRMLS_DC)
 {
        zval *object = object_ptr;
 
        ZVAL_DEREF(object);
-       if (Z_TYPE_P(object) == IS_NULL
-               || (Z_TYPE_P(object) == IS_BOOL && Z_LVAL_P(object) == 0)
-               || (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0)
-       ) {
-               if (EXPECTED(!Z_ISREF_P(object_ptr))) {
-                       SEPARATE_ZVAL(object);
+       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
+               if (Z_TYPE_P(object) == IS_NULL
+                       || (Z_TYPE_P(object) == IS_BOOL && Z_LVAL_P(object) == 0)
+                       || (Z_TYPE_P(object) == IS_STRING && Z_STRLEN_P(object) == 0)) {
+                       if (EXPECTED(object == object_ptr)) {
+                               /* object_ptr is not a reference */
+                               SEPARATE_ZVAL(object);
+                       }
+                       zval_dtor(object);
+                       object_init(object);
+                       zend_error(E_WARNING, "Creating default object from empty value");
                }
-               zval_dtor(object);
-               object_init(object);
-               zend_error(E_WARNING, "Creating default object from empty value");
        }
+       return object;
 }
 
 ZEND_API char * zend_verify_arg_class_kind(const zend_arg_info *cur_arg_info, ulong fetch_type, char **class_name, zend_class_entry **pce TSRMLS_DC)
@@ -722,16 +674,22 @@ static inline void zend_assign_to_object(zval *retval, zval *object_ptr, zval *p
        FREE_OP_IF_VAR(free_value);
 }
 
-static inline int zend_assign_to_string_offset(zval *str_offset, zval *value, int value_type TSRMLS_DC)
+static void zend_assign_to_string_offset(zval *str_offset, zval *value, int value_type, zval *result TSRMLS_DC)
 {
-       zval *str = Z_STR_OFFSET_P(str_offset)->str;
-       zend_uint offset = Z_STR_OFFSET_P(str_offset)->offset;
+       zval *str = Z_STR_OFFSET_STR_P(str_offset);
+       zend_uint offset = Z_STR_OFFSET_IDX_P(str_offset);
+       zend_string *old_str;
 
        if ((int)offset < 0) {
                zend_error(E_WARNING, "Illegal string offset:  %d", offset);
-               return 0;
+               STR_RELEASE(Z_STR_P(str));
+               if (result) {
+                       ZVAL_NULL(result);
+               }
+               return;
        }
 
+       old_str = Z_STR_P(str);
        if (offset >= Z_STRLEN_P(str)) {
                int old_len = Z_STRLEN_P(str);
                Z_STR_P(str) = STR_REALLOC(Z_STR_P(str), offset + 1, 0);
@@ -748,7 +706,7 @@ static inline int zend_assign_to_string_offset(zval *str_offset, zval *value, in
 
                ZVAL_COPY_VALUE(&tmp, value);
                if (value_type != IS_TMP_VAR) {
-                       zval_copy_ctor(&tmp);
+                       zval_opt_copy_ctor(&tmp);
                }
                convert_to_string(&tmp);
                Z_STRVAL_P(str)[offset] = Z_STRVAL(tmp)[0];
@@ -766,65 +724,92 @@ static inline int zend_assign_to_string_offset(zval *str_offset, zval *value, in
         * the value of an assignment to a string offset is undefined
        T(result->u.var).var = &T->str_offset.str;
        */
-       return 1;
+
+       STR_RELEASE(old_str);
+       if (result) {
+               zend_uchar c = (zend_uchar)Z_STRVAL_P(str)[offset];
+
+               if (CG(one_char_string)[c]) {
+                       ZVAL_INT_STR(result, CG(one_char_string)[c]);
+               } else {
+                       ZVAL_NEW_STR(result, STR_INIT(Z_STRVAL_P(str) + offset, 1, 0));
+               }
+       }
 }
 
 static inline zval* zend_assign_tmp_to_variable(zval *variable_ptr, zval *value TSRMLS_DC)
 {
        ZVAL_DEREF(variable_ptr);
-       if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
-           UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
-               Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr, value TSRMLS_CC);
-               return variable_ptr;
-       }
 
-       if (EXPECTED(!Z_REFCOUNTED_P(variable_ptr))) {
-               ZVAL_COPY_VALUE(variable_ptr, value);
-       } else if (UNEXPECTED(Z_REFCOUNT_P(variable_ptr) > 1)) {
-               /* we need to split */
-               Z_DELREF_P(variable_ptr);
-               GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
-               ZVAL_COPY_VALUE(variable_ptr, value);
-       } else {
-               zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
+       if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
+               zend_refcounted *garbage;
+
+               if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
+                   UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
+                       Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr, value TSRMLS_CC);
+                       return variable_ptr;
+               }
 
-               ZVAL_COPY_VALUE(variable_ptr, value);
-               _zval_dtor_func(garbage ZEND_FILE_LINE_CC);
+               garbage = Z_COUNTED_P(variable_ptr);
+               if (UNEXPECTED(GC_REFCOUNT(garbage) > 1)) {
+                       /* we need to split */
+                       GC_REFCOUNT(garbage)--;
+                       /* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */
+                       if ((Z_COLLECTABLE_P(variable_ptr)) &&
+                       UNEXPECTED(!GC_INFO(garbage))) {
+                               gc_possible_root(garbage TSRMLS_CC);
+                       }
+               } else {
+                       ZVAL_COPY_VALUE(variable_ptr, value);
+                       _zval_dtor_func(garbage ZEND_FILE_LINE_CC);
+                       return variable_ptr;
+               }
        }
+
+       ZVAL_COPY_VALUE(variable_ptr, value);
+       
        return variable_ptr;
 }
 
 static inline zval* zend_assign_const_to_variable(zval *variable_ptr, zval *value TSRMLS_DC)
 {
        ZVAL_DEREF(variable_ptr);
-       if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
-           UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
-               Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr, value TSRMLS_CC);
-               return variable_ptr;
-       }
 
-       if (EXPECTED(!Z_REFCOUNTED_P(variable_ptr))) {
-               ZVAL_COPY_VALUE(variable_ptr, value);
-               if (Z_REFCOUNTED_P(value)) {
-                       zval_copy_ctor(variable_ptr);
-               }
-       } else if (UNEXPECTED(Z_REFCOUNT_P(variable_ptr) > 1)) {
-               /* we need to split */
-               Z_DELREF_P(variable_ptr);
-               GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
-               ZVAL_COPY_VALUE(variable_ptr, value);
-               if (Z_REFCOUNTED_P(value)) {
-                       zval_copy_ctor(variable_ptr);
+       if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) {
+               zend_refcounted *garbage;
+
+               if (Z_TYPE_P(variable_ptr) == IS_OBJECT &&
+                   UNEXPECTED(Z_OBJ_HANDLER_P(variable_ptr, set) != NULL)) {
+                       Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr, value TSRMLS_CC);
+                       return variable_ptr;
                }
-       } else {
-               zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
 
-               ZVAL_COPY_VALUE(variable_ptr, value);
-               if (Z_REFCOUNTED_P(value)) {
-                       zval_copy_ctor(variable_ptr);
+               garbage = Z_COUNTED_P(variable_ptr);
+               if (UNEXPECTED(GC_REFCOUNT(garbage) > 1)) {
+                       /* we need to split */
+                       GC_REFCOUNT(garbage)--;
+                       /* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */
+                       if (Z_COLLECTABLE_P(variable_ptr) &&
+                       UNEXPECTED(!GC_INFO(garbage))) {
+                               gc_possible_root(garbage TSRMLS_CC);
+                       }
+               } else {
+                       ZVAL_COPY_VALUE(variable_ptr, value);
+                       /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
+                       if (UNEXPECTED(Z_OPT_COPYABLE_P(variable_ptr))) {
+                               _zval_copy_ctor_func(variable_ptr ZEND_FILE_LINE_CC);
+                       }
+                       _zval_dtor_func(garbage ZEND_FILE_LINE_CC);
+                       return variable_ptr;
                }
-               _zval_dtor_func(garbage ZEND_FILE_LINE_CC);
        }
+       
+       ZVAL_COPY_VALUE(variable_ptr, value);
+       /* IS_CONST can't be IS_OBJECT, IS_RESOURCE or IS_REFERENCE */
+       if (UNEXPECTED(Z_OPT_COPYABLE_P(variable_ptr))) {
+               _zval_copy_ctor_func(variable_ptr ZEND_FILE_LINE_CC);
+       }
+
        return variable_ptr;
 }
 
index fcf9159b2eb2768dcb615852fcd9922fa9e40a80..d060fae9dd841e23c22d1e781bb320054f912550 100644 (file)
@@ -139,8 +139,7 @@ END_EXTERN_C()
 static zend_always_inline void gc_check_possible_root(zval *z TSRMLS_DC)
 {
        ZVAL_DEREF(z);
-       if ((Z_TYPE_FLAGS_P(z) & IS_TYPE_COLLECTABLE) &&
-           UNEXPECTED(!Z_GC_INFO_P(z))) {
+       if (Z_COLLECTABLE_P(z) && UNEXPECTED(!Z_GC_INFO_P(z))) {
                gc_possible_root(Z_COUNTED_P(z) TSRMLS_CC);
        }
 }
index c4c7bcdca2152016b30c04fc5bb681e8b7c02e10..5a50b37156145e5ca3233f16b11d29e0519ccc4e 100644 (file)
@@ -80,7 +80,6 @@ typedef struct _zend_resource   zend_resource;
 typedef struct _zend_reference  zend_reference;
 typedef struct _zend_ast_ref    zend_ast_ref;
 typedef struct _zend_ast        zend_ast;
-typedef struct _zend_str_offset zend_str_offset;
 
 typedef int  (*compare_func_t)(const void *, const void * TSRMLS_DC);
 typedef void (*sort_func_t)(void *, size_t, size_t, compare_func_t TSRMLS_DC);
@@ -101,7 +100,6 @@ typedef union _zend_value {
        void             *ptr;
        zend_class_entry *ce;
        zend_function    *func;
-       zend_str_offset  *str_offset;
 } zend_value;
 
 struct _zval_struct {
@@ -119,6 +117,7 @@ struct _zval_struct {
        union {
                zend_uint     var_flags;
                zend_uint     next;                 /* hash collision chain */
+               zend_uint     str_offset;           /* string offset */
        } u2;
 };
 
@@ -142,12 +141,6 @@ struct _zend_string {
        char              val[1];
 };
 
-struct _zend_str_offset {
-       zend_refcounted   gc;
-       zval             *str;
-       int               offset;
-};
-
 typedef struct _Bucket {
        zend_ulong        h;                /* hash value (or numeric index)   */
        zend_string      *key;              /* string key or NULL for numerics */
@@ -251,6 +244,9 @@ static inline zend_uchar zval_get_type(const zval* pz) {
 #define Z_COUNTED(zval)                                (zval).value.counted
 #define Z_COUNTED_P(zval_p)                    Z_COUNTED(*(zval_p))
 
+#define Z_TYPE_FLAGS_SHIFT                     8
+#define Z_CONST_FLAGS_SHIFT                    8
+
 #define GC_REFCOUNT(p)                         ((zend_refcounted*)(p))->refcount
 #define GC_TYPE(p)                                     ((zend_refcounted*)(p))->u.v.type
 #define GC_FLAGS(p)                                    ((zend_refcounted*)(p))->u.v.flags
@@ -278,15 +274,15 @@ static inline zend_uchar zval_get_type(const zval* pz) {
 /* extended types */
 #define IS_INTERNED_STRING_EX          IS_STRING
 
-#define IS_STRING_EX                           (IS_STRING         | ((                   IS_TYPE_REFCOUNTED |                       IS_TYPE_COPYABLE) << 8))
-#define IS_ARRAY_EX                                    (IS_ARRAY          | ((                   IS_TYPE_REFCOUNTED | IS_TYPE_COLLECTABLE | IS_TYPE_COPYABLE) << 8))
-#define IS_OBJECT_EX                           (IS_OBJECT         | ((                   IS_TYPE_REFCOUNTED | IS_TYPE_COLLECTABLE                   ) << 8))
-#define IS_RESOURCE_EX                         (IS_RESOURCE       | ((                   IS_TYPE_REFCOUNTED                                         ) << 8))
-#define IS_REFERENCE_EX                                (IS_REFERENCE      | ((                   IS_TYPE_REFCOUNTED                                         ) << 8))
+#define IS_STRING_EX                           (IS_STRING         | ((                   IS_TYPE_REFCOUNTED |                       IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT))
+#define IS_ARRAY_EX                                    (IS_ARRAY          | ((                   IS_TYPE_REFCOUNTED | IS_TYPE_COLLECTABLE | IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT))
+#define IS_OBJECT_EX                           (IS_OBJECT         | ((                   IS_TYPE_REFCOUNTED | IS_TYPE_COLLECTABLE                   ) << Z_TYPE_FLAGS_SHIFT))
+#define IS_RESOURCE_EX                         (IS_RESOURCE       | ((                   IS_TYPE_REFCOUNTED                                         ) << Z_TYPE_FLAGS_SHIFT))
+#define IS_REFERENCE_EX                                (IS_REFERENCE      | ((                   IS_TYPE_REFCOUNTED                                         ) << Z_TYPE_FLAGS_SHIFT))
 
-#define IS_CONSTANT_EX                         (IS_CONSTANT       | ((IS_TYPE_CONSTANT | IS_TYPE_REFCOUNTED |                       IS_TYPE_COPYABLE) << 8))
-#define IS_CONSTANT_ARRAY_EX           (IS_CONSTANT_ARRAY | ((IS_TYPE_CONSTANT | IS_TYPE_REFCOUNTED |                       IS_TYPE_COPYABLE) << 8))
-#define IS_CONSTANT_AST_EX                     (IS_CONSTANT_AST   | ((IS_TYPE_CONSTANT | IS_TYPE_REFCOUNTED |                       IS_TYPE_COPYABLE) << 8))
+#define IS_CONSTANT_EX                         (IS_CONSTANT       | ((IS_TYPE_CONSTANT | IS_TYPE_REFCOUNTED |                       IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT))
+#define IS_CONSTANT_ARRAY_EX           (IS_CONSTANT_ARRAY | ((IS_TYPE_CONSTANT | IS_TYPE_REFCOUNTED |                       IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT))
+#define IS_CONSTANT_AST_EX                     (IS_CONSTANT_AST   | ((IS_TYPE_CONSTANT | IS_TYPE_REFCOUNTED |                       IS_TYPE_COPYABLE) << Z_TYPE_FLAGS_SHIFT))
 
 /* zval.u1.v.const_flags */
 #define IS_CONSTANT_UNQUALIFIED                0x010
@@ -330,9 +326,28 @@ static inline zend_uchar zval_get_type(const zval* pz) {
 #define Z_OBJ_DEC_APPLY_COUNT_P(zv) Z_OBJ_DEC_APPLY_COUNT(*(zv))
 
 /* All data types < IS_STRING have their constructor/destructors skipped */
-#define Z_REFCOUNTED(zval)                     (Z_TYPE_FLAGS(zval) & IS_TYPE_REFCOUNTED)
+#define Z_REFCOUNTED(zval)                     ((Z_TYPE_FLAGS(zval) & IS_TYPE_REFCOUNTED) != 0)
 #define Z_REFCOUNTED_P(zval_p)         Z_REFCOUNTED(*(zval_p))
 
+#define Z_COLLECTABLE(zval)                    ((Z_TYPE_FLAGS(zval) & IS_TYPE_COLLECTABLE) != 0)
+#define Z_COLLECTABLE_P(zval_p)                Z_COLLECTABLE(*(zval_p))
+
+#define Z_COPYABLE(zval)                       ((Z_TYPE_FLAGS(zval) & IS_TYPE_COPYABLE) != 0)
+#define Z_COPYABLE_P(zval_p)           Z_COPYABLE(*(zval_p))
+
+/* the following Z_OPT_* macros make better code when Z_TYPE_INFO accessed before */
+#define Z_OPT_TYPE(zval)                       (Z_TYPE_INFO(zval) & 0xff)
+#define Z_OPT_TYPE_P(zval_p)           Z_OPT_TYPE(*(zval_p))
+
+#define Z_OPT_REFCOUNTED(zval)         ((Z_TYPE_INFO(zval) & (IS_TYPE_REFCOUNTED << Z_TYPE_FLAGS_SHIFT)) != 0)
+#define Z_OPT_REFCOUNTED_P(zval_p)     Z_OPT_REFCOUNTED(*(zval_p))
+
+#define Z_OPT_COLLECTABLE(zval)                ((Z_TYPE_INFO(zval) & (IS_TYPE_COLLECTABLE << Z_TYPE_FLAGS_SHIFT)) != 0)
+#define Z_OPT_COLLECTABLE_P(zval_p)    Z_OPT_COLLECTABLE(*(zval_p))
+
+#define Z_OPT_COPYABLE(zval)           ((Z_TYPE_INFO(zval) & (IS_TYPE_COPYABLE << Z_TYPE_FLAGS_SHIFT)) != 0)
+#define Z_OPT_COPYABLE_P(zval_p)       Z_OPT_COPYABLE(*(zval_p))
+
 #define Z_ISREF(zval)                          (Z_TYPE(zval) == IS_REFERENCE)
 #define Z_ISREF_P(zval_p)                      Z_ISREF(*(zval_p))
 
@@ -420,9 +435,6 @@ static inline zend_uchar zval_get_type(const zval* pz) {
 #define Z_PTR(zval)                                    (zval).value.ptr
 #define Z_PTR_P(zval_p)                                Z_PTR(*(zval_p))
 
-#define Z_STR_OFFSET(zval)                     (zval).value.str_offset
-#define Z_STR_OFFSET_P(zval_p)         Z_STR_OFFSET(*(zval_p))
-
 #define ZVAL_UNDEF(z) do {                             \
                Z_TYPE_INFO_P(z) = IS_UNDEF;    \
        } while (0)
@@ -579,13 +591,16 @@ static inline zend_uchar zval_get_type(const zval* pz) {
                Z_TYPE_INFO_P(z) = IS_PTR;                                                              \
        } while (0)
 
-#define ZVAL_STR_OFFSET(z, s, o) do {                                                  \
-               zend_str_offset *x = emalloc(sizeof(zend_str_offset));  \
-               GC_REFCOUNT(x) = 1;                                                                             \
-               GC_TYPE_INFO(x) = IS_STR_OFFSET;                                                \
-               x->str = (s);                                                                                   \
-               x->offset = (o);                                                                                \
-               Z_STR_OFFSET_P(z) = x;                                                                  \
+
+#define Z_STR_OFFSET_STR(zval)         Z_INDIRECT(zval)
+#define Z_STR_OFFSET_STR_P(zval_p)     Z_STR_OFFSET_STR(*(zval_p))
+
+#define Z_STR_OFFSET_IDX(zval)         (zval).u2.str_offset
+#define Z_STR_OFFSET_IDX_P(zval_p)     Z_STR_OFFSET_IDX(*(zval_p))
+
+#define ZVAL_STR_OFFSET(z, s, i) do {                                                  \
+               Z_STR_OFFSET_STR_P(z) = (s);                                                    \
+               Z_STR_OFFSET_IDX_P(z) = (i);                                                    \
                Z_TYPE_INFO_P(z) = IS_STR_OFFSET;                                               \
        } while (0)
 
index 37accac1916081179a1bbfd2abbb61393a97651f..848efa3bf41a83171f34d3505361170dc2d8fd83 100644 (file)
@@ -43,7 +43,18 @@ ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC);
 static zend_always_inline void _zval_copy_ctor(zval *zvalue ZEND_FILE_LINE_DC)
 {
        if (Z_REFCOUNTED_P(zvalue)) {
-               if (Z_TYPE_FLAGS_P(zvalue) & IS_TYPE_COPYABLE) {
+               if (Z_COPYABLE_P(zvalue)) {
+                       _zval_copy_ctor_func(zvalue ZEND_FILE_LINE_RELAY_CC);
+               } else {
+                       Z_ADDREF_P(zvalue);
+               }
+       }
+}
+
+static zend_always_inline void _zval_opt_copy_ctor(zval *zvalue ZEND_FILE_LINE_DC)
+{
+       if (Z_OPT_REFCOUNTED_P(zvalue)) {
+               if (Z_OPT_COPYABLE_P(zvalue)) {
                        _zval_copy_ctor_func(zvalue ZEND_FILE_LINE_RELAY_CC);
                } else {
                        Z_ADDREF_P(zvalue);
@@ -60,6 +71,7 @@ ZEND_API void _zval_internal_dtor(zval *zvalue ZEND_FILE_LINE_DC);
 ZEND_API void _zval_internal_ptr_dtor(zval *zvalue ZEND_FILE_LINE_DC);
 ZEND_API void _zval_dtor_wrapper(zval *zvalue);
 #define zval_copy_ctor(zvalue) _zval_copy_ctor((zvalue) ZEND_FILE_LINE_CC)
+#define zval_opt_copy_ctor(zvalue) _zval_opt_copy_ctor((zvalue) ZEND_FILE_LINE_CC)
 #define zval_dtor(zvalue) _zval_dtor((zvalue) ZEND_FILE_LINE_CC)
 #define zval_ptr_dtor(zval_ptr) _zval_ptr_dtor((zval_ptr) ZEND_FILE_LINE_CC)
 #define zval_internal_dtor(zvalue) _zval_internal_dtor((zvalue) ZEND_FILE_LINE_CC)
index 758dcaa4bfcb63fd6c5a02cbff8c9eebad9e2126..3ef75f12796502accd5868c77d136df12ff72740 100644 (file)
@@ -340,10 +340,7 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -595,7 +592,7 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR|
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -694,7 +691,7 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -1701,17 +1698,7 @@ ZEND_VM_HANDLER(147, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMP|VAR|UNUSED|CV)
                value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
                variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
                if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-                       zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-                       if (zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC)) {
-                               if (RETURN_VALUE_USED(opline)) {
-                                       ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->str) + Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->offset, 1);
-                               }
-                       } else if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_NULL(EX_VAR(opline->result.var));
-                       }
-//??? instead of FREE_OP_VAR_PTR(free_op_data2);
-                       STR_RELEASE(old_str);
-                       efree(Z_STR_OFFSET_P(variable_ptr));
+                       zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
                } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
                        if (IS_TMP_FREE(free_op_data1)) {
                                zval_dtor(value);
@@ -1754,17 +1741,7 @@ ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV)
        variable_ptr = GET_OP1_ZVAL_PTR_PTR(BP_VAR_W);
 
        if (OP1_TYPE == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-               zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-               if (zend_assign_to_string_offset(variable_ptr, value, OP2_TYPE TSRMLS_CC)) {
-                       if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->str) + Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->offset, 1);
-                       }
-               } else if (RETURN_VALUE_USED(opline)) {
-                       ZVAL_NULL(EX_VAR(opline->result.var));
-               }
-//??? instead of FREE_OP1_VAR_PTR()
-               STR_RELEASE(old_str);
-               efree(Z_STR_OFFSET_P(variable_ptr));
+               zend_assign_to_string_offset(variable_ptr, value, OP2_TYPE, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
        } else if (OP1_TYPE == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) {
                if (IS_OP2_TMP_FREE()) {
                        zval_dtor(value);
@@ -2867,7 +2844,7 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY)
                if (OP1_TYPE == IS_CONST || OP1_TYPE == IS_TMP_VAR) {               
                        ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
                        if (OP1_TYPE != IS_TMP_VAR) {
-                               zval_copy_ctor(EX(return_value));
+                               zval_opt_copy_ctor(EX(return_value));
                        }
                        FREE_OP1_IF_VAR();
                } else if (Z_ISREF_P(retval_ptr)) {
@@ -2876,7 +2853,7 @@ ZEND_VM_HANDLER(62, ZEND_RETURN, CONST|TMP|VAR|CV, ANY)
                } else {
                        ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
                        if (OP1_TYPE == IS_CV) {
-                               if (Z_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
+                               if (Z_OPT_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
                        }
                }
        }
@@ -2975,7 +2952,7 @@ ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY)
        /* Not sure if a complete copy is what we want here */
        ZVAL_COPY_VALUE(&exception, value);
        if (!IS_OP1_TMP_FREE()) {
-               zval_copy_ctor(&exception);
+               zval_opt_copy_ctor(&exception);
        }
 
        zend_throw_exception_object(&exception TSRMLS_CC);
@@ -3059,7 +3036,7 @@ ZEND_VM_HANDLER(65, ZEND_SEND_VAL, CONST|TMP, ANY)
 
                ZVAL_COPY_VALUE(&valptr, value);
                if (!IS_OP1_TMP_FREE()) {
-                       zval_copy_ctor(&valptr);
+                       zval_opt_copy_ctor(&valptr);
                }
                zend_vm_stack_push(&valptr TSRMLS_CC);
                FREE_OP1_IF_VAR();
@@ -3141,7 +3118,7 @@ ZEND_VM_HANDLER(106, ZEND_SEND_VAR_NO_REF, VAR|CV, ANY)
                }
                ZVAL_COPY_VALUE(&val, varptr);
                if (!IS_OP1_TMP_FREE()) {
-                       zval_copy_ctor(&val);
+                       zval_opt_copy_ctor(&val);
                }
                FREE_OP1_IF_VAR();
                zend_vm_stack_push(&val TSRMLS_CC);
@@ -3849,7 +3826,7 @@ ZEND_VM_HANDLER(21, ZEND_CAST, CONST|TMP|VAR|CV, ANY)
        if (opline->extended_value != IS_STRING) {
                ZVAL_COPY_VALUE(result, expr);
                if (!IS_OP1_TMP_FREE()) {
-                       zval_copy_ctor(result);
+                       zval_opt_copy_ctor(result);
                }
        }
 
@@ -3880,7 +3857,7 @@ ZEND_VM_C_LABEL(cast_again):
                        } else {
                                ZVAL_COPY_VALUE(result, expr);
                                if (!IS_OP1_TMP_FREE()) {
-                                       zval_copy_ctor(result);
+                                       zval_opt_copy_ctor(result);
                                }
                        }
                        break;
@@ -4893,7 +4870,7 @@ ZEND_VM_HANDLER(152, ZEND_JMP_SET, CONST|TMP|VAR|CV, ANY)
        if (i_zend_is_true(value TSRMLS_CC)) {
                ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                if (!IS_OP1_TMP_FREE()) {
-                       zval_copy_ctor(EX_VAR(opline->result.var));
+                       zval_opt_copy_ctor(EX_VAR(opline->result.var));
                }
                FREE_OP1_IF_VAR();
 #if DEBUG_ZEND>=2
@@ -4922,7 +4899,7 @@ ZEND_VM_HANDLER(158, ZEND_JMP_SET_VAR, CONST|TMP|VAR|CV, ANY)
                } else {
                        ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                        if (!IS_OP1_TMP_FREE()) {
-                               zval_copy_ctor(EX_VAR(opline->result.var));
+                               zval_opt_copy_ctor(EX_VAR(opline->result.var));
                        }
                }
                FREE_OP1_IF_VAR();
@@ -4948,7 +4925,7 @@ ZEND_VM_HANDLER(22, ZEND_QM_ASSIGN, CONST|TMP|VAR|CV, ANY)
 
        ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
        if (!IS_OP1_TMP_FREE()) {
-               zval_copy_ctor(EX_VAR(opline->result.var));
+               zval_opt_copy_ctor(EX_VAR(opline->result.var));
        }
        FREE_OP1_IF_VAR();
        CHECK_EXCEPTION();
@@ -4969,7 +4946,7 @@ ZEND_VM_HANDLER(157, ZEND_QM_ASSIGN_VAR, CONST|TMP|VAR|CV, ANY)
        } else {
                ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                if (!IS_OP1_TMP_FREE()) {
-                       zval_copy_ctor(EX_VAR(opline->result.var));
+                       zval_opt_copy_ctor(EX_VAR(opline->result.var));
                }
        }
 
@@ -5347,7 +5324,7 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST)
        if (Z_TYPE_FLAGS_P(val) & IS_TYPE_CONSTANT) {
                ZVAL_COPY_VALUE(&c.value, val);
                if (Z_TYPE_P(val) == IS_CONSTANT_ARRAY) {
-                       zval_copy_ctor(&c.value);
+                       zval_opt_copy_ctor(&c.value);
                }
                zval_update_constant(&c.value, NULL TSRMLS_CC);
        } else {
@@ -5433,7 +5410,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
 
                                value = GET_OP1_ZVAL_PTR(BP_VAR_R);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!IS_OP1_TMP_FREE()) {
@@ -5470,7 +5447,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!IS_OP1_TMP_FREE()) {
@@ -5501,7 +5478,7 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!IS_OP2_TMP_FREE()) {
index 48bbb2b5e61d2888bd298df3cdd864f9e4e39a39..342762b941eec046a79e3c0cbd2d599ba5833fa3 100644 (file)
@@ -2551,7 +2551,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG
                if (IS_CONST == IS_CONST || IS_CONST == IS_TMP_VAR) {
                        ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
                        if (IS_CONST != IS_TMP_VAR) {
-                               zval_copy_ctor(EX(return_value));
+                               zval_opt_copy_ctor(EX(return_value));
                        }
 
                } else if (Z_ISREF_P(retval_ptr)) {
@@ -2560,7 +2560,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARG
                } else {
                        ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
                        if (IS_CONST == IS_CV) {
-                               if (Z_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
+                               if (Z_OPT_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
                        }
                }
        }
@@ -2646,7 +2646,7 @@ static int ZEND_FASTCALL  ZEND_THROW_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        /* Not sure if a complete copy is what we want here */
        ZVAL_COPY_VALUE(&exception, value);
        if (!0) {
-               zval_copy_ctor(&exception);
+               zval_opt_copy_ctor(&exception);
        }
 
        zend_throw_exception_object(&exception TSRMLS_CC);
@@ -2676,7 +2676,7 @@ static int ZEND_FASTCALL  ZEND_SEND_VAL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
 
                ZVAL_COPY_VALUE(&valptr, value);
                if (!0) {
-                       zval_copy_ctor(&valptr);
+                       zval_opt_copy_ctor(&valptr);
                }
                zend_vm_stack_push(&valptr TSRMLS_CC);
 
@@ -2770,7 +2770,7 @@ static int ZEND_FASTCALL  ZEND_CAST_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        if (opline->extended_value != IS_STRING) {
                ZVAL_COPY_VALUE(result, expr);
                if (!0) {
-                       zval_copy_ctor(result);
+                       zval_opt_copy_ctor(result);
                }
        }
 
@@ -2801,7 +2801,7 @@ cast_again:
                        } else {
                                ZVAL_COPY_VALUE(result, expr);
                                if (!0) {
-                                       zval_copy_ctor(result);
+                                       zval_opt_copy_ctor(result);
                                }
                        }
                        break;
@@ -3157,7 +3157,7 @@ static int ZEND_FASTCALL  ZEND_JMP_SET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_AR
        if (i_zend_is_true(value TSRMLS_CC)) {
                ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                if (!0) {
-                       zval_copy_ctor(EX_VAR(opline->result.var));
+                       zval_opt_copy_ctor(EX_VAR(opline->result.var));
                }
 
 #if DEBUG_ZEND>=2
@@ -3185,7 +3185,7 @@ static int ZEND_FASTCALL  ZEND_JMP_SET_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLE
                } else {
                        ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                        if (!0) {
-                               zval_copy_ctor(EX_VAR(opline->result.var));
+                               zval_opt_copy_ctor(EX_VAR(opline->result.var));
                        }
                }
 
@@ -3210,7 +3210,7 @@ static int ZEND_FASTCALL  ZEND_QM_ASSIGN_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_
 
        ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
        if (!0) {
-               zval_copy_ctor(EX_VAR(opline->result.var));
+               zval_opt_copy_ctor(EX_VAR(opline->result.var));
        }
 
        CHECK_EXCEPTION();
@@ -3231,7 +3231,7 @@ static int ZEND_FASTCALL  ZEND_QM_ASSIGN_VAR_SPEC_CONST_HANDLER(ZEND_OPCODE_HAND
        } else {
                ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                if (!0) {
-                       zval_copy_ctor(EX_VAR(opline->result.var));
+                       zval_opt_copy_ctor(EX_VAR(opline->result.var));
                }
        }
 
@@ -4208,7 +4208,7 @@ static int ZEND_FASTCALL  ZEND_DECLARE_CONST_SPEC_CONST_CONST_HANDLER(ZEND_OPCOD
        if (Z_TYPE_FLAGS_P(val) & IS_TYPE_CONSTANT) {
                ZVAL_COPY_VALUE(&c.value, val);
                if (Z_TYPE_P(val) == IS_CONSTANT_ARRAY) {
-                       zval_copy_ctor(&c.value);
+                       zval_opt_copy_ctor(&c.value);
                }
                zval_update_constant(&c.value, NULL TSRMLS_CC);
        } else {
@@ -4257,7 +4257,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE
 
                                value = opline->op1.zv;
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -4293,7 +4293,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -4323,7 +4323,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -4910,7 +4910,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_
 
                                value = opline->op1.zv;
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -4946,7 +4946,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -4976,7 +4976,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!1) {
@@ -5889,7 +5889,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_
 
                                value = opline->op1.zv;
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -5925,7 +5925,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -5955,7 +5955,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -6578,7 +6578,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL
 
                                value = opline->op1.zv;
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -6614,7 +6614,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -6644,7 +6644,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -7284,7 +7284,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A
 
                                value = opline->op1.zv;
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -7320,7 +7320,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -7350,7 +7350,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -7625,7 +7625,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                if (IS_TMP_VAR == IS_CONST || IS_TMP_VAR == IS_TMP_VAR) {
                        ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
                        if (IS_TMP_VAR != IS_TMP_VAR) {
-                               zval_copy_ctor(EX(return_value));
+                               zval_opt_copy_ctor(EX(return_value));
                        }
 
                } else if (Z_ISREF_P(retval_ptr)) {
@@ -7634,7 +7634,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                } else {
                        ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
                        if (IS_TMP_VAR == IS_CV) {
-                               if (Z_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
+                               if (Z_OPT_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
                        }
                }
        }
@@ -7720,7 +7720,7 @@ static int ZEND_FASTCALL  ZEND_THROW_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* Not sure if a complete copy is what we want here */
        ZVAL_COPY_VALUE(&exception, value);
        if (!1) {
-               zval_copy_ctor(&exception);
+               zval_opt_copy_ctor(&exception);
        }
 
        zend_throw_exception_object(&exception TSRMLS_CC);
@@ -7750,7 +7750,7 @@ static int ZEND_FASTCALL  ZEND_SEND_VAL_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
 
                ZVAL_COPY_VALUE(&valptr, value);
                if (!1) {
-                       zval_copy_ctor(&valptr);
+                       zval_opt_copy_ctor(&valptr);
                }
                zend_vm_stack_push(&valptr TSRMLS_CC);
 
@@ -7845,7 +7845,7 @@ static int ZEND_FASTCALL  ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        if (opline->extended_value != IS_STRING) {
                ZVAL_COPY_VALUE(result, expr);
                if (!1) {
-                       zval_copy_ctor(result);
+                       zval_opt_copy_ctor(result);
                }
        }
 
@@ -7876,7 +7876,7 @@ cast_again:
                        } else {
                                ZVAL_COPY_VALUE(result, expr);
                                if (!1) {
-                                       zval_copy_ctor(result);
+                                       zval_opt_copy_ctor(result);
                                }
                        }
                        break;
@@ -8259,7 +8259,7 @@ static int ZEND_FASTCALL  ZEND_JMP_SET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        if (i_zend_is_true(value TSRMLS_CC)) {
                ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                if (!1) {
-                       zval_copy_ctor(EX_VAR(opline->result.var));
+                       zval_opt_copy_ctor(EX_VAR(opline->result.var));
                }
 
 #if DEBUG_ZEND>=2
@@ -8288,7 +8288,7 @@ static int ZEND_FASTCALL  ZEND_JMP_SET_VAR_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_
                } else {
                        ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                        if (!1) {
-                               zval_copy_ctor(EX_VAR(opline->result.var));
+                               zval_opt_copy_ctor(EX_VAR(opline->result.var));
                        }
                }
 
@@ -8314,7 +8314,7 @@ static int ZEND_FASTCALL  ZEND_QM_ASSIGN_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
 
        ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
        if (!1) {
-               zval_copy_ctor(EX_VAR(opline->result.var));
+               zval_opt_copy_ctor(EX_VAR(opline->result.var));
        }
 
        CHECK_EXCEPTION();
@@ -8335,7 +8335,7 @@ static int ZEND_FASTCALL  ZEND_QM_ASSIGN_VAR_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLE
        } else {
                ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                if (!1) {
-                       zval_copy_ctor(EX_VAR(opline->result.var));
+                       zval_opt_copy_ctor(EX_VAR(opline->result.var));
                }
        }
 
@@ -9249,7 +9249,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_
 
                                value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!1) {
@@ -9285,7 +9285,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!1) {
@@ -9315,7 +9315,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -9902,7 +9902,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
 
                                value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!1) {
@@ -9938,7 +9938,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!1) {
@@ -9968,7 +9968,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!1) {
@@ -10881,7 +10881,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
 
                                value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!1) {
@@ -10917,7 +10917,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!1) {
@@ -10947,7 +10947,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -11438,7 +11438,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER
 
                                value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!1) {
@@ -11474,7 +11474,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!1) {
@@ -11504,7 +11504,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -12088,7 +12088,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
 
                                value = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!1) {
@@ -12124,7 +12124,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!1) {
@@ -12154,7 +12154,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -12621,7 +12621,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                if (IS_VAR == IS_CONST || IS_VAR == IS_TMP_VAR) {
                        ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
                        if (IS_VAR != IS_TMP_VAR) {
-                               zval_copy_ctor(EX(return_value));
+                               zval_opt_copy_ctor(EX(return_value));
                        }
                        zval_ptr_dtor_nogc(free_op1.var);
                } else if (Z_ISREF_P(retval_ptr)) {
@@ -12630,7 +12630,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                } else {
                        ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
                        if (IS_VAR == IS_CV) {
-                               if (Z_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
+                               if (Z_OPT_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
                        }
                }
        }
@@ -12717,7 +12717,7 @@ static int ZEND_FASTCALL  ZEND_THROW_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* Not sure if a complete copy is what we want here */
        ZVAL_COPY_VALUE(&exception, value);
        if (!0) {
-               zval_copy_ctor(&exception);
+               zval_opt_copy_ctor(&exception);
        }
 
        zend_throw_exception_object(&exception TSRMLS_CC);
@@ -12799,7 +12799,7 @@ static int ZEND_FASTCALL  ZEND_SEND_VAR_NO_REF_SPEC_VAR_HANDLER(ZEND_OPCODE_HAND
                }
                ZVAL_COPY_VALUE(&val, varptr);
                if (!0) {
-                       zval_copy_ctor(&val);
+                       zval_opt_copy_ctor(&val);
                }
                zval_ptr_dtor_nogc(free_op1.var);
                zend_vm_stack_push(&val TSRMLS_CC);
@@ -12962,7 +12962,7 @@ static int ZEND_FASTCALL  ZEND_CAST_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        if (opline->extended_value != IS_STRING) {
                ZVAL_COPY_VALUE(result, expr);
                if (!0) {
-                       zval_copy_ctor(result);
+                       zval_opt_copy_ctor(result);
                }
        }
 
@@ -12993,7 +12993,7 @@ cast_again:
                        } else {
                                ZVAL_COPY_VALUE(result, expr);
                                if (!0) {
-                                       zval_copy_ctor(result);
+                                       zval_opt_copy_ctor(result);
                                }
                        }
                        break;
@@ -13488,7 +13488,7 @@ static int ZEND_FASTCALL  ZEND_JMP_SET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS
        if (i_zend_is_true(value TSRMLS_CC)) {
                ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                if (!0) {
-                       zval_copy_ctor(EX_VAR(opline->result.var));
+                       zval_opt_copy_ctor(EX_VAR(opline->result.var));
                }
                zval_ptr_dtor_nogc(free_op1.var);
 #if DEBUG_ZEND>=2
@@ -13517,7 +13517,7 @@ static int ZEND_FASTCALL  ZEND_JMP_SET_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_
                } else {
                        ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                        if (!0) {
-                               zval_copy_ctor(EX_VAR(opline->result.var));
+                               zval_opt_copy_ctor(EX_VAR(opline->result.var));
                        }
                }
                zval_ptr_dtor_nogc(free_op1.var);
@@ -13543,7 +13543,7 @@ static int ZEND_FASTCALL  ZEND_QM_ASSIGN_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
 
        ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
        if (!0) {
-               zval_copy_ctor(EX_VAR(opline->result.var));
+               zval_opt_copy_ctor(EX_VAR(opline->result.var));
        }
        zval_ptr_dtor_nogc(free_op1.var);
        CHECK_EXCEPTION();
@@ -13564,7 +13564,7 @@ static int ZEND_FASTCALL  ZEND_QM_ASSIGN_VAR_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLE
        } else {
                ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                if (!0) {
-                       zval_copy_ctor(EX_VAR(opline->result.var));
+                       zval_opt_copy_ctor(EX_VAR(opline->result.var));
                }
        }
 
@@ -13883,10 +13883,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(int (*b
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -14137,7 +14134,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_CONST(incdec_t
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -14236,7 +14233,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_CONST(incdec_
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -15003,17 +15000,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_DIM_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HAN
                value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
                variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
                if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-                       zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-                       if (zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC)) {
-                               if (RETURN_VALUE_USED(opline)) {
-                                       ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->str) + Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->offset, 1);
-                               }
-                       } else if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_NULL(EX_VAR(opline->result.var));
-                       }
-//??? instead of FREE_OP_VAR_PTR(free_op_data2);
-                       STR_RELEASE(old_str);
-                       efree(Z_STR_OFFSET_P(variable_ptr));
+                       zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
                } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
                        if (IS_TMP_FREE(free_op_data1)) {
                                zval_dtor(value);
@@ -15056,17 +15043,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER
        variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
 
        if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-               zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-               if (zend_assign_to_string_offset(variable_ptr, value, IS_CONST TSRMLS_CC)) {
-                       if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->str) + Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->offset, 1);
-                       }
-               } else if (RETURN_VALUE_USED(opline)) {
-                       ZVAL_NULL(EX_VAR(opline->result.var));
-               }
-//??? instead of if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}
-               STR_RELEASE(old_str);
-               efree(Z_STR_OFFSET_P(variable_ptr));
+               zend_assign_to_string_offset(variable_ptr, value, IS_CONST, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
        } else if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) {
                if (0) {
                        zval_dtor(value);
@@ -15949,7 +15926,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_
 
                                value = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -15986,7 +15963,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -16017,7 +15994,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -16348,10 +16325,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(int (*bin
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -16603,7 +16577,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_TMP(incdec_t i
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -16702,7 +16676,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_TMP(incdec_t
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -17291,17 +17265,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_DIM_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDL
                value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
                variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
                if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-                       zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-                       if (zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC)) {
-                               if (RETURN_VALUE_USED(opline)) {
-                                       ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->str) + Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->offset, 1);
-                               }
-                       } else if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_NULL(EX_VAR(opline->result.var));
-                       }
-//??? instead of FREE_OP_VAR_PTR(free_op_data2);
-                       STR_RELEASE(old_str);
-                       efree(Z_STR_OFFSET_P(variable_ptr));
+                       zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
                } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
                        if (IS_TMP_FREE(free_op_data1)) {
                                zval_dtor(value);
@@ -17344,17 +17308,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_A
        variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
 
        if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-               zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-               if (zend_assign_to_string_offset(variable_ptr, value, IS_TMP_VAR TSRMLS_CC)) {
-                       if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->str) + Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->offset, 1);
-                       }
-               } else if (RETURN_VALUE_USED(opline)) {
-                       ZVAL_NULL(EX_VAR(opline->result.var));
-               }
-//??? instead of if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}
-               STR_RELEASE(old_str);
-               efree(Z_STR_OFFSET_P(variable_ptr));
+               zend_assign_to_string_offset(variable_ptr, value, IS_TMP_VAR, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
        } else if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) {
                if (1) {
                        zval_dtor(value);
@@ -17999,7 +17953,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
 
                                value = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -18036,7 +17990,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -18067,7 +18021,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!1) {
@@ -18398,10 +18352,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(int (*bin
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -18653,7 +18604,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_VAR(incdec_t i
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -18752,7 +18703,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_VAR(incdec_t
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -19520,17 +19471,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_DIM_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDL
                value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
                variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
                if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-                       zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-                       if (zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC)) {
-                               if (RETURN_VALUE_USED(opline)) {
-                                       ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->str) + Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->offset, 1);
-                               }
-                       } else if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_NULL(EX_VAR(opline->result.var));
-                       }
-//??? instead of FREE_OP_VAR_PTR(free_op_data2);
-                       STR_RELEASE(old_str);
-                       efree(Z_STR_OFFSET_P(variable_ptr));
+                       zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
                } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
                        if (IS_TMP_FREE(free_op_data1)) {
                                zval_dtor(value);
@@ -19573,17 +19514,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_A
        variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
 
        if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-               zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-               if (zend_assign_to_string_offset(variable_ptr, value, IS_VAR TSRMLS_CC)) {
-                       if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->str) + Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->offset, 1);
-                       }
-               } else if (RETURN_VALUE_USED(opline)) {
-                       ZVAL_NULL(EX_VAR(opline->result.var));
-               }
-//??? instead of if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}
-               STR_RELEASE(old_str);
-               efree(Z_STR_OFFSET_P(variable_ptr));
+               zend_assign_to_string_offset(variable_ptr, value, IS_VAR, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
        } else if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) {
                if (0) {
                        zval_dtor(value);
@@ -20440,7 +20371,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
 
                                value = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -20477,7 +20408,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -20508,7 +20439,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -20564,10 +20495,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(int (*
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -21125,17 +21053,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HA
                value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
                variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
                if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-                       zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-                       if (zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC)) {
-                               if (RETURN_VALUE_USED(opline)) {
-                                       ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->str) + Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->offset, 1);
-                               }
-                       } else if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_NULL(EX_VAR(opline->result.var));
-                       }
-//??? instead of FREE_OP_VAR_PTR(free_op_data2);
-                       STR_RELEASE(old_str);
-                       efree(Z_STR_OFFSET_P(variable_ptr));
+                       zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
                } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
                        if (IS_TMP_FREE(free_op_data1)) {
                                zval_dtor(value);
@@ -21567,7 +21485,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER
 
                                value = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -21604,7 +21522,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -21635,7 +21553,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -21966,10 +21884,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CV(int (*bina
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -22220,7 +22135,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_CV(incdec_t in
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -22319,7 +22234,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_CV(incdec_t i
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -22907,17 +22822,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_DIM_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLE
                value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
                variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
                if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-                       zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-                       if (zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC)) {
-                               if (RETURN_VALUE_USED(opline)) {
-                                       ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->str) + Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->offset, 1);
-                               }
-                       } else if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_NULL(EX_VAR(opline->result.var));
-                       }
-//??? instead of FREE_OP_VAR_PTR(free_op_data2);
-                       STR_RELEASE(old_str);
-                       efree(Z_STR_OFFSET_P(variable_ptr));
+                       zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
                } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
                        if (IS_TMP_FREE(free_op_data1)) {
                                zval_dtor(value);
@@ -22960,17 +22865,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_AR
        variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
 
        if (IS_VAR == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-               zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-               if (zend_assign_to_string_offset(variable_ptr, value, IS_CV TSRMLS_CC)) {
-                       if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->str) + Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->offset, 1);
-                       }
-               } else if (RETURN_VALUE_USED(opline)) {
-                       ZVAL_NULL(EX_VAR(opline->result.var));
-               }
-//??? instead of if (free_op1.var) {zval_ptr_dtor_nogc(free_op1.var);}
-               STR_RELEASE(old_str);
-               efree(Z_STR_OFFSET_P(variable_ptr));
+               zend_assign_to_string_offset(variable_ptr, value, IS_CV, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
        } else if (IS_VAR == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) {
                if (0) {
                        zval_dtor(value);
@@ -23676,7 +23571,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
 
                                value = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1 TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -23713,7 +23608,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -23744,7 +23639,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -23880,10 +23775,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(int
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -24133,7 +24025,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_CONST(incde
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -24232,7 +24124,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_CONST(incd
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -25133,7 +25025,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL
 
                                value = NULL;
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -25169,7 +25061,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -25199,7 +25091,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -25254,10 +25146,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(int (*
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -25508,7 +25397,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_TMP(incdec_
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -25607,7 +25496,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_TMP(incdec
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -26422,7 +26311,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER
 
                                value = NULL;
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -26458,7 +26347,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -26488,7 +26377,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!1) {
@@ -26543,10 +26432,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(int (*
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -26797,7 +26683,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_VAR(incdec_
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -26896,7 +26782,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_VAR(incdec
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -27711,7 +27597,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER
 
                                value = NULL;
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -27747,7 +27633,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -27777,7 +27663,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -27833,10 +27719,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(int
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -28113,7 +27996,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND
 
                                value = NULL;
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -28149,7 +28032,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -28179,7 +28062,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -28234,10 +28117,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(int (*b
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -28487,7 +28367,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_CV(incdec_t
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -28586,7 +28466,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_CV(incdec_
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -29399,7 +29279,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_
 
                                value = NULL;
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -29435,7 +29315,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -29465,7 +29345,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -29913,7 +29793,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                if (IS_CV == IS_CONST || IS_CV == IS_TMP_VAR) {
                        ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
                        if (IS_CV != IS_TMP_VAR) {
-                               zval_copy_ctor(EX(return_value));
+                               zval_opt_copy_ctor(EX(return_value));
                        }
 
                } else if (Z_ISREF_P(retval_ptr)) {
@@ -29922,7 +29802,7 @@ static int ZEND_FASTCALL  ZEND_RETURN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
                } else {
                        ZVAL_COPY_VALUE(EX(return_value), retval_ptr);
                        if (IS_CV == IS_CV) {
-                               if (Z_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
+                               if (Z_OPT_REFCOUNTED_P(retval_ptr)) Z_ADDREF_P(retval_ptr);
                        }
                }
        }
@@ -30008,7 +29888,7 @@ static int ZEND_FASTCALL  ZEND_THROW_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        /* Not sure if a complete copy is what we want here */
        ZVAL_COPY_VALUE(&exception, value);
        if (!0) {
-               zval_copy_ctor(&exception);
+               zval_opt_copy_ctor(&exception);
        }
 
        zend_throw_exception_object(&exception TSRMLS_CC);
@@ -30090,7 +29970,7 @@ static int ZEND_FASTCALL  ZEND_SEND_VAR_NO_REF_SPEC_CV_HANDLER(ZEND_OPCODE_HANDL
                }
                ZVAL_COPY_VALUE(&val, varptr);
                if (!0) {
-                       zval_copy_ctor(&val);
+                       zval_opt_copy_ctor(&val);
                }
 
                zend_vm_stack_push(&val TSRMLS_CC);
@@ -30241,7 +30121,7 @@ static int ZEND_FASTCALL  ZEND_CAST_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        if (opline->extended_value != IS_STRING) {
                ZVAL_COPY_VALUE(result, expr);
                if (!0) {
-                       zval_copy_ctor(result);
+                       zval_opt_copy_ctor(result);
                }
        }
 
@@ -30272,7 +30152,7 @@ cast_again:
                        } else {
                                ZVAL_COPY_VALUE(result, expr);
                                if (!0) {
-                                       zval_copy_ctor(result);
+                                       zval_opt_copy_ctor(result);
                                }
                        }
                        break;
@@ -30628,7 +30508,7 @@ static int ZEND_FASTCALL  ZEND_JMP_SET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
        if (i_zend_is_true(value TSRMLS_CC)) {
                ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                if (!0) {
-                       zval_copy_ctor(EX_VAR(opline->result.var));
+                       zval_opt_copy_ctor(EX_VAR(opline->result.var));
                }
 
 #if DEBUG_ZEND>=2
@@ -30656,7 +30536,7 @@ static int ZEND_FASTCALL  ZEND_JMP_SET_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_A
                } else {
                        ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                        if (!0) {
-                               zval_copy_ctor(EX_VAR(opline->result.var));
+                               zval_opt_copy_ctor(EX_VAR(opline->result.var));
                        }
                }
 
@@ -30681,7 +30561,7 @@ static int ZEND_FASTCALL  ZEND_QM_ASSIGN_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
 
        ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
        if (!0) {
-               zval_copy_ctor(EX_VAR(opline->result.var));
+               zval_opt_copy_ctor(EX_VAR(opline->result.var));
        }
 
        CHECK_EXCEPTION();
@@ -30702,7 +30582,7 @@ static int ZEND_FASTCALL  ZEND_QM_ASSIGN_VAR_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER
        } else {
                ZVAL_COPY_VALUE(EX_VAR(opline->result.var), value);
                if (!0) {
-                       zval_copy_ctor(EX_VAR(opline->result.var));
+                       zval_opt_copy_ctor(EX_VAR(opline->result.var));
                }
        }
 
@@ -31020,10 +30900,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CONST(int (*bi
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -31273,7 +31150,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_CONST(incdec_t
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -31372,7 +31249,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_CONST(incdec_t
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -32133,17 +32010,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_DIM_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HAND
                value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
                variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
                if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-                       zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-                       if (zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC)) {
-                               if (RETURN_VALUE_USED(opline)) {
-                                       ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->str) + Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->offset, 1);
-                               }
-                       } else if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_NULL(EX_VAR(opline->result.var));
-                       }
-//??? instead of FREE_OP_VAR_PTR(free_op_data2);
-                       STR_RELEASE(old_str);
-                       efree(Z_STR_OFFSET_P(variable_ptr));
+                       zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
                } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
                        if (IS_TMP_FREE(free_op_data1)) {
                                zval_dtor(value);
@@ -32186,17 +32053,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_
        variable_ptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC);
 
        if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-               zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-               if (zend_assign_to_string_offset(variable_ptr, value, IS_CONST TSRMLS_CC)) {
-                       if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->str) + Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->offset, 1);
-                       }
-               } else if (RETURN_VALUE_USED(opline)) {
-                       ZVAL_NULL(EX_VAR(opline->result.var));
-               }
-//??? instead of
-               STR_RELEASE(old_str);
-               efree(Z_STR_OFFSET_P(variable_ptr));
+               zend_assign_to_string_offset(variable_ptr, value, IS_CONST, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
        } else if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) {
                if (0) {
                        zval_dtor(value);
@@ -32867,7 +32724,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
 
                                value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -32903,7 +32760,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -32933,7 +32790,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -33264,10 +33121,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_TMP(int (*bina
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -33518,7 +33372,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_TMP(incdec_t in
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -33617,7 +33471,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_TMP(incdec_t i
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -34200,17 +34054,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_DIM_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLE
                value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
                variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
                if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-                       zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-                       if (zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC)) {
-                               if (RETURN_VALUE_USED(opline)) {
-                                       ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->str) + Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->offset, 1);
-                               }
-                       } else if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_NULL(EX_VAR(opline->result.var));
-                       }
-//??? instead of FREE_OP_VAR_PTR(free_op_data2);
-                       STR_RELEASE(old_str);
-                       efree(Z_STR_OFFSET_P(variable_ptr));
+                       zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
                } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
                        if (IS_TMP_FREE(free_op_data1)) {
                                zval_dtor(value);
@@ -34253,17 +34097,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
        variable_ptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC);
 
        if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-               zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-               if (zend_assign_to_string_offset(variable_ptr, value, IS_TMP_VAR TSRMLS_CC)) {
-                       if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->str) + Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->offset, 1);
-                       }
-               } else if (RETURN_VALUE_USED(opline)) {
-                       ZVAL_NULL(EX_VAR(opline->result.var));
-               }
-//??? instead of
-               STR_RELEASE(old_str);
-               efree(Z_STR_OFFSET_P(variable_ptr));
+               zend_assign_to_string_offset(variable_ptr, value, IS_TMP_VAR, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
        } else if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) {
                if (1) {
                        zval_dtor(value);
@@ -34789,7 +34623,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
 
                                value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -34825,7 +34659,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -34855,7 +34689,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!1) {
@@ -35186,10 +35020,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_VAR(int (*bina
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -35440,7 +35271,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_VAR(incdec_t in
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -35539,7 +35370,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_VAR(incdec_t i
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -36301,17 +36132,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_DIM_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLE
                value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
                variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
                if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-                       zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-                       if (zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC)) {
-                               if (RETURN_VALUE_USED(opline)) {
-                                       ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->str) + Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->offset, 1);
-                               }
-                       } else if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_NULL(EX_VAR(opline->result.var));
-                       }
-//??? instead of FREE_OP_VAR_PTR(free_op_data2);
-                       STR_RELEASE(old_str);
-                       efree(Z_STR_OFFSET_P(variable_ptr));
+                       zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
                } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
                        if (IS_TMP_FREE(free_op_data1)) {
                                zval_dtor(value);
@@ -36354,17 +36175,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
        variable_ptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC);
 
        if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-               zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-               if (zend_assign_to_string_offset(variable_ptr, value, IS_VAR TSRMLS_CC)) {
-                       if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->str) + Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->offset, 1);
-                       }
-               } else if (RETURN_VALUE_USED(opline)) {
-                       ZVAL_NULL(EX_VAR(opline->result.var));
-               }
-//??? instead of
-               STR_RELEASE(old_str);
-               efree(Z_STR_OFFSET_P(variable_ptr));
+               zend_assign_to_string_offset(variable_ptr, value, IS_VAR, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
        } else if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) {
                if (0) {
                        zval_dtor(value);
@@ -37101,7 +36912,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
 
                                value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -37137,7 +36948,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -37167,7 +36978,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -37223,10 +37034,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(int (*b
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -37781,17 +37589,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HAN
                value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
                variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
                if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-                       zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-                       if (zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC)) {
-                               if (RETURN_VALUE_USED(opline)) {
-                                       ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->str) + Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->offset, 1);
-                               }
-                       } else if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_NULL(EX_VAR(opline->result.var));
-                       }
-//??? instead of FREE_OP_VAR_PTR(free_op_data2);
-                       STR_RELEASE(old_str);
-                       efree(Z_STR_OFFSET_P(variable_ptr));
+                       zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
                } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
                        if (IS_TMP_FREE(free_op_data1)) {
                                zval_dtor(value);
@@ -38091,7 +37889,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_
 
                                value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -38127,7 +37925,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -38157,7 +37955,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
@@ -38488,10 +38286,7 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CV(int (*binar
                zend_error_noreturn(E_ERROR, "Cannot use string offset as an object");
        }
 
-       if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
-               make_real_object(object TSRMLS_CC);
-       }
-       ZVAL_DEREF(object);
+       object = make_real_object(object TSRMLS_CC);
 
        value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
 
@@ -38741,7 +38536,7 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_CV(incdec_t inc
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -38840,7 +38635,7 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_CV(incdec_t in
                zend_error_noreturn(E_ERROR, "Cannot increment/decrement overloaded objects nor string offsets");
        }
 
-       make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
+       object = make_real_object(object TSRMLS_CC); /* this should modify object only if it's empty */
 
        if (UNEXPECTED(Z_TYPE_P(object) != IS_OBJECT)) {
                zend_error(E_WARNING, "Attempt to increment/decrement property of non-object");
@@ -39422,17 +39217,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_DIM_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER
                value = get_zval_ptr((opline+1)->op1_type, &(opline+1)->op1, execute_data, &free_op_data1, BP_VAR_R);
                variable_ptr = _get_zval_ptr_ptr_var((opline+1)->op2.var, execute_data, &free_op_data2 TSRMLS_CC);
                if (UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-                       zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-                       if (zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type TSRMLS_CC)) {
-                               if (RETURN_VALUE_USED(opline)) {
-                                       ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->str) + Z_STR_OFFSET_P(EX_VAR((opline+1)->op2.var))->offset, 1);
-                               }
-                       } else if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_NULL(EX_VAR(opline->result.var));
-                       }
-//??? instead of FREE_OP_VAR_PTR(free_op_data2);
-                       STR_RELEASE(old_str);
-                       efree(Z_STR_OFFSET_P(variable_ptr));
+                       zend_assign_to_string_offset(variable_ptr, value, (opline+1)->op1_type, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
                } else if (UNEXPECTED(variable_ptr == &EG(error_zval))) {
                        if (IS_TMP_FREE(free_op_data1)) {
                                zval_dtor(value);
@@ -39475,17 +39260,7 @@ static int ZEND_FASTCALL  ZEND_ASSIGN_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
        variable_ptr = _get_zval_ptr_cv_BP_VAR_W(execute_data, opline->op1.var TSRMLS_CC);
 
        if (IS_CV == IS_VAR && UNEXPECTED(Z_TYPE_P(variable_ptr) == IS_STR_OFFSET)) {
-               zend_string *old_str = Z_STR_P(Z_STR_OFFSET_P(variable_ptr)->str);
-               if (zend_assign_to_string_offset(variable_ptr, value, IS_CV TSRMLS_CC)) {
-                       if (RETURN_VALUE_USED(opline)) {
-                               ZVAL_STRINGL(EX_VAR(opline->result.var), Z_STRVAL_P(Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->str) + Z_STR_OFFSET_P(EX_VAR(opline->op1.var))->offset, 1);
-                       }
-               } else if (RETURN_VALUE_USED(opline)) {
-                       ZVAL_NULL(EX_VAR(opline->result.var));
-               }
-//??? instead of
-               STR_RELEASE(old_str);
-               efree(Z_STR_OFFSET_P(variable_ptr));
+               zend_assign_to_string_offset(variable_ptr, value, IS_CV, (RETURN_VALUE_USED(opline) ? EX_VAR(opline->result.var) : NULL) TSRMLS_CC);
        } else if (IS_CV == IS_VAR && UNEXPECTED(variable_ptr == &EG(error_zval))) {
                if (0) {
                        zval_dtor(value);
@@ -40071,7 +39846,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
 
                                value = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var TSRMLS_CC);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -40107,7 +39882,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
                        ) {
 //???                          INIT_PZVAL_COPY(copy, value);
                                ZVAL_COPY_VALUE(&generator->value, value);
-                               if (Z_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
+                               if (Z_OPT_REFCOUNTED(generator->value)) Z_SET_REFCOUNT(generator->value, 1);
 
                                /* Temporary variables don't need ctor copying */
                                if (!0) {
@@ -40137,7 +39912,7 @@ static int ZEND_FASTCALL  ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
                ) {
 //???                  INIT_PZVAL_COPY(copy, key);
                        ZVAL_COPY_VALUE(&generator->key, key);
-                       if (Z_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
+                       if (Z_OPT_REFCOUNTED(generator->key)) Z_SET_REFCOUNT(generator->key, 1);
 
                        /* Temporary variables don't need ctor copying */
                        if (!0) {
index e774a7371b3c80e044e267cb386b4ec70334f181..b38dc6dcebc37d62e3d81073070c239c3e4c8c64 100644 (file)
@@ -832,6 +832,10 @@ PHP_FUNCTION(end)
                        RETURN_FALSE;
                }
 
+               if (Z_TYPE_P(entry) == IS_INDIRECT) {
+                       entry = Z_INDIRECT_P(entry);
+               }
+
                RETURN_ZVAL_FAST(entry);
        }
 }
@@ -855,6 +859,10 @@ PHP_FUNCTION(prev)
                        RETURN_FALSE;
                }
 
+               if (Z_TYPE_P(entry) == IS_INDIRECT) {
+                       entry = Z_INDIRECT_P(entry);
+               }
+
                RETURN_ZVAL_FAST(entry);
        }
 }
@@ -878,6 +886,10 @@ PHP_FUNCTION(next)
                        RETURN_FALSE;
                }
 
+               if (Z_TYPE_P(entry) == IS_INDIRECT) {
+                       entry = Z_INDIRECT_P(entry);
+               }
+
                RETURN_ZVAL_FAST(entry);
        }
 }
@@ -901,6 +913,10 @@ PHP_FUNCTION(reset)
                        RETURN_FALSE;
                }
 
+               if (Z_TYPE_P(entry) == IS_INDIRECT) {
+                       entry = Z_INDIRECT_P(entry);
+               }
+
                RETURN_ZVAL_FAST(entry);
        }
 }
@@ -921,6 +937,10 @@ PHP_FUNCTION(current)
                RETURN_FALSE;
        }
 
+       if (Z_TYPE_P(entry) == IS_INDIRECT) {
+               entry = Z_INDIRECT_P(entry);
+       }
+
        RETURN_ZVAL_FAST(entry);
 }
 /* }}} */