summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Zend/zend_gc.c61
-rw-r--r--Zend/zend_types.h2
-rw-r--r--Zend/zend_variables.c4
3 files changed, 33 insertions, 34 deletions
diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c
index d5c8ea8adc..27431b645e 100644
--- a/Zend/zend_gc.c
+++ b/Zend/zend_gc.c
@@ -204,9 +204,7 @@ ZEND_API void gc_init(void)
ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref)
{
- if (UNEXPECTED(GC_TYPE(ref) == IS_NULL) ||
- UNEXPECTED(CG(unclean_shutdown)) ||
- UNEXPECTED(GC_G(gc_active))) {
+ if (UNEXPECTED(CG(unclean_shutdown)) || UNEXPECTED(GC_G(gc_active))) {
return;
}
@@ -242,14 +240,14 @@ ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref)
GC_G(unused) = newRoot->prev;
}
- GC_REF_SET_PURPLE(ref);
+ GC_TRACE_SET_COLOR(ref, GC_PURPLE);
+ GC_INFO(ref) = (newRoot - GC_G(buf)) | GC_PURPLE;
+
newRoot->next = GC_G(roots).next;
newRoot->prev = &GC_G(roots);
GC_G(roots).next->prev = newRoot;
GC_G(roots).next = newRoot;
- GC_REF_SET_ADDRESS(ref, newRoot - GC_G(buf));
-
newRoot->ref = ref;
GC_BENCH_INC(zval_buffered);
@@ -283,7 +281,7 @@ tail_call:
ht = NULL;
GC_REF_SET_BLACK(ref);
- if (GC_TYPE(ref) == IS_OBJECT) {
+ if (GC_TYPE(ref) == IS_OBJECT && !(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED)) {
zend_object_get_gc_t get_gc;
zend_object *obj = (zend_object*)ref;
@@ -376,7 +374,7 @@ tail_call:
GC_BENCH_INC(zval_marked_grey);
GC_REF_SET_COLOR(ref, GC_GREY);
- if (GC_TYPE(ref) == IS_OBJECT) {
+ if (GC_TYPE(ref) == IS_OBJECT && !(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED)) {
zend_object_get_gc_t get_gc;
zend_object *obj = (zend_object*)ref;
@@ -487,7 +485,7 @@ tail_call:
gc_scan_black(ref);
} else {
GC_REF_SET_COLOR(ref, GC_WHITE);
- if (GC_TYPE(ref) == IS_OBJECT) {
+ if (GC_TYPE(ref) == IS_OBJECT && !(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED)) {
zend_object_get_gc_t get_gc;
zend_object *obj = (zend_object*)ref;
@@ -576,13 +574,16 @@ tail_call:
if (GC_REF_GET_COLOR(ref) == GC_WHITE) {
ht = NULL;
GC_REF_SET_BLACK(ref);
+ if (!GC_ADDRESS(GC_INFO(ref))) {
+ GC_FLAGS(ref) |= IS_GC_INNER_GARBAGE;
+ }
/* don't count references for compatibility ??? */
if (GC_TYPE(ref) != IS_REFERENCE) {
count++;
}
- if (GC_TYPE(ref) == IS_OBJECT) {
+ if (GC_TYPE(ref) == IS_OBJECT && !(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED)) {
zend_object_get_gc_t get_gc;
zend_object *obj = (zend_object*)ref;
@@ -608,20 +609,17 @@ tail_call:
*flags |= GC_HAS_INNER_CYCLES;
}
if (buf) {
+ GC_REFCOUNT(ref)++;
+ GC_FLAGS(ref) &= ~IS_GC_INNER_GARBAGE;
buf->ref = ref;
buf->next = GC_G(roots).next;
buf->prev = &GC_G(roots);
GC_G(roots).next->prev = buf;
GC_G(roots).next = buf;
GC_REF_SET_ADDRESS(ref, buf - GC_G(buf));
- *flags |= GC_HAS_DESTRUCTORS;
}
- } else {
- *flags |= GC_HAS_DESTRUCTORS;
}
- } else if (!GC_ADDRESS(GC_INFO(ref))) {
- GC_FLAGS(ref) |= IS_GC_INNER_CYCLE;
- *flags |= GC_HAS_INNER_CYCLES;
+ *flags |= GC_HAS_DESTRUCTORS;
}
ZVAL_OBJ(&tmp, obj);
ht = get_gc(&tmp, &zv, &n);
@@ -657,12 +655,10 @@ tail_call:
}
} else if (GC_TYPE(ref) == IS_ARRAY) {
if (!GC_ADDRESS(GC_INFO(ref))) {
- GC_FLAGS(ref) |= IS_GC_INNER_CYCLE;
*flags |= GC_HAS_INNER_CYCLES;
}
ht = (zend_array*)ref;
} else if (GC_TYPE(ref) == IS_REFERENCE) {
- GC_FLAGS(ref) |= IS_GC_INNER_CYCLE;
if (Z_REFCOUNTED(((zend_reference*)ref)->val)) {
ref = Z_COUNTED(((zend_reference*)ref)->val);
GC_REFCOUNT(ref)++;
@@ -670,7 +666,6 @@ tail_call:
}
return count;
} else {
- GC_FLAGS(ref) |= IS_GC_INNER_CYCLE;
return count;
}
@@ -719,6 +714,7 @@ static int gc_collect_roots(uint32_t *flags)
current = GC_G(roots).next;
while (current != &GC_G(roots)) {
+ GC_REFCOUNT(current->ref)++;
if (GC_REF_GET_COLOR(current->ref) == GC_WHITE) {
count += gc_collect_white(current->ref, flags);
}
@@ -753,14 +749,14 @@ static void gc_break_cycles(zend_refcounted *ref, zval *zv)
Bucket *p, *end;
tail_call:
- if (zv && !(GC_FLAGS(ref) & IS_GC_INNER_CYCLE)) {
+ if (zv && !(GC_FLAGS(ref) & IS_GC_INNER_GARBAGE)) {
GC_REFCOUNT(ref)--;
ZVAL_NULL(zv);
return;
}
- GC_FLAGS(ref) &= ~IS_GC_INNER_CYCLE;
+ GC_FLAGS(ref) &= ~IS_GC_INNER_GARBAGE;
- if (GC_TYPE(ref) == IS_OBJECT) {
+ if (GC_TYPE(ref) == IS_OBJECT && !(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED)) {
zend_object_get_gc_t get_gc;
zend_object *obj = (zend_object*)ref;
@@ -833,9 +829,10 @@ static void gc_remove_nested_data_from_buffer(zend_refcounted *ref)
tail_call:
if (GC_ADDRESS(GC_INFO(ref)) != 0 && GC_REF_GET_COLOR(ref) == GC_BLACK) {
GC_TRACE_REF(ref, "removing from buffer");
+ GC_REFCOUNT(ref)--;
GC_REMOVE_FROM_BUFFER(ref);
- if (GC_TYPE(ref) == IS_OBJECT) {
+ if (GC_TYPE(ref) == IS_OBJECT && !(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED)) {
zend_object_get_gc_t get_gc;
zend_object *obj = (zend_object*)ref;
@@ -960,16 +957,16 @@ ZEND_API int zend_gc_collect_cycles(void)
#endif
if (gc_flags & GC_HAS_DESTRUCTORS) {
- /* Remember reference counters before calling destructors */
- current = to_free.next;
- while (current != &to_free) {
- current->refcount = GC_REFCOUNT(current->ref);
- current = current->next;
- }
-
- /* Call destructors */
GC_TRACE("Calling destructors");
if (EG(objects_store).object_buckets) {
+ /* Remember reference counters before calling destructors */
+ current = to_free.next;
+ while (current != &to_free) {
+ current->refcount = GC_REFCOUNT(current->ref);
+ current = current->next;
+ }
+
+ /* Call destructors */
current = to_free.next;
while (current != &to_free) {
p = current->ref;
@@ -1026,6 +1023,7 @@ ZEND_API int zend_gc_collect_cycles(void)
if (EG(objects_store).object_buckets &&
IS_OBJ_VALID(EG(objects_store).object_buckets[obj->handle])) {
GC_TYPE(obj) = IS_NULL;
+ GC_INFO_SET_COLOR(GC_INFO(obj), GC_WHITE);
if (!(GC_FLAGS(obj) & IS_OBJ_FREE_CALLED)) {
GC_FLAGS(obj) |= IS_OBJ_FREE_CALLED;
if (obj->handlers->free_obj) {
@@ -1042,6 +1040,7 @@ ZEND_API int zend_gc_collect_cycles(void)
zend_array *arr = (zend_array*)p;
GC_TYPE(arr) = IS_NULL;
+ GC_INFO_SET_COLOR(GC_INFO(arr), GC_WHITE);
zend_hash_destroy(arr);
}
current = GC_G(next_to_free);
diff --git a/Zend/zend_types.h b/Zend/zend_types.h
index 9bdec29e12..64f3df55f1 100644
--- a/Zend/zend_types.h
+++ b/Zend/zend_types.h
@@ -419,7 +419,7 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
#define IS_OBJ_HAS_GUARDS (1<<6)
/* GC flags (common for all referenced) */
-#define IS_GC_INNER_CYCLE (1<<7)
+#define IS_GC_INNER_GARBAGE (1<<7)
#define Z_OBJ_APPLY_COUNT(zval) \
(Z_GC_FLAGS(zval) & IS_OBJ_APPLY_COUNT)
diff --git a/Zend/zend_variables.c b/Zend/zend_variables.c
index b15c761bec..36d532e098 100644
--- a/Zend/zend_variables.c
+++ b/Zend/zend_variables.c
@@ -43,8 +43,8 @@ ZEND_API void ZEND_FASTCALL _zval_dtor_func(zend_refcounted *p ZEND_FILE_LINE_DC
ZEND_ASSERT(GC_REFCOUNT(arr) <= 1);
/* break possible cycles */
- GC_TYPE(arr) = IS_NULL;
GC_REMOVE_FROM_BUFFER(arr);
+ GC_TYPE_INFO(arr) = IS_NULL | (GC_WHITE << 16);
zend_array_destroy(arr);
break;
}
@@ -98,8 +98,8 @@ ZEND_API void ZEND_FASTCALL _zval_dtor_func_for_ptr(zend_refcounted *p ZEND_FILE
zend_array *arr = (zend_array*)p;
/* break possible cycles */
- GC_TYPE(arr) = IS_NULL;
GC_REMOVE_FROM_BUFFER(arr);
+ GC_TYPE_INFO(arr) = IS_NULL | (GC_WHITE << 16);
zend_array_destroy(arr);
break;
}