mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-30 23:23:07 +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:
		| @@ -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) { | ||||
|         if (!v) p[1] = 0; | ||||
|         p[0] = m; | ||||
|         return p + 2; | ||||
|     } else { | ||||
|         { | ||||
|             JANET_OUT_OF_MEMORY; | ||||
|         } | ||||
|         return (void *)(2 * sizeof(int32_t)); | ||||
|     } | ||||
|     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; | ||||
| } | ||||
|  | ||||
| /* 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, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose