summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--py/gc.c117
1 files changed, 65 insertions, 52 deletions
diff --git a/py/gc.c b/py/gc.c
index bcf6cfcdda..2930e90110 100644
--- a/py/gc.c
+++ b/py/gc.c
@@ -459,78 +459,91 @@ void *gc_realloc(void *ptr_in, machine_uint_t n_bytes) {
return NULL;
}
- void *ptr_out = NULL;
- machine_uint_t ptr = (machine_uint_t)ptr_in;
-
+ // check for pure allocation
if (ptr_in == NULL) {
return gc_alloc(n_bytes, false);
}
- machine_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK) / BYTES_PER_BLOCK;
+ machine_uint_t ptr = (machine_uint_t)ptr_in;
+
+ // sanity check the ptr
+ if (!VERIFY_PTR(ptr)) {
+ return NULL;
+ }
+
// get first block
machine_uint_t block = BLOCK_FROM_PTR(ptr);
- // Sabity checks
- if (VERIFY_PTR(ptr) && ATB_GET_KIND(block) == AT_HEAD) {
+ // sanity check the ptr is pointing to the head of a block
+ if (ATB_GET_KIND(block) != AT_HEAD) {
+ return NULL;
+ }
- byte block_type;
- machine_uint_t n_free = 0;
- machine_uint_t n_blocks = 1; // counting HEAD block
- machine_uint_t max_block = gc_alloc_table_byte_len * BLOCKS_PER_ATB;
+ // compute number of new blocks that are requested
+ machine_uint_t new_blocks = (n_bytes + BYTES_PER_BLOCK) / 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
- 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;
- }
- 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);
- }
+ // 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
+ machine_uint_t n_free = 0;
+ machine_uint_t n_blocks = 1; // counting HEAD block
+ machine_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;
}
+ 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);
+ }
+ break;
+ }
+
+ // return original ptr if it already has the requested number of blocks
+ if (new_blocks == n_blocks) {
+ return ptr_in;
+ }
- if (new_blocks == n_blocks) {
- return ptr_in;
+ // check if we can shrink the allocated area
+ if (new_blocks < n_blocks) {
+ // free unneeded tail blocks
+ for (machine_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
+ ATB_ANY_TO_FREE(bl);
}
+ return ptr_in;
+ }
- if (new_blocks < n_blocks) {
- // free unneeded tail blocks
- for (machine_uint_t bl = block + new_blocks; ATB_GET_KIND(bl) == AT_TAIL; bl++) {
- ATB_ANY_TO_FREE(bl);
- }
- return ptr_in;
-
- // check if we can expand in place
- } else if (new_blocks <= n_blocks + n_free) {
- // mark few more blocks as used tail
- for (machine_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
- assert(ATB_GET_KIND(bl) == AT_FREE);
- ATB_FREE_TO_TAIL(bl);
- }
- return ptr_in;
+ // check if we can expand in place
+ if (new_blocks <= n_blocks + n_free) {
+ // mark few more blocks as used tail
+ for (machine_uint_t bl = block + n_blocks; bl < block + new_blocks; bl++) {
+ assert(ATB_GET_KIND(bl) == AT_FREE);
+ ATB_FREE_TO_TAIL(bl);
+ }
+ return ptr_in;
+ }
- // try to find a new contiguous chain
- } else if ((ptr_out = gc_alloc(n_bytes,
+ // can't resize inplace; try to find a new contiguous chain
+ void *ptr_out = gc_alloc(n_bytes,
#if MICROPY_ENABLE_FINALISER
- FTB_GET(block)
+ FTB_GET(block)
#else
- false
+ false
#endif
- )) != NULL) {
- DEBUG_printf("gc_realloc: allocating new block\n");
- memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK);
- gc_free(ptr_in);
- return ptr_out;
- }
+ );
+
+ // check that the alloc succeeded
+ if (ptr_out == NULL) {
+ return NULL;
}
- return NULL;
+ DEBUG_printf("gc_realloc: allocating new block\n");
+ memcpy(ptr_out, ptr_in, n_blocks * BYTES_PER_BLOCK);
+ gc_free(ptr_in);
+ return ptr_out;
}
#endif // Alternative gc_realloc impl