diff --git a/Makefile b/Makefile index e2ba7466..2e5d1a9a 100644 --- a/Makefile +++ b/Makefile @@ -65,7 +65,8 @@ all: $(JANET_TARGET) $(JANET_LIBRARY) ##### The bootstrap interpreter that compiles the core image ##### ################################################################## -JANET_BOOT_OBJECTS=$(patsubst src/%.c,build/%.boot.o,$(JANET_CORE_SOURCES) src/boot/boot.c) \ +JANET_BOOT_SOURCES=$(sort $(wildcard src/boot/*.c)) +JANET_BOOT_OBJECTS=$(patsubst src/%.c,build/%.boot.o,$(JANET_CORE_SOURCES) $(JANET_BOOT_SOURCES)) \ build/core.gen.o \ build/boot.gen.o @@ -77,7 +78,7 @@ build/janet_boot: $(JANET_BOOT_OBJECTS) # Now the reason we bootstrap in the first place build/core_image.c: build/janet_boot - JANET_PATH=$(JANET_PATH) JANET_INCLUDEDIR=$(INCLUDEDIR) build/janet_boot + JANET_PATH=$(JANET_PATH) build/janet_boot ########################################################## ##### The main interpreter program and shared object ##### diff --git a/ctest/array_test.c b/src/boot/array_test.c similarity index 97% rename from ctest/array_test.c rename to src/boot/array_test.c index 9b7a8fcc..1b743b72 100644 --- a/ctest/array_test.c +++ b/src/boot/array_test.c @@ -23,13 +23,13 @@ #include #include -int main() { +#include "tests.h" + +int array_test() { int i; JanetArray *array1, *array2; - janet_init(); - array1 = janet_array(10); array2 = janet_array(0); @@ -62,7 +62,5 @@ int main() { assert(array1->count == 5); - janet_deinit(); - return 0; } diff --git a/src/boot/boot.c b/src/boot/boot.c index 622d992d..6117b39c 100644 --- a/src/boot/boot.c +++ b/src/boot/boot.c @@ -21,16 +21,28 @@ */ #include +#include "tests.h" extern const unsigned char *janet_gen_boot; extern int32_t janet_gen_boot_size; int main() { - int status; - JanetTable *env; + + /* Init janet */ + janet_init(); + + /* Run tests */ + array_test(); + buffer_test(); + number_test(); + system_test(); + table_test(); + + /* C tests passed */ /* Set up VM */ - janet_init(); + int status; + JanetTable *env; env = janet_core_env(); /* Run bootstrap script to generate core image */ diff --git a/ctest/buffer_test.c b/src/boot/buffer_test.c similarity index 97% rename from ctest/buffer_test.c rename to src/boot/buffer_test.c index a4345f0c..34596fc3 100644 --- a/ctest/buffer_test.c +++ b/src/boot/buffer_test.c @@ -23,13 +23,13 @@ #include #include -int main() { +#include "tests.h" + +int buffer_test() { int i; JanetBuffer *buffer1, *buffer2; - janet_init(); - buffer1 = janet_buffer(100); buffer2 = janet_buffer(0); @@ -58,7 +58,5 @@ int main() { assert(buffer1->data[i] == buffer2->data[i]); } - janet_deinit(); - return 0; } diff --git a/ctest/number_test.c b/src/boot/number_test.c similarity index 97% rename from ctest/number_test.c rename to src/boot/number_test.c index 89c755a5..48455c85 100644 --- a/ctest/number_test.c +++ b/src/boot/number_test.c @@ -25,6 +25,8 @@ #include #include +#include "tests.h" + /* Check a subset of numbers against system implementation. * Note that this depends on the system implementation being correct, * which may not be the case for old or non compliant systems. Also, @@ -41,9 +43,7 @@ static void test_valid_str(const char *str) { assert(cnum == jnum); } -int main() { - - janet_init(); +int number_test() { test_valid_str("1.0"); test_valid_str("1"); @@ -63,7 +63,5 @@ int main() { test_valid_str("0000000011111111111111111111111111"); test_valid_str(".112312333333323123123123123123123"); - janet_deinit(); - return 0; } diff --git a/ctest/system_test.c b/src/boot/system_test.c similarity index 97% rename from ctest/system_test.c rename to src/boot/system_test.c index 91faf70e..cf991f96 100644 --- a/ctest/system_test.c +++ b/src/boot/system_test.c @@ -24,7 +24,9 @@ #include #include -int main() { +#include "tests.h" + +int system_test() { #ifdef JANET_32 assert(sizeof(void *) == 4); @@ -32,8 +34,6 @@ int main() { assert(sizeof(void *) == 8); #endif - janet_init(); - /* Reflexive testing and nanbox testing */ assert(janet_equals(janet_wrap_nil(), janet_wrap_nil())); assert(janet_equals(janet_wrap_false(), janet_wrap_false())); @@ -48,7 +48,5 @@ int main() { assert(janet_equals(janet_cstringv("a string."), janet_cstringv("a string."))); assert(janet_equals(janet_csymbolv("sym"), janet_csymbolv("sym"))); - janet_deinit(); - return 0; } diff --git a/ctest/table_test.c b/src/boot/table_test.c similarity index 98% rename from ctest/table_test.c rename to src/boot/table_test.c index af9567cf..148a43c5 100644 --- a/ctest/table_test.c +++ b/src/boot/table_test.c @@ -23,12 +23,12 @@ #include #include -int main() { +#include "tests.h" + +int table_test() { JanetTable *t1, *t2; - janet_init(); - t1 = janet_table(10); t2 = janet_table(0); @@ -61,7 +61,5 @@ int main() { assert(janet_equals(janet_table_get(t2, janet_csymbolv("t2key1")), janet_wrap_integer(10))); assert(janet_equals(janet_table_get(t2, janet_csymbolv("t2key2")), janet_wrap_integer(100))); - janet_deinit(); - return 0; } diff --git a/src/boot/tests.h b/src/boot/tests.h new file mode 100644 index 00000000..65e40433 --- /dev/null +++ b/src/boot/tests.h @@ -0,0 +1,11 @@ +#ifndef TESTS_H_DNMBUYYL +#define TESTS_H_DNMBUYYL + +/* Tests */ +extern int array_test(); +extern int buffer_test(); +extern int number_test(); +extern int system_test(); +extern int table_test(); + +#endif /* end of include guard: TESTS_H_DNMBUYYL */ diff --git a/src/core/abstract.c b/src/core/abstract.c index ff123fbf..66bff463 100644 --- a/src/core/abstract.c +++ b/src/core/abstract.c @@ -27,10 +27,9 @@ /* Create new userdata */ void *janet_abstract(const JanetAbstractType *atype, size_t size) { - char *data = janet_gcalloc(JANET_MEMORY_ABSTRACT, sizeof(JanetAbstractHeader) + size); - JanetAbstractHeader *header = (JanetAbstractHeader *)data; - void *a = data + sizeof(JanetAbstractHeader); + JanetAbstractHead *header = janet_gcalloc(JANET_MEMORY_ABSTRACT, + sizeof(JanetAbstractHead) + size); header->size = size; header->type = atype; - return a; + return (void *) & (header->data); } diff --git a/src/core/debug.c b/src/core/debug.c index c4718339..033fb3e7 100644 --- a/src/core/debug.c +++ b/src/core/debug.c @@ -54,7 +54,7 @@ void janet_debug_find( JanetFuncDef **def_out, int32_t *pc_out, const uint8_t *source, int32_t offset) { /* Scan the heap for right func def */ - JanetGCMemoryHeader *current = janet_vm_blocks; + JanetGCObject *current = janet_vm_blocks; /* Keep track of the best source mapping we have seen so far */ int32_t besti = -1; int32_t best_range = INT32_MAX; diff --git a/src/core/gc.c b/src/core/gc.c index 662104c1..3d16d16e 100644 --- a/src/core/gc.c +++ b/src/core/gc.c @@ -99,7 +99,7 @@ void janet_mark(Janet x) { } static void janet_mark_string(const uint8_t *str) { - janet_gc_mark(janet_string_raw(str)); + janet_gc_mark(janet_string_head(str)); } static void janet_mark_buffer(JanetBuffer *buffer) { @@ -154,16 +154,16 @@ recur: /* Manual tail recursion */ } static void janet_mark_struct(const JanetKV *st) { - if (janet_gc_reachable(janet_struct_raw(st))) + if (janet_gc_reachable(janet_struct_head(st))) return; - janet_gc_mark(janet_struct_raw(st)); + janet_gc_mark(janet_struct_head(st)); janet_mark_kvs(st, janet_struct_capacity(st)); } static void janet_mark_tuple(const Janet *tuple) { - if (janet_gc_reachable(janet_tuple_raw(tuple))) + if (janet_gc_reachable(janet_tuple_head(tuple))) return; - janet_gc_mark(janet_tuple_raw(tuple)); + janet_gc_mark(janet_tuple_head(tuple)); janet_mark_many(tuple, janet_tuple_length(tuple)); } @@ -244,15 +244,13 @@ recur: } /* Deinitialize a block of memory */ -static void janet_deinit_block(JanetGCMemoryHeader *block) { - void *mem = ((char *)(block + 1)); - JanetAbstractHeader *h = (JanetAbstractHeader *)mem; - switch (block->flags & JANET_MEM_TYPEBITS) { +static void janet_deinit_block(JanetGCObject *mem) { + switch (mem->flags & JANET_MEM_TYPEBITS) { default: case JANET_MEMORY_FUNCTION: break; /* Do nothing for non gc types */ case JANET_MEMORY_SYMBOL: - janet_symbol_deinit((const uint8_t *)mem + 2 * sizeof(int32_t)); + janet_symbol_deinit(((JanetStringHead *) mem)->data); break; case JANET_MEMORY_ARRAY: janet_array_deinit((JanetArray *) mem); @@ -266,11 +264,13 @@ static void janet_deinit_block(JanetGCMemoryHeader *block) { case JANET_MEMORY_BUFFER: janet_buffer_deinit((JanetBuffer *) mem); break; - case JANET_MEMORY_ABSTRACT: - if (h->type->gc) { - janet_assert(!h->type->gc((void *)(h + 1), h->size), "finalizer failed"); + case JANET_MEMORY_ABSTRACT: { + JanetAbstractHead *head = (JanetAbstractHead *)mem; + if (head->type->gc) { + janet_assert(!head->type->gc(head->data, head->size), "finalizer failed"); } - break; + } + break; case JANET_MEMORY_FUNCENV: { JanetFuncEnv *env = (JanetFuncEnv *)mem; if (0 == env->offset) @@ -293,9 +293,9 @@ static void janet_deinit_block(JanetGCMemoryHeader *block) { /* Iterate over all allocated memory, and free memory that is not * marked as reachable. Flip the gc color flag for next sweep. */ void janet_sweep() { - JanetGCMemoryHeader *previous = NULL; - JanetGCMemoryHeader *current = janet_vm_blocks; - JanetGCMemoryHeader *next; + JanetGCObject *previous = NULL; + JanetGCObject *current = janet_vm_blocks; + JanetGCObject *next; while (NULL != current) { next = current->next; if (current->flags & (JANET_MEM_REACHABLE | JANET_MEM_DISABLED)) { @@ -316,29 +316,26 @@ void janet_sweep() { /* Allocate some memory that is tracked for garbage collection */ void *janet_gcalloc(enum JanetMemoryType type, size_t size) { - JanetGCMemoryHeader *mdata; - size_t total = size + sizeof(JanetGCMemoryHeader); + JanetGCObject *mem; /* Make sure everything is inited */ janet_assert(NULL != janet_vm_cache, "please initialize janet before use"); - void *mem = malloc(total); + mem = malloc(size); /* Check for bad malloc */ if (NULL == mem) { JANET_OUT_OF_MEMORY; } - mdata = (JanetGCMemoryHeader *)mem; - /* Configure block */ - mdata->flags = type; + mem->flags = type; /* Prepend block to heap list */ janet_vm_next_collection += (int32_t) size; - mdata->next = janet_vm_blocks; - janet_vm_blocks = mdata; + mem->next = janet_vm_blocks; + janet_vm_blocks = mem; - return (char *) mem + sizeof(JanetGCMemoryHeader); + return (void *)mem; } /* Run garbage collection */ @@ -423,10 +420,10 @@ int janet_gcunrootall(Janet root) { /* Free all allocated memory */ void janet_clear_memory(void) { - JanetGCMemoryHeader *current = janet_vm_blocks; + JanetGCObject *current = janet_vm_blocks; while (NULL != current) { janet_deinit_block(current); - JanetGCMemoryHeader *next = current->next; + JanetGCObject *next = current->next; free(current); current = next; } diff --git a/src/core/gc.h b/src/core/gc.h index a574bc38..66e8d949 100644 --- a/src/core/gc.h +++ b/src/core/gc.h @@ -28,7 +28,7 @@ #endif /* The metadata header associated with an allocated block of memory */ -#define janet_gc_header(mem) ((JanetGCMemoryHeader *)(mem) - 1) +#define janet_gc_header(mem) ((JanetGCObject *)(mem)) #define JANET_MEM_TYPEBITS 0xFF #define JANET_MEM_REACHABLE 0x100 @@ -40,13 +40,6 @@ #define janet_gc_mark(m) (janet_gc_header(m)->flags |= JANET_MEM_REACHABLE) #define janet_gc_reachable(m) (janet_gc_header(m)->flags & JANET_MEM_REACHABLE) -/* Memory header struct. Node of a linked list of memory blocks. */ -typedef struct JanetGCMemoryHeader JanetGCMemoryHeader; -struct JanetGCMemoryHeader { - JanetGCMemoryHeader *next; - uint32_t flags; -}; - /* Memory types for the GC. Different from JanetType to include funcenv and funcdef. */ enum JanetMemoryType { JANET_MEMORY_NONE, diff --git a/src/core/marsh.c b/src/core/marsh.c index b79d00ee..b3c6e950 100644 --- a/src/core/marsh.c +++ b/src/core/marsh.c @@ -407,7 +407,7 @@ static void marshal_one(MarshalState *st, Janet x, int flags) { int32_t i, count, flag; const Janet *tup = janet_unwrap_tuple(x); count = janet_tuple_length(tup); - flag = janet_tuple_flag(tup); + flag = janet_tuple_flag(tup) >> 16; pushbyte(st, LB_TUPLE); pushint(st, count); pushint(st, flag); @@ -1042,7 +1042,7 @@ static const uint8_t *unmarshal_one( /* Tuple */ Janet *tup = janet_tuple_begin(len); int32_t flag = readint(st, &data); - janet_tuple_flag(tup) = flag; + janet_tuple_flag(tup) |= flag << 16; for (int32_t i = 0; i < len; i++) { data = unmarshal_one(st, data, tup + i, flags + 1); } diff --git a/src/core/parse.c b/src/core/parse.c index ab2abca3..841440b3 100644 --- a/src/core/parse.c +++ b/src/core/parse.c @@ -348,7 +348,7 @@ static int comment(JanetParser *p, JanetParseState *state, uint8_t c) { static Janet close_tuple(JanetParser *p, JanetParseState *state, int32_t flag) { Janet *ret = janet_tuple_begin(state->argn); - janet_tuple_flag(ret) = flag; + janet_tuple_flag(ret) |= flag; for (int32_t i = state->argn - 1; i >= 0; i--) ret[i] = p->args[--p->argcount]; return janet_wrap_tuple(janet_tuple_end(ret)); diff --git a/src/core/string.c b/src/core/string.c index cb495cc6..c2db76a4 100644 --- a/src/core/string.c +++ b/src/core/string.c @@ -31,11 +31,11 @@ /* Begin building a string */ uint8_t *janet_string_begin(int32_t length) { - char *data = janet_gcalloc(JANET_MEMORY_STRING, 2 * sizeof(int32_t) + length + 1); - uint8_t *str = (uint8_t *)(data + 2 * sizeof(int32_t)); - janet_string_length(str) = length; - str[length] = 0; - return str; + JanetStringHead *head = janet_gcalloc(JANET_MEMORY_STRING, sizeof(JanetStringHead) + length + 1); + head->length = length; + uint8_t *data = (uint8_t *)head->data; + data[length] = 0; + return data; } /* Finish building a string */ @@ -46,14 +46,13 @@ const uint8_t *janet_string_end(uint8_t *str) { /* Load a buffer as a string */ const uint8_t *janet_string(const uint8_t *buf, int32_t len) { - int32_t hash = janet_string_calchash(buf, len); - char *data = janet_gcalloc(JANET_MEMORY_STRING, 2 * sizeof(int32_t) + len + 1); - uint8_t *str = (uint8_t *)(data + 2 * sizeof(int32_t)); - memcpy(str, buf, len); - str[len] = 0; - janet_string_length(str) = len; - janet_string_hash(str) = hash; - return str; + JanetStringHead *head = janet_gcalloc(JANET_MEMORY_STRING, sizeof(JanetStringHead) + len + 1); + head->length = len; + head->hash = janet_string_calchash(buf, len); + uint8_t *data = (uint8_t *)head->data; + memcpy(data, buf, len); + data[len] = 0; + return data; } /* Compare two strings */ diff --git a/src/core/struct.c b/src/core/struct.c index b549b620..ec798b5b 100644 --- a/src/core/struct.c +++ b/src/core/struct.c @@ -29,18 +29,18 @@ /* Begin creation of a struct */ JanetKV *janet_struct_begin(int32_t count) { - /* Calculate capacity as power of 2 after 2 * count. */ int32_t capacity = janet_tablen(2 * count); if (capacity < 0) capacity = janet_tablen(count + 1); - size_t s = sizeof(int32_t) * 4 + (capacity * sizeof(JanetKV)); - char *data = janet_gcalloc(JANET_MEMORY_STRUCT, s); - JanetKV *st = (JanetKV *)(data + 4 * sizeof(int32_t)); + size_t size = sizeof(JanetStructHead) + capacity * sizeof(JanetKV); + JanetStructHead *head = janet_gcalloc(JANET_MEMORY_STRUCT, size); + head->length = count; + head->capacity = capacity; + head->hash = 0; + + JanetKV *st = (JanetKV *)(head->data); janet_memempty(st, capacity); - janet_struct_length(st) = count; - janet_struct_capacity(st) = capacity; - janet_struct_hash(st) = 0; return st; } diff --git a/src/core/symcache.c b/src/core/symcache.c index a0c76e7d..ea11b377 100644 --- a/src/core/symcache.c +++ b/src/core/symcache.c @@ -25,6 +25,8 @@ * checks, all symbols are interned so that there is a single copy of it in the * whole program. Equality is then just a pointer check. */ +#include + #ifndef JANET_AMALG #include #include "state.h" @@ -176,10 +178,10 @@ const uint8_t *janet_symbol(const uint8_t *str, int32_t len) { const uint8_t **bucket = janet_symcache_findmem(str, len, hash, &success); if (success) return *bucket; - newstr = (uint8_t *) janet_gcalloc(JANET_MEMORY_SYMBOL, 2 * sizeof(int32_t) + len + 1) - + (2 * sizeof(int32_t)); - janet_string_hash(newstr) = hash; - janet_string_length(newstr) = len; + JanetStringHead *head = janet_gcalloc(JANET_MEMORY_SYMBOL, sizeof(JanetStringHead) + len + 1); + head->hash = hash; + head->length = len; + newstr = (uint8_t *)(head->data); memcpy(newstr, str, len); newstr[len] = 0; janet_symcache_put((const uint8_t *)newstr, bucket); @@ -188,9 +190,7 @@ const uint8_t *janet_symbol(const uint8_t *str, int32_t len) { /* Get a symbol from a cstring */ const uint8_t *janet_csymbol(const char *cstr) { - int32_t len = 0; - while (cstr[len]) len++; - return janet_symbol((const uint8_t *)cstr, len); + return janet_symbol((const uint8_t *)cstr, strlen(cstr)); } /* Store counter for genysm to avoid quadratic behavior */ @@ -234,13 +234,11 @@ const uint8_t *janet_symbol_gen(void) { hash, &status); } while (status && (inc_gensym(), 1)); - sym = (uint8_t *) janet_gcalloc( - JANET_MEMORY_SYMBOL, - 2 * sizeof(int32_t) + sizeof(gensym_counter)) + - (2 * sizeof(int32_t)); + JanetStringHead *head = janet_gcalloc(JANET_MEMORY_SYMBOL, sizeof(JanetStringHead) + sizeof(gensym_counter)); + head->length = sizeof(gensym_counter) - 1; + head->hash = hash; + sym = (uint8_t *)(head->data); memcpy(sym, gensym_counter, sizeof(gensym_counter)); - janet_string_length(sym) = sizeof(gensym_counter) - 1; - janet_string_hash(sym) = hash; janet_symcache_put((const uint8_t *)sym, bucket); return (const uint8_t *)sym; } diff --git a/src/core/tuple.c b/src/core/tuple.c index 8af69092..64a058ba 100644 --- a/src/core/tuple.c +++ b/src/core/tuple.c @@ -31,13 +31,12 @@ * which should be filled with Janets. The memory will not be collected until * janet_tuple_end is called. */ Janet *janet_tuple_begin(int32_t length) { - char *data = janet_gcalloc(JANET_MEMORY_TUPLE, 5 * sizeof(int32_t) + length * sizeof(Janet)); - Janet *tuple = (Janet *)(data + (5 * sizeof(int32_t))); - janet_tuple_length(tuple) = length; - janet_tuple_sm_start(tuple) = -1; - janet_tuple_sm_end(tuple) = -1; - janet_tuple_flag(tuple) = 0; - return tuple; + size_t size = sizeof(JanetTupleHead) + (length * sizeof(Janet)); + JanetTupleHead *head = janet_gcalloc(JANET_MEMORY_TUPLE, size); + head->sm_start = -1; + head->sm_end = -1; + head->length = length; + return (Janet *)(head->data); } /* Finish building a tuple */ diff --git a/src/include/janet.h b/src/include/janet.h index 47387d16..20567af6 100644 --- a/src/include/janet.h +++ b/src/include/janet.h @@ -204,6 +204,7 @@ extern "C" { #include #include #include +#include /* Names of all of the types */ extern const char *const janet_type_names[16]; @@ -256,15 +257,23 @@ typedef union Janet Janet; typedef struct Janet Janet; #endif -/* All of the janet types */ +/* Use type punning for GC objects */ +typedef struct JanetGCObject JanetGCObject; + +/* All of the primary Janet GCed types */ typedef struct JanetFunction JanetFunction; typedef struct JanetArray JanetArray; typedef struct JanetBuffer JanetBuffer; typedef struct JanetTable JanetTable; typedef struct JanetFiber JanetFiber; +/* Prefixed Janet types */ +typedef struct JanetTupleHead JanetTupleHead; +typedef struct JanetStructHead JanetStructHead; +typedef struct JanetStringHead JanetStringHead; +typedef struct JanetAbstractHead JanetAbstractHead; + /* Other structs */ -typedef struct JanetAbstractHeader JanetAbstractHeader; typedef struct JanetFuncDef JanetFuncDef; typedef struct JanetFuncEnv JanetFuncEnv; typedef struct JanetKV JanetKV; @@ -576,6 +585,14 @@ JANET_API int janet_checkint64(Janet x); #define janet_checktypes(x, tps) ((1 << janet_type(x)) & (tps)) +/* GC Object type pun. The lower 16 bits of flags are reserved for the garbage collector, + * but the upper 16 can be used per type for custom flags. The current collector is a linked + * list of blocks, which is naive but works. */ +struct JanetGCObject { + int32_t flags; + JanetGCObject *next; +}; + /* Fiber signal masks. */ #define JANET_FIBER_MASK_ERROR 2 #define JANET_FIBER_MASK_DEBUG 4 @@ -601,14 +618,15 @@ JANET_API int janet_checkint64(Janet x); /* A lightweight green thread in janet. Does not correspond to * operating system threads. */ struct JanetFiber { - Janet *data; - JanetFiber *child; /* Keep linked list of fibers for restarting pending fibers */ + JanetGCObject gc; /* GC Object stuff */ + int32_t flags; /* More flags */ int32_t frame; /* Index of the stack frame */ int32_t stackstart; /* Beginning of next args */ int32_t stacktop; /* Top of stack. Where values are pushed and popped from. */ int32_t capacity; int32_t maxstack; /* Arbitrary defined limit for stack overflow */ - int32_t flags; /* Various flags */ + Janet *data; + JanetFiber *child; /* Keep linked list of fibers for restarting pending fibers */ }; /* Mark if a stack frame is a tail call for debugging */ @@ -631,25 +649,28 @@ struct JanetStackFrame { /* A dynamic array type. */ struct JanetArray { - Janet *data; + JanetGCObject gc; int32_t count; int32_t capacity; + Janet *data; }; /* A byte buffer type. Used as a mutable string or string builder. */ struct JanetBuffer { - uint8_t *data; + JanetGCObject gc; int32_t count; int32_t capacity; + uint8_t *data; }; /* A mutable associative data type. Backed by a hashtable. */ struct JanetTable { - JanetKV *data; - JanetTable *proto; + JanetGCObject gc; int32_t count; int32_t capacity; int32_t deleted; + JanetKV *data; + JanetTable *proto; }; /* A key value pair in a struct or table */ @@ -658,6 +679,41 @@ struct JanetKV { Janet value; }; +/* Prefix for a tuple */ +struct JanetTupleHead { + JanetGCObject gc; + int32_t length; + int32_t hash; + int32_t sm_start; + int32_t sm_end; + const Janet data[]; +}; + +/* Prefix for a struct */ +struct JanetStructHead { + JanetGCObject gc; + int32_t length; + int32_t hash; + int32_t capacity; + const JanetKV data[]; +}; + +/* Prefix for a string */ +struct JanetStringHead { + JanetGCObject gc; + int32_t length; + int32_t hash; + const uint8_t data[]; +}; + +/* Prefix for an abstract value */ +struct JanetAbstractHead { + JanetGCObject gc; + const JanetAbstractType *type; + size_t size; + char data[]; +}; + /* Some function definition flags */ #define JANET_FUNCDEF_FLAG_VARARG 0x10000 #define JANET_FUNCDEF_FLAG_NEEDSENV 0x20000 @@ -677,6 +733,7 @@ struct JanetSourceMapping { /* A function definition. Contains information needed to instantiate closures. */ struct JanetFuncDef { + JanetGCObject gc; int32_t *environments; /* Which environments to capture from parent. */ Janet *constants; JanetFuncDef **defs; @@ -698,6 +755,7 @@ struct JanetFuncDef { /* A function environment */ struct JanetFuncEnv { + JanetGCObject gc; union { JanetFiber *fiber; Janet *values; @@ -709,6 +767,7 @@ struct JanetFuncEnv { /* A function */ struct JanetFunction { + JanetGCObject gc; JanetFuncDef *def; JanetFuncEnv *envs[]; }; @@ -748,12 +807,6 @@ struct JanetAbstractType { void (*put)(void *data, Janet key, Janet value); }; -/* Contains information about abstract types */ -struct JanetAbstractHeader { - const JanetAbstractType *type; - size_t size; -}; - struct JanetReg { const char *name; JanetCFunction cfun; @@ -986,14 +1039,14 @@ JANET_API void janet_buffer_push_u64(JanetBuffer *buffer, uint64_t x); /* Tuple */ -#define JANET_TUPLE_FLAG_BRACKETCTOR 1 +#define JANET_TUPLE_FLAG_BRACKETCTOR 0x10000 -#define janet_tuple_raw(t) ((int32_t *)(t) - 5) -#define janet_tuple_length(t) (janet_tuple_raw(t)[0]) -#define janet_tuple_hash(t) ((janet_tuple_raw(t)[1])) -#define janet_tuple_sm_start(t) ((janet_tuple_raw(t)[2])) -#define janet_tuple_sm_end(t) ((janet_tuple_raw(t)[3])) -#define janet_tuple_flag(t) ((janet_tuple_raw(t)[4])) +#define janet_tuple_head(t) ((JanetTupleHead *)((char *)t - offsetof(JanetTupleHead, data))) +#define janet_tuple_length(t) (janet_tuple_head(t)->length) +#define janet_tuple_hash(t) (janet_tuple_head(t)->hash) +#define janet_tuple_sm_start(t) (janet_tuple_head(t)->sm_start) +#define janet_tuple_sm_end(t) (janet_tuple_head(t)->sm_end) +#define janet_tuple_flag(t) (janet_tuple_head(t)->gc.flags) JANET_API Janet *janet_tuple_begin(int32_t length); JANET_API const Janet *janet_tuple_end(Janet *tuple); JANET_API const Janet *janet_tuple_n(const Janet *values, int32_t n); @@ -1001,9 +1054,9 @@ JANET_API int janet_tuple_equal(const Janet *lhs, const Janet *rhs); JANET_API int janet_tuple_compare(const Janet *lhs, const Janet *rhs); /* String/Symbol functions */ -#define janet_string_raw(s) ((int32_t *)(s) - 2) -#define janet_string_length(s) (janet_string_raw(s)[0]) -#define janet_string_hash(s) ((janet_string_raw(s)[1])) +#define janet_string_head(s) ((JanetStringHead *)((char *)s - offsetof(JanetStringHead, data))) +#define janet_string_length(s) (janet_string_head(s)->length) +#define janet_string_hash(s) (janet_string_head(s)->hash) JANET_API uint8_t *janet_string_begin(int32_t length); JANET_API const uint8_t *janet_string_end(uint8_t *str); JANET_API const uint8_t *janet_string(const uint8_t *buf, int32_t len); @@ -1033,11 +1086,10 @@ JANET_API const uint8_t *janet_symbol_gen(void); #define janet_ckeywordv(cstr) janet_wrap_keyword(janet_ckeyword(cstr)) /* Structs */ -#define janet_struct_raw(t) ((int32_t *)(t) - 4) -#define janet_struct_length(t) (janet_struct_raw(t)[0]) -#define janet_struct_capacity(t) (janet_struct_raw(t)[1]) -#define janet_struct_hash(t) (janet_struct_raw(t)[2]) -/* Do something with the 4th header slot - flags? */ +#define janet_struct_head(t) ((JanetStructHead *)((char *)t - offsetof(JanetStructHead, data))) +#define janet_struct_length(t) (janet_struct_head(t)->length) +#define janet_struct_capacity(t) (janet_struct_head(t)->capacity) +#define janet_struct_hash(t) (janet_struct_head(t)->hash) JANET_API JanetKV *janet_struct_begin(int32_t count); JANET_API void janet_struct_put(JanetKV *st, Janet key, Janet value); JANET_API const JanetKV *janet_struct_end(JanetKV *st); @@ -1073,7 +1125,7 @@ JANET_API Janet janet_dictionary_get(const JanetKV *data, int32_t cap, Janet key JANET_API const JanetKV *janet_dictionary_next(const JanetKV *kvs, int32_t cap, const JanetKV *kv); /* Abstract */ -#define janet_abstract_header(u) ((JanetAbstractHeader *)(u) - 1) +#define janet_abstract_header(u) ((JanetAbstractHead *)((char *)u - offsetof(JanetAbstractHead, data))) #define janet_abstract_type(u) (janet_abstract_header(u)->type) #define janet_abstract_size(u) (janet_abstract_header(u)->size) JANET_API void *janet_abstract(const JanetAbstractType *type, size_t size);