|
|
@ -23,77 +23,95 @@ |
|
|
|
|
|
|
|
|
/* Macros */ |
|
|
/* Macros */ |
|
|
|
|
|
|
|
|
#define YA_IS_FREE(block) (((block)[0] & 1) == 0) |
|
|
|
|
|
|
|
|
#define YA_IS_ALLOC(block) ((block)[-1] & 1) |
|
|
|
|
|
#define YA_SZ_BLOCK(size) ((size) & -2) |
|
|
#define YA_ROUND_DIV(n, m) (((n) + ((m)-1)) / (m)) |
|
|
#define YA_ROUND_DIV(n, m) (((n) + ((m)-1)) / (m)) |
|
|
#define YA_ROUND(n, m) (YA_ROUND_DIV(n,m) * (m)) |
|
|
|
|
|
|
|
|
#define YA_ROUND(n, m) (YA_ROUND_DIV(n,m) * (m)) |
|
|
|
|
|
|
|
|
/* Globals */ |
|
|
/* Globals */ |
|
|
|
|
|
|
|
|
intptr_t *heap_start = NULL; |
|
|
|
|
|
intptr_t *heap_end = NULL; |
|
|
|
|
|
|
|
|
intptr_t *heap_start = NULL; // space for 2 words before |
|
|
|
|
|
intptr_t *heap_end = NULL; // first block outside heap |
|
|
|
|
|
|
|
|
/* Local declarations */ |
|
|
/* Local declarations */ |
|
|
|
|
|
|
|
|
int heap_init(); |
|
|
|
|
|
int heap_extend(); |
|
|
|
|
|
|
|
|
intptr_t *heap_init(); |
|
|
|
|
|
intptr_t *heap_extend(intptr_t size); |
|
|
|
|
|
|
|
|
void block_join(intptr_t *block); |
|
|
|
|
|
|
|
|
intptr_t *block_join(intptr_t *block); |
|
|
|
|
|
|
|
|
/* Function definitions */ |
|
|
/* Function definitions */ |
|
|
|
|
|
|
|
|
#ifdef YA_DEBUG |
|
|
#ifdef YA_DEBUG |
|
|
void ya_print_blocks() { |
|
|
void ya_print_blocks() { |
|
|
for (intptr_t *ptr = heap_start; ptr < heap_end; ptr += ptr[0]) { |
|
|
|
|
|
fprintf(stderr, "Block at %p, size %ld\n", ptr, ptr[0]); |
|
|
|
|
|
|
|
|
intptr_t *block; |
|
|
|
|
|
intptr_t block_size; |
|
|
|
|
|
for (block = heap_start; block < heap_end; block += block_size) { |
|
|
|
|
|
block_size = YA_SZ_BLOCK(block[-1]); |
|
|
|
|
|
fprintf(stderr, "Block at %p size = %ld alloc = %d\n", |
|
|
|
|
|
block, block_size, YA_IS_ALLOC(block)); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
#endif |
|
|
#endif |
|
|
|
|
|
|
|
|
void block_join_prev(intptr_t *block) { |
|
|
|
|
|
intptr_t *prev = block - block[-1]; |
|
|
|
|
|
if (prev >= heap_start && YA_IS_FREE(prev)) { |
|
|
|
|
|
intptr_t size = prev[0] + block[0]; |
|
|
|
|
|
prev[0] = size; |
|
|
|
|
|
block[block[0] - 1] = size; |
|
|
|
|
|
|
|
|
intptr_t *block_join_prev(intptr_t *block) { |
|
|
|
|
|
intptr_t prev_size = YA_SZ_BLOCK(block[-2]); |
|
|
|
|
|
intptr_t *prev = block - prev_size; |
|
|
|
|
|
if (prev <= heap_start || YA_IS_ALLOC(prev)) { |
|
|
|
|
|
return block; |
|
|
} |
|
|
} |
|
|
|
|
|
intptr_t block_size = YA_SZ_BLOCK(block[-1]); |
|
|
|
|
|
intptr_t size = prev_size + block_size; |
|
|
|
|
|
prev[-1] = size; |
|
|
|
|
|
block[block_size - 2] = size; |
|
|
|
|
|
return prev; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void block_join_next(intptr_t *block) { |
|
|
|
|
|
intptr_t *next = block + block[0]; |
|
|
|
|
|
if (next < heap_end && YA_IS_FREE(next)) { |
|
|
|
|
|
intptr_t size = next[0] + block[0]; |
|
|
|
|
|
block[0] = size; |
|
|
|
|
|
next[next[0] - 1] = size; |
|
|
|
|
|
|
|
|
intptr_t *block_join_next(intptr_t *block) { |
|
|
|
|
|
intptr_t block_size = YA_SZ_BLOCK(block[-1]); |
|
|
|
|
|
intptr_t *next = block + block_size; |
|
|
|
|
|
if (next >= heap_end || YA_IS_ALLOC(next)) { |
|
|
|
|
|
return block; |
|
|
} |
|
|
} |
|
|
|
|
|
intptr_t next_size = YA_SZ_BLOCK(next[-1]); |
|
|
|
|
|
intptr_t size = next_size + block_size; |
|
|
|
|
|
block[-1] = size; |
|
|
|
|
|
next[next_size - 2] = size; |
|
|
|
|
|
return block; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void block_join(intptr_t *block) { |
|
|
|
|
|
|
|
|
intptr_t *block_join(intptr_t *block) { |
|
|
if (block > heap_start) { |
|
|
if (block > heap_start) { |
|
|
block_join_prev(block); |
|
|
|
|
|
|
|
|
block = block_join_prev(block); |
|
|
} |
|
|
} |
|
|
block_join_next(block); |
|
|
|
|
|
|
|
|
return block_join_next(block); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void block_split(intptr_t *block, intptr_t size) { |
|
|
void block_split(intptr_t *block, intptr_t size) { |
|
|
intptr_t old_size = block[0]; |
|
|
|
|
|
block[0] = size; |
|
|
|
|
|
block[size - 1] = size; |
|
|
|
|
|
block[size] = old_size - size; |
|
|
|
|
|
block[old_size - 1] = old_size - size; |
|
|
|
|
|
|
|
|
intptr_t old_size = YA_SZ_BLOCK(block[-1]); |
|
|
|
|
|
block[-1] = size; |
|
|
|
|
|
block[size - 2] = size; |
|
|
|
|
|
block[size - 1] = old_size - size; |
|
|
|
|
|
block[old_size - 2] = old_size - size; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
int heap_init() { |
|
|
|
|
|
heap_start = sbrk(0); |
|
|
|
|
|
if (heap_start == (void*) -1) { |
|
|
|
|
|
|
|
|
intptr_t *heap_init() { |
|
|
|
|
|
intptr_t size_w = YA_SZ_CHUNK / YA_SZ_WORD; |
|
|
|
|
|
void *ptr = sbrk(YA_SZ_WORD * (size_w + 2)); |
|
|
|
|
|
if (ptr == (void*) -1) { |
|
|
heap_start = NULL; |
|
|
heap_start = NULL; |
|
|
heap_end = NULL; |
|
|
heap_end = NULL; |
|
|
return -1; |
|
|
|
|
|
|
|
|
return NULL; |
|
|
} |
|
|
} |
|
|
heap_end = heap_start; |
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
heap_start = ptr; |
|
|
|
|
|
heap_start += 2; // space for the first block[-1] + dword alignment |
|
|
|
|
|
heap_end = heap_start + size_w; |
|
|
|
|
|
heap_start[-1] = size_w; |
|
|
|
|
|
heap_end[-2] = size_w; |
|
|
|
|
|
return heap_start; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
int heap_extend(intptr_t size_w) { |
|
|
|
|
|
|
|
|
intptr_t *heap_extend(intptr_t size_w) { |
|
|
fprintf(stderr, "heap_extend: old heap_start = %p, heap_end = %p\n", |
|
|
fprintf(stderr, "heap_extend: old heap_start = %p, heap_end = %p\n", |
|
|
heap_start, heap_end); |
|
|
heap_start, heap_end); |
|
|
intptr_t size = YA_ROUND(size_w * YA_SZ_WORD, YA_SZ_CHUNK); |
|
|
intptr_t size = YA_ROUND(size_w * YA_SZ_WORD, YA_SZ_CHUNK); |
|
|
@ -101,19 +119,14 @@ int heap_extend(intptr_t size_w) { |
|
|
fprintf(stderr, "heap_extend: %ld bytes, %ld words\n", size, size_w); |
|
|
fprintf(stderr, "heap_extend: %ld bytes, %ld words\n", size, size_w); |
|
|
void *ptr = sbrk(size); |
|
|
void *ptr = sbrk(size); |
|
|
if (ptr == (void *) - 1) { |
|
|
if (ptr == (void *) - 1) { |
|
|
return -1; |
|
|
|
|
|
|
|
|
return NULL; |
|
|
} |
|
|
} |
|
|
fprintf(stderr, "heap_extend: %ld bytes, %ld words\n", size, size_w); |
|
|
|
|
|
heap_end[0] = size_w; |
|
|
|
|
|
heap_end[size_w - 1] = size_w; |
|
|
|
|
|
fprintf(stderr, "heap_extend: heap_end = %p, heap_end + size_w = %p\n", |
|
|
|
|
|
heap_end, heap_end + size_w); |
|
|
|
|
|
fprintf(stderr, "heap_extend: heap_end[0] = %ld, heap_end[size_w - 1] = %ld\n", |
|
|
|
|
|
heap_end[0], heap_end[size_w - 1]); |
|
|
|
|
|
heap_end += size_w; |
|
|
|
|
|
|
|
|
intptr_t *block = ptr; // == heap_end |
|
|
|
|
|
heap_end = block + size_w; |
|
|
|
|
|
block[-1] = size_w; |
|
|
|
|
|
heap_end[-2] = size_w; |
|
|
fprintf(stderr, "heap_extend: new heap_end = %p\n", heap_end); |
|
|
fprintf(stderr, "heap_extend: new heap_end = %p\n", heap_end); |
|
|
block_join(ptr); |
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
return block_join(ptr); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void *malloc(size_t size) { |
|
|
void *malloc(size_t size) { |
|
|
@ -121,34 +134,44 @@ void *malloc(size_t size) { |
|
|
return NULL; |
|
|
return NULL; |
|
|
} |
|
|
} |
|
|
if (heap_start == NULL || heap_end == NULL) { |
|
|
if (heap_start == NULL || heap_end == NULL) { |
|
|
if (heap_init() != 0) { |
|
|
|
|
|
|
|
|
if (!heap_init()) { |
|
|
return NULL; |
|
|
return NULL; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
intptr_t size_w = YA_ROUND_DIV(size + 2, YA_SZ_WORD); // size in words |
|
|
|
|
|
intptr_t align_dw = YA_ROUND(size_w, 2); // round to dword |
|
|
|
|
|
|
|
|
intptr_t size_w = YA_ROUND_DIV(size, YA_SZ_WORD); // size in words |
|
|
|
|
|
fprintf(stderr, "size_w = %ld\n", size_w); |
|
|
|
|
|
size_w = 2 + YA_ROUND(size_w, 2); // round to dword and make space for tags |
|
|
|
|
|
fprintf(stderr, "size_w = %ld\n", size_w); |
|
|
intptr_t *block; |
|
|
intptr_t *block; |
|
|
for (block = heap_start; block < heap_end; block += block[0]) { |
|
|
|
|
|
if (YA_IS_FREE(block) && block[0] >= align_dw) { |
|
|
|
|
|
|
|
|
intptr_t block_size; |
|
|
|
|
|
for (block = heap_start; block < heap_end; block += block_size) { |
|
|
|
|
|
block_size = YA_SZ_BLOCK(block[-1]); |
|
|
|
|
|
if (!YA_IS_ALLOC(block) && size_w <= block_size) { |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
fprintf(stderr, "size_w = %ld, align_dw = %ld\n", size_w, align_dw); |
|
|
|
|
|
if (block >= heap_end) { // could not find block, extend heap |
|
|
if (block >= heap_end) { // could not find block, extend heap |
|
|
if (heap_extend(align_dw) != 0) { |
|
|
|
|
|
return NULL; |
|
|
|
|
|
} |
|
|
|
|
|
block = heap_end - heap_end[-1]; |
|
|
|
|
|
if (!YA_IS_FREE(block) || block[0] < align_dw) { |
|
|
|
|
|
|
|
|
block = heap_extend(size_w); |
|
|
|
|
|
if (!block) { |
|
|
return NULL; |
|
|
return NULL; |
|
|
} |
|
|
} |
|
|
|
|
|
block_size = YA_SZ_BLOCK(block[-1]); |
|
|
} |
|
|
} |
|
|
if (block[0] > align_dw) { |
|
|
|
|
|
block_split(block, align_dw); |
|
|
|
|
|
|
|
|
if (size_w < block_size) { |
|
|
|
|
|
block_split(block, size_w); |
|
|
} |
|
|
} |
|
|
block[0] |= 1; |
|
|
|
|
|
return block + 1; |
|
|
|
|
|
|
|
|
block[-1] |= 1; |
|
|
|
|
|
block[block_size - 2] |= 1; |
|
|
|
|
|
return block; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
void free(void *ptr) { |
|
|
void free(void *ptr) { |
|
|
|
|
|
intptr_t *block = ptr; |
|
|
|
|
|
if (block < heap_start || block > heap_end || !YA_IS_ALLOC(block)) { |
|
|
|
|
|
return; // TODO: provoke segfault |
|
|
|
|
|
} |
|
|
|
|
|
intptr_t block_size = YA_SZ_BLOCK(block[-1]); |
|
|
|
|
|
block[-1] &= -2; // erase allocated bit |
|
|
|
|
|
block[block_size - 2] &= -2; |
|
|
|
|
|
block_join(block); |
|
|
} |
|
|
} |