#include #include #include #include #include "regions.h" /* Module: regions Date: 14 Feb 92 Purpose: Fast & easy memory allocator for the mudlle compiler Based on the concept of blocks: you allocate memory from a block, and can free the whole block at one go. Individual deallocations are not possible. */ #define ALIGN(x, n) (((x) + ((n) - 1)) & ~((n) - 1)) #define BLOCK_SIZE 8172 /* Should probably be chosen w/ respect to malloc implementation */ #define BIG_SIZE 16364 typedef double max_aligned_type; struct Region { #ifndef USEMALLOC char *pos; /* Where next to allocate from */ char *end; /* End of block */ #endif struct Region *previous; max_aligned_type data[1]; }; nomem_handler nomem_h; void region_init(void) { } #ifdef BWGC region newregion(void) { return NULL; } void deleteregion(region b) /* Effect: Free all memory allocated in region b. */ { } void deleteregion_ptr(region *r) /* Effect: Free all memory allocated in region *r and sets *r to NULL. */ { } static void *allocate(region b, unsigned long size) /* Effects: Allocates size bytes from block b. The result is aligned correctly for all types. Returns: A pointer to the start of the block. Note: In this implementation, 12 + average(size)/2 bytes will be wasted for every BLOCK_SIZE bytes allocated. */ { return GC_malloc(size); } #else static struct Region *make_block(int size) { struct Region *newp = (struct Region *)malloc(offsetof(struct Region, data) + size); if (!newp) return NULL; #ifndef USEMALLOC newp->pos = (char *)newp->data; newp->end = newp->pos + size; #endif newp->previous = 0; return newp; } region newregion(void) /* Return: A new region from which to allocate some memory. */ { region newp = (region)malloc(sizeof *newp); if (!newp) return (region)nomem_h(NULL, 0); *newp = make_block(BLOCK_SIZE); if (!*newp) { free(newp); return (region)nomem_h(NULL, 0); } return newp; } void deleteregion(region b) /* Effect: Free all memory allocated in region b. */ { struct Region *blk = *b; while (blk) { struct Region *prev = blk->previous; free(blk); blk = prev; } free(b); } void deleteregion_ptr(region *r) /* Effect: Free all memory allocated in region *r and sets *r to NULL. */ { deleteregion(*r); *r = NULL; } static void *allocate(region b, unsigned long size) /* Effects: Allocates size bytes from block b. The result is aligned correctly for all types. Returns: A pointer to the start of the block. Note: In this implementation, 12 + average(size)/2 bytes will be wasted for every BLOCK_SIZE bytes allocated. */ { #ifdef USEMALLOC struct Region *old = *b, *new = make_block(size); new->previous = old; *b = new; return &new->data; #else struct Region *blk = *b; void *result; size = ALIGN(size, sizeof(max_aligned_type)); result = blk->pos; if ((blk->pos += size) >= blk->end) { /* Block full, get new one */ int bsize; struct Region *newp; if (size < BLOCK_SIZE / 4) bsize = BLOCK_SIZE; else if (size >= BIG_SIZE) bsize = size; else bsize = size * 4; newp = make_block(bsize); if (!newp) return nomem_h(b, size); newp->previous = blk; *b = newp; result = newp->pos; newp->pos += size; } return result; #endif } #endif void *int_ralloc(region r, size_t size) { void *newo = allocate(r, size); if (newo) memset(newo, 0, size); return newo; } void *int_rarrayalloc(region r, size_t n, size_t size) { return int_ralloc(r, n * size); } char *rstralloc(region r, size_t size) { return (char *)allocate(r, size); } char *rstrdup(region r, const char *s) { int l = strlen(s); char *news = (char *)allocate(r, l + 1); if (news) memcpy(news, s, l + 1); return news; } nomem_handler set_nomem_handler(nomem_handler newhandler) { nomem_handler oldh = nomem_h; nomem_h = newhandler; return oldh; }