summaryrefslogtreecommitdiff
path: root/src/lib/memory.c
diff options
context:
space:
mode:
authorpeter <peter@pmikkelsen.com>2026-08-30 20:52:43 +0000
committerpeter <peter@pmikkelsen.com>2026-08-30 20:52:43 +0000
commit729964bea692f9683860978b89848784a7fc2f46 (patch)
treeba5b37a61206142fce18214c7af341ac837a7923 /src/lib/memory.c
parent04827577ea502a9f0edc69e00e008751c8119cbc (diff)
Still a lot to be done, but I'm going to bed.
Two remaining big issues: * aplwc (the parameter passed "everywhere") - should it move or not? * values returned from the public API should not move. FossilOrigin-Name: 31ab3154b8f3d5ac167218496e9e204324bf0ac9d36b7bada8fe2a6c8f93d51c
Diffstat (limited to 'src/lib/memory.c')
-rw-r--r--src/lib/memory.c241
1 files changed, 207 insertions, 34 deletions
diff --git a/src/lib/memory.c b/src/lib/memory.c
index 94f903c..8a91d2d 100644
--- a/src/lib/memory.c
+++ b/src/lib/memory.c
@@ -1,41 +1,201 @@
#include "aplwc_internal.h"
+#define ALIGNMENT 8
+#define HEADER_SIZE (sizeof(struct chunk) + (sizeof(struct chunk) % ALIGNMENT))
+
+enum chunk_tag {
+ CHUNK_TAG_FREE,
+ CHUNK_TAG_APLWC_LINE,
+ CHUNK_TAG_STRING,
+ CHUNK_TAG_TOKEN_LIST,
+ CHUNK_TAG_APLWC_VALUE,
+ CHUNK_TAG_APLWC_MODULE
+};
+
+struct chunk {
+ struct chunk *next;
+ size_t size;
+ enum chunk_tag tag;
+ uint8_t *data;
+};
+
void
-memory_init(struct aplwc *aplwc, uint8_t *data , size_t size)
+memory_init(struct aplwc *aplwc)
{
- aplwc->data = data;
- aplwc->size = size;
- aplwc->offset = 0;
+ aplwc->data = NULL;
+ aplwc->unaligned_data = NULL;
+ aplwc->size = 0;
+ aplwc->memptrs = NULL;
}
-static void *
-alloc(struct aplwc *aplwc, size_t size, size_t align)
+void
+memory_destroy(struct aplwc *aplwc)
{
- uintptr_t ptr;
- size_t alloc_size, adjust;
- void *p;
+ if(aplwc->fns.dealloc)
+ aplwc->fns.dealloc(aplwc->unaligned_data);
+}
- ptr = ((uintptr_t)aplwc->data) + aplwc->offset;
- alloc_size = size;
+static void
+fixrefs(struct aplwc *aplwc, uint8_t *new, uint8_t *old)
+{
+#define FIX(ptr) do{ \
+ if(ptr){ \
+ (ptr) = (void*)(((uint8_t*)(ptr))+add); \
+ (ptr) = (void*)(((uint8_t*)(ptr))-sub); \
+ } \
+}while(0)
- if(NEVER(align == 0))
- return NULL;
- adjust = ptr % align;
+#define FIX_DATA(type, ptr) FIX(((type *)c->data)->ptr)
- if(adjust)
- alloc_size += align - adjust;
+ struct chunk *c;
+ struct memory_ptr_frame *frame;
+ size_t add, sub, i;
- if((aplwc->size - aplwc->offset) >= alloc_size){
- p = aplwc->data+aplwc->offset+alloc_size-size;
- assert((((uintptr_t)p) % align) == 0);
- aplwc->offset += alloc_size;
- memset(p, 0, size);
+ if(new > old){
+ add = new-old;
+ sub = 0;
}else{
- p = NULL;
- aplwc->last_error = APLWC_OUT_OF_MEMORY;
+ add = 0;
+ sub = old-new;
}
- return p;
+ for(c = (struct chunk *)new; c; c = c->next){
+ FIX(c->next);
+ FIX(c->data);
+
+ switch(c->tag){
+ case CHUNK_TAG_APLWC_LINE:
+ FIX_DATA(struct aplwc_line, text);
+ FIX_DATA(struct aplwc_line, tokens);
+ break;
+ case CHUNK_TAG_STRING:
+ break;
+ case CHUNK_TAG_TOKEN_LIST:
+ FIX_DATA(struct token_list, text);
+ break;
+ case CHUNK_TAG_APLWC_VALUE:
+ break;
+ case CHUNK_TAG_APLWC_MODULE:
+ FIX_DATA(struct aplwc_module, name);
+ FIX_DATA(struct aplwc_module, tokens);
+ FIX_DATA(struct aplwc_module, link);
+ break;
+ case CHUNK_TAG_FREE:
+ break;
+ }
+ }
+
+ for(frame = aplwc->memptrs; frame; frame = frame->link)
+ for(i = 0; i < frame->count; i++)
+ if(frame->ptrs[i])
+ FIX(*frame->ptrs[i]);
+
+#undef FIX
+#undef FIX_DATA
+}
+
+static enum aplwc_rc
+grow(struct aplwc *aplwc, size_t extra)
+{
+ uint8_t *unaligned_data, *aligned_data;
+ size_t unaligned_newsize, aligned_newsize, adjust;
+ struct chunk **free;
+
+ if(aplwc->fns.alloc == NULL)
+ goto error;
+
+ unaligned_data = aplwc->fns.alloc(aplwc->size + extra + HEADER_SIZE + 2*ALIGNMENT, 0, &unaligned_newsize);
+ if(unaligned_data == NULL)
+ goto error;
+
+ adjust = ((uintptr_t)unaligned_data) % ALIGNMENT;
+ if(adjust)
+ adjust = ALIGNMENT - adjust;
+ aligned_newsize = unaligned_newsize - adjust;
+ aligned_data = unaligned_data + adjust;
+
+ aligned_newsize -= aligned_newsize % ALIGNMENT;
+
+ assert(aligned_newsize >= (aplwc->size + extra));
+
+ if(aplwc->data){
+ memmove(aligned_data, aplwc->data, aplwc->size);
+ fixrefs(aplwc, aligned_data, aplwc->data);
+ if(aplwc->fns.dealloc)
+ aplwc->fns.dealloc(aplwc->unaligned_data);
+ for(free = (struct chunk **)&aligned_data; (*free); free = &(*free)->next)
+ assert((*free)->tag != CHUNK_TAG_FREE);
+ }else
+ free = (struct chunk **)&aligned_data;
+
+
+ (*free) = (struct chunk *)(aligned_data + aplwc->size);
+ (*free)->tag = CHUNK_TAG_FREE;
+ (*free)->data = NULL;
+ (*free)->size = aligned_newsize - aplwc->size;
+ (*free)->next = NULL;
+
+ aplwc->unaligned_data = unaligned_data;
+ aplwc->data = aligned_data;
+ aplwc->size = aligned_newsize;
+ return 1;
+
+error:
+ aplwc->last_error = APLWC_OUT_OF_MEMORY;
+ return 0;
+}
+
+static struct chunk *
+find_free(struct aplwc *aplwc, size_t min)
+{
+ struct chunk *c;
+
+ min += HEADER_SIZE;
+
+ if(aplwc->data == NULL)
+ return NULL;
+
+ for(c = (struct chunk *)aplwc->data; c; c = c->next){
+ if((c->tag == CHUNK_TAG_FREE) && (c->size >= min))
+ break;
+ }
+
+ return c;
+}
+
+static void *
+alloc(struct aplwc *aplwc, size_t size, enum chunk_tag tag)
+{
+ struct chunk *free;
+ struct chunk *new;
+
+retry:
+ free = find_free(aplwc, size);
+ if(!free){
+ if(grow(aplwc, size))
+ goto retry;
+ else
+ return NULL;
+ }
+
+ assert(free->data == NULL);
+
+ new = free;
+
+ if(free->size > (size + 2*HEADER_SIZE)){
+ free = (struct chunk *)(((uint8_t*)free) + HEADER_SIZE + size);
+ free->tag = CHUNK_TAG_FREE;
+ free->size = new->size - (HEADER_SIZE + size);
+ free->data = NULL;
+ }
+
+ new->tag = tag;
+ new->size = sizeof(struct chunk) + size;
+ new->data = ((uint8_t*)new) + sizeof(struct chunk);
+
+ new->data += ((uintptr_t)new->data) % ALIGNMENT;
+
+ return new->data;
}
void
@@ -47,13 +207,25 @@ memory_free_root(struct aplwc *aplwc, void *p)
UNUSED_PARAMETER(aplwc);
}
-struct aplwc *
-memory_alloc_aplwc(struct aplwc *aplwc)
+void
+memptrs_add(struct aplwc *aplwc, struct memory_ptr_frame *frame, void ***ptrs, size_t count)
{
- struct aplwc *p;
+ size_t i;
- p = alloc(aplwc, sizeof(struct aplwc), alignof(struct aplwc));
- return p;
+ frame->ptrs = ptrs;
+ frame->link = aplwc->memptrs;
+ frame->count = count;
+ aplwc->memptrs = frame;
+
+ for(i = 0; i < count; i++)
+ frame->ptrs[i] = NULL;
+}
+
+void
+memptrs_remove(struct aplwc *aplwc, struct memory_ptr_frame *frame)
+{
+ assert(aplwc->memptrs == frame);
+ aplwc->memptrs = frame->link;
}
struct aplwc_line *
@@ -61,7 +233,7 @@ memory_alloc_aplwc_line(struct aplwc *aplwc)
{
struct aplwc_line *p;
- p = alloc(aplwc, sizeof(struct aplwc_line), alignof(struct aplwc_line));
+ p = alloc(aplwc, sizeof(struct aplwc_line), CHUNK_TAG_APLWC_LINE);
return p;
}
@@ -70,7 +242,8 @@ memory_alloc_string(struct aplwc *aplwc, size_t bytes)
{
struct string *p;
- p = alloc(aplwc, sizeof(struct string) + bytes, alignof(struct string));
+ p = alloc(aplwc, sizeof(struct string) + bytes, CHUNK_TAG_STRING);
+
return p;
}
@@ -79,7 +252,7 @@ memory_alloc_token_list(struct aplwc *aplwc, size_t tokens)
{
struct token_list *p;
- p = alloc(aplwc, sizeof(struct token_list) + (tokens * sizeof(struct token)), alignof(struct token_list));
+ p = alloc(aplwc, sizeof(struct token_list) + (tokens * sizeof(struct token)), CHUNK_TAG_TOKEN_LIST);
return p;
}
@@ -88,7 +261,7 @@ memory_alloc_aplwc_value(struct aplwc *aplwc)
{
struct aplwc_value *p;
- p = alloc(aplwc, sizeof(struct aplwc_value), alignof(struct aplwc_value));
+ p = alloc(aplwc, sizeof(struct aplwc_value), CHUNK_TAG_APLWC_VALUE);
return p;
}
@@ -97,6 +270,6 @@ memory_alloc_aplwc_module(struct aplwc *aplwc)
{
struct aplwc_module *p;
- p = alloc(aplwc, sizeof(struct aplwc_module), alignof(struct aplwc_module));
+ p = alloc(aplwc, sizeof(struct aplwc_module), CHUNK_TAG_APLWC_MODULE);
return p;
}