Skip to content

Commit 9b0b373

Browse files
committed
py: Fix GC realloc issue, where memory chunks were never shrunk.
Previously, a realloc to a smaller memory chunk size would not free the unused blocks in the tail of the chunk.
1 parent 4859edb commit 9b0b373

File tree

1 file changed

+19
-13
lines changed

1 file changed

+19
-13
lines changed

py/gc.c

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -567,22 +567,28 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
567567
// compute number of new blocks that are requested
568568
mp_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK;
569569

570-
// get the number of consecutive tail blocks and
571-
// the number of free blocks after last tail block
572-
// stop if we reach (or are at) end of heap
570+
// Get the total number of consecutive blocks that are already allocated to
571+
// this chunk of memory, and then count the number of free blocks following
572+
// it. Stop if we reach the end of the heap, or if we find enough extra
573+
// free blocks to satisfy the realloc. Note that we need to compute the
574+
// total size of the existing memory chunk so we can correctly and
575+
// efficiently shrink it (see below for shrinking code).
573576
mp_uint_t n_free = 0;
574577
mp_uint_t n_blocks = 1; // counting HEAD block
575578
mp_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
576-
while (block + n_blocks + n_free < max_block) {
577-
if (n_blocks + n_free >= new_blocks) {
578-
// stop as soon as we find enough blocks for n_bytes
579-
break;
579+
for (mp_uint_t bl = block + n_blocks; bl < max_block; bl++) {
580+
byte block_type = ATB_GET_KIND(bl);
581+
if (block_type == AT_TAIL) {
582+
n_blocks++;
583+
continue;
580584
}
581-
byte block_type = ATB_GET_KIND(block + n_blocks + n_free);
582-
switch (block_type) {
583-
case AT_FREE: n_free++; continue;
584-
case AT_TAIL: n_blocks++; continue;
585-
case AT_MARK: assert(0);
585+
if (block_type == AT_FREE) {
586+
n_free++;
587+
if (n_blocks + n_free >= new_blocks) {
588+
// stop as soon as we find enough blocks for n_bytes
589+
break;
590+
}
591+
continue;
586592
}
587593
break;
588594
}
@@ -595,7 +601,7 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) {
595601
// check if we can shrink the allocated area
596602
if (new_blocks < n_blocks) {
597603
// free unneeded tail blocks
598-
for (mp_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
604+
for (mp_uint_t bl = block + new_blocks, count = n_blocks - new_blocks; count > 0; bl++, count--) {
599605
ATB_ANY_TO_FREE(bl);
600606
}
601607

0 commit comments

Comments
 (0)