1
0
mirror of https://github.com/janet-lang/janet synced 2024-11-29 11:29:54 +00:00

Add an optional finalizer to scratch resources.

A finalizer can be attached to scratch allocations efficiently at any point in
it's lifecycle via janet_sfinalizer. Care was taken to keep allocations aligned
with  platform alignment requirements.

A big drawbacks to this approach is the waste of up to 16 bytes per scratch
allocation in the case the scratch memory does not require a finalizer.
This commit is contained in:
Andrew Chambers 2019-11-28 17:26:45 +13:00
parent 74d51ab08b
commit a3fb2d6e0a
2 changed files with 32 additions and 7 deletions

View File

@ -40,6 +40,13 @@ JANET_THREAD_LOCAL uint32_t janet_vm_root_count;
JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity; JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity;
/* Scratch Memory */ /* Scratch Memory */
#ifdef JANET_64
#define SCRATCH_HDR_SIZE 16 /* smalloc must guarantee 16 byte alignment. */
#elif JANET_32
#define SCRATCH_HDR_SIZE 8 /* smalloc must guarantee 8 byte alignment. */
#else
#error "unknown scratch alignment"
#endif
JANET_THREAD_LOCAL void **janet_scratch_mem; JANET_THREAD_LOCAL void **janet_scratch_mem;
JANET_THREAD_LOCAL size_t janet_scratch_cap; JANET_THREAD_LOCAL size_t janet_scratch_cap;
JANET_THREAD_LOCAL size_t janet_scratch_len; JANET_THREAD_LOCAL size_t janet_scratch_len;
@ -347,10 +354,18 @@ void *janet_gcalloc(enum JanetMemoryType type, size_t size) {
return (void *)mem; return (void *)mem;
} }
static void free_one_scratch(void *mem) {
ScratchFinalizer finalize = *(ScratchFinalizer*)mem;
if (finalize)
finalize((char*)mem + SCRATCH_HDR_SIZE);
free(mem);
}
/* Free all allocated scratch memory */ /* Free all allocated scratch memory */
static void janet_free_all_scratch(void) { static void janet_free_all_scratch(void) {
for (size_t i = 0; i < janet_scratch_len; i++) for (size_t i = 0; i < janet_scratch_len; i++) {
free(janet_scratch_mem[i]); free_one_scratch(janet_scratch_mem[i]);
}
janet_scratch_len = 0; janet_scratch_len = 0;
} }
@ -457,10 +472,11 @@ void janet_gcunlock(int handle) {
/* Scratch memory API */ /* Scratch memory API */
void *janet_smalloc(size_t size) { void *janet_smalloc(size_t size) {
void *mem = malloc(size); void *mem = malloc(SCRATCH_HDR_SIZE+size);
if (NULL == mem) { if (NULL == mem) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
*(ScratchFinalizer*)mem = NULL;
if (janet_scratch_len == janet_scratch_cap) { if (janet_scratch_len == janet_scratch_cap) {
size_t newcap = 2 * janet_scratch_cap + 2; size_t newcap = 2 * janet_scratch_cap + 2;
void **newmem = (void **) realloc(janet_scratch_mem, newcap * sizeof(void *)); void **newmem = (void **) realloc(janet_scratch_mem, newcap * sizeof(void *));
@ -471,20 +487,21 @@ void *janet_smalloc(size_t size) {
janet_scratch_mem = newmem; janet_scratch_mem = newmem;
} }
janet_scratch_mem[janet_scratch_len++] = mem; janet_scratch_mem[janet_scratch_len++] = mem;
return mem; return (char*)mem + SCRATCH_HDR_SIZE;
} }
void *janet_srealloc(void *mem, size_t size) { void *janet_srealloc(void *mem, size_t size) {
if (NULL == mem) return janet_smalloc(size); if (NULL == mem) return janet_smalloc(size);
mem = (char*)mem - SCRATCH_HDR_SIZE;
if (janet_scratch_len) { if (janet_scratch_len) {
for (size_t i = janet_scratch_len - 1; ; i--) { for (size_t i = janet_scratch_len - 1; ; i--) {
if (janet_scratch_mem[i] == mem) { if (janet_scratch_mem[i] == mem) {
void *newmem = realloc(mem, size); void *newmem = realloc(mem, size+SCRATCH_HDR_SIZE);
if (NULL == newmem) { if (NULL == newmem) {
JANET_OUT_OF_MEMORY; JANET_OUT_OF_MEMORY;
} }
janet_scratch_mem[i] = newmem; janet_scratch_mem[i] = newmem;
return newmem; return (char*)newmem + SCRATCH_HDR_SIZE;
} }
if (i == 0) break; if (i == 0) break;
} }
@ -492,13 +509,19 @@ void *janet_srealloc(void *mem, size_t size) {
janet_exit("invalid janet_srealloc"); janet_exit("invalid janet_srealloc");
} }
void janet_sfinalizer(void *mem, ScratchFinalizer finalizer) {
mem = (char*)mem - SCRATCH_HDR_SIZE;
*(ScratchFinalizer*)mem = finalizer;
}
void janet_sfree(void *mem) { void janet_sfree(void *mem) {
if (NULL == mem) return; if (NULL == mem) return;
mem = (char*)mem - SCRATCH_HDR_SIZE;
if (janet_scratch_len) { if (janet_scratch_len) {
for (size_t i = janet_scratch_len - 1; ; i--) { for (size_t i = janet_scratch_len - 1; ; i--) {
if (janet_scratch_mem[i] == mem) { if (janet_scratch_mem[i] == mem) {
janet_scratch_mem[i] = janet_scratch_mem[--janet_scratch_len]; janet_scratch_mem[i] = janet_scratch_mem[--janet_scratch_len];
free(mem); free_one_scratch(mem);
return; return;
} }
if (i == 0) break; if (i == 0) break;

View File

@ -1304,8 +1304,10 @@ JANET_API Janet janet_mcall(const char *name, int32_t argc, Janet *argv);
JANET_API void janet_stacktrace(JanetFiber *fiber, Janet err); JANET_API void janet_stacktrace(JanetFiber *fiber, Janet err);
/* Scratch Memory API */ /* Scratch Memory API */
typedef void (*ScratchFinalizer)(void*);
JANET_API void *janet_smalloc(size_t size); JANET_API void *janet_smalloc(size_t size);
JANET_API void *janet_srealloc(void *mem, size_t size); JANET_API void *janet_srealloc(void *mem, size_t size);
JANET_API void janet_sfinalizer(void *mem, ScratchFinalizer finalizer);
JANET_API void janet_sfree(void *mem); JANET_API void janet_sfree(void *mem);
/* C Library helpers */ /* C Library helpers */