From 0c0e9e537588136a6a290bbb2e47cae43bbcfd18 Mon Sep 17 00:00:00 2001 From: Titouan Rigoudy Date: Thu, 18 Dec 2014 19:38:29 -0500 Subject: [PATCH] Replaced some macros with inline functions --- ya_block.c | 85 ++++++++++++++++++++++++++++++++++-------------------- ya_block.h | 41 +++++++++++++++++++------- yamalloc.c | 54 +++++++++++++++++----------------- 3 files changed, 109 insertions(+), 71 deletions(-) diff --git a/ya_block.c b/ya_block.c index c8fed85..2d2ed9b 100644 --- a/ya_block.c +++ b/ya_block.c @@ -4,12 +4,21 @@ * Defines operations on blocks and boundary tags */ +/*---------------------*/ +/* Feature test macros */ +/*---------------------*/ + +#define _DEFAULT_SOURCE // for sbrk + /*----------*/ /* Includes */ /*----------*/ -#include "ya_block.h" +#include +#include + #include "ya_debug.h" +#include "ya_block.h" /*---------*/ /* Globals */ @@ -24,12 +33,15 @@ intptr_t *heap_end = NULL; // first block outside heap #ifdef YA_DEBUG void block_print_range(intptr_t *start, intptr_t *end) { + if (!start || !end) { + return; + } intptr_t *block; - intptr_t block_size; - for (block = start; block < end; block += block_size) { - block_size = YA_BLK_SZ(block); + intptr_t size; + for (block = start; block < end; block += size) { + size = block_size(block); printf("Block at %p size = %ld alloc = %d\n", - block, block_size, YA_BLK_IS_ALLOC(block)); + block, size, block_is_alloc(block)); } } #endif @@ -42,16 +54,24 @@ void block_init(intptr_t *block, intptr_t size) { /* Sets the allocated bit in the block's boundary tags. */ void block_alloc(intptr_t *block) { - intptr_t block_size = YA_BLK_SZ(block); - block[-1] |= 1; - block[block_size-2] |= 1; + intptr_t size = block_size(block); + block[-1] |= 1; + block[size-2] |= 1; } /* Erases the allocated bit in the block's boundary tags. */ void block_free(intptr_t *block) { - intptr_t block_size = YA_BLK_SZ(block); - block[-1] &= -2; - block[block_size-2] &= -2; + intptr_t size = block_size(block); + block[-1] &= -2; + block[size-2] &= -2; +} + +/* Fills block with zeros. */ +void block_clear(intptr_t *block) { + intptr_t *end = block + block_size(block) - 2; + for (intptr_t *p = block; p < end; p++) { + *p = 0; + } } /* Returns the size in words of the smallest block that can @@ -68,46 +88,47 @@ intptr_t block_fit(size_t n_bytes) { /* Tries to coalesce a block with its previous neighbor. * Returns a pointer to the coalesced block. */ intptr_t *block_join_prev(intptr_t *block) { - intptr_t prev_size = YA_TAG_SZ(block[-2]); + if (block < heap_start + YA_BLK_MIN_SZ) { + return block; // there cannot be a previous block + } + intptr_t prev_size = tag_size(block[-2]); intptr_t *prev = block - prev_size; - if (prev <= heap_start || YA_BLK_IS_ALLOC(prev)) { + if (prev <= heap_start || block_is_alloc(prev)) { return block; } - intptr_t block_size = YA_BLK_SZ(block); - block_init(prev, prev_size + block_size); + intptr_t size = block_size(block); + block_init(prev, prev_size + size); ya_debug("block_join_prev: joining %p:%ld and %p:%ld -> %p:%ld\n", - block, block_size, prev, prev_size, prev, prev_size + block_size); + block, size, prev, prev_size, prev, prev_size + size); return prev; } /* Tries to colesce a block with its next neighbor. * Returns the unchanged pointer to the block. */ intptr_t *block_join_next(intptr_t *block) { - intptr_t block_size = YA_BLK_SZ(block); - intptr_t *next = block + block_size; - if (next >= heap_end || YA_BLK_IS_ALLOC(next)) { + intptr_t size = block_size(block); + intptr_t *next = block + size; + if (next >= heap_end || block_is_alloc(next)) { return block; } - intptr_t next_size = YA_BLK_SZ(next); - block_init(block, block_size + next_size); + intptr_t next_size = block_size(next); + block_init(block, size + next_size); ya_debug("block_join_next: joining %p:%ld and %p:%ld -> %p:%ld\n", - block, block_size, next, next_size, block, block_size + next_size); + block, size, next, next_size, block, size + next_size); return block; } /* Tries to coalesce a block with its previous and next neighbors. * Returns a pointer to the coalesced block. */ intptr_t *block_join(intptr_t *block) { - if (block > heap_start) { - block = block_join_prev(block); - } + block = block_join_prev(block); return block_join_next(block); } /* Split the block [block_size] into [size, block_size - size] if possible * Returns a pointer to the second block or NULL if no split occurred. */ intptr_t *block_split(intptr_t *block, intptr_t size) { - intptr_t next_size = YA_BLK_SZ(block) - size; + intptr_t next_size = block_size(block) - size; if (next_size < YA_BLK_MIN_SZ) { return NULL; // not enough space to warrant a split } @@ -119,17 +140,17 @@ intptr_t *block_split(intptr_t *block, intptr_t size) { /* Try to find a free block at least size words big by walking the boundary * tags. If no block is found the heap is grown adequately. * Returns a pointer to the block or NULL in case of failure. */ -intptr_t *block_find(intptr_t size) { +intptr_t *block_find(intptr_t min_size) { intptr_t *block; - intptr_t block_size; - for (block = heap_start; block < heap_end; block += block_size) { - block_size = YA_BLK_SZ(block); - if (!YA_BLK_IS_ALLOC(block) && size <= block_size) { + intptr_t size; + for (block = heap_start; block < heap_end; block += size) { + size = block_size(block); + if (!block_is_alloc(block) && min_size <= size) { return block; } } // could not find block, extend heap - return heap_extend(size); + return heap_extend(min_size); } /* Initializes the heap by calling sbrk to allocate some starter memory. diff --git a/ya_block.h b/ya_block.h index 27adfe9..841b132 100644 --- a/ya_block.h +++ b/ya_block.h @@ -12,6 +12,7 @@ #include // for size_t #include // for intptr_t +#include /*-----------*/ /* Constants */ @@ -27,15 +28,6 @@ /* Macros */ /*--------*/ -#define YA_TAG_IS_ALLOC(tag) ((tag) & 1) -#define YA_TAG_SZ(tag) ((tag) & -2) - -#define YA_BLK_IS_ALLOC(block) YA_TAG_IS_ALLOC((block)[-1]) -#define YA_BLK_SZ(block) YA_TAG_SZ((block)[-1]) - -#define YA_END_IS_ALLOC(b_end) YA_TAG_IS_ALLOC((b_end)[0]) -#define YA_END_SZ(b_end) YA_TAG_SZ((b_end)[0]) - #define YA_ROUND_DIV(n, m) (((n) + ((m)-1)) / (m)) #define YA_ROUND(n, m) (YA_ROUND_DIV(n,m) * (m)) @@ -46,6 +38,30 @@ extern intptr_t *heap_start; // with space for 2 words before extern intptr_t *heap_end ; // first block outside heap +/*---------*/ +/* Inlines */ +/*---------*/ + +/* Returns true iff the boundary tag has the allocated bit set. */ +static inline bool tag_is_alloc(intptr_t tag) { + return tag & 1; +} + +/* Returns true iff the block's boundary tag has the allocated bit set. */ +static inline bool block_is_alloc(intptr_t *block) { + return tag_is_alloc(block[-1]); +} + +/* Returns the size stored in the boundary tag. */ +static inline intptr_t tag_size(intptr_t tag) { + return tag & -2; +} + +/* Returns the size stored in the block's boundary tag. */ +static inline intptr_t block_size(intptr_t *block) { + return tag_size(block[-1]); +} + /*--------------*/ /* Declarations */ /*--------------*/ @@ -59,7 +75,7 @@ intptr_t *heap_init(); * Returns a pointer to the last (free) block or NULL in case of failure. */ intptr_t *heap_extend(intptr_t size_w); -#ifdef DEBUG +#ifdef YA_DEBUG /* Prints each block in the range from the block at start to the one at end */ void block_print_range(intptr_t *start, intptr_t *end); #endif @@ -73,6 +89,9 @@ void block_alloc(intptr_t *block); /* Erases the allocated bit in the block's boundary tags. */ void block_free(intptr_t *block); +/* Fills block with zeros. */ +void block_clear(intptr_t *block); + /* Returns the size in words of the smallest block that can * store n_bytes bytes. Takes alignment and boundary tags into account */ intptr_t block_fit(size_t n_bytes); @@ -96,6 +115,6 @@ intptr_t *block_split(intptr_t *block, intptr_t size); /* Try to find a free block at least size words big by walking the boundary * tags. If no block is found the heap is grown adequately. * Returns a pointer to the block or NULL in case of failure. */ -intptr_t *block_find(intptr_t size); +intptr_t *block_find(intptr_t min_size); #endif diff --git a/yamalloc.c b/yamalloc.c index 126b173..bcefeec 100644 --- a/yamalloc.c +++ b/yamalloc.c @@ -49,8 +49,8 @@ void ya_print_blocks() { /* Allocates enough memory to store at least size bytes. * Returns a dword-aligned pointer to the memory or NULL in case of failure. */ -void *malloc(size_t size) { - if (size == 0) { +void *malloc(size_t n_bytes) { + if (n_bytes == 0) { return NULL; } if (heap_start == NULL || heap_end == NULL) { @@ -58,12 +58,9 @@ void *malloc(size_t size) { return NULL; } } - intptr_t size_w = block_fit(size); - intptr_t *block = block_find(size_w); - intptr_t block_size = YA_BLK_SZ(block); - if (size_w < block_size) { - block_split(block, size_w); - } + intptr_t min_size = block_fit(n_bytes); + intptr_t *block = block_find(min_size); + block_split(block, min_size); block_alloc(block); return block; } @@ -73,7 +70,7 @@ void *malloc(size_t size) { * behavior occurs. */ void free(void *ptr) { intptr_t *block = ptr; - if (block < heap_start || block > heap_end || !YA_BLK_IS_ALLOC(block)) { + if (block < heap_start || block > heap_end || !block_is_alloc(block)) { return; // TODO: provoke segfault } block_free(block); @@ -83,12 +80,10 @@ void free(void *ptr) { /* Allocates enough memory to store an array of nmemb elements, * each size bytes large, and clears the memory. * Returns the pointer to the allocated memory or NULL in case of failure. */ -void *calloc(size_t nmemb, size_t size) { - intptr_t *block = malloc(size * nmemb); - intptr_t block_size = YA_BLK_SZ(block); - for (int i = 0; i < block_size - 2; i++) { - block[i] = 0; - } +void *calloc(size_t nmemb, size_t n_bytes) { + intptr_t *block = malloc(n_bytes * nmemb); + intptr_t size = block_size(block); + block_clear(block); return block; } @@ -98,34 +93,37 @@ void *calloc(size_t nmemb, size_t size) { * If ptr does not point to memory previously allocated by malloc, calloc or * realloc, undefined behavior occurs. * */ -void *realloc(void *ptr, size_t size) { +void *realloc(void *ptr, size_t n_bytes) { if (!ptr) { - return malloc(size); + return malloc(n_bytes); } - if (size == 0) { + if (n_bytes == 0) { free(ptr); } intptr_t *block = ptr; if (block < heap_start) { return NULL; // TODO: provoke segfault } - intptr_t size_w = block_fit(size); - intptr_t block_size = YA_BLK_SZ(block); // segfault if ptr after heap end - if (size_w <= block_size) { - intptr_t *next = block_split(block, size_w); + intptr_t new_size = block_fit(n_bytes); + intptr_t size = block_size(block); // segfault if ptr after heap end + if (new_size == size) { + return ptr; // don't change anything + } + if (new_size < size) { + intptr_t *next = block_split(block, new_size); if (next) { block_join_next(next); // coalesce the leftovers } block_alloc(block); return block; } - intptr_t *next = block + block_size; + intptr_t *next = block + size; // try to use next free block if (next < heap_end) { - intptr_t next_size = YA_BLK_SZ(next); - if (!YA_BLK_IS_ALLOC(next) && size_w <= block_size + next_size) { + intptr_t next_size = block_size(next); + if (!block_is_alloc(next) && new_size <= size + next_size) { block_join_next(block); // coalesce - block_split(block, size_w); // split if possible + block_split(block, new_size); // split if possible // no need to coalesce block_alloc(block); // mark block as allocated return block; @@ -134,8 +132,8 @@ void *realloc(void *ptr, size_t size) { // resizing failed, so allocate a whole new block and copy // could handle the case when the block is the last in the heap // a bit more gracefully and just grow the heap instead of copying - intptr_t *new_block = malloc(size); - for (int i = 0; i < block_size; i++) { + intptr_t *new_block = malloc(n_bytes); + for (int i = 0; i < size; i++) { new_block[i] = block[i]; } free(block);