#include #include "private.h" #include "context.h" #include "node.h" /*--------------------------------------------------------- */ static void lub_heap_free_leading_memory(lub_heap_t * this, lub_heap_block_t * block, size_t size) { lub_heap_block_t *prev_block = lub_heap_block_getprevious(block); if (prev_block && prev_block->free.tag.free) { /* * add the excess bytes to a preceeding free block */ lub_heap_graft_to_top(this, prev_block, block, (size >> 2), BOOL_FALSE, BOOL_FALSE); } else { /* * convert the excess bytes into a free block */ lub_heap_init_free_block(this, block, size, block->alloc.tag.segment, BOOL_FALSE); } this->stats.alloc_bytes -= size; } /*--------------------------------------------------------- */ static void lub_heap_free_trailing_memory(lub_heap_t * this, lub_heap_block_t * block, size_t size) { bool_t done = BOOL_FALSE; lub_heap_block_t *next_block = lub_heap_block_getnext(block); lub_heap_tag_t *tail = lub_heap_block__get_tail(block); char *ptr = (char *)&tail[1] - size; if (next_block && next_block->free.tag.free) { /* * try and add the excess bytes to a following free block */ lub_heap_graft_to_bottom(this, next_block, ptr, (size >> 2), BOOL_FALSE, BOOL_FALSE); done = BOOL_TRUE; } else if (size >= sizeof(lub_heap_free_block_t)) { /* * convert the excess bytes into a free block */ lub_heap_init_free_block(this, ptr, size, BOOL_FALSE, tail->segment); done = BOOL_TRUE; } if (done) { /* correct the word count for the block */ block->alloc.tag.words -= (size >> 2); tail = lub_heap_block__get_tail(block); tail->segment = 0; tail->free = 0; tail->words = block->alloc.tag.words; this->stats.alloc_bytes -= size; } } /*--------------------------------------------------------- */ void lub_heap_align_block(lub_heap_t * this, lub_heap_align_t alignment, char **ptr, size_t * size) { if (*ptr) { lub_heap_block_t *block = lub_heap_block_from_ptr(*ptr); lub_heap_block_t *new_block; lub_heap_tag_t *new_tail; /* find the second occurance of an alignment boundary */ size_t tmp = (alignment - 1); char *new_ptr = (char *)(((size_t) * ptr + tmp + alignment) & ~tmp); size_t leading_bytes = (new_ptr - *ptr); size_t trailing_bytes; /* check this is a allocated block */ assert(0 == block->alloc.tag.free); /* * We MUST have left sufficient space to fit a free block and * leak dection node if necessary. */ assert(leading_bytes >= (sizeof(lub_heap_free_block_t) + sizeof(lub_heap_node_t))); if ((0 < lub_heap_frame_count) && (0 == this->suppress)) { /* * If leak detection is enabled then offset the pointer back by the size of * a lub_heap_node; which will be filled out by lub_heap_post_realloc() */ new_ptr -= sizeof(lub_heap_node_t); leading_bytes -= sizeof(lub_heap_node_t); } /* * Create a new header just before the new pointer */ new_block = lub_heap_block_from_ptr(new_ptr); new_block->alloc.tag.free = 0; new_block->alloc.tag.segment = 0; new_block->alloc.tag.words = block->alloc.tag.words - (leading_bytes >> 2); /* fix the size in the tail */ new_tail = lub_heap_block__get_tail(new_block); new_tail->words = new_block->alloc.tag.words; lub_heap_free_leading_memory(this, block, leading_bytes); /* identify any trailing excess memory */ trailing_bytes = (new_block->alloc.tag.words << 2) - (*size - (alignment << 1)); if (trailing_bytes) { lub_heap_free_trailing_memory(this, new_block, trailing_bytes); } *size = (new_block->alloc.tag.words << 2); /* size including the lub_heap_alloc_block_t details */ *ptr = new_ptr; } }