mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 15:43:01 +00:00 
			
		
		
		
	Tables created via table_init cannot leak memory.
Before, if Janet paniced without calling table_deinit on a table created via table_init, Janet leaked memory. This changes tables so that tables created via table_init us scratch memory for auto cleanup instead of normal malloc/free.
This commit is contained in:
		| @@ -265,7 +265,7 @@ static void janet_deinit_block(JanetGCObject *mem) { | |||||||
|             free(((JanetArray *) mem)->data); |             free(((JanetArray *) mem)->data); | ||||||
|             break; |             break; | ||||||
|         case JANET_MEMORY_TABLE: |         case JANET_MEMORY_TABLE: | ||||||
|             janet_table_deinit((JanetTable *) mem); |             free(((JanetTable *) mem)->data); | ||||||
|             break; |             break; | ||||||
|         case JANET_MEMORY_FIBER: |         case JANET_MEMORY_FIBER: | ||||||
|             free(((JanetFiber *)mem)->data); |             free(((JanetFiber *)mem)->data); | ||||||
|   | |||||||
| @@ -27,14 +27,32 @@ | |||||||
| #include <math.h> | #include <math.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| /* Initialize a table */ | #define JANET_TABLE_FLAG_STACK 0x10000 | ||||||
| JanetTable *janet_table_init(JanetTable *table, int32_t capacity) { |  | ||||||
|  | static void *janet_memalloc_empty_local(int32_t count) { | ||||||
|  |     int32_t i; | ||||||
|  |     void *mem = janet_smalloc(count * sizeof(JanetKV)); | ||||||
|  |     JanetKV *mmem = (JanetKV *)mem; | ||||||
|  |     for (i = 0; i < count; i++) { | ||||||
|  |         JanetKV *kv = mmem + i; | ||||||
|  |         kv->key = janet_wrap_nil(); | ||||||
|  |         kv->value = janet_wrap_nil(); | ||||||
|  |     } | ||||||
|  |     return mem; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | static JanetTable *janet_table_init_impl(JanetTable *table, int32_t capacity, int stackalloc) { | ||||||
|     JanetKV *data; |     JanetKV *data; | ||||||
|     capacity = janet_tablen(capacity); |     capacity = janet_tablen(capacity); | ||||||
|  |     if (stackalloc) table->gc.flags = JANET_TABLE_FLAG_STACK; | ||||||
|     if (capacity) { |     if (capacity) { | ||||||
|         data = (JanetKV *) janet_memalloc_empty(capacity); |         if (stackalloc) { | ||||||
|         if (NULL == data) { |             data = janet_memalloc_empty_local(capacity); | ||||||
|             JANET_OUT_OF_MEMORY; |         } else { | ||||||
|  |             data = (JanetKV *) janet_memalloc_empty(capacity); | ||||||
|  |             if (NULL == data) { | ||||||
|  |                 JANET_OUT_OF_MEMORY; | ||||||
|  |             } | ||||||
|         } |         } | ||||||
|         table->data = data; |         table->data = data; | ||||||
|         table->capacity = capacity; |         table->capacity = capacity; | ||||||
| @@ -48,15 +66,20 @@ JanetTable *janet_table_init(JanetTable *table, int32_t capacity) { | |||||||
|     return table; |     return table; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /* Initialize a table */ | ||||||
|  | JanetTable *janet_table_init(JanetTable *table, int32_t capacity) { | ||||||
|  |     return janet_table_init_impl(table, capacity, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
| /* Deinitialize a table */ | /* Deinitialize a table */ | ||||||
| void janet_table_deinit(JanetTable *table) { | void janet_table_deinit(JanetTable *table) { | ||||||
|     free(table->data); |     janet_sfree(table->data); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Create a new table */ | /* Create a new table */ | ||||||
| JanetTable *janet_table(int32_t capacity) { | JanetTable *janet_table(int32_t capacity) { | ||||||
|     JanetTable *table = janet_gcalloc(JANET_MEMORY_TABLE, sizeof(JanetTable)); |     JanetTable *table = janet_gcalloc(JANET_MEMORY_TABLE, sizeof(JanetTable)); | ||||||
|     return janet_table_init(table, capacity); |     return janet_table_init_impl(table, capacity, 0); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Find the bucket that contains the given key. Will also return | /* Find the bucket that contains the given key. Will also return | ||||||
| @@ -68,9 +91,15 @@ JanetKV *janet_table_find(JanetTable *t, Janet key) { | |||||||
| /* Resize the dictionary table. */ | /* Resize the dictionary table. */ | ||||||
| static void janet_table_rehash(JanetTable *t, int32_t size) { | static void janet_table_rehash(JanetTable *t, int32_t size) { | ||||||
|     JanetKV *olddata = t->data; |     JanetKV *olddata = t->data; | ||||||
|     JanetKV *newdata = (JanetKV *) janet_memalloc_empty(size); |     JanetKV *newdata; | ||||||
|     if (NULL == newdata) { |     int islocal = t->gc.flags & JANET_TABLE_FLAG_STACK; | ||||||
|         JANET_OUT_OF_MEMORY; |     if (islocal) { | ||||||
|  |         newdata = (JanetKV *) janet_memalloc_empty_local(size); | ||||||
|  |     } else { | ||||||
|  |         newdata = (JanetKV *) janet_memalloc_empty(size); | ||||||
|  |         if (NULL == newdata) { | ||||||
|  |             JANET_OUT_OF_MEMORY; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
|     int32_t i, oldcapacity; |     int32_t i, oldcapacity; | ||||||
|     oldcapacity = t->capacity; |     oldcapacity = t->capacity; | ||||||
| @@ -84,7 +113,11 @@ static void janet_table_rehash(JanetTable *t, int32_t size) { | |||||||
|             *newkv = *kv; |             *newkv = *kv; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     free(olddata); |     if (islocal) { | ||||||
|  |         janet_sfree(olddata); | ||||||
|  |     } else { | ||||||
|  |         free(olddata); | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| /* Get a value out of the table */ | /* Get a value out of the table */ | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose