Skip to content

Commit 276080e

Browse files
committed
Added GC checks and improvements
1 parent 10d4fdb commit 276080e

File tree

3 files changed

+33
-34
lines changed

3 files changed

+33
-34
lines changed

Zend/zend_gc.c

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -204,9 +204,7 @@ ZEND_API void gc_init(void)
204204

205205
ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref)
206206
{
207-
if (UNEXPECTED(GC_TYPE(ref) == IS_NULL) ||
208-
UNEXPECTED(CG(unclean_shutdown)) ||
209-
UNEXPECTED(GC_G(gc_active))) {
207+
if (UNEXPECTED(CG(unclean_shutdown)) || UNEXPECTED(GC_G(gc_active))) {
210208
return;
211209
}
212210

@@ -242,14 +240,14 @@ ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref)
242240
GC_G(unused) = newRoot->prev;
243241
}
244242

245-
GC_REF_SET_PURPLE(ref);
243+
GC_TRACE_SET_COLOR(ref, GC_PURPLE);
244+
GC_INFO(ref) = (newRoot - GC_G(buf)) | GC_PURPLE;
245+
246246
newRoot->next = GC_G(roots).next;
247247
newRoot->prev = &GC_G(roots);
248248
GC_G(roots).next->prev = newRoot;
249249
GC_G(roots).next = newRoot;
250250

251-
GC_REF_SET_ADDRESS(ref, newRoot - GC_G(buf));
252-
253251
newRoot->ref = ref;
254252

255253
GC_BENCH_INC(zval_buffered);
@@ -283,7 +281,7 @@ static void gc_scan_black(zend_refcounted *ref)
283281
ht = NULL;
284282
GC_REF_SET_BLACK(ref);
285283

286-
if (GC_TYPE(ref) == IS_OBJECT) {
284+
if (GC_TYPE(ref) == IS_OBJECT && !(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED)) {
287285
zend_object_get_gc_t get_gc;
288286
zend_object *obj = (zend_object*)ref;
289287

@@ -376,7 +374,7 @@ static void gc_mark_grey(zend_refcounted *ref)
376374
GC_BENCH_INC(zval_marked_grey);
377375
GC_REF_SET_COLOR(ref, GC_GREY);
378376

379-
if (GC_TYPE(ref) == IS_OBJECT) {
377+
if (GC_TYPE(ref) == IS_OBJECT && !(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED)) {
380378
zend_object_get_gc_t get_gc;
381379
zend_object *obj = (zend_object*)ref;
382380

@@ -487,7 +485,7 @@ static void gc_scan(zend_refcounted *ref)
487485
gc_scan_black(ref);
488486
} else {
489487
GC_REF_SET_COLOR(ref, GC_WHITE);
490-
if (GC_TYPE(ref) == IS_OBJECT) {
488+
if (GC_TYPE(ref) == IS_OBJECT && !(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED)) {
491489
zend_object_get_gc_t get_gc;
492490
zend_object *obj = (zend_object*)ref;
493491

@@ -576,13 +574,16 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags)
576574
if (GC_REF_GET_COLOR(ref) == GC_WHITE) {
577575
ht = NULL;
578576
GC_REF_SET_BLACK(ref);
577+
if (!GC_ADDRESS(GC_INFO(ref))) {
578+
GC_FLAGS(ref) |= IS_GC_INNER_GARBAGE;
579+
}
579580

580581
/* don't count references for compatibility ??? */
581582
if (GC_TYPE(ref) != IS_REFERENCE) {
582583
count++;
583584
}
584585

585-
if (GC_TYPE(ref) == IS_OBJECT) {
586+
if (GC_TYPE(ref) == IS_OBJECT && !(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED)) {
586587
zend_object_get_gc_t get_gc;
587588
zend_object *obj = (zend_object*)ref;
588589

@@ -608,20 +609,17 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags)
608609
*flags |= GC_HAS_INNER_CYCLES;
609610
}
610611
if (buf) {
612+
GC_REFCOUNT(ref)++;
613+
GC_FLAGS(ref) &= ~IS_GC_INNER_GARBAGE;
611614
buf->ref = ref;
612615
buf->next = GC_G(roots).next;
613616
buf->prev = &GC_G(roots);
614617
GC_G(roots).next->prev = buf;
615618
GC_G(roots).next = buf;
616619
GC_REF_SET_ADDRESS(ref, buf - GC_G(buf));
617-
*flags |= GC_HAS_DESTRUCTORS;
618620
}
619-
} else {
620-
*flags |= GC_HAS_DESTRUCTORS;
621621
}
622-
} else if (!GC_ADDRESS(GC_INFO(ref))) {
623-
GC_FLAGS(ref) |= IS_GC_INNER_CYCLE;
624-
*flags |= GC_HAS_INNER_CYCLES;
622+
*flags |= GC_HAS_DESTRUCTORS;
625623
}
626624
ZVAL_OBJ(&tmp, obj);
627625
ht = get_gc(&tmp, &zv, &n);
@@ -657,20 +655,17 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags)
657655
}
658656
} else if (GC_TYPE(ref) == IS_ARRAY) {
659657
if (!GC_ADDRESS(GC_INFO(ref))) {
660-
GC_FLAGS(ref) |= IS_GC_INNER_CYCLE;
661658
*flags |= GC_HAS_INNER_CYCLES;
662659
}
663660
ht = (zend_array*)ref;
664661
} else if (GC_TYPE(ref) == IS_REFERENCE) {
665-
GC_FLAGS(ref) |= IS_GC_INNER_CYCLE;
666662
if (Z_REFCOUNTED(((zend_reference*)ref)->val)) {
667663
ref = Z_COUNTED(((zend_reference*)ref)->val);
668664
GC_REFCOUNT(ref)++;
669665
goto tail_call;
670666
}
671667
return count;
672668
} else {
673-
GC_FLAGS(ref) |= IS_GC_INNER_CYCLE;
674669
return count;
675670
}
676671

@@ -719,6 +714,7 @@ static int gc_collect_roots(uint32_t *flags)
719714

720715
current = GC_G(roots).next;
721716
while (current != &GC_G(roots)) {
717+
GC_REFCOUNT(current->ref)++;
722718
if (GC_REF_GET_COLOR(current->ref) == GC_WHITE) {
723719
count += gc_collect_white(current->ref, flags);
724720
}
@@ -753,14 +749,14 @@ static void gc_break_cycles(zend_refcounted *ref, zval *zv)
753749
Bucket *p, *end;
754750

755751
tail_call:
756-
if (zv && !(GC_FLAGS(ref) & IS_GC_INNER_CYCLE)) {
752+
if (zv && !(GC_FLAGS(ref) & IS_GC_INNER_GARBAGE)) {
757753
GC_REFCOUNT(ref)--;
758754
ZVAL_NULL(zv);
759755
return;
760756
}
761-
GC_FLAGS(ref) &= ~IS_GC_INNER_CYCLE;
757+
GC_FLAGS(ref) &= ~IS_GC_INNER_GARBAGE;
762758

763-
if (GC_TYPE(ref) == IS_OBJECT) {
759+
if (GC_TYPE(ref) == IS_OBJECT && !(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED)) {
764760
zend_object_get_gc_t get_gc;
765761
zend_object *obj = (zend_object*)ref;
766762

@@ -833,9 +829,10 @@ static void gc_remove_nested_data_from_buffer(zend_refcounted *ref)
833829
tail_call:
834830
if (GC_ADDRESS(GC_INFO(ref)) != 0 && GC_REF_GET_COLOR(ref) == GC_BLACK) {
835831
GC_TRACE_REF(ref, "removing from buffer");
832+
GC_REFCOUNT(ref)--;
836833
GC_REMOVE_FROM_BUFFER(ref);
837834

838-
if (GC_TYPE(ref) == IS_OBJECT) {
835+
if (GC_TYPE(ref) == IS_OBJECT && !(GC_FLAGS(ref) & IS_OBJ_FREE_CALLED)) {
839836
zend_object_get_gc_t get_gc;
840837
zend_object *obj = (zend_object*)ref;
841838

@@ -960,16 +957,16 @@ ZEND_API int zend_gc_collect_cycles(void)
960957
#endif
961958

962959
if (gc_flags & GC_HAS_DESTRUCTORS) {
963-
/* Remember reference counters before calling destructors */
964-
current = to_free.next;
965-
while (current != &to_free) {
966-
current->refcount = GC_REFCOUNT(current->ref);
967-
current = current->next;
968-
}
969-
970-
/* Call destructors */
971960
GC_TRACE("Calling destructors");
972961
if (EG(objects_store).object_buckets) {
962+
/* Remember reference counters before calling destructors */
963+
current = to_free.next;
964+
while (current != &to_free) {
965+
current->refcount = GC_REFCOUNT(current->ref);
966+
current = current->next;
967+
}
968+
969+
/* Call destructors */
973970
current = to_free.next;
974971
while (current != &to_free) {
975972
p = current->ref;
@@ -1026,6 +1023,7 @@ ZEND_API int zend_gc_collect_cycles(void)
10261023
if (EG(objects_store).object_buckets &&
10271024
IS_OBJ_VALID(EG(objects_store).object_buckets[obj->handle])) {
10281025
GC_TYPE(obj) = IS_NULL;
1026+
GC_INFO_SET_COLOR(GC_INFO(obj), GC_WHITE);
10291027
if (!(GC_FLAGS(obj) & IS_OBJ_FREE_CALLED)) {
10301028
GC_FLAGS(obj) |= IS_OBJ_FREE_CALLED;
10311029
if (obj->handlers->free_obj) {
@@ -1042,6 +1040,7 @@ ZEND_API int zend_gc_collect_cycles(void)
10421040
zend_array *arr = (zend_array*)p;
10431041

10441042
GC_TYPE(arr) = IS_NULL;
1043+
GC_INFO_SET_COLOR(GC_INFO(arr), GC_WHITE);
10451044
zend_hash_destroy(arr);
10461045
}
10471046
current = GC_G(next_to_free);

Zend/zend_types.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ static zend_always_inline zend_uchar zval_get_type(const zval* pz) {
419419
#define IS_OBJ_HAS_GUARDS (1<<6)
420420

421421
/* GC flags (common for all referenced) */
422-
#define IS_GC_INNER_CYCLE (1<<7)
422+
#define IS_GC_INNER_GARBAGE (1<<7)
423423

424424
#define Z_OBJ_APPLY_COUNT(zval) \
425425
(Z_GC_FLAGS(zval) & IS_OBJ_APPLY_COUNT)

Zend/zend_variables.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ ZEND_API void ZEND_FASTCALL _zval_dtor_func(zend_refcounted *p ZEND_FILE_LINE_DC
4343
ZEND_ASSERT(GC_REFCOUNT(arr) <= 1);
4444

4545
/* break possible cycles */
46-
GC_TYPE(arr) = IS_NULL;
4746
GC_REMOVE_FROM_BUFFER(arr);
47+
GC_TYPE_INFO(arr) = IS_NULL | (GC_WHITE << 16);
4848
zend_array_destroy(arr);
4949
break;
5050
}
@@ -98,8 +98,8 @@ ZEND_API void ZEND_FASTCALL _zval_dtor_func_for_ptr(zend_refcounted *p ZEND_FILE
9898
zend_array *arr = (zend_array*)p;
9999

100100
/* break possible cycles */
101-
GC_TYPE(arr) = IS_NULL;
102101
GC_REMOVE_FROM_BUFFER(arr);
102+
GC_TYPE_INFO(arr) = IS_NULL | (GC_WHITE << 16);
103103
zend_array_destroy(arr);
104104
break;
105105
}

0 commit comments

Comments
 (0)