mirror of
https://github.com/janet-lang/janet
synced 2024-11-25 09:47:17 +00:00
Add scratch memory API.
This should make it easier to write code that does not leak memory on panics.
This commit is contained in:
parent
0a54e1ed62
commit
c150f2f2c1
@ -270,7 +270,7 @@
|
||||
"Inline raw byte file as a c file."
|
||||
[source dest name]
|
||||
(rule dest [source]
|
||||
(print "creating embedded source " dest "...")
|
||||
(print "generating " dest "...")
|
||||
(def f (file/open source :r))
|
||||
(if (not f) (error (string "file " f " not found")))
|
||||
(def out (file/open dest :w))
|
||||
|
@ -39,6 +39,11 @@ JANET_THREAD_LOCAL Janet *janet_vm_roots;
|
||||
JANET_THREAD_LOCAL uint32_t janet_vm_root_count;
|
||||
JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity;
|
||||
|
||||
/* Scratch Memory */
|
||||
JANET_THREAD_LOCAL void **janet_scratch_mem;
|
||||
JANET_THREAD_LOCAL size_t janet_scratch_cap;
|
||||
JANET_THREAD_LOCAL size_t janet_scratch_len;
|
||||
|
||||
/* Helpers for marking the various gc types */
|
||||
static void janet_mark_funcenv(JanetFuncEnv *env);
|
||||
static void janet_mark_funcdef(JanetFuncDef *def);
|
||||
@ -342,6 +347,13 @@ void *janet_gcalloc(enum JanetMemoryType type, size_t size) {
|
||||
return (void *)mem;
|
||||
}
|
||||
|
||||
/* Free all allocated scratch memory */
|
||||
static void janet_free_all_scratch(void) {
|
||||
for (size_t i = 0; i < janet_scratch_len; i++)
|
||||
free(janet_scratch_mem[i]);
|
||||
janet_scratch_len = 0;
|
||||
}
|
||||
|
||||
/* Run garbage collection */
|
||||
void janet_collect(void) {
|
||||
uint32_t i;
|
||||
@ -356,6 +368,7 @@ void janet_collect(void) {
|
||||
}
|
||||
janet_sweep();
|
||||
janet_vm_next_collection = 0;
|
||||
janet_free_all_scratch();
|
||||
}
|
||||
|
||||
/* Add a root value to the GC. This prevents the GC from removing a value
|
||||
@ -429,6 +442,8 @@ void janet_clear_memory(void) {
|
||||
current = next;
|
||||
}
|
||||
janet_vm_blocks = NULL;
|
||||
janet_free_all_scratch();
|
||||
free(janet_scratch_mem);
|
||||
}
|
||||
|
||||
/* Primitives for suspending GC. */
|
||||
@ -438,3 +453,56 @@ int janet_gclock(void) {
|
||||
void janet_gcunlock(int handle) {
|
||||
janet_vm_gc_suspend = handle;
|
||||
}
|
||||
|
||||
/* Scratch memory API */
|
||||
|
||||
void *janet_smalloc(size_t size) {
|
||||
void *mem = malloc(size);
|
||||
if (NULL == mem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
if (janet_scratch_len == janet_scratch_cap) {
|
||||
size_t newcap = 2 * janet_scratch_cap + 2;
|
||||
void **newmem = (void **) realloc(janet_scratch_mem, newcap * sizeof(void *));
|
||||
if (NULL == newmem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_scratch_cap = newcap;
|
||||
janet_scratch_mem = newmem;
|
||||
}
|
||||
janet_scratch_mem[janet_scratch_len++] = mem;
|
||||
return mem;
|
||||
}
|
||||
|
||||
void *janet_srealloc(void *mem, size_t size) {
|
||||
if (NULL == mem) return janet_smalloc(size);
|
||||
if (janet_scratch_len) {
|
||||
for (size_t i = janet_scratch_len - 1; ; i--) {
|
||||
if (janet_scratch_mem[i] == mem) {
|
||||
void *newmem = realloc(mem, size);
|
||||
if (NULL == newmem) {
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
janet_scratch_mem[i] = newmem;
|
||||
return newmem;
|
||||
}
|
||||
if (i == 0) break;
|
||||
}
|
||||
}
|
||||
janet_exit("invalid janet_srealloc");
|
||||
}
|
||||
|
||||
void janet_sfree(void *mem) {
|
||||
if (NULL == mem) return;
|
||||
if (janet_scratch_len) {
|
||||
for (size_t i = janet_scratch_len - 1; ; i--) {
|
||||
if (janet_scratch_mem[i] == mem) {
|
||||
janet_scratch_mem[i] = janet_scratch_mem[--janet_scratch_len];
|
||||
free(mem);
|
||||
return;
|
||||
}
|
||||
if (i == 0) break;
|
||||
}
|
||||
}
|
||||
janet_exit("invalid janet_sfree");
|
||||
}
|
||||
|
@ -65,4 +65,9 @@ extern JANET_THREAD_LOCAL Janet *janet_vm_roots;
|
||||
extern JANET_THREAD_LOCAL uint32_t janet_vm_root_count;
|
||||
extern JANET_THREAD_LOCAL uint32_t janet_vm_root_capacity;
|
||||
|
||||
/* Scratch memory */
|
||||
extern JANET_THREAD_LOCAL void **janet_scratch_mem;
|
||||
extern JANET_THREAD_LOCAL size_t janet_scratch_cap;
|
||||
extern JANET_THREAD_LOCAL size_t janet_scratch_len;
|
||||
|
||||
#endif /* JANET_STATE_H_defined */
|
||||
|
@ -30,17 +30,10 @@ void *janet_v_grow(void *v, int32_t increment, int32_t itemsize) {
|
||||
int32_t dbl_cur = (NULL != v) ? 2 * janet_v__cap(v) : 0;
|
||||
int32_t min_needed = janet_v_count(v) + increment;
|
||||
int32_t m = dbl_cur > min_needed ? dbl_cur : min_needed;
|
||||
int32_t *p = (int32_t *) realloc(v ? janet_v__raw(v) : 0, itemsize * m + sizeof(int32_t) * 2);
|
||||
if (NULL != p) {
|
||||
int32_t *p = (int32_t *) janet_srealloc(v ? janet_v__raw(v) : 0, itemsize * m + sizeof(int32_t) * 2);
|
||||
if (!v) p[1] = 0;
|
||||
p[0] = m;
|
||||
return p + 2;
|
||||
} else {
|
||||
{
|
||||
JANET_OUT_OF_MEMORY;
|
||||
}
|
||||
return (void *)(2 * sizeof(int32_t));
|
||||
}
|
||||
}
|
||||
|
||||
/* Convert a buffer to normal allocated memory (forget capacity) */
|
||||
|
@ -33,16 +33,15 @@
|
||||
*/
|
||||
|
||||
/* This is mainly used code such as the assembler or compiler, which
|
||||
* need vector like data structures that are not garbage collected
|
||||
* and used only from C */
|
||||
* need vector like data structures that are only garbage collected in case
|
||||
* of an error, and normally rely on malloc/free. */
|
||||
|
||||
#define janet_v_free(v) (((v) != NULL) ? (free(janet_v__raw(v)), 0) : 0)
|
||||
#define janet_v_free(v) (((v) != NULL) ? (janet_sfree(janet_v__raw(v)), 0) : 0)
|
||||
#define janet_v_push(v, x) (janet_v__maybegrow(v, 1), (v)[janet_v__cnt(v)++] = (x))
|
||||
#define janet_v_pop(v) (janet_v_count(v) ? janet_v__cnt(v)-- : 0)
|
||||
#define janet_v_count(v) (((v) != NULL) ? janet_v__cnt(v) : 0)
|
||||
#define janet_v_last(v) ((v)[janet_v__cnt(v) - 1])
|
||||
#define janet_v_empty(v) (((v) != NULL) ? (janet_v__cnt(v) = 0) : 0)
|
||||
#define janet_v_copy(v) (janet_v_copymem((v), sizeof(*(v))))
|
||||
#define janet_v_flatten(v) (janet_v_flattenmem((v), sizeof(*(v))))
|
||||
|
||||
#define janet_v__raw(v) ((int32_t *)(v) - 2)
|
||||
@ -55,7 +54,6 @@
|
||||
|
||||
/* Actual functions defined in vector.c */
|
||||
void *janet_v_grow(void *v, int32_t increment, int32_t itemsize);
|
||||
void *janet_v_copymem(void *v, int32_t itemsize);
|
||||
void *janet_v_flattenmem(void *v, int32_t itemsize);
|
||||
|
||||
#endif
|
||||
|
@ -906,6 +906,10 @@ int janet_init(void) {
|
||||
janet_vm_roots = NULL;
|
||||
janet_vm_root_count = 0;
|
||||
janet_vm_root_capacity = 0;
|
||||
/* Scratch memory */
|
||||
janet_scratch_mem = NULL;
|
||||
janet_scratch_len = 0;
|
||||
janet_scratch_cap = 0;
|
||||
/* Initialize registry */
|
||||
janet_vm_registry = janet_table(0);
|
||||
janet_gcroot(janet_wrap_table(janet_vm_registry));
|
||||
|
@ -1281,6 +1281,11 @@ JANET_API JanetSignal janet_pcall(JanetFunction *fun, int32_t argn, const Janet
|
||||
JANET_API Janet janet_call(JanetFunction *fun, int32_t argc, const Janet *argv);
|
||||
JANET_API void janet_stacktrace(JanetFiber *fiber, Janet err);
|
||||
|
||||
/* Scratch Memory API */
|
||||
JANET_API void *janet_smalloc(size_t size);
|
||||
JANET_API void *janet_srealloc(void *mem, size_t size);
|
||||
JANET_API void janet_sfree(void *mem);
|
||||
|
||||
/* C Library helpers */
|
||||
typedef enum {
|
||||
JANET_BINDING_NONE,
|
||||
|
Loading…
Reference in New Issue
Block a user