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:
parent
74d51ab08b
commit
a3fb2d6e0a
@ -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;
|
||||||
|
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user