@@ -204,9 +204,7 @@ ZEND_API void gc_init(void)
204
204
205
205
ZEND_API void ZEND_FASTCALL gc_possible_root (zend_refcounted * ref )
206
206
{
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 ))) {
210
208
return ;
211
209
}
212
210
@@ -242,14 +240,14 @@ ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref)
242
240
GC_G (unused ) = newRoot -> prev ;
243
241
}
244
242
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
+
246
246
newRoot -> next = GC_G (roots ).next ;
247
247
newRoot -> prev = & GC_G (roots );
248
248
GC_G (roots ).next -> prev = newRoot ;
249
249
GC_G (roots ).next = newRoot ;
250
250
251
- GC_REF_SET_ADDRESS (ref , newRoot - GC_G (buf ));
252
-
253
251
newRoot -> ref = ref ;
254
252
255
253
GC_BENCH_INC (zval_buffered );
@@ -283,7 +281,7 @@ static void gc_scan_black(zend_refcounted *ref)
283
281
ht = NULL ;
284
282
GC_REF_SET_BLACK (ref );
285
283
286
- if (GC_TYPE (ref ) == IS_OBJECT ) {
284
+ if (GC_TYPE (ref ) == IS_OBJECT && !( GC_FLAGS ( ref ) & IS_OBJ_FREE_CALLED ) ) {
287
285
zend_object_get_gc_t get_gc ;
288
286
zend_object * obj = (zend_object * )ref ;
289
287
@@ -376,7 +374,7 @@ static void gc_mark_grey(zend_refcounted *ref)
376
374
GC_BENCH_INC (zval_marked_grey );
377
375
GC_REF_SET_COLOR (ref , GC_GREY );
378
376
379
- if (GC_TYPE (ref ) == IS_OBJECT ) {
377
+ if (GC_TYPE (ref ) == IS_OBJECT && !( GC_FLAGS ( ref ) & IS_OBJ_FREE_CALLED ) ) {
380
378
zend_object_get_gc_t get_gc ;
381
379
zend_object * obj = (zend_object * )ref ;
382
380
@@ -487,7 +485,7 @@ static void gc_scan(zend_refcounted *ref)
487
485
gc_scan_black (ref );
488
486
} else {
489
487
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 ) ) {
491
489
zend_object_get_gc_t get_gc ;
492
490
zend_object * obj = (zend_object * )ref ;
493
491
@@ -576,13 +574,16 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags)
576
574
if (GC_REF_GET_COLOR (ref ) == GC_WHITE ) {
577
575
ht = NULL ;
578
576
GC_REF_SET_BLACK (ref );
577
+ if (!GC_ADDRESS (GC_INFO (ref ))) {
578
+ GC_FLAGS (ref ) |= IS_GC_INNER_GARBAGE ;
579
+ }
579
580
580
581
/* don't count references for compatibility ??? */
581
582
if (GC_TYPE (ref ) != IS_REFERENCE ) {
582
583
count ++ ;
583
584
}
584
585
585
- if (GC_TYPE (ref ) == IS_OBJECT ) {
586
+ if (GC_TYPE (ref ) == IS_OBJECT && !( GC_FLAGS ( ref ) & IS_OBJ_FREE_CALLED ) ) {
586
587
zend_object_get_gc_t get_gc ;
587
588
zend_object * obj = (zend_object * )ref ;
588
589
@@ -608,20 +609,17 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags)
608
609
* flags |= GC_HAS_INNER_CYCLES ;
609
610
}
610
611
if (buf ) {
612
+ GC_REFCOUNT (ref )++ ;
613
+ GC_FLAGS (ref ) &= ~IS_GC_INNER_GARBAGE ;
611
614
buf -> ref = ref ;
612
615
buf -> next = GC_G (roots ).next ;
613
616
buf -> prev = & GC_G (roots );
614
617
GC_G (roots ).next -> prev = buf ;
615
618
GC_G (roots ).next = buf ;
616
619
GC_REF_SET_ADDRESS (ref , buf - GC_G (buf ));
617
- * flags |= GC_HAS_DESTRUCTORS ;
618
620
}
619
- } else {
620
- * flags |= GC_HAS_DESTRUCTORS ;
621
621
}
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 ;
625
623
}
626
624
ZVAL_OBJ (& tmp , obj );
627
625
ht = get_gc (& tmp , & zv , & n );
@@ -657,20 +655,17 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags)
657
655
}
658
656
} else if (GC_TYPE (ref ) == IS_ARRAY ) {
659
657
if (!GC_ADDRESS (GC_INFO (ref ))) {
660
- GC_FLAGS (ref ) |= IS_GC_INNER_CYCLE ;
661
658
* flags |= GC_HAS_INNER_CYCLES ;
662
659
}
663
660
ht = (zend_array * )ref ;
664
661
} else if (GC_TYPE (ref ) == IS_REFERENCE ) {
665
- GC_FLAGS (ref ) |= IS_GC_INNER_CYCLE ;
666
662
if (Z_REFCOUNTED (((zend_reference * )ref )-> val )) {
667
663
ref = Z_COUNTED (((zend_reference * )ref )-> val );
668
664
GC_REFCOUNT (ref )++ ;
669
665
goto tail_call ;
670
666
}
671
667
return count ;
672
668
} else {
673
- GC_FLAGS (ref ) |= IS_GC_INNER_CYCLE ;
674
669
return count ;
675
670
}
676
671
@@ -719,6 +714,7 @@ static int gc_collect_roots(uint32_t *flags)
719
714
720
715
current = GC_G (roots ).next ;
721
716
while (current != & GC_G (roots )) {
717
+ GC_REFCOUNT (current -> ref )++ ;
722
718
if (GC_REF_GET_COLOR (current -> ref ) == GC_WHITE ) {
723
719
count += gc_collect_white (current -> ref , flags );
724
720
}
@@ -753,14 +749,14 @@ static void gc_break_cycles(zend_refcounted *ref, zval *zv)
753
749
Bucket * p , * end ;
754
750
755
751
tail_call :
756
- if (zv && !(GC_FLAGS (ref ) & IS_GC_INNER_CYCLE )) {
752
+ if (zv && !(GC_FLAGS (ref ) & IS_GC_INNER_GARBAGE )) {
757
753
GC_REFCOUNT (ref )-- ;
758
754
ZVAL_NULL (zv );
759
755
return ;
760
756
}
761
- GC_FLAGS (ref ) &= ~IS_GC_INNER_CYCLE ;
757
+ GC_FLAGS (ref ) &= ~IS_GC_INNER_GARBAGE ;
762
758
763
- if (GC_TYPE (ref ) == IS_OBJECT ) {
759
+ if (GC_TYPE (ref ) == IS_OBJECT && !( GC_FLAGS ( ref ) & IS_OBJ_FREE_CALLED ) ) {
764
760
zend_object_get_gc_t get_gc ;
765
761
zend_object * obj = (zend_object * )ref ;
766
762
@@ -833,9 +829,10 @@ static void gc_remove_nested_data_from_buffer(zend_refcounted *ref)
833
829
tail_call :
834
830
if (GC_ADDRESS (GC_INFO (ref )) != 0 && GC_REF_GET_COLOR (ref ) == GC_BLACK ) {
835
831
GC_TRACE_REF (ref , "removing from buffer" );
832
+ GC_REFCOUNT (ref )-- ;
836
833
GC_REMOVE_FROM_BUFFER (ref );
837
834
838
- if (GC_TYPE (ref ) == IS_OBJECT ) {
835
+ if (GC_TYPE (ref ) == IS_OBJECT && !( GC_FLAGS ( ref ) & IS_OBJ_FREE_CALLED ) ) {
839
836
zend_object_get_gc_t get_gc ;
840
837
zend_object * obj = (zend_object * )ref ;
841
838
@@ -960,16 +957,16 @@ ZEND_API int zend_gc_collect_cycles(void)
960
957
#endif
961
958
962
959
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 */
971
960
GC_TRACE ("Calling destructors" );
972
961
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 */
973
970
current = to_free .next ;
974
971
while (current != & to_free ) {
975
972
p = current -> ref ;
@@ -1026,6 +1023,7 @@ ZEND_API int zend_gc_collect_cycles(void)
1026
1023
if (EG (objects_store ).object_buckets &&
1027
1024
IS_OBJ_VALID (EG (objects_store ).object_buckets [obj -> handle ])) {
1028
1025
GC_TYPE (obj ) = IS_NULL ;
1026
+ GC_INFO_SET_COLOR (GC_INFO (obj ), GC_WHITE );
1029
1027
if (!(GC_FLAGS (obj ) & IS_OBJ_FREE_CALLED )) {
1030
1028
GC_FLAGS (obj ) |= IS_OBJ_FREE_CALLED ;
1031
1029
if (obj -> handlers -> free_obj ) {
@@ -1042,6 +1040,7 @@ ZEND_API int zend_gc_collect_cycles(void)
1042
1040
zend_array * arr = (zend_array * )p ;
1043
1041
1044
1042
GC_TYPE (arr ) = IS_NULL ;
1043
+ GC_INFO_SET_COLOR (GC_INFO (arr ), GC_WHITE );
1045
1044
zend_hash_destroy (arr );
1046
1045
}
1047
1046
current = GC_G (next_to_free );
0 commit comments