Allow allocate_memory() to reuse holes when matching exactly.
This requires recovering the pointer of the allocation, which could be done by adding up neighbor lengths, but the simpler way is to stop NULLing it out in the first place and instead mark an allocation as freed by the client by setting the lowest bit of the length (which is always zero in a valid length).
This commit is contained in:
parent
d6d02c67d2
commit
5bdb8c45dd
@ -37,6 +37,10 @@
|
||||
// impossible to support zero-length allocations).
|
||||
#define FREE 0
|
||||
|
||||
// The lowest two bits of a valid length are always zero, so we can use them to mark an allocation
|
||||
// as freed by the client but not yet reclaimed into the FREE middle.
|
||||
#define HOLE 1
|
||||
|
||||
static supervisor_allocation allocations[CIRCUITPY_SUPERVISOR_ALLOC_COUNT];
|
||||
// We use uint32_t* to ensure word (4 byte) alignment.
|
||||
uint32_t* low_address;
|
||||
@ -67,9 +71,10 @@ void free_memory(supervisor_allocation* allocation) {
|
||||
high_address += allocation->length / 4;
|
||||
allocation->length = FREE;
|
||||
for (index++; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT; index++) {
|
||||
if (allocations[index].ptr != NULL) {
|
||||
if (!(allocations[index].length & HOLE)) {
|
||||
break;
|
||||
}
|
||||
// Division automatically shifts out the HOLE bit.
|
||||
high_address += allocations[index].length / 4;
|
||||
allocations[index].length = FREE;
|
||||
}
|
||||
@ -77,7 +82,7 @@ void free_memory(supervisor_allocation* allocation) {
|
||||
low_address = allocation->ptr;
|
||||
allocation->length = FREE;
|
||||
for (index--; index >= 0; index--) {
|
||||
if (allocations[index].ptr != NULL) {
|
||||
if (!(allocations[index].length & HOLE)) {
|
||||
break;
|
||||
}
|
||||
low_address -= allocations[index].length / 4;
|
||||
@ -85,9 +90,10 @@ void free_memory(supervisor_allocation* allocation) {
|
||||
}
|
||||
} else {
|
||||
// Freed memory isn't in the middle so skip updating bounds. The memory will be added to the
|
||||
// middle when the memory to the inside is freed.
|
||||
// middle when the memory to the inside is freed. We still need its length, but setting
|
||||
// only the lowest bit is nondestructive.
|
||||
allocation->length |= HOLE;
|
||||
}
|
||||
allocation->ptr = NULL;
|
||||
}
|
||||
|
||||
supervisor_allocation* allocation_from_ptr(void *ptr) {
|
||||
@ -107,7 +113,7 @@ supervisor_allocation* allocate_remaining_memory(void) {
|
||||
}
|
||||
|
||||
supervisor_allocation* allocate_memory(uint32_t length, bool high) {
|
||||
if (length == 0 || (high_address - low_address) * 4 < (int32_t) length || length % 4 != 0) {
|
||||
if (length == 0 || length % 4 != 0) {
|
||||
return NULL;
|
||||
}
|
||||
uint8_t index = 0;
|
||||
@ -116,15 +122,21 @@ supervisor_allocation* allocate_memory(uint32_t length, bool high) {
|
||||
index = CIRCUITPY_SUPERVISOR_ALLOC_COUNT - 1;
|
||||
direction = -1;
|
||||
}
|
||||
supervisor_allocation* alloc;
|
||||
for (; index < CIRCUITPY_SUPERVISOR_ALLOC_COUNT; index += direction) {
|
||||
if (allocations[index].length == FREE) {
|
||||
alloc = &allocations[index];
|
||||
if (alloc->length == FREE) {
|
||||
break;
|
||||
}
|
||||
// If a hole matches in length exactly, we can reuse it.
|
||||
if (alloc->length == (length | HOLE)) {
|
||||
alloc->length = length;
|
||||
return alloc;
|
||||
}
|
||||
}
|
||||
if (index >= CIRCUITPY_SUPERVISOR_ALLOC_COUNT) {
|
||||
if (index >= CIRCUITPY_SUPERVISOR_ALLOC_COUNT || (high_address - low_address) * 4 < (int32_t) length) {
|
||||
return NULL;
|
||||
}
|
||||
supervisor_allocation* alloc = &allocations[index];
|
||||
if (high) {
|
||||
high_address -= length / 4;
|
||||
alloc->ptr = high_address;
|
||||
|
Loading…
x
Reference in New Issue
Block a user