mirror of
https://github.com/janet-lang/janet
synced 2024-11-28 19:19:53 +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:
parent
efb2ab06cb
commit
64a80c57e3
@ -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 */
|
||||||
|
Loading…
Reference in New Issue
Block a user