@@ -983,6 +983,9 @@ static void gc_scan_black(zend_refcounted *ref, gc_stack *stack)
983983handle_ht :
984984 n = ht -> nNumUsed ;
985985 zv = ht -> arPacked ;
986+ if (GC_FLAGS (ht ) & GC_NOT_COLLECTABLE ) {
987+ goto next ;
988+ }
986989 if (HT_IS_PACKED (ht )) {
987990 goto handle_zvals ;
988991 }
@@ -1041,7 +1044,7 @@ static void gc_scan_black(zend_refcounted *ref, gc_stack *stack)
10411044 * counts and mark visited nodes grey. See MarkGray() in Bacon & Rajan. */
10421045static void gc_mark_grey (zend_refcounted * ref , gc_stack * stack )
10431046{
1044- HashTable * ht ;
1047+ HashTable * ht , * zvals_ht = NULL ;
10451048 Bucket * p ;
10461049 zval * zv ;
10471050 uint32_t n ;
@@ -1129,9 +1132,11 @@ static void gc_mark_grey(zend_refcounted *ref, gc_stack *stack)
11291132 goto handle_ht ;
11301133 }
11311134 }
1132- handle_zvals :
1135+ handle_zvals :;
1136+ bool is_primitive = true;
11331137 for (; n != 0 ; n -- ) {
11341138 if (Z_COLLECTABLE_P (zv )) {
1139+ is_primitive = false;
11351140 ref = Z_COUNTED_P (zv );
11361141 GC_DELREF (ref );
11371142 if (!GC_REF_CHECK_COLOR (ref , GC_GREY )) {
@@ -1148,29 +1153,40 @@ static void gc_mark_grey(zend_refcounted *ref, gc_stack *stack)
11481153 }
11491154 zv ++ ;
11501155 }
1156+ zvals_ht = NULL ;
11511157 goto tail_call ;
11521158 }
11531159 }
11541160 zv ++ ;
11551161 }
1162+ if (is_primitive && zvals_ht ) {
1163+ GC_ADD_FLAGS (zvals_ht , GC_NOT_COLLECTABLE );
1164+ }
1165+ zvals_ht = NULL ;
11561166 }
11571167 } else if (GC_TYPE (ref ) == IS_ARRAY ) {
11581168 ZEND_ASSERT (((zend_array * )ref ) != & EG (symbol_table ));
11591169 ht = (zend_array * )ref ;
11601170handle_ht :
11611171 n = ht -> nNumUsed ;
1172+ if (GC_FLAGS (ht ) & GC_NOT_COLLECTABLE ) {
1173+ goto next ;
1174+ }
11621175 if (HT_IS_PACKED (ht )) {
11631176 zv = ht -> arPacked ;
1177+ zvals_ht = ht ;
11641178 goto handle_zvals ;
11651179 }
11661180
1181+ bool is_primitive = true;
11671182 p = ht -> arData ;
11681183 for (; n != 0 ; n -- ) {
11691184 zv = & p -> val ;
11701185 if (Z_TYPE_P (zv ) == IS_INDIRECT ) {
11711186 zv = Z_INDIRECT_P (zv );
11721187 }
11731188 if (Z_COLLECTABLE_P (zv )) {
1189+ is_primitive = false;
11741190 ref = Z_COUNTED_P (zv );
11751191 GC_DELREF (ref );
11761192 if (!GC_REF_CHECK_COLOR (ref , GC_GREY )) {
@@ -1196,6 +1212,9 @@ static void gc_mark_grey(zend_refcounted *ref, gc_stack *stack)
11961212 }
11971213 p ++ ;
11981214 }
1215+ if (is_primitive ) {
1216+ GC_ADD_FLAGS (ht , GC_NOT_COLLECTABLE );
1217+ }
11991218 } else if (GC_TYPE (ref ) == IS_REFERENCE ) {
12001219 if (Z_COLLECTABLE (((zend_reference * )ref )-> val )) {
12011220 ref = Z_COUNTED (((zend_reference * )ref )-> val );
@@ -1378,6 +1397,9 @@ static void gc_scan(zend_refcounted *ref, gc_stack *stack)
13781397
13791398handle_ht :
13801399 n = ht -> nNumUsed ;
1400+ if (GC_FLAGS (ht ) & GC_NOT_COLLECTABLE ) {
1401+ goto next ;
1402+ }
13811403 if (HT_IS_PACKED (ht )) {
13821404 zv = ht -> arPacked ;
13831405 goto handle_zvals ;
@@ -1623,6 +1645,9 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags, gc_stack *sta
16231645
16241646handle_ht :
16251647 n = ht -> nNumUsed ;
1648+ if (GC_FLAGS (ht ) & GC_NOT_COLLECTABLE ) {
1649+ goto next ;
1650+ }
16261651 if (HT_IS_PACKED (ht )) {
16271652 zv = ht -> arPacked ;
16281653 goto handle_zvals ;
@@ -1811,6 +1836,9 @@ static int gc_remove_nested_data_from_buffer(zend_refcounted *ref, gc_root_buffe
18111836
18121837handle_ht :
18131838 n = ht -> nNumUsed ;
1839+ if (GC_FLAGS (ht ) & GC_NOT_COLLECTABLE ) {
1840+ goto next ;
1841+ }
18141842 if (HT_IS_PACKED (ht )) {
18151843 zv = ht -> arPacked ;
18161844 goto handle_zvals ;
0 commit comments