252
252
253
253
ZEND_API int (* gc_collect_cycles )(void );
254
254
255
+ /*
256
+ * The type of a root buffer entry.
257
+ *
258
+ * The lower two bits are used for flags and need to be masked out to
259
+ * reconstruct a pointer.
260
+ *
261
+ * When a node in the root buffer is removed, the non-flag bits of the
262
+ * unused entry are used to store the index of the next entry in the unused
263
+ * list. */
255
264
typedef struct _gc_root_buffer {
256
265
zend_refcounted * ref ;
257
266
} gc_root_buffer ;
@@ -260,14 +269,7 @@ typedef struct _zend_gc_globals {
260
269
/*
261
270
* The root buffer, which stores possible roots of reference cycles. It is
262
271
* also used to store garbage to be collected at the end of a run.
263
- * A single array which is reallocated as necessary.
264
- *
265
- * The lower two bits in each entry are used for flags and need to be masked
266
- * out to reconstruct a pointer.
267
- *
268
- * When an object in the root buffer is removed, the non-flag bits of the
269
- * unused entry are used to store the index of the next entry in the unused
270
- * list. */
272
+ * A single array which is reallocated as necessary. */
271
273
gc_root_buffer * buf ;
272
274
273
275
bool gc_enabled ;
@@ -282,12 +284,12 @@ typedef struct _zend_gc_globals {
282
284
uint32_t num_roots ; /* number of roots in GC buffer */
283
285
284
286
uint32_t gc_runs ; /* number of GC runs since reset */
285
- uint32_t collected ; /* number of collected objects since reset */
287
+ uint32_t collected ; /* number of collected nodes since reset */
286
288
287
289
zend_hrtime_t activated_at ; /* the timestamp of the last reset */
288
290
zend_hrtime_t collector_time ; /* time spent running GC (ns) */
289
291
zend_hrtime_t dtor_time ; /* time spent calling destructors (ns) */
290
- zend_hrtime_t free_time ; /* time spent destroying objects and freeing memory (ns) */
292
+ zend_hrtime_t free_time ; /* time spent destroying nodes and freeing memory (ns) */
291
293
292
294
uint32_t dtor_idx ; /* root buffer index */
293
295
uint32_t dtor_end ;
@@ -400,8 +402,8 @@ static void gc_stack_free(gc_stack *stack)
400
402
* Map a full index to a compressed index.
401
403
*
402
404
* The root buffer can have up to 2^30 entries, but we only have 20 bits to
403
- * store the index. So we use the 1<<19 as a compression flag and use the other
404
- * 19 bits to store the index modulo 2^19. */
405
+ * store the index. So we use the 1<<19 bit as a compression flag and use the
406
+ * other 19 bits to store the index modulo 2^19. */
405
407
static zend_always_inline uint32_t gc_compress (uint32_t idx )
406
408
{
407
409
if (EXPECTED (idx < GC_MAX_UNCOMPRESSED )) {
@@ -506,7 +508,6 @@ static zend_always_inline void gc_remove_from_roots(gc_root_buffer *root)
506
508
GC_BENCH_DEC (root_buf_length );
507
509
}
508
510
509
- /* Destroy the root buffer */
510
511
static void root_buffer_dtor (zend_gc_globals * gc_globals )
511
512
{
512
513
if (gc_globals -> buf ) {
@@ -636,7 +637,6 @@ ZEND_API bool gc_protected(void)
636
637
return GC_G (gc_protected );
637
638
}
638
639
639
- /* Reallocate the GC root buffer */
640
640
static void gc_grow_root_buffer (void )
641
641
{
642
642
size_t new_size ;
@@ -662,7 +662,7 @@ static void gc_grow_root_buffer(void)
662
662
GC_G (buf_size ) = new_size ;
663
663
}
664
664
665
- /* Adjust the GC activation threshold given the number of objects collected by the last run */
665
+ /* Adjust the GC activation threshold given the number of nodes collected by the last run */
666
666
static void gc_adjust_threshold (int count )
667
667
{
668
668
uint32_t new_threshold ;
@@ -693,7 +693,7 @@ static void gc_adjust_threshold(int count)
693
693
}
694
694
}
695
695
696
- /* Add an object as a possible root, and perform a GC run unless one is active already . */
696
+ /* Perform a GC run and then add a node as a possible root . */
697
697
static zend_never_inline void ZEND_FASTCALL gc_possible_root_when_full (zend_refcounted * ref )
698
698
{
699
699
uint32_t idx ;
@@ -738,7 +738,7 @@ static zend_never_inline void ZEND_FASTCALL gc_possible_root_when_full(zend_refc
738
738
GC_BENCH_PEAK (root_buf_peak , root_buf_length );
739
739
}
740
740
741
- /* Add a possible root object to the buffer.
741
+ /* Add a possible root node to the buffer.
742
742
* Maybe perform a GC run. */
743
743
ZEND_API void ZEND_FASTCALL gc_possible_root (zend_refcounted * ref )
744
744
{
@@ -810,14 +810,13 @@ static void ZEND_FASTCALL gc_extra_root(zend_refcounted *ref)
810
810
GC_BENCH_PEAK (root_buf_peak , root_buf_length );
811
811
}
812
812
813
- /* Remove an object from the root buffer given its compressed index */
813
+ /* Remove a node from the root buffer given its compressed index */
814
814
static zend_never_inline void ZEND_FASTCALL gc_remove_compressed (zend_refcounted * ref , uint32_t idx )
815
815
{
816
816
gc_root_buffer * root = gc_decompress (ref , idx );
817
817
gc_remove_from_roots (root );
818
818
}
819
819
820
- /* Remove an object from the root buffer */
821
820
ZEND_API void ZEND_FASTCALL gc_remove_from_buffer (zend_refcounted * ref )
822
821
{
823
822
gc_root_buffer * root ;
@@ -841,10 +840,10 @@ ZEND_API void ZEND_FASTCALL gc_remove_from_buffer(zend_refcounted *ref)
841
840
gc_remove_from_roots (root );
842
841
}
843
842
844
- /* Traverse the graph of objects referred to by ref. Change grey objects back
845
- * to black, and restore their reference counts . See ScanBlack() in Bacon & Rajan.
846
- * To implement a depth-first search, discovered objects are added to a stack which
847
- * is processed iteratively. */
843
+ /* Mark all nodes reachable from ref as black (live). Restore the reference
844
+ * counts decremented by gc_mark_grey() . See ScanBlack() in Bacon & Rajan.
845
+ * To implement a depth-first search, discovered nodes are added to a stack
846
+ * which is processed iteratively. */
848
847
static void gc_scan_black (zend_refcounted * ref , gc_stack * stack )
849
848
{
850
849
HashTable * ht ;
@@ -1044,8 +1043,8 @@ static void gc_scan_black(zend_refcounted *ref, gc_stack *stack)
1044
1043
}
1045
1044
}
1046
1045
1047
- /* Traverse the graph of objects referred to by ref. Decrement the reference
1048
- * counts and mark visited objects grey. See MarkGray() in Bacon & Rajan. */
1046
+ /* Traverse the graph of nodes referred to by ref. Decrement the reference
1047
+ * counts and mark visited nodes grey. See MarkGray() in Bacon & Rajan. */
1049
1048
static void gc_mark_grey (zend_refcounted * ref , gc_stack * stack )
1050
1049
{
1051
1050
HashTable * ht ;
@@ -1258,8 +1257,9 @@ static void gc_compact(void)
1258
1257
}
1259
1258
}
1260
1259
1261
- /* For all roots marked purple, traverse the graph, marking referred objects grey.
1262
- * See MarkRoots() in Bacon & Rajan. */
1260
+ /* For all roots marked purple, traverse the graph, decrementing the reference
1261
+ * count of visited nodes. Mark visited nodes grey so that their reference
1262
+ * counts will only be decremented once. See MarkRoots() in Bacon & Rajan. */
1263
1263
static void gc_mark_roots (gc_stack * stack )
1264
1264
{
1265
1265
gc_root_buffer * current , * last ;
@@ -1470,7 +1470,7 @@ static void gc_scan_roots(gc_stack *stack)
1470
1470
}
1471
1471
}
1472
1472
1473
- /* Add an object to the buffer with the garbage flag, so that it will be
1473
+ /* Add a node to the buffer with the garbage flag, so that it will be
1474
1474
* destroyed and freed when the scan is complete. */
1475
1475
static void gc_add_garbage (zend_refcounted * ref )
1476
1476
{
@@ -1497,7 +1497,7 @@ static void gc_add_garbage(zend_refcounted *ref)
1497
1497
GC_G (num_roots )++ ;
1498
1498
}
1499
1499
1500
- /* Traverse the reference graph from ref, marking any white objects as garbage. */
1500
+ /* Traverse the reference graph from ref, marking any white nodes as garbage. */
1501
1501
static int gc_collect_white (zend_refcounted * ref , uint32_t * flags , gc_stack * stack )
1502
1502
{
1503
1503
int count = 0 ;
0 commit comments