]> granicus.if.org Git - php/commitdiff
Refactored GC (incomplete)
authorDmitry Stogov <dmitry@zend.com>
Wed, 19 Mar 2014 13:00:28 +0000 (17:00 +0400)
committerDmitry Stogov <dmitry@zend.com>
Wed, 19 Mar 2014 13:00:28 +0000 (17:00 +0400)
27 files changed:
Zend/zend.h
Zend/zend_closures.c
Zend/zend_execute.c
Zend/zend_execute.h
Zend/zend_gc.c
Zend/zend_gc.h
Zend/zend_generators.c
Zend/zend_objects.c
Zend/zend_objects_API.c
Zend/zend_objects_API.h
Zend/zend_operators.c
Zend/zend_string.h
Zend/zend_types.h
Zend/zend_variables.c
Zend/zend_variables.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/date/php_date.c
ext/reflection/php_reflection.c
ext/spl/spl_array.c
ext/spl/spl_directory.c
ext/spl/spl_dllist.c
ext/spl/spl_fixedarray.c
ext/spl/spl_heap.c
ext/spl/spl_iterators.c
ext/spl/spl_observer.c
ext/standard/array.c

index 261a77bd9a57dc9290a8009da3f8a1b11a345900..90cf94d8f29820ed49f150e15701d153356dad73 100644 (file)
@@ -681,6 +681,16 @@ END_EXTERN_C()
                zval_copy_ctor(__z1);                                                   \
        } while (0)
 
+#define ZVAL_UNREF(z) do {                                                             \
+               zval *_z = (z);                                                                 \
+               zend_reference *ref;                                                    \
+               ZEND_ASSERT(Z_ISREF_P(_z));                                             \
+               ref = Z_REF_P(_z);                                                              \
+               ZVAL_COPY_VALUE(_z, &ref->val);                                 \
+               GC_REMOVE_FROM_BUFFER(ref);                                             \
+               efree(ref);                                                                             \
+       } while (0)
+
 // TODO: invalud ???
 #define INIT_PZVAL_COPY(z, v)                                                  \
        do {                                                                                            \
@@ -720,9 +730,7 @@ END_EXTERN_C()
                zval *__zv = (zv);                                                              \
                if (Z_ISREF_P(__zv)) {                                                  \
                        if (Z_REFCOUNT_P(__zv) == 1) {                          \
-                               zend_reference *ref = Z_REF_P(__zv);    \
-                               ZVAL_COPY_VALUE(__zv, &ref->val);               \
-                               efree(ref);                                                             \
+                               ZVAL_UNREF(__zv);                                               \
                        } else {                                                                        \
                                zval *ref = Z_REFVAL_P(__zv);                   \
                                Z_DELREF_P(__zv);                                               \
index 8f60e670e58ebbe5ee254716f5716c41466ffce2..61808927f1d44106c4dbedc2f238f474de34044b 100644 (file)
@@ -242,6 +242,7 @@ static void zend_closure_free_storage(zend_object *object TSRMLS_DC) /* {{{ */
                zval_ptr_dtor(&closure->this_ptr);
        }
 
+       GC_REMOVE_FROM_BUFFER(closure);
        efree(closure);
 }
 /* }}} */
index 517681704190096ae1edc2ed964dbe184b7dd3c5..12c7625744d45e82b0824d35df9885456aebd94c 100644 (file)
@@ -96,9 +96,7 @@ 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));
-                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                        zval_dtor(z);
-                       efree(z);
                }
        }
 }
@@ -911,11 +909,10 @@ static inline zval* zend_assign_tmp_to_variable(zval *variable_ptr, zval *value
                GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
                ZVAL_COPY_VALUE(variable_ptr, value);
        } else {
-               zval garbage;
+               zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
 
-               ZVAL_COPY_VALUE(&garbage, variable_ptr);
                ZVAL_COPY_VALUE(variable_ptr, value);
-               _zval_dtor_func(&garbage ZEND_FILE_LINE_CC);
+               _zval_dtor_func(garbage ZEND_FILE_LINE_CC);
        }
        return variable_ptr;
 }
@@ -946,21 +943,20 @@ static inline zval* zend_assign_const_to_variable(zval *variable_ptr, zval *valu
                        zval_copy_ctor(variable_ptr);
                }
        } else {
-               zval garbage;
+               zend_refcounted *garbage = Z_COUNTED_P(variable_ptr);
 
-               ZVAL_COPY_VALUE(&garbage, variable_ptr);
                ZVAL_COPY_VALUE(variable_ptr, value);
                if (Z_REFCOUNTED_P(value)) {
                        zval_copy_ctor(variable_ptr);
                }
-               _zval_dtor_func(&garbage ZEND_FILE_LINE_CC);
+               _zval_dtor_func(garbage ZEND_FILE_LINE_CC);
        }
        return variable_ptr;
 }
 
 static inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value TSRMLS_DC)
 {
-       zval garbage;
+       zend_refcounted *garbage;
        int is_ref = 0;
 
        if (EXPECTED(!Z_REFCOUNTED_P(variable_ptr))) {  
@@ -982,7 +978,7 @@ static inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value TSRM
                Z_OBJ_HANDLER_P(variable_ptr, set)(variable_ptr, value TSRMLS_CC);
        } else if (EXPECTED(variable_ptr != value)) {
                if (Z_REFCOUNT_P(variable_ptr)==1) {
-                       ZVAL_COPY_VALUE(&garbage, variable_ptr);
+                       garbage = Z_COUNTED_P(variable_ptr);
                        if (EXPECTED(!Z_ISREF_P(value))) {
                                if (!is_ref) {
                                        ZVAL_COPY(variable_ptr, value);
@@ -992,15 +988,13 @@ static inline zval* zend_assign_to_variable(zval *variable_ptr, zval *value TSRM
                        } else {
                                if (Z_REFCOUNT_P(value) == 1) {
 //??? auto dereferencing
-                                       zend_reference *ref = Z_REF_P(value);
-                                       ZVAL_COPY_VALUE(value, Z_REFVAL_P(value));
+                                       ZVAL_UNREF(value);
                                        ZVAL_COPY(variable_ptr, value);
-                                       efree(ref);
                                } else {
                                        ZVAL_DUP(variable_ptr, Z_REFVAL_P(value));
                                }
                        }                               
-                       _zval_dtor_func(&garbage ZEND_FILE_LINE_CC);
+                       _zval_dtor_func(garbage ZEND_FILE_LINE_CC);
                } else { /* we need to split */
                        Z_DELREF_P(variable_ptr);
                        GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr);
@@ -1015,10 +1009,8 @@ assign_simple:
 assign_ref:
                                if (Z_REFCOUNT_P(value) == 1) {
 //??? auto dereferencing
-                                       zend_reference *ref = Z_REF_P(value);
-                                       ZVAL_COPY_VALUE(value, Z_REFVAL_P(value));
+                                       ZVAL_UNREF(value);
                                        ZVAL_COPY(variable_ptr, value);
-                                       efree(ref);
                                } else {
                                        ZVAL_DUP(variable_ptr, Z_REFVAL_P(value));
                                }
index 5c9651feb800ab4ce9ce7dfe8f39e45e83d991ce..10bc3f8c2377e7d52d852107a1d6a630cedbbc80 100644 (file)
@@ -79,8 +79,7 @@ static zend_always_inline void i_zval_ptr_dtor(zval *zval_ptr ZEND_FILE_LINE_DC
            (type != IS_STRING || !IS_INTERNED(Z_STR_P(zval_ptr)))) {
                if (!Z_DELREF_P(zval_ptr)) {
                        ZEND_ASSERT(zval_ptr != &EG(uninitialized_zval));
-                       GC_REMOVE_ZVAL_FROM_BUFFER(zval_ptr);
-                       _zval_dtor_func_for_ptr(zval_ptr ZEND_FILE_LINE_CC);
+                       _zval_dtor_func_for_ptr(Z_COUNTED_P(zval_ptr) ZEND_FILE_LINE_CC);
                } else {
                        if (Z_REFCOUNT_P(zval_ptr) == 1 && Z_TYPE_P(zval_ptr) == IS_REFERENCE) {
                                /* convert reference to regular value */
@@ -98,8 +97,7 @@ static zend_always_inline void i_zval_ptr_dtor_nogc(zval *zval_ptr ZEND_FILE_LIN
        if (Z_REFCOUNTED_P(zval_ptr)) {
                if (!Z_DELREF_P(zval_ptr)) {
                        ZEND_ASSERT(zval_ptr != &EG(uninitialized_zval));
-                       GC_REMOVE_ZVAL_FROM_BUFFER(zval_ptr);
-                       _zval_dtor_func_for_ptr(zval_ptr ZEND_FILE_LINE_CC);
+                       _zval_dtor_func_for_ptr(Z_COUNTED_P(zval_ptr) ZEND_FILE_LINE_CC);
                } else {
                        if (Z_REFCOUNT_P(zval_ptr) == 1 && Z_TYPE_P(zval_ptr) == IS_REFERENCE) {
                                /* convert reference to regular value */
index 4b31f979da464be1ca87d79752be9045180e84d1..57f9455fd1c2c2e79cb7556792f75427a33caa33 100644 (file)
@@ -30,10 +30,10 @@ ZEND_API int gc_globals_id;
 ZEND_API zend_gc_globals gc_globals;
 #endif
 
-#define GC_REMOVE_FROM_BUFFER(current) \
-       gc_remove_from_buffer((current) TSRMLS_CC)
+#define GC_REMOVE_FROM_ROOTS(current) \
+       gc_remove_from_roots((current) TSRMLS_CC)
 
-static zend_always_inline void gc_remove_from_buffer(gc_root_buffer *root TSRMLS_DC)
+static zend_always_inline void gc_remove_from_roots(gc_root_buffer *root TSRMLS_DC)
 {
        root->next->prev = root->prev;
        root->prev->next = root->next;
@@ -60,10 +60,13 @@ static void gc_globals_ctor_ex(zend_gc_globals *gc_globals TSRMLS_DC)
        gc_globals->roots.next = &gc_globals->roots;
        gc_globals->roots.prev = &gc_globals->roots;
        gc_globals->unused = NULL;
-       gc_globals->zval_to_free = NULL;
-       gc_globals->free_list = NULL;
+//???  gc_globals->zval_to_free = NULL;
+//???  gc_globals->free_list = NULL;
        gc_globals->next_to_free = NULL;
 
+       gc_globals->to_free.next = &gc_globals->to_free;
+       gc_globals->to_free.prev = &gc_globals->to_free;
+
        gc_globals->gc_runs = 0;
        gc_globals->collected = 0;
 
@@ -71,13 +74,9 @@ static void gc_globals_ctor_ex(zend_gc_globals *gc_globals TSRMLS_DC)
        gc_globals->root_buf_length = 0;
        gc_globals->root_buf_peak = 0;
        gc_globals->zval_possible_root = 0;
-       gc_globals->zobj_possible_root = 0;
        gc_globals->zval_buffered = 0;
-       gc_globals->zobj_buffered = 0;
        gc_globals->zval_remove_from_buffer = 0;
-       gc_globals->zobj_remove_from_buffer = 0;
        gc_globals->zval_marked_grey = 0;
-       gc_globals->zobj_marked_grey = 0;
 #endif
 }
 
@@ -106,23 +105,22 @@ ZEND_API void gc_reset(TSRMLS_D)
        GC_G(root_buf_length) = 0;
        GC_G(root_buf_peak) = 0;
        GC_G(zval_possible_root) = 0;
-       GC_G(zobj_possible_root) = 0;
        GC_G(zval_buffered) = 0;
-       GC_G(zobj_buffered) = 0;
        GC_G(zval_remove_from_buffer) = 0;
-       GC_G(zobj_remove_from_buffer) = 0;
        GC_G(zval_marked_grey) = 0;
-       GC_G(zobj_marked_grey) = 0;
 #endif
 
        GC_G(roots).next = &GC_G(roots);
        GC_G(roots).prev = &GC_G(roots);
 
+       GC_G(to_free).next = &GC_G(to_free);
+       GC_G(to_free).prev = &GC_G(to_free);
+
        if (GC_G(buf)) {
                GC_G(unused) = NULL;
                GC_G(first_unused) = GC_G(buf) + 1;
 
-               GC_G(zval_to_free) = NULL;
+//???          GC_G(zval_to_free) = NULL;
        } else {
                GC_G(unused) = NULL;
                GC_G(first_unused) = NULL;
@@ -139,12 +137,17 @@ ZEND_API void gc_init(TSRMLS_D)
        }
 }
 
-ZEND_API void gc_zval_possible_root(zend_refcounted *ref TSRMLS_DC)
+ZEND_API void gc_possible_root(zend_refcounted *ref TSRMLS_DC)
 {
-       if (UNEXPECTED(GC_G(free_list) != NULL &&
-                      GC_ADDRESS(ref->u.v.buffer) &&
-                          GC_GET_COLOR(ref->u.v.buffer) == GC_BLACK &&
-                          GC_ADDRESS(ref->u.v.buffer) >= GC_G(last_unused) - GC_G(buf))) {
+       /* don't colect references (collext arrays and objects) */
+//???  if (ref->u.v.type == IS_REFERENCE) {
+//???          ZEND_ASSERT(Z_REFCOUNTED(((zend_reference*)ref)->val));
+//???          ref = Z_COUNTED(((zend_reference*)ref)->val);
+//???  }
+
+       if (UNEXPECTED(GC_ADDRESS(ref->u.v.gc_info) &&
+                          GC_GET_COLOR(ref->u.v.gc_info) == GC_BLACK &&
+                          GC_ADDRESS(ref->u.v.gc_info) >= GC_G(last_unused) - GC_G(buf))) {
                /* The given zval is a garbage that is going to be deleted by
                 * currently running GC */
                return;
@@ -152,10 +155,10 @@ ZEND_API void gc_zval_possible_root(zend_refcounted *ref TSRMLS_DC)
 
        GC_BENCH_INC(zval_possible_root);
 
-       if (GC_GET_COLOR(ref->u.v.buffer) != GC_PURPLE) {
-               GC_SET_PURPLE(ref->u.v.buffer);
+       if (GC_GET_COLOR(ref->u.v.gc_info) != GC_PURPLE) {
+               GC_SET_PURPLE(ref->u.v.gc_info);
 
-               if (!GC_ADDRESS(ref->u.v.buffer)) {
+               if (!GC_ADDRESS(ref->u.v.gc_info)) {
                        gc_root_buffer *newRoot = GC_G(unused);
 
                        if (newRoot) {
@@ -165,7 +168,7 @@ ZEND_API void gc_zval_possible_root(zend_refcounted *ref TSRMLS_DC)
                                GC_G(first_unused)++;
                        } else {
                                if (!GC_G(gc_enabled)) {
-                                       GC_SET_BLACK(ref->u.v.buffer);
+                                       GC_SET_BLACK(ref->u.v.gc_info);
                                        return;
                                }
                                ref->refcount++;
@@ -175,7 +178,7 @@ ZEND_API void gc_zval_possible_root(zend_refcounted *ref TSRMLS_DC)
                                if (!newRoot) {
                                        return;
                                }
-                               GC_SET_PURPLE(ref->u.v.buffer);
+                               GC_SET_PURPLE(ref->u.v.gc_info);
                                GC_G(unused) = newRoot->prev;
                        }
 
@@ -184,7 +187,7 @@ ZEND_API void gc_zval_possible_root(zend_refcounted *ref TSRMLS_DC)
                        GC_G(roots).next->prev = newRoot;
                        GC_G(roots).next = newRoot;
 
-                       GC_SET_ADDRESS(ref->u.v.buffer, newRoot - GC_G(buf));
+                       GC_SET_ADDRESS(ref->u.v.gc_info, newRoot - GC_G(buf));
 
                        newRoot->ref = ref;
 
@@ -195,87 +198,27 @@ ZEND_API void gc_zval_possible_root(zend_refcounted *ref TSRMLS_DC)
        }
 }
 
-//???
-#if 0
-ZEND_API void gc_zobj_possible_root(zval *zv TSRMLS_DC)
+ZEND_API void gc_remove_from_buffer(zend_refcounted *ref TSRMLS_DC)
 {
-       struct _store_object *obj;
-
-       if (UNEXPECTED(Z_OBJ_HT_P(zv)->get_gc == NULL ||
-           EG(objects_store).object_buckets == NULL)) {
-               return;
-       }
-
-       GC_BENCH_INC(zobj_possible_root);
-
-       obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj;
-       if (GC_GET_COLOR(obj->buffered) != GC_PURPLE) {
-               GC_SET_PURPLE(obj->buffered);
-               if (!GC_ADDRESS(obj->buffered)) {
-                       gc_root_buffer *newRoot = GC_G(unused);
-
-                       if (newRoot) {
-                               GC_G(unused) = newRoot->prev;
-                       } else if (GC_G(first_unused) != GC_G(last_unused)) {
-                               newRoot = GC_G(first_unused);
-                               GC_G(first_unused)++;
-                       } else {
-                               if (!GC_G(gc_enabled)) {
-                                       GC_ZVAL_SET_BLACK(zv);
-                                       return;
-                               }
-                               zv->refcount__gc++;
-                               gc_collect_cycles(TSRMLS_C);
-                               zv->refcount__gc--;
-                               newRoot = GC_G(unused);
-                               if (!newRoot) {
-                                       return;
-                               }
-                               obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(zv)].bucket.obj;
-                               GC_SET_PURPLE(obj->buffered);
-                               GC_G(unused) = newRoot->prev;
-                       }
-
-                       newRoot->next = GC_G(roots).next;
-                       newRoot->prev = &GC_G(roots);
-                       GC_G(roots).next->prev = newRoot;
-                       GC_G(roots).next = newRoot;
-
-                       GC_SET_ADDRESS(obj->buffered, newRoot);
-
-                       newRoot->handle = Z_OBJ_HANDLE_P(zv);
-                       newRoot->u.handlers = Z_OBJ_HT_P(zv);
+       gc_root_buffer *root;
 
-                       GC_BENCH_INC(zobj_buffered);
-                       GC_BENCH_INC(root_buf_length);
-                       GC_BENCH_PEAK(root_buf_peak, root_buf_length);
-               }
-       }
-}
-#endif
-
-ZEND_API void gc_remove_zval_from_buffer(zend_refcounted *ref TSRMLS_DC)
-{
-//???  gc_root_buffer* root_buffer = GC_ADDRESS(ref->u.v.buffer);
-
-       if (UNEXPECTED(GC_G(free_list) != NULL &&
-                          GC_GET_COLOR(ref->u.v.buffer) == GC_BLACK &&
-                          GC_ADDRESS(ref->u.v.buffer) >= GC_G(last_unused) - GC_G(buf))) {
+       if (UNEXPECTED(GC_GET_COLOR(ref->u.v.gc_info) == GC_BLACK &&
+                          GC_ADDRESS(ref->u.v.gc_info) >= GC_G(last_unused) - GC_G(buf))) {
                /* The given zval is a garbage that is going to be deleted by
                 * currently running GC */
-//???          if (GC_G(next_to_free) == (zval_gc_info*)zv) {
-//???                  GC_G(next_to_free) = ((zval_gc_info*)zv)->u.next;
-//???          }
                return;
        }
+//???
+       root = GC_G(buf) + GC_ADDRESS(ref->u.v.gc_info);
+       if (GC_G(next_to_free) == root) {
+               GC_G(next_to_free) = root->next;
+       }
        GC_BENCH_INC(zval_remove_from_buffer);
-       GC_REMOVE_FROM_BUFFER(GC_G(buf) + GC_ADDRESS(ref->u.v.buffer));
-       ref->u.v.buffer = 0;
+       GC_REMOVE_FROM_ROOTS(root);
+       ref->u.v.gc_info = 0;
 }
 
-//???
-#if 0
-static void zval_scan_black(zval *pz TSRMLS_DC)
+static void gc_scan_black(zend_refcounted *ref TSRMLS_DC)
 {
        HashTable *ht;
        uint idx;
@@ -283,212 +226,156 @@ static void zval_scan_black(zval *pz TSRMLS_DC)
 
 tail_call:
        ht = NULL;
-       GC_ZVAL_SET_BLACK(pz);
+       GC_SET_BLACK(ref->u.v.gc_info);
 
-       if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
+       if (ref->u.v.type == IS_OBJECT && EG(objects_store).object_buckets) {
                zend_object_get_gc_t get_gc;
-               struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
+               zend_object *obj = (zend_object*)ref;
 
-               obj->refcount++;
-               if (GC_GET_COLOR(obj->buffered) != GC_BLACK) {
-                       GC_SET_BLACK(obj->buffered);
-                       if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                    (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
-                               int i, n;
-                               zval **table;
-                               HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
+               if (EXPECTED(IS_VALID(EG(objects_store).object_buckets[obj->handle]) &&
+                            (get_gc = obj->handlers->get_gc) != NULL)) {
+                       int i, n;
+                       zval *table;
+                       zval tmp;
+                       HashTable *props;
 
-                               while (n > 0 && !table[n-1]) n--;
-                               for (i = 0; i < n; i++) {
-                                       if (table[i]) {
-                                               pz = table[i];
-                                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                                       pz->refcount__gc++;
-                                               }
-                                               if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
-                                                       if (!props && i == n - 1) {
-                                                               goto tail_call;
-                                                       } else {
-                                                               zval_scan_black(pz TSRMLS_CC);
-                                                       }
+                       ZVAL_OBJ(&tmp, obj);
+                       props = get_gc(&tmp, &table, &n TSRMLS_CC);
+                       while (n > 0 && !Z_REFCOUNTED(table[n-1])) n--;
+                       for (i = 0; i < n; i++) {
+                               if (Z_REFCOUNTED(table[i])) {
+                                       ref = Z_COUNTED(table[i]);
+                                       if (ref->u.v.type != IS_ARRAY || (zend_array*)ref != &EG(symbol_table)) {
+                                               ref->refcount++;
+                                       }
+                                       if (GC_GET_COLOR(ref->u.v.gc_info) != GC_BLACK) {
+                                               if (!props && i == n - 1) {
+                                                       goto tail_call;
+                                               } else {
+                                                       gc_scan_black(ref TSRMLS_CC);
                                                }
                                        }
                                }
-                               if (!props) {
-                                       return;
-                               }
-                               ht = props;
                        }
+                       if (!props) {
+                               return;
+                       }
+                       ht = props;
                }
-       } else if (Z_TYPE_P(pz) == IS_ARRAY) {
-               if (Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                       ht = Z_ARRVAL_P(pz);
+       } else if (ref->u.v.type == IS_ARRAY) {
+               if ((zend_array*)ref != &EG(symbol_table)) {
+                       ht = &((zend_array*)ref)->ht;
+               }
+       } else if (ref->u.v.type == IS_REFERENCE) {
+               if (Z_REFCOUNTED(((zend_reference*)ref)->val)) {
+                       if (UNEXPECTED(!EG(objects_store).object_buckets) &&
+                           Z_TYPE(((zend_reference*)ref)->val) == IS_OBJECT) {
+                               return;
+                       }
+                       ref = Z_COUNTED(((zend_reference*)ref)->val);
+                       if (ref->u.v.type != IS_ARRAY || (zend_array*)ref != &EG(symbol_table)) {
+                               ref->refcount++;
+                       }
+                       if (GC_GET_COLOR(ref->u.v.gc_info) != GC_BLACK) {
+                               goto tail_call;
+                       }
                }
+               return;
        }
        if (!ht) return;
        for (idx = 0; idx < ht->nNumUsed; idx++) {
                p = ht->arData + idx;
-               if (!p->xData) continue;
-               pz = (zval*)p->xData;
-               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                       pz->refcount__gc++;
+               if (!Z_REFCOUNTED(p->val)) continue;
+               ref = Z_COUNTED(p->val);
+               if (ref->u.v.type != IS_ARRAY || (zend_array*)ref != &EG(symbol_table)) {
+                       ref->refcount++;
                }
-               if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
+               if (GC_GET_COLOR(ref->u.v.gc_info) != GC_BLACK) {
                        if (idx == ht->nNumUsed-1) {
                                goto tail_call;
                        } else {
-                               zval_scan_black(pz TSRMLS_CC);
+                               gc_scan_black(ref TSRMLS_CC);
                        }
                }
        }
 }
 
-static void zobj_scan_black(struct _store_object *obj, zval *pz TSRMLS_DC)
-{
-       uint idx;
-       Bucket *p;
-       zend_object_get_gc_t get_gc;
-
-       GC_SET_BLACK(obj->buffered);
-       if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                    (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
-               int i, n;
-               zval **table;
-               HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
-
-               for (i = 0; i < n; i++) {
-                       if (table[i]) {
-                               pz = table[i];
-                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                       pz->refcount__gc++;
-                               }
-                               if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
-                                       zval_scan_black(pz TSRMLS_CC);
-                               }
-                       }
-               }
-               if (!props) {
-                       return;
-               }
-               for (idx = 0; idx < props->nNumUsed; idx++) {
-                       p = props->arData + idx;
-                       if (!p->xData) continue;
-                       pz = (zval*)p->xData;
-                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                               pz->refcount__gc++;
-                       }
-                       if (GC_ZVAL_GET_COLOR(pz) != GC_BLACK) {
-                               zval_scan_black(pz TSRMLS_CC);
-                       }
-               }
-       }
-}
-
-static void zval_mark_grey(zval *pz TSRMLS_DC)
+static void gc_mark_grey(zend_refcounted *ref TSRMLS_DC)
 {
     HashTable *ht;
     uint idx;
        Bucket *p;
 
 tail_call:
-       if (GC_ZVAL_GET_COLOR(pz) != GC_GREY) {
+       if (GC_GET_COLOR(ref->u.v.gc_info) != GC_GREY) {
                ht = NULL;
                GC_BENCH_INC(zval_marked_grey);
-               GC_ZVAL_SET_COLOR(pz, GC_GREY);
+               GC_SET_COLOR(ref->u.v.gc_info, GC_GREY);
 
-               if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
+               if (ref->u.v.type == IS_OBJECT && EG(objects_store).object_buckets) {
                        zend_object_get_gc_t get_gc;
-                       struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
-
-                       obj->refcount--;
-                       if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
-                               GC_BENCH_INC(zobj_marked_grey);
-                               GC_SET_COLOR(obj->buffered, GC_GREY);
-                               if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                            (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
-                                       int i, n;
-                                       zval **table;
-                                       HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
+                       zend_object *obj = (zend_object*)ref;
 
-                                       while (n > 0 && !table[n-1]) n--;
-                                       for (i = 0; i < n; i++) {
-                                               if (table[i]) {
-                                                       pz = table[i];
-                                                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                                               pz->refcount__gc--;
-                                                       }
-                                                       if (!props && i == n - 1) {
-                                                               goto tail_call;
-                                                       } else {
-                                                               zval_mark_grey(pz TSRMLS_CC);
-                                                       }
+                       if (EXPECTED(IS_VALID(EG(objects_store).object_buckets[obj->handle]) &&
+                            (get_gc = obj->handlers->get_gc) != NULL)) {
+                               int i, n;
+                               zval *table;
+                               zval tmp;
+
+                               ZVAL_OBJ(&tmp, obj);
+                               HashTable *props = get_gc(&tmp, &table, &n TSRMLS_CC);
+
+                               while (n > 0 && !Z_REFCOUNTED(table[n-1])) n--;
+                               for (i = 0; i < n; i++) {
+                                       if (Z_REFCOUNTED(table[i])) {
+                                               ref = Z_COUNTED(table[i]);
+                                               if (ref->u.v.type != IS_ARRAY || ((zend_array*)ref) != &EG(symbol_table)) {
+                                                       ref->refcount--;
+                                               }
+                                               if (!props && i == n - 1) {
+                                                       goto tail_call;
+                                               } else {
+                                                       gc_mark_grey(ref TSRMLS_CC);
                                                }
                                        }
-                                       if (!props) {
-                                               return;
-                                       }
-                                       ht = props;
                                }
+                               if (!props) {
+                                       return;
+                               }
+                               ht = props;
                        }
-               } else if (Z_TYPE_P(pz) == IS_ARRAY) {
-                       if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
-                               GC_ZVAL_SET_BLACK(pz);
+               } else if (ref->u.v.type == IS_ARRAY) {
+                       if (((zend_array*)ref) == &EG(symbol_table)) {
+                               GC_SET_BLACK(ref->u.v.gc_info);
                        } else {
-                               ht = Z_ARRVAL_P(pz);
+                               ht = &((zend_array*)ref)->ht;
                        }
+               } else if (ref->u.v.type == IS_REFERENCE) {
+                       if (Z_REFCOUNTED(((zend_reference*)ref)->val)) {
+                               if (UNEXPECTED(!EG(objects_store).object_buckets) &&
+                                   Z_TYPE(((zend_reference*)ref)->val) == IS_OBJECT) {
+                                       return;
+                               }
+                               ref = Z_COUNTED(((zend_reference*)ref)->val);
+                               if (ref->u.v.type != IS_ARRAY || (zend_array*)ref != &EG(symbol_table)) {
+                                       ref->refcount--;
+                               }
+                               goto tail_call;
+                       }
+                       return;
                }
                if (!ht) return;
                for (idx = 0; idx < ht->nNumUsed; idx++) {
                        p = ht->arData + idx;
-                       if (!p->xData) continue;
-                       pz = (zval*)p->xData;
-                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                               pz->refcount__gc--;
+                       if (!Z_REFCOUNTED(p->val)) continue;
+                       ref = Z_COUNTED(p->val);
+                       if (ref->u.v.type != IS_ARRAY || ((zend_array*)ref) != &EG(symbol_table)) {
+                               ref->refcount--;
                        }
                        if (idx == ht->nNumUsed-1) {
                                goto tail_call;
                        } else {
-                               zval_mark_grey(pz TSRMLS_CC);
-                       }
-               }
-       }
-}
-
-static void zobj_mark_grey(struct _store_object *obj, zval *pz TSRMLS_DC)
-{
-       uint idx;
-       Bucket *p;
-       zend_object_get_gc_t get_gc;
-
-       if (GC_GET_COLOR(obj->buffered) != GC_GREY) {
-               GC_BENCH_INC(zobj_marked_grey);
-               GC_SET_COLOR(obj->buffered, GC_GREY);
-               if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                            (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
-                       int i, n;
-                       zval **table;
-                       HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
-
-                       for (i = 0; i < n; i++) {
-                               if (table[i]) {
-                                       pz = table[i];
-                                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                               pz->refcount__gc--;
-                                       }
-                                       zval_mark_grey(pz TSRMLS_CC);
-                               }
-                       }
-                       if (!props) {
-                               return;
-                       }
-                       for (idx = 0; idx < props->nNumUsed; idx++) {
-                               p = props->arData + idx;
-                               if (!p->xData) continue;
-                               pz = (zval*)p->xData;
-                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                       pz->refcount__gc--;
-                               }
-                               zval_mark_grey(pz TSRMLS_CC);
+                               gc_mark_grey(ref TSRMLS_CC);
                        }
                }
        }
@@ -499,137 +386,85 @@ static void gc_mark_roots(TSRMLS_D)
        gc_root_buffer *current = GC_G(roots).next;
 
        while (current != &GC_G(roots)) {
-               if (current->handle) {
-                       if (EG(objects_store).object_buckets) {
-                               struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
-
-                               if (GC_GET_COLOR(obj->buffered) == GC_PURPLE) {
-                                       zval z;
-
-                                       INIT_PZVAL(&z);
-                                       Z_OBJ_HANDLE(z) = current->handle;
-                                       Z_OBJ_HT(z) = current->u.handlers;
-                                       zobj_mark_grey(obj, &z TSRMLS_CC);
-                               } else {
-                                       GC_SET_ADDRESS(obj->buffered, NULL);
-                                       GC_REMOVE_FROM_BUFFER(current);
-                               }
-                       }
+               if (GC_GET_COLOR(current->ref->u.v.gc_info) == GC_PURPLE) {
+                       gc_mark_grey(current->ref TSRMLS_CC);
                } else {
-                       if (GC_ZVAL_GET_COLOR(current->u.pz) == GC_PURPLE) {
-                               zval_mark_grey(current->u.pz TSRMLS_CC);
-                       } else {
-                               GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
-                               GC_REMOVE_FROM_BUFFER(current);
-                       }
+                       GC_SET_ADDRESS(current->ref->u.v.gc_info, 0);
+                       GC_REMOVE_FROM_ROOTS(current);
                }
                current = current->next;
        }
 }
 
-static void zval_scan(zval *pz TSRMLS_DC)
+static void gc_scan(zend_refcounted *ref TSRMLS_DC)
 {
     HashTable *ht;
     uint idx;
        Bucket *p;
 
 tail_call:     
-       if (GC_ZVAL_GET_COLOR(pz) == GC_GREY) {
+       if (GC_GET_COLOR(ref->u.v.gc_info) == GC_GREY) {
                ht = NULL;
-               if (pz->refcount__gc > 0) {
-                       zval_scan_black(pz TSRMLS_CC);
+               if (ref->refcount > 0) {
+                       gc_scan_black(ref TSRMLS_CC);
                } else {
-                       GC_ZVAL_SET_COLOR(pz, GC_WHITE);
-                       if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
+                       GC_SET_COLOR(ref->u.v.gc_info, GC_WHITE);
+                       if (ref->u.v.type == IS_OBJECT && EG(objects_store).object_buckets) {
                                zend_object_get_gc_t get_gc;
-                               struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
-
-                               if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
-                                       if (obj->refcount > 0) {
-                                               zobj_scan_black(obj, pz TSRMLS_CC);
-                                       } else {
-                                               GC_SET_COLOR(obj->buffered, GC_WHITE);
-                                               if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                                            (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
-                                                       int i, n;
-                                                       zval **table;
-                                                       HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
-
-                                                       while (n > 0 && !table[n-1]) n--;
-                                                       for (i = 0; i < n; i++) {
-                                                               if (table[i]) {
-                                                                       pz = table[i];
-                                                                       if (!props && i == n - 1) {
-                                                                               goto tail_call;
-                                                                       } else {
-                                                                               zval_scan(pz TSRMLS_CC);
-                                                                       }
-                                                               }
-                                                       }
-                                                       if (!props) {
-                                                               return;
+                               zend_object *obj = (zend_object*)ref;
+
+                               if (EXPECTED(IS_VALID(EG(objects_store).object_buckets[obj->handle]) &&
+                                            (get_gc = obj->handlers->get_gc) != NULL)) {
+                                       int i, n;
+                                       zval *table;
+                                       zval tmp;
+                                       HashTable *props;
+                                       
+                                       ZVAL_OBJ(&tmp, obj);
+                                       props = get_gc(&tmp, &table, &n TSRMLS_CC);
+                                       while (n > 0 && !Z_REFCOUNTED(table[n-1])) n--;
+                                       for (i = 0; i < n; i++) {
+                                               if (Z_REFCOUNTED(table[i])) {
+                                                       ref = Z_COUNTED(table[i]);
+                                                       if (!props && i == n - 1) {
+                                                               goto tail_call;
+                                                       } else {
+                                                               gc_scan(ref TSRMLS_CC);
                                                        }
-                                                       ht = props;
                                                }
                                        }
+                                       if (!props) {
+                                               return;
+                                       }
+                                       ht = props;
                                }
-                       } else if (Z_TYPE_P(pz) == IS_ARRAY) {
-                               if (Z_ARRVAL_P(pz) == &EG(symbol_table)) {
-                                       GC_ZVAL_SET_BLACK(pz);
+                       } else if (ref->u.v.type == IS_ARRAY) {
+                               if ((zend_array*)ref == &EG(symbol_table)) {
+                                       GC_SET_BLACK(ref->u.v.gc_info);
                                } else {
-                                       ht = Z_ARRVAL_P(pz);
+                                       ht = &((zend_array*)ref)->ht;
+                               }
+                       } else if (ref->u.v.type == IS_REFERENCE) {
+                               if (Z_REFCOUNTED(((zend_reference*)ref)->val)) {
+                                       if (UNEXPECTED(!EG(objects_store).object_buckets) &&
+                                           Z_TYPE(((zend_reference*)ref)->val) == IS_OBJECT) {
+                                               return;
+                                       }
+                                       ref = Z_COUNTED(((zend_reference*)ref)->val);
+                                       goto tail_call;
                                }
+                               return;
                        }
                }
                if (!ht) return;
                for (idx = 0; idx < ht->nNumUsed; idx++) {
                        p = ht->arData + idx;
-                       if (!p->xData) continue;
+                       if (!Z_REFCOUNTED(p->val)) continue;
+                       ref = Z_COUNTED(p->val);
                        if (idx == ht->nNumUsed-1) {
-                               pz = (zval*)p->xData;
                                goto tail_call;
                        } else {
-                               zval_scan((zval*)p->xData TSRMLS_CC);
-                       }
-               }
-       }
-}
-
-static void zobj_scan(zval *pz TSRMLS_DC)
-{
-       uint idx;
-       Bucket *p;
-       zend_object_get_gc_t get_gc;
-
-       if (EG(objects_store).object_buckets) {
-               struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
-
-               if (GC_GET_COLOR(obj->buffered) == GC_GREY) {
-                       if (obj->refcount > 0) {
-                               zobj_scan_black(obj, pz TSRMLS_CC);
-                       } else {
-                               GC_SET_COLOR(obj->buffered, GC_WHITE);
-                               if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                            (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
-                                       int i, n;
-                                       zval **table;
-                                       HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
-
-                                       for (i = 0; i < n; i++) {
-                                               if (table[i]) {
-                                                       pz = table[i];
-                                                       zval_scan(pz TSRMLS_CC);
-                       }
-                                       }
-                                       if (!props) {
-                                               return;
-                                       }
-                                       for (idx = 0; idx < props->nNumUsed; idx++) {                                           
-                                               p = props->arData + idx;
-                                               if (!p->xData) continue;
-                                               zval_scan((zval*)p->xData TSRMLS_CC);
-                                       }
-                               }
+                               gc_scan(ref TSRMLS_CC);
                        }
                }
        }
@@ -640,258 +475,253 @@ static void gc_scan_roots(TSRMLS_D)
        gc_root_buffer *current = GC_G(roots).next;
 
        while (current != &GC_G(roots)) {
-               if (current->handle) {
-                       zval z;
-
-                       INIT_PZVAL(&z);
-                       Z_OBJ_HANDLE(z) = current->handle;
-                       Z_OBJ_HT(z) = current->u.handlers;
-                       zobj_scan(&z TSRMLS_CC);
-               } else {
-                       zval_scan(current->u.pz TSRMLS_CC);
-               }
+               gc_scan(current->ref TSRMLS_CC);
                current = current->next;
        }
 }
 
-static void zval_collect_white(zval *pz TSRMLS_DC)
+static int gc_collect_white(zend_refcounted *ref TSRMLS_DC)
 {
+       int count = 0;
        HashTable *ht;
        uint idx;
        Bucket *p;
 
 tail_call:
-       if (((zval_gc_info*)(pz))->u.buffered == (gc_root_buffer*)GC_WHITE) {
+       if (ref->u.v.gc_info == GC_WHITE) {
                ht = NULL;
-               GC_ZVAL_SET_BLACK(pz);
+               GC_SET_BLACK(ref->u.v.gc_info);
 
-               if (Z_TYPE_P(pz) == IS_OBJECT && EG(objects_store).object_buckets) {
+               /* don't count references for compatibilty */
+               if (ref->u.v.type != IS_REFERENCE) {
+                       count++;
+               }
+               /* put into list to free */
+//???
+//             ref->gc_next = GC_G(zval_to_free);
+//             GC_G(zval_to_free) = ref;
+               if (ref->u.v.type == IS_OBJECT && EG(objects_store).object_buckets) {
                        zend_object_get_gc_t get_gc;
-                       struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
-
-                       if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
-                               /* PURPLE instead of BLACK to prevent buffering in nested gc calls */
-                               GC_SET_PURPLE(obj->buffered);
-
-                               if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                            (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
-                                       int i, n;
-                                       zval **table, *zv;
-                                       HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
+                       zend_object *obj = (zend_object*)ref;
 
-                                       if (!props) {
-                                               /* restore refcount and put into list to free */
-                                               pz->refcount__gc++;
-                                               ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
-                                               GC_G(zval_to_free) = (zval_gc_info*)pz;
-                                       }
+                       /* PURPLE instead of BLACK to prevent buffering in nested gc calls */
+//???          GC_SET_PURPLE(obj->gc.u.v.gc_info);
 
-                                       while (n > 0 && !table[n-1]) n--;
-                                       for (i = 0; i < n; i++) {
-                                               if (table[i]) {
-                                                       zv = table[i];
-                                                       if (Z_TYPE_P(zv) != IS_ARRAY || Z_ARRVAL_P(zv) != &EG(symbol_table)) {
-                                                               zv->refcount__gc++;
-                                                       }
-                                                       if (!props && i == n - 1) {
-                                                               pz = zv;
-                                                               goto tail_call;
-                                                       } else {
-                                                               zval_collect_white(zv TSRMLS_CC);
-                                                       }
+                       if (EXPECTED(IS_VALID(EG(objects_store).object_buckets[obj->handle]) &&
+                                    (get_gc = obj->handlers->get_gc) != NULL)) {
+                               int i, n;
+                               zval *table;
+                               zval tmp;
+                               HashTable *props;
+                               
+                               ZVAL_OBJ(&tmp, obj);
+                               props = get_gc(&tmp, &table, &n TSRMLS_CC);
+                               while (n > 0 && !Z_REFCOUNTED(table[n-1])) n--;
+                               for (i = 0; i < n; i++) {
+                                       if (Z_REFCOUNTED(table[i])) {
+                                               ref = Z_COUNTED(table[i]);
+                                               if (ref->u.v.type != IS_ARRAY || (zend_array*)ref != &EG(symbol_table)) {
+                                                       ref->refcount++;
+                                               }
+                                               if (!props && i == n - 1) {
+                                                       goto tail_call;
+                                               } else {
+                                                       count += gc_collect_white(ref TSRMLS_CC);
                                                }
                                        }
-                                       if (!props) {
-                                               return;
-                                       }
-                                       ht = props;
                                }
+                               if (!props) {
+                                       return count;
+                               }
+                               ht = props;
                        }
-               } else {
-                       if (Z_TYPE_P(pz) == IS_ARRAY) {
-                               ht = Z_ARRVAL_P(pz);
+               } else if (ref->u.v.type == IS_ARRAY) {
+                       ht = &((zend_array*)ref)->ht;
+               } else if (ref->u.v.type == IS_REFERENCE) {
+                       if (Z_REFCOUNTED(((zend_reference*)ref)->val)) {
+                               if (UNEXPECTED(!EG(objects_store).object_buckets) &&
+                                   Z_TYPE(((zend_reference*)ref)->val) == IS_OBJECT) {
+                                       return count;
+                               }
+                               ref = Z_COUNTED(((zend_reference*)ref)->val);
+                               if (ref->u.v.type != IS_ARRAY || (zend_array*)ref != &EG(symbol_table)) {
+                                       ref->refcount++;
+                               }
+                               goto tail_call;
                        }
+                       return count;
                }
 
-               /* restore refcount and put into list to free */
-               pz->refcount__gc++;
-               ((zval_gc_info*)pz)->u.next = GC_G(zval_to_free);
-               GC_G(zval_to_free) = (zval_gc_info*)pz;
-
-               if (!ht) return;
-
+               if (!ht) return count;
                for (idx = 0; idx < ht->nNumUsed; idx++) {
                        p = ht->arData + idx;
-                       if (!p->xData) continue;
-                       pz = (zval*)p->xData;
-                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                               pz->refcount__gc++;
+                       if (!Z_REFCOUNTED(p->val)) continue;
+                       ref = Z_COUNTED(p->val);
+                       if (ref->u.v.type != IS_ARRAY || (zend_array*)ref != &EG(symbol_table)) {
+                               ref->refcount++;
                        }
                        if (idx == ht->nNumUsed-1) {
                                goto tail_call;
                        } else {
-                               zval_collect_white(pz TSRMLS_CC);
-                       }
-               }
-       }
-}
-
-static void zobj_collect_white(zval *pz TSRMLS_DC)
-{
-       uint idx;
-       Bucket *p;
-
-       if (EG(objects_store).object_buckets) {
-               zend_object_get_gc_t get_gc;
-               struct _store_object *obj = &EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].bucket.obj;
-
-               if (obj->buffered == (gc_root_buffer*)GC_WHITE) {
-                       /* PURPLE instead of BLACK to prevent buffering in nested gc calls */
-                       GC_SET_PURPLE(obj->buffered);
-
-                       if (EXPECTED(EG(objects_store).object_buckets[Z_OBJ_HANDLE_P(pz)].valid &&
-                                    (get_gc = Z_OBJ_HANDLER_P(pz, get_gc)) != NULL)) {
-                               int i, n;
-                               zval **table;
-                               HashTable *props = get_gc(pz, &table, &n TSRMLS_CC);
-
-                               for (i = 0; i < n; i++) {
-                                       if (table[i]) {
-                                               pz = table[i];
-                                               if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                                       pz->refcount__gc++;
-                                               }
-                                               zval_collect_white(pz TSRMLS_CC);
-                                       }
-                               }
-                               if (!props) {
-                                       return;
-                               }
-                               for (idx = 0; idx < props->nNumUsed; idx++) {
-                                       p = props->arData + idx;
-                                       if (!p->xData) continue;
-                                       pz = (zval*)p->xData;
-                                       if (Z_TYPE_P(pz) != IS_ARRAY || Z_ARRVAL_P(pz) != &EG(symbol_table)) {
-                                               pz->refcount__gc++;
-                                       }
-                                       zval_collect_white(pz TSRMLS_CC);
-                               }
+                               count += gc_collect_white(ref TSRMLS_CC);
                        }
                }
        }
+       return count;
 }
 
-static void gc_collect_roots(TSRMLS_D)
+static int gc_collect_roots(TSRMLS_D)
 {
+       int count = 0;
        gc_root_buffer *current = GC_G(roots).next;
 
        while (current != &GC_G(roots)) {
-               if (current->handle) {
-                       if (EG(objects_store).object_buckets) {
-                               struct _store_object *obj = &EG(objects_store).object_buckets[current->handle].bucket.obj;
-                               zval z;
-
-                               GC_SET_ADDRESS(obj->buffered, NULL);
-                               INIT_PZVAL(&z);
-                               Z_OBJ_HANDLE(z) = current->handle;
-                               Z_OBJ_HT(z) = current->u.handlers;
-                               zobj_collect_white(&z TSRMLS_CC);
-                       }
+               GC_SET_ADDRESS(current->ref->u.v.gc_info, 0);
+               if (current->ref->u.v.gc_info == GC_WHITE) {
+                       count += gc_collect_white(current->ref TSRMLS_CC);
+                       GC_SET_ADDRESS(current->ref->u.v.gc_info, current - GC_G(buf));
                } else {
-                       GC_ZVAL_SET_ADDRESS(current->u.pz, NULL);
-                       zval_collect_white(current->u.pz TSRMLS_CC);
+                       GC_REMOVE_FROM_ROOTS(current);
                }
-
-               GC_REMOVE_FROM_BUFFER(current);
                current = current->next;
        }
+       /* relink remaining roots into list to free */
+       if (GC_G(roots).next != &GC_G(roots)) {
+               if (GC_G(to_free).next == &GC_G(to_free)) {
+                       /* move roots into list to free */
+                       GC_G(to_free).next = GC_G(roots).next;
+                       GC_G(to_free).prev = GC_G(roots).prev;
+                       GC_G(to_free).next->prev = &GC_G(to_free);
+                       GC_G(to_free).prev->next = &GC_G(to_free);
+               } else {
+                       /* add roots into list to free */
+//???
+                       gc_root_buffer *p1 = GC_G(to_free).next;
+                       gc_root_buffer *p2 = GC_G(to_free).prev;
+                       gc_root_buffer *p3 = GC_G(roots).next;
+                       gc_root_buffer *p4 = GC_G(roots).prev;
+               
+                       p2->next = p3;
+                       p3->prev = p2;
+                       p4->next = &GC_G(to_free);
+                       GC_G(to_free).prev = p4;
+               }
+
+               GC_G(roots).next = &GC_G(roots);
+               GC_G(roots).prev = &GC_G(roots);
+       }
+       return count;
 }
-#endif
 
-#define FREE_LIST_END ((zval_gc_info*)(~(zend_uintptr_t)GC_COLOR))
+//???#define FREE_LIST_END ((zend_refcounted*)(~(zend_uintptr_t)GC_COLOR))
+//???#define FREE_LIST_END NULL
 
 ZEND_API int gc_collect_cycles(TSRMLS_D)
 {
-//???
-       return 0;
-#if 0
        int count = 0;
 
        if (GC_G(roots).next != &GC_G(roots)) {
-               zval_gc_info *p, *q, *orig_free_list, *orig_next_to_free;
+               gc_root_buffer *current, *orig_next_to_free;
+               zend_refcounted *p;
+//???          zend_refcounted *p, *q, *orig_free_list, *orig_next_to_free;
 
                if (GC_G(gc_active)) {
                        return 0;
                }
                GC_G(gc_runs)++;
-               GC_G(zval_to_free) = FREE_LIST_END;
+//???          GC_G(zval_to_free) = FREE_LIST_END;
                GC_G(gc_active) = 1;
                gc_mark_roots(TSRMLS_C);
                gc_scan_roots(TSRMLS_C);
-               gc_collect_roots(TSRMLS_C);
+               count = gc_collect_roots(TSRMLS_C);
 
-               orig_free_list = GC_G(free_list);
+//???          orig_free_list = GC_G(free_list);
                orig_next_to_free = GC_G(next_to_free);
-               p = GC_G(free_list) = GC_G(zval_to_free);
-               GC_G(zval_to_free) = NULL;
+//???          p = GC_G(free_list) = GC_G(zval_to_free);
+//???          GC_G(zval_to_free) = NULL;
                GC_G(gc_active) = 0;
 
                /* First call destructors */
-               while (p != FREE_LIST_END) {
-                       if (Z_TYPE(p->z) == IS_OBJECT) {
-                               if (EG(objects_store).object_buckets &&
-                                       EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
-                                       EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0 &&
-                                       EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor &&
-                                       !EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called) {
-
-                                       EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].destructor_called = 1;
-                                       EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount++;
-                                       EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.dtor(EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.object, Z_OBJ_HANDLE(p->z) TSRMLS_CC);
-                                       EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount--;
+               current = GC_G(to_free).next;
+               while (current != &GC_G(to_free)) {
+                       p = current->ref;
+                       GC_G(next_to_free) = current->next;
+                       if (p->u.v.type == IS_OBJECT) {
+                               zend_object *obj = (zend_object*)p;
+
+                               if (obj->handlers->dtor_obj &&
+                                   EG(objects_store).object_buckets &&
+                                       IS_VALID(EG(objects_store).object_buckets[obj->handle]) &&
+                                       !(obj->gc.u.v.flags & IS_OBJ_DESTRUCTOR_CALLED)) {
+
+                                       obj->gc.u.v.flags |= IS_OBJ_DESTRUCTOR_CALLED;
+                                       obj->gc.refcount++;
+                                       obj->handlers->dtor_obj(obj TSRMLS_CC);
+                                       obj->gc.refcount--;
                                }
                        }
-                       count++;
-                       p = p->u.next;
+//???
+                       current = GC_G(next_to_free);
                }
 
                /* Destroy zvals */
-               p = GC_G(free_list);
-               while (p != FREE_LIST_END) {
-                       GC_G(next_to_free) = p->u.next;
-                       if (Z_TYPE(p->z) == IS_OBJECT) {
-                               if (EG(objects_store).object_buckets &&
-                                       EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].valid &&
-                                       EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount <= 0) {
-                                       EG(objects_store).object_buckets[Z_OBJ_HANDLE(p->z)].bucket.obj.refcount = 1;
-                                       Z_TYPE(p->z) = IS_NULL;
-                                       zend_objects_store_del_ref_by_handle_ex(Z_OBJ_HANDLE(p->z), Z_OBJ_HT(p->z) TSRMLS_CC);
+//???          p = GC_G(free_list);
+               current = GC_G(to_free).next;
+               while (current != &GC_G(to_free)) {
+                       p = current->ref;
+                       GC_G(next_to_free) = current->next;
+//???          while (p != FREE_LIST_END) {
+//???
+//???                  GC_G(next_to_free) = p->gc_next;
+                       if (1 /*&& p->refcount <= 0 ???*/) {
+                               if (p->u.v.type == IS_OBJECT) {
+                                       zend_object *obj = (zend_object*)p;
+
+                                       if (EG(objects_store).object_buckets &&
+                                               IS_VALID(EG(objects_store).object_buckets[obj->handle])) {
+//???                                          obj->gc.refcount = 0;
+//???                                          Z_TYPE(p->z) = IS_NULL;
+                                               obj->gc.u.v.type = IS_NULL;
+                                               zend_objects_store_free(obj TSRMLS_CC);
+                                       }
+                               } else if (p->u.v.type == IS_ARRAY) {
+                                       zend_array *arr = (zend_array*)p;
+
+                                       arr->gc.u.v.type = IS_NULL;
+                                       zend_hash_destroy(&arr->ht);
+                                       efree(arr);
+                               } else if (p->u.v.type == IS_REFERENCE) {
+                                       zend_reference *ref = (zend_reference*)p;
+
+                                       ref->gc.u.v.type = IS_NULL;
+                                       if (EXPECTED(EG(objects_store).object_buckets != NULL) ||
+                                           Z_TYPE(ref->val) != IS_OBJECT) {
+                                               zval_dtor(&ref->val);
+                                       }
+                                       efree(ref);
+                               } else {
+//???                                  zval_dtor(&p->z);
+//???                                  Z_TYPE(p->z) = IS_NULL;
                                }
-                       } else if (Z_TYPE(p->z) == IS_ARRAY) {
-                               Z_TYPE(p->z) = IS_NULL;
-                               zend_hash_destroy(Z_ARRVAL(p->z));
-                               FREE_HASHTABLE(Z_ARRVAL(p->z));
-                       } else {
-                               zval_dtor(&p->z);
-                               Z_TYPE(p->z) = IS_NULL;
                        }
-                       p = GC_G(next_to_free);
+//???
+                       current = GC_G(next_to_free);
                }
 
                /* Free zvals */
-               p = GC_G(free_list);
-               while (p != FREE_LIST_END) {
-                       q = p->u.next;
-                       FREE_ZVAL_EX(&p->z);
-                       p = q;
-               }
+//???          p = GC_G(free_list);
+//???          while (p != FREE_LIST_END) {
+//???                  q = p->gc_next;
+//???                  efree(p);
+//???                  p = q;
+//???          }
+
                GC_G(collected) += count;
-               GC_G(free_list) = orig_free_list;
+//???          GC_G(free_list) = orig_free_list;
                GC_G(next_to_free) = orig_next_to_free;
        }
 
        return count;
-#endif
 }
 
 /*
index f714033962e0a6323d6ed427bb642e465465032c..29e2ca6e029789d96173aeffd1f311cdb0d9d0d3 100644 (file)
        do {(v) = (v) | GC_COLOR;} while (0)
 
 #define GC_ZVAL_ADDRESS(v) \
-       GC_ADDRESS(Z_GC_BUFFER_P(v))
+       GC_ADDRESS(Z_GC_INFO_P(v))
 #define GC_ZVAL_SET_ADDRESS(v, a) \
-       GC_SET_ADDRESS(Z_GC_BUFFER_P(v), (a))
+       GC_SET_ADDRESS(Z_GC_INFO_P(v), (a))
 #define GC_ZVAL_GET_COLOR(v) \
-       GC_GET_COLOR(Z_GC_BUFFER_P(v))
+       GC_GET_COLOR(Z_GC_INFO_P(v))
 #define GC_ZVAL_SET_COLOR(v, c) \
-       GC_SET_COLOR(Z_GC_BUFFER_P(v), (c))
+       GC_SET_COLOR(Z_GC_INFO_P(v), (c))
 #define GC_ZVAL_SET_BLACK(v) \
-       GC_SET_BLACK(Z_GC_BUFFER_P(v))
+       GC_SET_BLACK(Z_GC_INFO_P(v))
 #define GC_ZVAL_SET_PURPLE(v) \
-       GC_SET_PURPLE(Z_GC_BUFFER_P(v))
+       GC_SET_PURPLE(Z_GC_INFO_P(v))
 
 typedef struct _gc_root_buffer {
        struct _gc_root_buffer   *prev;         /* double-linked list               */
@@ -89,9 +89,8 @@ typedef struct _zend_gc_globals {
        gc_root_buffer   *first_unused;         /* pointer to first unused buffer   */
        gc_root_buffer   *last_unused;          /* pointer to last unused buffer    */
 
-       zend_refcounted  *zval_to_free;         /* temporary list of zvals to free */
-       zend_refcounted  *free_list;
-       zend_refcounted  *next_to_free;
+       gc_root_buffer    to_free;                      /* list to free                     */
+       gc_root_buffer   *next_to_free;
 
        zend_uint gc_runs;
        zend_uint collected;
@@ -100,13 +99,9 @@ typedef struct _zend_gc_globals {
        zend_uint root_buf_length;
        zend_uint root_buf_peak;
        zend_uint zval_possible_root;
-       zend_uint zobj_possible_root;
        zend_uint zval_buffered;
-       zend_uint zobj_buffered;
        zend_uint zval_remove_from_buffer;
-       zend_uint zobj_remove_from_buffer;
        zend_uint zval_marked_grey;
-       zend_uint zobj_marked_grey;
 #endif
 
 } zend_gc_globals;
@@ -123,8 +118,8 @@ extern ZEND_API zend_gc_globals gc_globals;
 
 BEGIN_EXTERN_C()
 ZEND_API int  gc_collect_cycles(TSRMLS_D);
-ZEND_API void gc_zval_possible_root(zend_refcounted *ref TSRMLS_DC);
-ZEND_API void gc_remove_zval_from_buffer(zend_refcounted *ref TSRMLS_DC);
+ZEND_API void gc_possible_root(zend_refcounted *ref TSRMLS_DC);
+ZEND_API void gc_remove_from_buffer(zend_refcounted *ref TSRMLS_DC);
 ZEND_API void gc_globals_ctor(TSRMLS_D);
 ZEND_API void gc_globals_dtor(TSRMLS_D);
 ZEND_API void gc_init(TSRMLS_D);
@@ -132,24 +127,21 @@ ZEND_API void gc_reset(TSRMLS_D);
 END_EXTERN_C()
 
 #define GC_ZVAL_CHECK_POSSIBLE_ROOT(z) \
-       gc_zval_check_possible_root((z) TSRMLS_CC)
+       gc_check_possible_root((z) TSRMLS_CC)
 
-#define GC_REMOVE_ZVAL_FROM_BUFFER(z) do { \
-               if (GC_ZVAL_ADDRESS(z)) { \
-                       gc_remove_zval_from_buffer(Z_COUNTED_P(z) TSRMLS_CC); \
+#define GC_REMOVE_FROM_BUFFER(p) do { \
+               zend_refcounted *_p = (zend_refcounted*)(p); \
+               if (GC_ADDRESS(_p->u.v.gc_info)) { \
+                       gc_remove_from_buffer(_p TSRMLS_CC); \
                } \
        } while (0)
 
-#define GC_REMOVE_ZOBJ_FROM_BUFFER(z) do { \
-               if (GC_ADDRESS((z)->gc.u.v.buffer)) { \
-                       gc_remove_zval_from_buffer(&(z)->gc TSRMLS_CC); \
-               } \
-       } while (0)
-
-static zend_always_inline void gc_zval_check_possible_root(zval *z TSRMLS_DC)
+static zend_always_inline void gc_check_possible_root(zval *z TSRMLS_DC)
 {
-       if (Z_TYPE_P(z) == IS_ARRAY || Z_TYPE_P(z) == IS_OBJECT) {
-               gc_zval_possible_root(Z_COUNTED_P(z) TSRMLS_CC);
+       if (Z_TYPE_P(z) == IS_OBJECT ||
+           (Z_ISREF_P(z) && 
+            (Z_TYPE_P(Z_REFVAL_P(z)) == IS_ARRAY || Z_TYPE_P(Z_REFVAL_P(z)) == IS_OBJECT))) {
+               gc_possible_root(Z_COUNTED_P(z) TSRMLS_CC);
        }
 }
 
index 483628dbaf6b52a410e9c1c85899e2a2eae2440f..47a0797cf975d69cf4b9ad32aaa549b40e6464d7 100644 (file)
@@ -207,6 +207,8 @@ static void zend_generator_free_storage(zend_object *object TSRMLS_DC) /* {{{ */
        zend_generator_close(generator, 0 TSRMLS_CC);
 
        zend_object_std_dtor(&generator->std TSRMLS_CC);
+
+       GC_REMOVE_FROM_BUFFER(generator);
        efree(generator);
 }
 /* }}} */
index 27c9f6c5f6cacb17cb63bfa51f287f2607f5bfe6..50785b86ec8fc56f3f9b767ea62e2a189e82fd26 100644 (file)
@@ -31,7 +31,7 @@ ZEND_API void zend_object_std_init(zend_object *object, zend_class_entry *ce TSR
        object->gc.refcount = 1;
        object->gc.u.v.type = IS_OBJECT;
        object->gc.u.v.flags = 0;
-       object->gc.u.v.buffer = 0;
+       object->gc.u.v.gc_info = 0;
        object->ce = ce;
        object->properties = NULL;
        object->guards = NULL;
@@ -125,6 +125,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object TSRMLS_DC)
 ZEND_API void zend_object_free(zend_object *object TSRMLS_DC)
 {
        zend_object_std_dtor(object TSRMLS_CC);
+       GC_REMOVE_FROM_BUFFER(object);
        efree(object);
 }
 
index a4a5055b70f8b9c0c156b0b2df8c22eb51580f99..77b7ee103a364b364945242b0c163110c0d1cca9 100644 (file)
@@ -53,10 +53,6 @@ ZEND_API void zend_objects_store_call_destructors(zend_objects_store *objects TS
                                obj->gc.refcount++;
                                obj->handlers->dtor_obj(obj TSRMLS_CC);
                                obj->gc.refcount--;
-
-                               if (obj->gc.refcount == 0) {
-                                       GC_REMOVE_ZOBJ_FROM_BUFFER(obj TSRMLS_CC);
-                               }
                        }
                }
        }
@@ -86,7 +82,6 @@ ZEND_API void zend_objects_store_free_object_storage(zend_objects_store *objects
                zend_object *obj = objects->object_buckets[i];
 
                if (IS_VALID(obj)) {
-                       GC_REMOVE_ZOBJ_FROM_BUFFER(obj TSRMLS_CC);
                        objects->object_buckets[i] = SET_INVALID(obj);
                        if (obj->handlers->free_obj) {
                                obj->handlers->free_obj(obj TSRMLS_CC);
@@ -121,6 +116,17 @@ ZEND_API void zend_objects_store_put(zend_object *object TSRMLS_DC)
             SET_BUCKET_NUMBER(EG(objects_store).object_buckets[handle], EG(objects_store).free_list_head);     \
                        EG(objects_store).free_list_head = handle;
 
+ZEND_API void zend_objects_store_free(zend_object *object TSRMLS_DC) /* {{{ */
+{
+       int handle = object->handle;
+
+       if (object->handlers->free_obj) {
+               object->handlers->free_obj(object TSRMLS_CC);
+       }
+       ZEND_OBJECTS_STORE_ADD_TO_FREE_LIST(handle);
+}
+/* }}} */
+
 ZEND_API void zend_objects_store_del(zend_object *object TSRMLS_DC) /* {{{ */
 {
        /*      Make sure we hold a reference count during the destructor call
@@ -149,7 +155,6 @@ ZEND_API void zend_objects_store_del(zend_object *object TSRMLS_DC) /* {{{ */
                        if (object->gc.refcount == 0) {
                                zend_uint handle = object->handle;
 
-//???                          GC_REMOVE_ZOBJ_FROM_BUFFER(obj);
                                if (object->handlers->free_obj) {
                                        zend_try {
                                                object->handlers->free_obj(object TSRMLS_CC);
@@ -251,7 +256,7 @@ ZEND_API zend_object *zend_object_create_proxy(zval *object, zval *member TSRMLS
 
        obj->std.gc.refcount = 1;
        obj->std.gc.u.v.type = IS_OBJECT;
-       obj->std.gc.u.v.buffer = 0;
+       obj->std.gc.u.v.gc_info = 0;
        obj->std.ce = NULL;
        obj->std.properties = NULL;
        obj->std.guards = NULL;
index 647bfeaee57f8a790ef7df6eee7c554e95b47840..61147dd8c6b2a01c4a601ac1c3ab5f37997aeed9 100644 (file)
@@ -88,6 +88,7 @@ ZEND_API void zend_objects_store_destroy(zend_objects_store *objects);
 /* Store API functions */
 ZEND_API void zend_objects_store_put(zend_object *object TSRMLS_DC);
 ZEND_API void zend_objects_store_del(zend_object *object TSRMLS_DC);
+ZEND_API void zend_objects_store_free(zend_object *object TSRMLS_DC);
 
 /* See comment in zend_objects_API.c before you use this */
 ZEND_API void zend_object_store_set_object(zval *zobject, zend_object *object TSRMLS_DC);
index fdfa5aba3b97b75c394b08a2232c3a57c6960423..514dbb1e2fd1d2f1a101ccff06cd9c37126024de 100644 (file)
@@ -187,9 +187,7 @@ try_again:
        switch (Z_TYPE_P(op)) {
                case IS_REFERENCE:
                        if (Z_REFCOUNT_P(op) == 1) {
-                               zend_reference *ref = Z_REF_P(op);
-                               ZVAL_COPY_VALUE(op, Z_REFVAL_P(op));
-                               efree(ref);
+                               ZVAL_UNREF(op);
                        } else {
                                Z_DELREF_P(op);
                                ZVAL_COPY_VALUE(op, Z_REFVAL_P(op));
@@ -1531,7 +1529,6 @@ static inline void zend_free_obj_get_result(zval *op TSRMLS_DC) /* {{{ */
 {
        if (Z_REFCOUNTED_P(op)) {
                if (Z_REFCOUNT_P(op) == 0) {
-                       GC_REMOVE_ZVAL_FROM_BUFFER(op);
                        zval_dtor(op);
                } else {
                        zval_ptr_dtor(op);
index e3467a8b7681379054eb4e8b319e12aac4d716ab..8c93ef48ac69864f6d02f925db3444b17e5a0504 100644 (file)
@@ -100,7 +100,7 @@ static zend_always_inline zend_string *zend_str_alloc(int len, int persistent)
        ret->gc.refcount = 1;
        ret->gc.u.v.type = IS_STRING;
        ret->gc.u.v.flags = (persistent ? IS_STR_PERSISTENT : 0);
-       ret->gc.u.v.buffer = 0;
+       ret->gc.u.v.gc_info = 0;
        ret->h = 0;
        ret->len = len;
        return ret;
index f2361ef4544552707b8dea82749c666d0be79941..91c59c7679c2c54e5f263ffe68bc71219b864f91 100644 (file)
@@ -103,10 +103,10 @@ struct _zend_refcounted {
                struct {
                        zend_uchar        type;
                        zend_uchar        flags;    /* used for strings & objects */
-                       zend_ushort       buffer;   /* keeps GC root number or 0 */
+                       zend_ushort       gc_info;  /* keeps GC root number (or 0) and color */
                } v;
                zend_uint long_type;
-       } u;                                                    
+       } u;
 };
 
 struct _zend_string {
@@ -271,8 +271,8 @@ struct _zend_ast_ref {
 #define Z_GC_TYPE(zval)                                Z_COUNTED(zval)->type
 #define Z_GC_TYPE_P(zval_p)                    Z_GC_TYPE(*(zval_p))
 
-#define Z_GC_BUFFER(zval)                      Z_COUNTED(zval)->u.v.buffer
-#define Z_GC_BUFFER_P(zval_p)          Z_GC_BUFFER(*(zval_p))
+#define Z_GC_INFO(zval)                                Z_COUNTED(zval)->u.v.gc_info
+#define Z_GC_INFO_P(zval_p)                    Z_GC_INFO(*(zval_p))
 
 #define Z_STR(zval)                                    (zval).value.str
 #define Z_STR_P(zval_p)                                Z_STR(*(zval_p))
@@ -395,7 +395,7 @@ struct _zend_ast_ref {
                zend_array *_arr = emalloc(sizeof(zend_array));                 \
                _arr->gc.refcount = 1;                                                                  \
                _arr->gc.u.v.type = IS_ARRAY;                                                   \
-               _arr->gc.u.v.buffer = 0;                                                                \
+               _arr->gc.u.v.gc_info = 0;                                                               \
                Z_ARR_P(__z) = _arr;                                                                    \
                Z_TYPE_P(__z) = IS_ARRAY;                                                               \
        } while (0)
@@ -405,7 +405,7 @@ struct _zend_ast_ref {
                zend_array *_arr = malloc(sizeof(zend_array));                  \
                _arr->gc.refcount = 1;                                                                  \
                _arr->gc.u.v.type = IS_ARRAY;                                                   \
-               _arr->gc.u.v.buffer = 0;                                                                \
+               _arr->gc.u.v.gc_info = 0;                                                               \
                Z_ARR_P(__z) = _arr;                                                                    \
                Z_TYPE_P(__z) = IS_ARRAY;                                                               \
        } while (0)
@@ -426,7 +426,7 @@ struct _zend_ast_ref {
                zend_resource *_res = emalloc(sizeof(zend_resource));   \
                _res->gc.refcount = 1;                                                                  \
                _res->gc.u.v.type = IS_RESOURCE;                                                \
-               _res->gc.u.v.buffer = 0;                                                                \
+               _res->gc.u.v.gc_info = 0;                                                               \
                _res->handle = (h);                                                                             \
                _res->type = (t);                                                                               \
                _res->ptr = (p);                                                                                \
@@ -439,7 +439,7 @@ struct _zend_ast_ref {
                zend_resource *_res = malloc(sizeof(zend_resource));    \
                _res->gc.refcount = 1;                                                                  \
                _res->gc.u.v.type = IS_RESOURCE;                                                \
-               _res->gc.u.v.buffer = 0;                                                                \
+               _res->gc.u.v.gc_info = 0;                                                               \
                _res->handle = (h);                                                                             \
                _res->type = (t);                                                                               \
                _res->ptr = (p);                                                                                \
@@ -458,7 +458,7 @@ struct _zend_ast_ref {
                zend_reference *_ref = emalloc(sizeof(zend_reference)); \
                _ref->gc.refcount = 1;                                                                  \
                _ref->gc.u.v.type = IS_REFERENCE;                                               \
-               _ref->gc.u.v.buffer = 0;                                                                \
+               _ref->gc.u.v.gc_info = 0;                                                               \
                _ref->val = *(r);                                                                               \
                Z_REF_P(z) = _ref;                                                                              \
                Z_TYPE_P(z) = IS_REFERENCE;                                                             \
@@ -469,7 +469,7 @@ struct _zend_ast_ref {
                zend_ast_ref *_ast = emalloc(sizeof(zend_ast_ref));             \
                _ast->gc.refcount = 1;                                                                  \
                _ast->gc.u.v.type = IS_CONSTANT_AST;                                    \
-               _ast->gc.u.v.buffer = 0;                                                                \
+               _ast->gc.u.v.gc_info = 0;                                                               \
                _ast->ast = (a);                                                                                \
                Z_AST_P(__z) = _ast;                                                                    \
                Z_TYPE_P(__z) = IS_CONSTANT_AST;                                                \
@@ -499,7 +499,7 @@ struct _zend_ast_ref {
                zend_str_offset *x = emalloc(sizeof(zend_str_offset));  \
                x->gc.refcount = 1;                                                                             \
                x->gc.u.v.type = IS_STR_OFFSET;                                                 \
-               x->gc.u.v.buffer = 0;                                                                   \
+               x->gc.u.v.gc_info = 0;                                                                  \
                x->str = (s);                                                                                   \
                x->offset = (o);                                                                                \
                Z_STR_OFFSET_P(z) = x;                                                                  \
index f016f85f0071c37f86429f817a78469bd1ae1049..20f8b1adb68cc2b4572e5a0c4ae515f25ef3180a 100644 (file)
 #include "zend_constants.h"
 #include "zend_list.h"
 
-ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC)
+ZEND_API void _zval_dtor_func(zend_refcounted *p ZEND_FILE_LINE_DC)
 {
-       switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
+//???  switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
+       switch (p->u.v.type) {
                case IS_STRING:
-               case IS_CONSTANT:
-                       CHECK_ZVAL_STRING_REL(zvalue);
-                       STR_RELEASE(Z_STR_P(zvalue));
-                       break;
+               case IS_CONSTANT: {
+                               zend_string *str = (zend_string*)p;
+//???                          CHECK_ZVAL_STRING_REL(zvalue);
+                               STR_RELEASE(str);
+                               goto exit;
+                       }
                case IS_ARRAY:
                case IS_CONSTANT_ARRAY: {
+                               zend_array *arr =(zend_array*)p;
                                TSRMLS_FETCH();
 
-                               if (Z_ARRVAL_P(zvalue) != &EG(symbol_table).ht) {
+                               if (arr != &EG(symbol_table)) {
                                        /* break possible cycles */
-                                       Z_TYPE_P(zvalue) = IS_NULL;
-                                       zend_hash_destroy(Z_ARRVAL_P(zvalue));
-                                       efree(Z_ARR_P(zvalue));
+                                       arr->gc.u.v.type = IS_NULL;
+                                       zend_hash_destroy(&arr->ht);
+                                       goto gc_exit;
                                }
+                               goto exit;
                        }
-                       break;
-               case IS_CONSTANT_AST:
-                       zend_ast_destroy(Z_AST_P(zvalue)->ast);
-                       efree(Z_AST_P(zvalue));
-                       break;
-               case IS_OBJECT:
-                       {
+               case IS_CONSTANT_AST: {
+                               zend_ast_ref *ast =(zend_ast_ref*)p;
+               
+                               zend_ast_destroy(ast->ast);
+                               efree(ast);
+                               goto exit;
+                       }
+               case IS_OBJECT: {
+                               zend_object *obj = (zend_object*)p;
                                TSRMLS_FETCH();
 
-                               OBJ_RELEASE(Z_OBJ_P(zvalue));
+                               OBJ_RELEASE(obj);
+                               goto exit;
                        }
-                       break;
-               case IS_RESOURCE:
-                       {
+               case IS_RESOURCE: {
+                               zend_resource *res = (zend_resource*)p;
                                TSRMLS_FETCH();
 
-                               if (Z_DELREF_P(zvalue) == 0) {
+                               if (--res->gc.refcount == 0) {
                                        /* destroy resource */
-                                       zend_list_delete(Z_RES_P(zvalue));
+                                       zend_list_delete(res);
                                }
+                               goto exit;
                        }
-                       break;
-               case IS_REFERENCE:
-                       if (Z_DELREF_P(zvalue) == 0) {
-                               zval_dtor(Z_REFVAL_P(zvalue));
-                               efree(Z_REF_P(zvalue));
+               case IS_REFERENCE: {
+                               zend_reference *ref = (zend_reference*)p;
+                               if (--ref->gc.refcount == 0) {
+                                       zval_dtor(&ref->val);
+                                       goto gc_exit;
+                               }
+                               goto exit;
                        }
-                       break;
-               case IS_LONG:
-               case IS_DOUBLE:
-               case IS_BOOL:
-               case IS_NULL:
                default:
-                       return;
-                       break;
+                       goto exit;
        }
+gc_exit:
+       GC_REMOVE_FROM_BUFFER(p);
+       efree(p);
+exit:
+       return;
 }
 
-ZEND_API void _zval_dtor_func_for_ptr(zval *zvalue ZEND_FILE_LINE_DC)
+ZEND_API void _zval_dtor_func_for_ptr(zend_refcounted *p ZEND_FILE_LINE_DC)
 {
-       switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
+//???  switch (Z_TYPE_P(zvalue) & IS_CONSTANT_TYPE_MASK) {
+       switch (p->u.v.type) {
                case IS_STRING:
-               case IS_CONSTANT:
-                       CHECK_ZVAL_STRING_REL(zvalue);
-                       STR_FREE(Z_STR_P(zvalue));
-                       break;
+               case IS_CONSTANT: {
+                               zend_string *str = (zend_string*)p;
+//???                          CHECK_ZVAL_STRING_REL(zvalue);
+                               STR_FREE(str);
+                               goto exit;
+                       }
                case IS_ARRAY:
                case IS_CONSTANT_ARRAY: {
+                               zend_array *arr =(zend_array*)p;
                                TSRMLS_FETCH();
 
-                               if (Z_ARRVAL_P(zvalue) != &EG(symbol_table).ht) {
+                               if (arr != &EG(symbol_table)) {
                                        /* break possible cycles */
-                                       Z_TYPE_P(zvalue) = IS_NULL;
-                                       zend_hash_destroy(Z_ARRVAL_P(zvalue));
-                                       efree(Z_ARR_P(zvalue));
+                                       arr->gc.u.v.type = IS_NULL;
+                                       zend_hash_destroy(&arr->ht);
+                                       goto gc_exit;
                                }
+                               goto exit;
                        }
-                       break;
-               case IS_CONSTANT_AST:
-                       zend_ast_destroy(Z_AST_P(zvalue)->ast);
-                       efree(Z_AST_P(zvalue));
-                       break;
-               case IS_OBJECT:
-                       {
+               case IS_CONSTANT_AST: {
+                               zend_ast_ref *ast =(zend_ast_ref*)p;
+
+                               zend_ast_destroy(ast->ast);
+                               efree(ast);
+                               goto exit;
+                       }
+               case IS_OBJECT: {
+                               zend_object *obj = (zend_object*)p;
                                TSRMLS_FETCH();
 
-                               zend_objects_store_del(Z_OBJ_P(zvalue) TSRMLS_CC);
+                               zend_objects_store_del(obj TSRMLS_CC);
+                               goto exit;
                        }
-                       break;
-               case IS_RESOURCE:
-                       {
+               case IS_RESOURCE: {
+                               zend_resource *res = (zend_resource*)p;
                                TSRMLS_FETCH();
 
                                /* destroy resource */
-                               zend_list_delete(Z_RES_P(zvalue));
+                               zend_list_delete(res);
+                               goto exit;
+                       }
+               case IS_REFERENCE: {
+                               zend_reference *ref = (zend_reference*)p;
+
+                               zval_dtor(&ref->val);
+                               goto gc_exit;
                        }
-                       break;
-               case IS_REFERENCE:
-                       zval_dtor(Z_REFVAL_P(zvalue));
-                       efree(Z_REF_P(zvalue));
-                       break;
-               case IS_LONG:
-               case IS_DOUBLE:
-               case IS_BOOL:
-               case IS_NULL:
                default:
-                       return;
-                       break;
+                       goto exit;
        }
+gc_exit:
+       GC_REMOVE_FROM_BUFFER(p);
+       efree(p);
+exit:
+       return;
 }
 
 ZEND_API void _zval_internal_dtor(zval *zvalue ZEND_FILE_LINE_DC)
@@ -264,7 +282,6 @@ ZEND_API void _zval_dtor_wrapper(zval *zvalue)
 {
        TSRMLS_FETCH();
 
-       GC_REMOVE_ZVAL_FROM_BUFFER(zvalue);
        zval_dtor(zvalue);
 }
 
index 2e2b183d761c45cd6d685ae16c4467973affad98..c62a194e21ef799ebbd61c7247fc6d2a647fd899 100644 (file)
 
 BEGIN_EXTERN_C()
 
-ZEND_API void _zval_dtor_func(zval *zvalue ZEND_FILE_LINE_DC);
-ZEND_API void _zval_dtor_func_for_ptr(zval *zvalue ZEND_FILE_LINE_DC);
+ZEND_API void _zval_dtor_func(zend_refcounted *p ZEND_FILE_LINE_DC);
+ZEND_API void _zval_dtor_func_for_ptr(zend_refcounted *p ZEND_FILE_LINE_DC);
 
 static zend_always_inline void _zval_dtor(zval *zvalue ZEND_FILE_LINE_DC)
 {
        if (!Z_REFCOUNTED_P(zvalue)) {
                return;
        }
-       _zval_dtor_func(zvalue ZEND_FILE_LINE_RELAY_CC);
+       _zval_dtor_func(Z_COUNTED_P(zvalue) ZEND_FILE_LINE_RELAY_CC);
 }
 
 ZEND_API void _zval_copy_ctor_func(zval *zvalue ZEND_FILE_LINE_DC);
index 14483a427fcd0b01a8cba7788fe08262f58dcea6..8076ba6caa71337e2ca5cd2cd406f4aeb924d13a 100644 (file)
@@ -405,7 +405,6 @@ ZEND_VM_HELPER_EX(zend_binary_assign_op_obj_helper, VAR|UNUSED|CV, CONST|TMP|VAR
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -652,7 +651,6 @@ ZEND_VM_HELPER_EX(zend_pre_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR|
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -750,7 +748,6 @@ ZEND_VM_HELPER_EX(zend_post_incdec_property_helper, VAR|UNUSED|CV, CONST|TMP|VAR
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -4368,16 +4365,11 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET, CONST|TMP|VAR|CV, ANY)
 //??? dereference
                                if (Z_ISREF_P(array_ref)) {
                                        if (Z_REFCOUNT_P(array_ref) == 1) {
-                                               zend_reference *ref = Z_REF_P(array_ref);
-                                               ZVAL_COPY(array_ref, &ref->val);
-                                               efree(ref);
+                                               ZVAL_UNREF(array_ref);
                                                array_ptr = array_ref;
-                                       } else {
-                                               Z_ADDREF_P(array_ref);
                                        }
-                               } else {
-                                       Z_ADDREF_P(array_ref);
                                }
+                               Z_ADDREF_P(array_ref);
                        }
                }
        }
index dc625815f47a222ecbb2aac897913fabe4e89c57..c635d8a06d7cd86106c6b5edbe9eb410121b7c82 100644 (file)
@@ -3079,16 +3079,11 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_A
 //??? dereference
                                if (Z_ISREF_P(array_ref)) {
                                        if (Z_REFCOUNT_P(array_ref) == 1) {
-                                               zend_reference *ref = Z_REF_P(array_ref);
-                                               ZVAL_COPY(array_ref, &ref->val);
-                                               efree(ref);
+                                               ZVAL_UNREF(array_ref);
                                                array_ptr = array_ref;
-                                       } else {
-                                               Z_ADDREF_P(array_ref);
                                        }
-                               } else {
-                                       Z_ADDREF_P(array_ref);
                                }
+                               Z_ADDREF_P(array_ref);
                        }
                }
        }
@@ -8180,16 +8175,11 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG
 //??? dereference
                                if (Z_ISREF_P(array_ref)) {
                                        if (Z_REFCOUNT_P(array_ref) == 1) {
-                                               zend_reference *ref = Z_REF_P(array_ref);
-                                               ZVAL_COPY(array_ref, &ref->val);
-                                               efree(ref);
+                                               ZVAL_UNREF(array_ref);
                                                array_ptr = array_ref;
-                                       } else {
-                                               Z_ADDREF_P(array_ref);
                                        }
-                               } else {
-                                       Z_ADDREF_P(array_ref);
                                }
+                               Z_ADDREF_P(array_ref);
                        }
                }
        }
@@ -13359,16 +13349,11 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG
 //??? dereference
                                if (Z_ISREF_P(array_ref)) {
                                        if (Z_REFCOUNT_P(array_ref) == 1) {
-                                               zend_reference *ref = Z_REF_P(array_ref);
-                                               ZVAL_COPY(array_ref, &ref->val);
-                                               efree(ref);
+                                               ZVAL_UNREF(array_ref);
                                                array_ptr = array_ref;
-                                       } else {
-                                               Z_ADDREF_P(array_ref);
                                        }
-                               } else {
-                                       Z_ADDREF_P(array_ref);
                                }
+                               Z_ADDREF_P(array_ref);
                        }
                }
        }
@@ -14079,7 +14064,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CONST(int (*b
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -14325,7 +14309,6 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_CONST(incdec_t
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -14423,7 +14406,6 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_CONST(incdec_
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -16577,7 +16559,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_TMP(int (*bin
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -16824,7 +16805,6 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_TMP(incdec_t i
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -16922,7 +16902,6 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_TMP(incdec_t
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -18653,7 +18632,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_VAR(int (*bin
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -18900,7 +18878,6 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_VAR(incdec_t i
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -18998,7 +18975,6 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_VAR(incdec_t
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -20843,7 +20819,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_UNUSED(int (*
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -22264,7 +22239,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_VAR_CV(int (*bina
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -22510,7 +22484,6 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_VAR_CV(incdec_t in
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -22608,7 +22581,6 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_VAR_CV(incdec_t i
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -24195,7 +24167,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CONST(int
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -24440,7 +24411,6 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_CONST(incde
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -24538,7 +24508,6 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_CONST(incd
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -25599,7 +25568,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_TMP(int (*
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -25845,7 +25813,6 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_TMP(incdec_
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -25943,7 +25910,6 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_TMP(incdec
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -26920,7 +26886,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_VAR(int (*
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -27166,7 +27131,6 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_VAR(incdec_
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -27264,7 +27228,6 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_VAR(incdec
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -28242,7 +28205,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_UNUSED(int
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -28658,7 +28620,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_UNUSED_CV(int (*b
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -28903,7 +28864,6 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_UNUSED_CV(incdec_t
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -29001,7 +28961,6 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_UNUSED_CV(incdec_
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -30907,16 +30866,11 @@ static int ZEND_FASTCALL  ZEND_FE_RESET_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS
 //??? dereference
                                if (Z_ISREF_P(array_ref)) {
                                        if (Z_REFCOUNT_P(array_ref) == 1) {
-                                               zend_reference *ref = Z_REF_P(array_ref);
-                                               ZVAL_COPY(array_ref, &ref->val);
-                                               efree(ref);
+                                               ZVAL_UNREF(array_ref);
                                                array_ptr = array_ref;
-                                       } else {
-                                               Z_ADDREF_P(array_ref);
                                        }
-                               } else {
-                                       Z_ADDREF_P(array_ref);
                                }
+                               Z_ADDREF_P(array_ref);
                        }
                }
        }
@@ -31495,7 +31449,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CONST(int (*bi
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -31740,7 +31693,6 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_CONST(incdec_t
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -31838,7 +31790,6 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_CONST(incdec_t
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -33775,7 +33726,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_TMP(int (*bina
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -34021,7 +33971,6 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_TMP(incdec_t in
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -34119,7 +34068,6 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_TMP(incdec_t i
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -35726,7 +35674,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_VAR(int (*bina
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -35972,7 +35919,6 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_VAR(incdec_t in
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -36070,7 +36016,6 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_VAR(incdec_t i
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -37790,7 +37735,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_UNUSED(int (*b
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -39077,7 +39021,6 @@ static int ZEND_FASTCALL zend_binary_assign_op_obj_helper_SPEC_CV_CV(int (*binar
                                        zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                        if (Z_REFCOUNT_P(z) == 0) {
-                                               GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                                zval_dtor(z);
                                        }
                                        z = value;
@@ -39322,7 +39265,6 @@ static int ZEND_FASTCALL zend_pre_incdec_property_helper_SPEC_CV_CV(incdec_t inc
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
@@ -39420,7 +39362,6 @@ static int ZEND_FASTCALL zend_post_incdec_property_helper_SPEC_CV_CV(incdec_t in
                                zval *value = Z_OBJ_HT_P(z)->get(z TSRMLS_CC);
 
                                if (Z_REFCOUNT_P(z) == 0) {
-                                       GC_REMOVE_ZVAL_FROM_BUFFER(z);
                                        zval_dtor(z);
                                }
                                z = value;
index 65fe5c46ed370eeeab253a9d0f3aeecff920ecc8..8c08ddba20876ab1b707d7986b8a52c27af2096e 100644 (file)
@@ -2440,6 +2440,7 @@ static void date_object_free_storage_date(zend_object *object TSRMLS_DC) /* {{{
        }
 
        zend_object_std_dtor(&intern->std TSRMLS_CC);
+       GC_REMOVE_FROM_BUFFER(object);
        efree(intern);
 } /* }}} */
 
@@ -2451,6 +2452,7 @@ static void date_object_free_storage_timezone(zend_object *object TSRMLS_DC) /*
                free(intern->tzi.z.abbr);
        }
        zend_object_std_dtor(&intern->std TSRMLS_CC);
+       GC_REMOVE_FROM_BUFFER(object);
        efree(intern);
 } /* }}} */
 
@@ -2460,6 +2462,7 @@ static void date_object_free_storage_interval(zend_object *object TSRMLS_DC) /*
 
        timelib_rel_time_dtor(intern->diff);
        zend_object_std_dtor(&intern->std TSRMLS_CC);
+       GC_REMOVE_FROM_BUFFER(object);
        efree(intern);
 } /* }}} */
 
@@ -2481,6 +2484,7 @@ static void date_object_free_storage_period(zend_object *object TSRMLS_DC) /* {{
 
        timelib_rel_time_dtor(intern->interval);
        zend_object_std_dtor(&intern->std TSRMLS_CC);
+       GC_REMOVE_FROM_BUFFER(object);
        efree(intern);
 } /* }}} */
 
index 9c822029feb478f8c11224fa5e4ac022b638ed81..148dae43783a0e8a4ab53408581170b53b9ae8e0 100644 (file)
@@ -319,6 +319,7 @@ static void reflection_free_objects_storage(zend_object *object TSRMLS_DC) /* {{
        intern->ptr = NULL;
        zval_ptr_dtor(&intern->obj);
        zend_object_std_dtor(object TSRMLS_CC);
+       GC_REMOVE_FROM_BUFFER(object);
        efree(intern);
 }
 /* }}} */
index 82f166fe6d9a980ec52e9f126ec335c379922df9..c6634ecf8a12a042cc047b3be142caf2421287d2 100644 (file)
@@ -170,6 +170,7 @@ static void spl_array_object_free_storage(zend_object *object TSRMLS_DC)
                efree(intern->debug_info);
        }
 
+       GC_REMOVE_FROM_BUFFER(object);
        efree(intern);
 }
 /* }}} */
index b86994c7d2215323c2d6630558b036f234a8409f..86d745463f80b52268707011508d262520f0652c 100644 (file)
@@ -127,6 +127,7 @@ static void spl_filesystem_object_free_storage(zend_object *object TSRMLS_DC) /*
                //????zend_iterator_dtor(&intern->it->intern);
        }
 
+       GC_REMOVE_FROM_BUFFER(object);
        efree(intern);
 } /* }}} */
 
index 8f444d006109f8878acd545d30996ff5692b207e..f453ba717555611ec6fe16624f19897fcba96ae1 100644 (file)
@@ -367,6 +367,7 @@ static void spl_dllist_object_free_storage(zend_object *object TSRMLS_DC) /* {{{
                efree(intern->debug_info);
        }
 
+       GC_REMOVE_FROM_BUFFER(object);
        efree(intern);
 }
 /* }}} */
index 0a8b8502fdfca5f429280d7b300c0e5dee2fe2c9..784d1db96879233175f96b2ada156e5ec793dc66 100644 (file)
@@ -210,6 +210,7 @@ static void spl_fixedarray_object_free_storage(zend_object *object TSRMLS_DC) /*
        zend_object_std_dtor(&intern->std TSRMLS_CC);
        zval_ptr_dtor(&intern->retval);
 
+       GC_REMOVE_FROM_BUFFER(object);
        efree(intern);
 }
 /* }}} */
index 969fdba736ae87a7b3f81a45bfed1f001ef1f477..5358e3da9d883731766845023ce6efd6dbdc6477 100644 (file)
@@ -378,6 +378,7 @@ static void spl_heap_object_free_storage(zend_object *object TSRMLS_DC) /* {{{ *
                efree(intern->debug_info);
        }
 
+       GC_REMOVE_FROM_BUFFER(object);
        efree(intern);
 }
 /* }}} */
index 55587c48af377b63a6eacb372ab33f39f0bb4049..f424491966c2872ec1771b4f9f2e403a346817c1 100644 (file)
@@ -889,6 +889,7 @@ static void spl_RecursiveIteratorIterator_free_storage(zend_object *_object TSRM
 
        smart_str_free(&object->postfix[0]);
 
+       GC_REMOVE_FROM_BUFFER(_object);
        efree(object);
 }
 /* }}} */
@@ -2268,6 +2269,7 @@ static void spl_dual_it_free_storage(zend_object *_object TSRMLS_DC)
 
        //zend_object_std_dtor(&object->std TSRMLS_CC);
 
+       GC_REMOVE_FROM_BUFFER(_object);
        efree(object);
 }
 /* }}} */
index 803ca4a59c4b97b895e8c75766d6bedcda21127b..3728e45005e60ce8d54386b64ebea703bbe13d79 100644 (file)
@@ -114,6 +114,7 @@ void spl_SplObjectStorage_free_storage(zend_object *object TSRMLS_DC) /* {{{ */
                efree(intern->debug_info);
        }
 
+       GC_REMOVE_FROM_BUFFER(object);
        efree(intern);
 } /* }}} */
 
index cb3aa761bc0c1735f916898862acda78e04064cc..ab16b67ee0a5c470127dc9944a542e4d83b6c9ab 100644 (file)
@@ -2258,9 +2258,7 @@ PHPAPI int php_array_merge(HashTable *dest, HashTable *src, int recursive TSRMLS
                                        
                                        if (Z_ISREF_P(dest_entry)) {
                                                if (Z_REFCOUNT_P(dest_entry) == 1) {
-                                                       zend_reference *ref = Z_REF_P(dest_entry);
-                                                       ZVAL_COPY_VALUE(dest_entry, dest_zval);
-                                                       efree(ref);
+                                                       ZVAL_UNREF(dest_entry);
                                                } else {
                                                        Z_DELREF_P(dest_entry);
                                                        ZVAL_DUP(dest_entry, dest_zval);