3333
3434#define CIRCUITPY_SUPERVISOR_ALLOC_COUNT (12)
3535
36+ // Using a zero length to mark an unused allocation makes the code a bit shorter (but makes it
37+ // impossible to support zero-length allocations).
38+ #define FREE 0
39+
40+ // The lowest two bits of a valid length are always zero, so we can use them to mark an allocation
41+ // as freed by the client but not yet reclaimed into the FREE middle.
42+ #define HOLE 1
43+
3644static supervisor_allocation allocations [CIRCUITPY_SUPERVISOR_ALLOC_COUNT ];
3745// We use uint32_t* to ensure word (4 byte) alignment.
3846uint32_t * low_address ;
@@ -61,25 +69,31 @@ void free_memory(supervisor_allocation* allocation) {
6169 }
6270 if (allocation -> ptr == high_address ) {
6371 high_address += allocation -> length / 4 ;
72+ allocation -> length = FREE ;
6473 for (index ++ ; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT ; index ++ ) {
65- if (allocations [index ].ptr != NULL ) {
74+ if (!( allocations [index ].length & HOLE ) ) {
6675 break ;
6776 }
77+ // Division automatically shifts out the HOLE bit.
6878 high_address += allocations [index ].length / 4 ;
79+ allocations [index ].length = FREE ;
6980 }
7081 } else if (allocation -> ptr + allocation -> length / 4 == low_address ) {
7182 low_address = allocation -> ptr ;
83+ allocation -> length = FREE ;
7284 for (index -- ; index >= 0 ; index -- ) {
73- if (allocations [index ].ptr != NULL ) {
85+ if (!( allocations [index ].length & HOLE ) ) {
7486 break ;
7587 }
7688 low_address -= allocations [index ].length / 4 ;
89+ allocations [index ].length = FREE ;
7790 }
7891 } else {
7992 // Freed memory isn't in the middle so skip updating bounds. The memory will be added to the
80- // middle when the memory to the inside is freed.
93+ // middle when the memory to the inside is freed. We still need its length, but setting
94+ // only the lowest bit is nondestructive.
95+ allocation -> length |= HOLE ;
8196 }
82- allocation -> ptr = NULL ;
8397}
8498
8599supervisor_allocation * allocation_from_ptr (void * ptr ) {
@@ -99,7 +113,7 @@ supervisor_allocation* allocate_remaining_memory(void) {
99113}
100114
101115supervisor_allocation * allocate_memory (uint32_t length , bool high ) {
102- if (( high_address - low_address ) * 4 < ( int32_t ) length || length % 4 != 0 ) {
116+ if (length == 0 || length % 4 != 0 ) {
103117 return NULL ;
104118 }
105119 uint8_t index = 0 ;
@@ -108,15 +122,21 @@ supervisor_allocation* allocate_memory(uint32_t length, bool high) {
108122 index = CIRCUITPY_SUPERVISOR_ALLOC_COUNT - 1 ;
109123 direction = -1 ;
110124 }
125+ supervisor_allocation * alloc ;
111126 for (; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT ; index += direction ) {
112- if (allocations [index ].ptr == NULL ) {
127+ alloc = & allocations [index ];
128+ if (alloc -> length == FREE && (high_address - low_address ) * 4 >= (int32_t ) length ) {
113129 break ;
114130 }
131+ // If a hole matches in length exactly, we can reuse it.
132+ if (alloc -> length == (length | HOLE )) {
133+ alloc -> length = length ;
134+ return alloc ;
135+ }
115136 }
116137 if (index >= CIRCUITPY_SUPERVISOR_ALLOC_COUNT ) {
117138 return NULL ;
118139 }
119- supervisor_allocation * alloc = & allocations [index ];
120140 if (high ) {
121141 high_address -= length / 4 ;
122142 alloc -> ptr = high_address ;
0 commit comments