From 0bb141777055f0ed1e8403ca426ac3e4304830e0 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Mon, 23 Sep 2024 22:15:36 +0200 Subject: [PATCH] Add gc_cut --- sources/iron_gc.c | 7 +++++++ sources/iron_gc.h | 1 + sources/libs/gc.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++- sources/libs/gc.h | 1 + 4 files changed, 56 insertions(+), 1 deletion(-) diff --git a/sources/iron_gc.c b/sources/iron_gc.c index a2609f61..4e8ae969 100644 --- a/sources/iron_gc.c +++ b/sources/iron_gc.c @@ -32,6 +32,9 @@ void gc_root(void *ptr) { void gc_unroot(void *ptr) { } +void *gc_cut(void *ptr, size_t pos, size_t size) { +} + void *gc_realloc(void *ptr, size_t size) { #ifdef HEAP_SIZE // NOTE: gc_realloc is not implemented when HEAP_SIZE is defined @@ -90,6 +93,10 @@ void gc_unroot(void *ptr) { _gc_unroot(ptr); } +void *gc_cut(void *ptr, size_t pos, size_t size) { + _gc_cut(ptr, pos, size); +} + void *gc_realloc(void *ptr, size_t size) { return ptr == NULL ? gc_alloc(size) : _gc_realloc(ptr, size); } diff --git a/sources/iron_gc.h b/sources/iron_gc.h index 5d1167a0..d9962576 100644 --- a/sources/iron_gc.h +++ b/sources/iron_gc.h @@ -10,6 +10,7 @@ void gc_array(void *ptr, int *length); void gc_leaf(void *ptr); void gc_root(void *ptr); void gc_unroot(void *ptr); +void *gc_cut(void *ptr, size_t pos, size_t size); void *gc_realloc(void *ptr, size_t size); void gc_free(void *ptr); void gc_pause(); diff --git a/sources/libs/gc.c b/sources/libs/gc.c index bff9d112..718e4588 100644 --- a/sources/libs/gc.c +++ b/sources/libs/gc.c @@ -36,6 +36,7 @@ #define GC_TAG_LEAF 0x1 #define GC_TAG_MARK 0x2 #define GC_TAG_ROOT 0x4 +#define GC_TAG_CUT 0x8 #if defined(_MSC_VER) && !defined(__clang__) #define __builtin_frame_address(x) ((void)(x), _AddressOfReturnAddress()) @@ -47,7 +48,8 @@ typedef struct gc_allocation { int *array_length; // if this alloc is an array char tag; // the tag for mark-and-sweep char roots; // number of root users - struct gc_allocation_t *next; // separate chaining + struct gc_allocation *next; // separate chaining + struct gc_allocation *cut; } gc_allocation_t; typedef struct gc_allocation_map { @@ -79,6 +81,7 @@ static gc_allocation_t *gc_allocation_new(void *ptr, size_t size) { a->tag = GC_TAG_NONE; a->roots = 0; a->next = NULL; + a->cut = NULL; return a; } @@ -309,6 +312,39 @@ void _gc_unroot(void *ptr) { } } +static inline uint64_t pad(int di, int n) { + return (n - (di % n)) % n; +} + +// Cut out a leaf out of an existing allocation +void *_gc_cut(void *ptr, size_t pos, size_t size) { + size += pad(size, 8); + + // Start + gc_allocation_t *start = gc_allocation_map_get(gc->allocs, ptr); + while (start->cut) { + start = start->cut; + } + size_t start_size = start->size; + pos -= start->ptr - ptr; + start->size = pos; + + // Middle + gc_allocation_t *middle = gc_allocation_new(start->ptr + pos, size); + middle->tag |= GC_TAG_CUT; + middle->tag |= GC_TAG_LEAF; + start->cut = middle; + gc_allocation_map_put(gc->allocs, middle); + + // End + gc_allocation_t *end = gc_allocation_new(start->ptr + pos + size, start_size - size - pos); + end->tag |= GC_TAG_CUT; + middle->cut = end; + gc_allocation_map_put(gc->allocs, end); + + return middle->ptr; +} + static void gc_mark_alloc(void *ptr) { gc_allocation_t *alloc = gc_allocation_map_get(gc->allocs, ptr); /* Mark if alloc exists and is not tagged already, otherwise skip */ @@ -317,6 +353,7 @@ static void gc_mark_alloc(void *ptr) { if (!(alloc->tag & GC_TAG_LEAF)) { // Skip contents /* Iterate over allocation contents and mark them as well */ int size = alloc->array_length ? (*alloc->array_length) * PTRSIZE : alloc->size; + for (char *p = (char *)alloc->ptr; p <= (char *)alloc->ptr + size - PTRSIZE; ++p) { gc_mark_alloc(*(void **)p); } @@ -370,13 +407,22 @@ static size_t gc_sweep() { chunk->tag &= ~GC_TAG_MARK; chunk = chunk->next; } + else if (chunk->tag & GC_TAG_CUT) { + chunk = chunk->next; + } else { /* no reference to this chunk, hence delete it */ total += chunk->size; free(chunk->ptr); /* and remove it from the bookkeeping */ next = chunk->next; + gc_allocation_t *cut = chunk->cut; gc_allocation_map_remove(gc->allocs, chunk->ptr, false); + while (cut) { + gc_allocation_t *next = cut->cut; + gc_allocation_map_remove(gc->allocs, cut->ptr, false); + cut = next; + } chunk = next; } } diff --git a/sources/libs/gc.h b/sources/libs/gc.h index cbcd42e2..b95b1ff3 100644 --- a/sources/libs/gc.h +++ b/sources/libs/gc.h @@ -16,5 +16,6 @@ void _gc_array(void *ptr, int *length); void _gc_leaf(void *ptr); void _gc_root(void *ptr); void _gc_unroot(void *ptr); +void *_gc_cut(void *ptr, size_t pos, size_t size); void *_gc_realloc(void *ptr, size_t size); void _gc_free(void *ptr);