@@ -983,6 +983,9 @@ static void gc_scan_black(zend_refcounted *ref, gc_stack *stack)
983
983
handle_ht :
984
984
n = ht -> nNumUsed ;
985
985
zv = ht -> arPacked ;
986
+ if (GC_FLAGS (ht ) & GC_NOT_COLLECTABLE ) {
987
+ goto next ;
988
+ }
986
989
if (HT_IS_PACKED (ht )) {
987
990
goto handle_zvals ;
988
991
}
@@ -1041,7 +1044,7 @@ static void gc_scan_black(zend_refcounted *ref, gc_stack *stack)
1041
1044
* counts and mark visited nodes grey. See MarkGray() in Bacon & Rajan. */
1042
1045
static void gc_mark_grey (zend_refcounted * ref , gc_stack * stack )
1043
1046
{
1044
- HashTable * ht ;
1047
+ HashTable * ht , * zvals_ht = NULL ;
1045
1048
Bucket * p ;
1046
1049
zval * zv ;
1047
1050
uint32_t n ;
@@ -1129,9 +1132,11 @@ static void gc_mark_grey(zend_refcounted *ref, gc_stack *stack)
1129
1132
goto handle_ht ;
1130
1133
}
1131
1134
}
1132
- handle_zvals :
1135
+ handle_zvals :;
1136
+ bool is_primitive = true;
1133
1137
for (; n != 0 ; n -- ) {
1134
1138
if (Z_COLLECTABLE_P (zv )) {
1139
+ is_primitive = false;
1135
1140
ref = Z_COUNTED_P (zv );
1136
1141
GC_DELREF (ref );
1137
1142
if (!GC_REF_CHECK_COLOR (ref , GC_GREY )) {
@@ -1148,29 +1153,40 @@ static void gc_mark_grey(zend_refcounted *ref, gc_stack *stack)
1148
1153
}
1149
1154
zv ++ ;
1150
1155
}
1156
+ zvals_ht = NULL ;
1151
1157
goto tail_call ;
1152
1158
}
1153
1159
}
1154
1160
zv ++ ;
1155
1161
}
1162
+ if (is_primitive && zvals_ht ) {
1163
+ GC_ADD_FLAGS (zvals_ht , GC_NOT_COLLECTABLE );
1164
+ }
1165
+ zvals_ht = NULL ;
1156
1166
}
1157
1167
} else if (GC_TYPE (ref ) == IS_ARRAY ) {
1158
1168
ZEND_ASSERT (((zend_array * )ref ) != & EG (symbol_table ));
1159
1169
ht = (zend_array * )ref ;
1160
1170
handle_ht :
1161
1171
n = ht -> nNumUsed ;
1172
+ if (GC_FLAGS (ht ) & GC_NOT_COLLECTABLE ) {
1173
+ goto next ;
1174
+ }
1162
1175
if (HT_IS_PACKED (ht )) {
1163
1176
zv = ht -> arPacked ;
1177
+ zvals_ht = ht ;
1164
1178
goto handle_zvals ;
1165
1179
}
1166
1180
1181
+ bool is_primitive = true;
1167
1182
p = ht -> arData ;
1168
1183
for (; n != 0 ; n -- ) {
1169
1184
zv = & p -> val ;
1170
1185
if (Z_TYPE_P (zv ) == IS_INDIRECT ) {
1171
1186
zv = Z_INDIRECT_P (zv );
1172
1187
}
1173
1188
if (Z_COLLECTABLE_P (zv )) {
1189
+ is_primitive = false;
1174
1190
ref = Z_COUNTED_P (zv );
1175
1191
GC_DELREF (ref );
1176
1192
if (!GC_REF_CHECK_COLOR (ref , GC_GREY )) {
@@ -1196,6 +1212,9 @@ static void gc_mark_grey(zend_refcounted *ref, gc_stack *stack)
1196
1212
}
1197
1213
p ++ ;
1198
1214
}
1215
+ if (is_primitive ) {
1216
+ GC_ADD_FLAGS (ht , GC_NOT_COLLECTABLE );
1217
+ }
1199
1218
} else if (GC_TYPE (ref ) == IS_REFERENCE ) {
1200
1219
if (Z_COLLECTABLE (((zend_reference * )ref )-> val )) {
1201
1220
ref = Z_COUNTED (((zend_reference * )ref )-> val );
@@ -1378,6 +1397,9 @@ static void gc_scan(zend_refcounted *ref, gc_stack *stack)
1378
1397
1379
1398
handle_ht :
1380
1399
n = ht -> nNumUsed ;
1400
+ if (GC_FLAGS (ht ) & GC_NOT_COLLECTABLE ) {
1401
+ goto next ;
1402
+ }
1381
1403
if (HT_IS_PACKED (ht )) {
1382
1404
zv = ht -> arPacked ;
1383
1405
goto handle_zvals ;
@@ -1623,6 +1645,9 @@ static int gc_collect_white(zend_refcounted *ref, uint32_t *flags, gc_stack *sta
1623
1645
1624
1646
handle_ht :
1625
1647
n = ht -> nNumUsed ;
1648
+ if (GC_FLAGS (ht ) & GC_NOT_COLLECTABLE ) {
1649
+ goto next ;
1650
+ }
1626
1651
if (HT_IS_PACKED (ht )) {
1627
1652
zv = ht -> arPacked ;
1628
1653
goto handle_zvals ;
@@ -1811,6 +1836,9 @@ static int gc_remove_nested_data_from_buffer(zend_refcounted *ref, gc_root_buffe
1811
1836
1812
1837
handle_ht :
1813
1838
n = ht -> nNumUsed ;
1839
+ if (GC_FLAGS (ht ) & GC_NOT_COLLECTABLE ) {
1840
+ goto next ;
1841
+ }
1814
1842
if (HT_IS_PACKED (ht )) {
1815
1843
zv = ht -> arPacked ;
1816
1844
goto handle_zvals ;
0 commit comments