From 9b0b373e5e400b5ddb88928d169a64502c880888 Mon Sep 17 00:00:00 2001 From: Damien George Date: Wed, 15 Oct 2014 18:24:47 +0000 Subject: [PATCH] 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. --- py/gc.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/py/gc.c b/py/gc.c index 969b6edd29..c641e738f2 100644 --- a/py/gc.c +++ b/py/gc.c @@ -567,22 +567,28 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) { // compute number of new blocks that are requested mp_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK - 1) / BYTES_PER_BLOCK; - // get the number of consecutive tail blocks and - // the number of free blocks after last tail block - // stop if we reach (or are at) end of heap + // Get the total number of consecutive blocks that are already allocated to + // this chunk of memory, and then count the number of free blocks following + // it. Stop if we reach the end of the heap, or if we find enough extra + // free blocks to satisfy the realloc. Note that we need to compute the + // total size of the existing memory chunk so we can correctly and + // efficiently shrink it (see below for shrinking code). mp_uint_t n_free = 0; mp_uint_t n_blocks = 1; // counting HEAD block mp_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB; - while (block + n_blocks + n_free < max_block) { - if (n_blocks + n_free >= new_blocks) { - // stop as soon as we find enough blocks for n_bytes - break; + for (mp_uint_t bl = block + n_blocks; bl < max_block; bl++) { + byte block_type = ATB_GET_KIND(bl); + if (block_type == AT_TAIL) { + n_blocks++; + continue; } - byte block_type = ATB_GET_KIND(block + n_blocks + n_free); - switch (block_type) { - case AT_FREE: n_free++; continue; - case AT_TAIL: n_blocks++; continue; - case AT_MARK: assert(0); + if (block_type == AT_FREE) { + n_free++; + if (n_blocks + n_free >= new_blocks) { + // stop as soon as we find enough blocks for n_bytes + break; + } + continue; } break; } @@ -595,7 +601,7 @@ void *gc_realloc(void *ptr_in, mp_uint_t n_bytes) { // check if we can shrink the allocated area if (new_blocks < n_blocks) { // free unneeded tail blocks - for (mp_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) { + for (mp_uint_t bl = block + new_blocks, count = n_blocks - new_blocks; count > 0; bl++, count--) { ATB_ANY_TO_FREE(bl); }