|
|
@ -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
|
|
|
|
|
|
|
|