@@ -27,15 +27,17 @@ typedef unsigned char byte;
2727#define STACK_SIZE (64) // tunable; minimum is 1
2828
2929STATIC byte * gc_alloc_table_start ;
30- STATIC byte * gc_mpobj_table_start ;
3130STATIC machine_uint_t gc_alloc_table_byte_len ;
32- STATIC machine_uint_t gc_mpobj_table_byte_len ;
31+ #if MICROPY_ENABLE_FINALISER
32+ STATIC byte * gc_finaliser_table_start ;
33+ #endif
3334STATIC machine_uint_t * gc_pool_start ;
3435STATIC machine_uint_t * gc_pool_end ;
3536
3637STATIC int gc_stack_overflow ;
3738STATIC machine_uint_t gc_stack [STACK_SIZE ];
3839STATIC machine_uint_t * gc_sp ;
40+ STATIC bool gc_lock ;
3941
4042// ATB = allocation table byte
4143// 0b00 = FREE -- free block
@@ -67,38 +69,58 @@ STATIC machine_uint_t *gc_sp;
6769#define ATB_HEAD_TO_MARK (block ) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] |= (AT_MARK << BLOCK_SHIFT(block)); } while (0)
6870#define ATB_MARK_TO_HEAD (block ) do { gc_alloc_table_start[(block) / BLOCKS_PER_ATB] &= (~(AT_TAIL << BLOCK_SHIFT(block))); } while (0)
6971
70- #define ATB_SET_MPOBJ (block ) do { gc_mpobj_table_start[(block) / 8] |= (1<<(block%8)); } while (0)
71- #define ATB_CLR_MPOBJ (block ) do { gc_mpobj_table_start[(block) / 8] &= (~(1<<(block%8))); } while (0)
72- #define ATB_IS_MPOBJ (block ) ((gc_mpobj_table_start[(block) / 8]>>(block%8))&0x01)
73-
7472#define BLOCK_FROM_PTR (ptr ) (((ptr) - (machine_uint_t)gc_pool_start) / BYTES_PER_BLOCK)
7573#define PTR_FROM_BLOCK (block ) (((block) * BYTES_PER_BLOCK + (machine_uint_t)gc_pool_start))
7674#define ATB_FROM_BLOCK (bl ) ((bl) / BLOCKS_PER_ATB)
7775
76+ #if MICROPY_ENABLE_FINALISER
77+ // FTB = finaliser table byte
78+ // if set, then the corresponding block may have a finaliser
79+
80+ #define BLOCKS_PER_FTB (8)
81+
82+ #define FTB_GET (block ) ((gc_finaliser_table_start[(block) / BLOCKS_PER_FTB] >> ((block) & 7)) & 1)
83+ #define FTB_SET (block ) do { gc_finaliser_table_start[(block) / BLOCKS_PER_FTB] |= (1 << ((block) & 7)); } while (0)
84+ #define FTB_CLEAR (block ) do { gc_finaliser_table_start[(block) / BLOCKS_PER_FTB] &= (~(1 << ((block) & 7))); } while (0)
85+ #endif
86+
7887// TODO waste less memory; currently requires that all entries in alloc_table have a corresponding block in pool
7988void gc_init (void * start , void * end ) {
8089 // align end pointer on block boundary
8190 end = (void * )((machine_uint_t )end & (~(BYTES_PER_BLOCK - 1 )));
82- DEBUG_printf ("Initializing GC heap: %p-%p\n" , start , end );
91+ DEBUG_printf ("Initializing GC heap: %p..%p = %ld bytes\n" , start , end , end - start );
92+
93+ // calculate parameters for GC (T=total, A=alloc table, F=finaliser table, P=pool; all in bytes):
94+ // T = A + F + P
95+ // F = A * BLOCKS_PER_ATB / BLOCKS_PER_FTB
96+ // P = A * BLOCKS_PER_ATB * BYTES_PER_BLOCK
97+ // => T = A * (1 + BLOCKS_PER_ATB / BLOCKS_PER_FTB + BLOCKS_PER_ATB * BYTES_PER_BLOCK)
98+ machine_uint_t total_byte_len = end - start ;
99+ #if MICROPY_ENABLE_FINALISER
100+ gc_alloc_table_byte_len = total_byte_len * BITS_PER_BYTE / (BITS_PER_BYTE + BITS_PER_BYTE * BLOCKS_PER_ATB / BLOCKS_PER_FTB + BITS_PER_BYTE * BLOCKS_PER_ATB * BYTES_PER_BLOCK );
101+ #else
102+ gc_alloc_table_byte_len = total_byte_len / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK );
103+ #endif
104+
83105
84- // calculate parameters for GC
85- machine_uint_t total_word_len = (machine_uint_t * )end - (machine_uint_t * )start ;
86- gc_alloc_table_byte_len = total_word_len * BYTES_PER_WORD / (1 + BITS_PER_BYTE / 2 * BYTES_PER_BLOCK );
87106 gc_alloc_table_start = (byte * )start ;
88107
89- gc_mpobj_table_byte_len = (gc_alloc_table_byte_len * BITS_PER_BYTE / 2 )/8 ;
90- gc_mpobj_table_start = gc_alloc_table_start + gc_alloc_table_byte_len ;
108+ #if MICROPY_ENABLE_FINALISER
109+ machine_uint_t gc_finaliser_table_byte_len = (gc_alloc_table_byte_len * BLOCKS_PER_ATB ) / BLOCKS_PER_FTB ;
110+ gc_finaliser_table_start = gc_alloc_table_start + gc_alloc_table_byte_len ;
111+ #endif
91112
92- machine_uint_t gc_pool_block_len = (gc_alloc_table_byte_len * BITS_PER_BYTE / 2 ) - (gc_mpobj_table_byte_len / BYTES_PER_BLOCK );
93- machine_uint_t gc_pool_word_len = gc_pool_block_len * WORDS_PER_BLOCK ;
94- gc_pool_start = (machine_uint_t * )end - gc_pool_word_len ;
113+ machine_uint_t gc_pool_block_len = gc_alloc_table_byte_len * BLOCKS_PER_ATB ;
114+ gc_pool_start = end - gc_pool_block_len * BYTES_PER_BLOCK ;
95115 gc_pool_end = end ;
96116
97117 // clear ATBs
98118 memset (gc_alloc_table_start , 0 , gc_alloc_table_byte_len );
99119
100- // clear MPOBJ flags
101- memset (gc_mpobj_table_start , 0 , gc_mpobj_table_byte_len );
120+ #if MICROPY_ENABLE_FINALISER
121+ // clear FTBs
122+ memset (gc_finaliser_table_start , 0 , gc_finaliser_table_byte_len );
123+ #endif
102124
103125 // allocate first block because gc_pool_start points there and it will never
104126 // be freed, so allocating 1 block with null pointers will minimise memory loss
@@ -107,9 +129,15 @@ void gc_init(void *start, void *end) {
107129 gc_pool_start [i ] = 0 ;
108130 }
109131
132+ // unlock the GC
133+ gc_lock = false;
134+
110135 DEBUG_printf ("GC layout:\n" );
111- DEBUG_printf (" alloc table at %p, length " UINT_FMT " bytes\n" , gc_alloc_table_start , gc_alloc_table_byte_len );
112- DEBUG_printf (" pool at %p, length " UINT_FMT " blocks = " UINT_FMT " words = " UINT_FMT " bytes\n" , gc_pool_start , gc_pool_block_len , gc_pool_word_len , gc_pool_word_len * BYTES_PER_WORD );
136+ DEBUG_printf (" alloc table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n" , gc_alloc_table_start , gc_alloc_table_byte_len , gc_alloc_table_byte_len * BLOCKS_PER_ATB );
137+ #if MICROPY_ENABLE_FINALISER
138+ DEBUG_printf (" finaliser table at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n" , gc_finaliser_table_start , gc_finaliser_table_byte_len , gc_finaliser_table_byte_len * BLOCKS_PER_FTB );
139+ #endif
140+ DEBUG_printf (" pool at %p, length " UINT_FMT " bytes, " UINT_FMT " blocks\n" , gc_pool_start , gc_pool_block_len * BYTES_PER_BLOCK , gc_pool_block_len );
113141}
114142
115143#define VERIFY_PTR (ptr ) ( \
@@ -176,16 +204,22 @@ STATIC void gc_sweep(void) {
176204 for (machine_uint_t block = 0 ; block < gc_alloc_table_byte_len * BLOCKS_PER_ATB ; block ++ ) {
177205 switch (ATB_GET_KIND (block )) {
178206 case AT_HEAD :
179- if (ATB_IS_MPOBJ (block )) {
180- mp_obj_t dest [2 ];
181- mp_load_method ((mp_obj_t * )PTR_FROM_BLOCK (block ), MP_QSTR___del__ , dest );
182- // load_method returned a method
183- if (dest [1 ] != MP_OBJ_NULL ) {
184- mp_call_method_n_kw (0 , 0 , dest );
207+ #if MICROPY_ENABLE_FINALISER
208+ if (FTB_GET (block )) {
209+ mp_obj_t obj = (mp_obj_t )PTR_FROM_BLOCK (block );
210+ if (((mp_obj_base_t * )obj )-> type != MP_OBJ_NULL ) {
211+ // if the object has a type then see if it has a __del__ method
212+ mp_obj_t dest [2 ];
213+ mp_load_method_maybe (obj , MP_QSTR___del__ , dest );
214+ if (dest [0 ] != MP_OBJ_NULL ) {
215+ // load_method returned a method
216+ mp_call_method_n_kw (0 , 0 , dest );
217+ }
185218 }
186- // clear mpobj flag
187- ATB_CLR_MPOBJ (block );
219+ // clear finaliser flag
220+ FTB_CLEAR (block );
188221 }
222+ #endif
189223 free_tail = 1 ;
190224 // fall through to free the head
191225
@@ -204,6 +238,7 @@ STATIC void gc_sweep(void) {
204238}
205239
206240void gc_collect_start (void ) {
241+ gc_lock = true;
207242 gc_stack_overflow = 0 ;
208243 gc_sp = gc_stack ;
209244}
@@ -219,6 +254,7 @@ void gc_collect_root(void **ptrs, machine_uint_t len) {
219254void gc_collect_end (void ) {
220255 gc_deal_with_stack_overflow ();
221256 gc_sweep ();
257+ gc_lock = false;
222258}
223259
224260void gc_info (gc_info_t * info ) {
@@ -266,10 +302,14 @@ void gc_info(gc_info_t *info) {
266302 info -> free *= BYTES_PER_BLOCK ;
267303}
268304
269- void * _gc_alloc (machine_uint_t n_bytes , bool is_mpobj ) {
305+ void * gc_alloc (machine_uint_t n_bytes , bool has_finaliser ) {
270306 machine_uint_t n_blocks = ((n_bytes + BYTES_PER_BLOCK - 1 ) & (~(BYTES_PER_BLOCK - 1 ))) / BYTES_PER_BLOCK ;
271307 DEBUG_printf ("gc_alloc(" UINT_FMT " bytes -> " UINT_FMT " blocks)\n" , n_bytes , n_blocks );
272308
309+ if (gc_lock ) {
310+ // TODO
311+ }
312+
273313 // check for 0 allocation
274314 if (n_blocks == 0 ) {
275315 return NULL ;
@@ -315,25 +355,37 @@ void *_gc_alloc(machine_uint_t n_bytes, bool is_mpobj) {
315355 ATB_FREE_TO_TAIL (bl );
316356 }
317357
318- if (is_mpobj ) {
319- // set mp_obj flag only if it has del
320- ATB_SET_MPOBJ (start_block );
358+ // get pointer to first block
359+ void * ret_ptr = (void * )(gc_pool_start + start_block * WORDS_PER_BLOCK );
360+
361+ #if MICROPY_ENABLE_FINALISER
362+ if (has_finaliser ) {
363+ // clear type pointer in case it is never set
364+ ((mp_obj_base_t * )ret_ptr )-> type = MP_OBJ_NULL ;
365+ // set mp_obj flag only if it has a finaliser
366+ FTB_SET (start_block );
321367 }
368+ #endif
322369
323- // return pointer to first block
324- return (void * )(gc_pool_start + start_block * WORDS_PER_BLOCK );
370+ return ret_ptr ;
325371}
326372
373+ /*
327374void *gc_alloc(machine_uint_t n_bytes) {
328375 return _gc_alloc(n_bytes, false);
329376}
330377
331- void * gc_alloc_mp_obj (machine_uint_t n_bytes ) {
378+ void *gc_alloc_with_finaliser (machine_uint_t n_bytes) {
332379 return _gc_alloc(n_bytes, true);
333380}
381+ */
334382
335383// force the freeing of a piece of memory
336384void gc_free (void * ptr_in ) {
385+ if (gc_lock ) {
386+ // TODO
387+ }
388+
337389 machine_uint_t ptr = (machine_uint_t )ptr_in ;
338390
339391 if (VERIFY_PTR (ptr )) {
@@ -386,12 +438,16 @@ void *gc_realloc(void *ptr, machine_uint_t n_bytes) {
386438}
387439#else
388440void * gc_realloc (void * ptr_in , machine_uint_t n_bytes ) {
441+ if (gc_lock ) {
442+ // TODO
443+ }
444+
389445 void * ptr_out = NULL ;
390446 machine_uint_t block = 0 ;
391447 machine_uint_t ptr = (machine_uint_t )ptr_in ;
392448
393449 if (ptr_in == NULL ) {
394- return gc_alloc (n_bytes );
450+ return gc_alloc (n_bytes , false );
395451 }
396452
397453 if (VERIFY_PTR (ptr ) // verify pointer
@@ -444,7 +500,13 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
444500 ptr_out = ptr_in ;
445501
446502 // try to find a new contiguous chain
447- } else if ((ptr_out = gc_alloc (n_bytes )) != NULL ) {
503+ } else if ((ptr_out = gc_alloc (n_bytes ,
504+ #if MICROPY_ENABLE_FINALISER
505+ FTB_GET (block )
506+ #else
507+ false
508+ #endif
509+ )) != NULL ) {
448510 DEBUG_printf ("gc_realloc: allocating new block\n" );
449511 memcpy (ptr_out , ptr_in , n_existing );
450512 gc_free (ptr_in );
@@ -489,18 +551,18 @@ void gc_test(void) {
489551 gc_init (heap , heap + len / sizeof (machine_uint_t ));
490552 void * ptrs [100 ];
491553 {
492- machine_uint_t * * p = gc_alloc (16 );
493- p [0 ] = gc_alloc (64 );
494- p [1 ] = gc_alloc (1 );
495- p [2 ] = gc_alloc (1 );
496- p [3 ] = gc_alloc (1 );
497- machine_uint_t * * * p2 = gc_alloc (16 );
554+ machine_uint_t * * p = gc_alloc (16 , false );
555+ p [0 ] = gc_alloc (64 , false );
556+ p [1 ] = gc_alloc (1 , false );
557+ p [2 ] = gc_alloc (1 , false );
558+ p [3 ] = gc_alloc (1 , false );
559+ machine_uint_t * * * p2 = gc_alloc (16 , false );
498560 p2 [0 ] = p ;
499561 p2 [1 ] = p ;
500562 ptrs [0 ] = p2 ;
501563 }
502564 for (int i = 0 ; i < 25 ; i += 2 ) {
503- machine_uint_t * p = gc_alloc (i );
565+ machine_uint_t * p = gc_alloc (i , false );
504566 printf ("p=%p\n" , p );
505567 if (i & 3 ) {
506568 //ptrs[i] = p;
0 commit comments