@@ -471,6 +471,24 @@ static inline mp_state_mem_area_t *gc_get_ptr_area(const void *ptr) {
471471#endif
472472#endif
473473
474+ // Use this to debug a specific pointer that should have been collected and break on the particular
475+ // allocation that returns the pointer.
476+ // Set debug_collect to true to perform the subtree scan for everything and print out any blocks that
477+ // have pointers that would have been collected. Then, set the block's ptr to target_ptr to print out
478+ // the allocation that returns the pointer. Set target_count to the number of allocations to skip
479+ // before breaking on the allocation (so you can get a backtrace.) This approach only works if the
480+ // code is deterministic. You may want to turn off USB host to make it so.
481+ //
482+ // Otherwise, you can inspect word 0 of the block to likely get the Python object type of the memory
483+ // that should have been collected. Compare that pointer to those in the matching firmware.elf.map.
484+ static bool debug_collect = false;
485+ static void * target_ptr = (void * )0x1101b8d0 ;
486+
487+ #if MICROPY_ENABLE_SELECTIVE_COLLECT
488+ static uint32_t target_count = 100 ;
489+ static uint32_t current_count = 0 ;
490+ #endif
491+
474492// Take the given block as the topmost block on the stack. Check all it's
475493// children: mark the unmarked child blocks and put those newly marked
476494// blocks on the stack. When all children have been checked, pop off the
@@ -506,12 +524,14 @@ static void MP_NO_INSTRUMENT PLACE_IN_ITCM(gc_mark_subtree)(size_t block)
506524 #endif
507525
508526 // Only scan the block's children if it's not a leaf
509- if (should_scan ) {
527+ if (debug_collect || should_scan ) {
510528 // check this block's children
511529 void * * ptrs = (void * * )PTR_FROM_BLOCK (area , block );
512530 for (size_t i = n_blocks * BYTES_PER_BLOCK / sizeof (void * ); i > 0 ; i -- , ptrs ++ ) {
513531 MICROPY_GC_HOOK_LOOP (i );
514532 void * ptr = * ptrs ;
533+ void * * block_ptr = ptrs ;
534+ bool found_collect_candidate = false;
515535 // If this is a heap pointer that hasn't been marked, mark it and push
516536 // it's children to the stack.
517537 #if MICROPY_GC_SPLIT_HEAP
@@ -526,6 +546,19 @@ static void MP_NO_INSTRUMENT PLACE_IN_ITCM(gc_mark_subtree)(size_t block)
526546 }
527547 mp_state_mem_area_t * ptr_area = area ;
528548 #endif
549+ if (!should_scan ) {
550+ if (!found_collect_candidate ) {
551+ console_uart_printf ("should have scanned %p\n" , block_ptr );
552+ // This is often the pointer to the Python type in RAM.
553+ // It is helpful to know the allocation path that should use mp_obj_malloc.
554+ console_uart_printf (" [0] = %p\n" , block_ptr [0 ]);
555+ console_uart_printf (" [1] = %p\n" , block_ptr [1 ]);
556+ }
557+ console_uart_printf (" [%d] = %p\n" , i , ptr );
558+ found_collect_candidate = true;
559+ ptr = NULL ;
560+ continue ;
561+ }
529562 size_t ptr_block = BLOCK_FROM_PTR (ptr_area , ptr );
530563 if (ATB_GET_KIND (ptr_area , ptr_block ) != AT_HEAD ) {
531564 // This block is already marked.
@@ -925,7 +958,7 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) {
925958
926959 // CIRCUITPY-CHANGE
927960 #if CIRCUITPY_DEBUG
928- gc_dump_alloc_table (& mp_plat_print );
961+ // gc_dump_alloc_table(&mp_plat_print);
929962 #endif
930963 return NULL ;
931964 }
@@ -1027,6 +1060,22 @@ void *gc_alloc(size_t n_bytes, unsigned int alloc_flags) {
10271060 memorymonitor_track_allocation (end_block - start_block + 1 );
10281061 #endif
10291062
1063+ #if MICROPY_ENABLE_SELECTIVE_COLLECT
1064+ if (debug_collect ) {
1065+ if (ret_ptr == target_ptr ) {
1066+ if (current_count == target_count && do_not_collect ) {
1067+ asm ("bkpt" );
1068+ }
1069+ console_uart_printf ("target_count = %d\n" , current_count );
1070+ current_count ++ ;
1071+ }
1072+
1073+ if (target_ptr != NULL && ret_ptr == target_ptr ) {
1074+ console_uart_printf ("gc_alloc(%d, %01x) = %p\n" , n_bytes , alloc_flags , ret_ptr );
1075+ }
1076+ }
1077+ #endif
1078+
10301079 return ret_ptr ;
10311080}
10321081
@@ -1060,6 +1109,10 @@ void gc_free(void *ptr) {
10601109 return ;
10611110 }
10621111
1112+ if (debug_collect && target_ptr != NULL && ptr == target_ptr ) {
1113+ console_uart_printf ("gc_free(%p)\n" , ptr );
1114+ }
1115+
10631116 // get the GC block number corresponding to this pointer
10641117 mp_state_mem_area_t * area ;
10651118 #if MICROPY_GC_SPLIT_HEAP
@@ -1345,6 +1398,9 @@ void *gc_realloc(void *ptr_in, size_t n_bytes, bool allow_move) {
13451398 // can't resize inplace; try to find a new contiguous chain
13461399 void * ptr_out = gc_alloc (n_bytes , alloc_flags );
13471400
1401+ if (debug_collect && target_ptr != NULL && (ptr_out == target_ptr || ptr_in == target_ptr )) {
1402+ console_uart_printf ("gc_realloc: moving %p -> %p, %d -> %d bytes\n" , ptr_in , ptr_out , n_blocks * BYTES_PER_BLOCK , n_bytes );
1403+ }
13481404 // check that the alloc succeeded
13491405 if (ptr_out == NULL ) {
13501406 return NULL ;
0 commit comments