@@ -204,9 +204,7 @@ ZEND_API void gc_init(void)
204204
205205ZEND_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
755751tail_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)
833829tail_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 );
0 commit comments