@@ -477,29 +477,20 @@ static void gc_deal_with_stack_overflow(void) {
477477 }
478478}
479479
480- static void gc_sweep (void ) {
481- #if MICROPY_PY_GC_COLLECT_RETVAL
482- MP_STATE_MEM (gc_collected ) = 0 ;
483- #endif
484- // free unmarked heads and their tails
485- int free_tail = 0 ;
486- #if MICROPY_GC_SPLIT_HEAP_AUTO
487- mp_state_mem_area_t * prev_area = NULL ;
488- #endif
489- for (mp_state_mem_area_t * area = & MP_STATE_MEM (area ); area != NULL ; area = NEXT_AREA (area )) {
490- size_t end_block = area -> gc_alloc_table_byte_len * BLOCKS_PER_ATB ;
491- if (area -> gc_last_used_block < end_block ) {
492- end_block = area -> gc_last_used_block + 1 ;
493- }
494-
495- size_t last_used_block = 0 ;
496-
497- for (size_t block = 0 ; block < end_block ; block ++ ) {
498- MICROPY_GC_HOOK_LOOP (block );
499- switch (ATB_GET_KIND (area , block )) {
500- case AT_HEAD :
501- #if MICROPY_ENABLE_FINALISER
502- if (FTB_GET (area , block )) {
480+ // Run finalisers for all to-be-freed blocks
481+ static void gc_sweep_run_finalisers (void ) {
482+ #if MICROPY_ENABLE_FINALISER
483+ for (const mp_state_mem_area_t * area = & MP_STATE_MEM (area ); area != NULL ; area = NEXT_AREA (area )) {
484+ assert (area -> gc_last_used_block <= area -> gc_alloc_table_byte_len * BLOCKS_PER_ATB );
485+ // Small speed optimisation: skip over empty FTB blocks
486+ size_t ftb_end = area -> gc_last_used_block / BLOCKS_PER_FTB ; // index is inclusive
487+ for (size_t ftb_idx = 0 ; ftb_idx <= ftb_end ; ftb_idx ++ ) {
488+ byte ftb = area -> gc_finaliser_table_start [ftb_idx ];
489+ size_t block = ftb_idx * BLOCKS_PER_FTB ;
490+ while (ftb ) {
491+ MICROPY_GC_HOOK_LOOP (block );
492+ if (ftb & 1 ) { // FTB_GET(area, block) shortcut
493+ if (ATB_GET_KIND (area , block ) == AT_HEAD ) {
503494 mp_obj_base_t * obj = (mp_obj_base_t * )PTR_FROM_BLOCK (area , block );
504495 if (obj -> type != NULL ) {
505496 // if the object has a type then see if it has a __del__ method
@@ -519,7 +510,35 @@ static void gc_sweep(void) {
519510 // clear finaliser flag
520511 FTB_CLEAR (area , block );
521512 }
522- #endif
513+ }
514+ ftb >>= 1 ;
515+ block ++ ;
516+ }
517+ }
518+ }
519+ #endif // MICROPY_ENABLE_FINALISER
520+ }
521+
522+ static void gc_sweep (void ) {
523+ #if MICROPY_PY_GC_COLLECT_RETVAL
524+ MP_STATE_MEM (gc_collected ) = 0 ;
525+ #endif
526+ // free unmarked heads and their tails
527+ int free_tail = 0 ;
528+ #if MICROPY_GC_SPLIT_HEAP_AUTO
529+ mp_state_mem_area_t * prev_area = NULL ;
530+ #endif
531+
532+ gc_sweep_run_finalisers ();
533+
534+ for (mp_state_mem_area_t * area = & MP_STATE_MEM (area ); area != NULL ; area = NEXT_AREA (area )) {
535+ size_t last_used_block = 0 ;
536+ assert (area -> gc_last_used_block <= area -> gc_alloc_table_byte_len * BLOCKS_PER_ATB );
537+
538+ for (size_t block = 0 ; block <= area -> gc_last_used_block ; block ++ ) {
539+ MICROPY_GC_HOOK_LOOP (block );
540+ switch (ATB_GET_KIND (area , block )) {
541+ case AT_HEAD :
523542 free_tail = 1 ;
524543 DEBUG_printf ("gc_sweep(%p)\n" , (void * )PTR_FROM_BLOCK (area , block ));
525544 #if MICROPY_PY_GC_COLLECT_RETVAL
0 commit comments