mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 07:33:01 +00:00 
			
		
		
		
	Add struct type.
This commit is contained in:
		
							
								
								
									
										7
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								Makefile
									
									
									
									
									
								
							| @@ -7,6 +7,7 @@ CFLAGS=-std=c99 -Wall -Wextra -Wpedantic -g -I./include | ||||
| PREFIX=/usr/local | ||||
| GST_TARGET=client/gst | ||||
| GST_CORELIB=core/libgst.a | ||||
| GST_INTERNAL_HEADERS=$(addprefix core/, cache.h) | ||||
| GST_HEADERS=$(addprefix include/gst/, gst.h stl.h compile.h disasm.h parse.h) | ||||
|  | ||||
| all: $(GST_TARGET) | ||||
| @@ -15,7 +16,7 @@ all: $(GST_TARGET) | ||||
| ##### The core vm and runtime ##### | ||||
| ################################### | ||||
| GST_CORE_SOURCES=$(addprefix core/,\ | ||||
| 				 compile.c disasm.c parse.c stl.c strings.c \ | ||||
| 				 compile.c disasm.c parse.c stl.c strings.c ids.c \ | ||||
| 				 value.c vm.c ds.c gc.c thread.c serialize.c capi.c) | ||||
| GST_CORE_OBJECTS=$(patsubst %.c,%.o,$(GST_CORE_SOURCES)) | ||||
| $(GST_CORELIB): $(GST_CORE_OBJECTS) $(GST_HEADERS) | ||||
| @@ -26,11 +27,11 @@ $(GST_CORELIB): $(GST_CORE_OBJECTS) $(GST_HEADERS) | ||||
| ############################## | ||||
| GST_CLIENT_SOURCES=client/main.c | ||||
| GST_CLIENT_OBJECTS=$(patsubst %.c,%.o,$(GST_CLIENT_SOURCES)) | ||||
| $(GST_TARGET): $(GST_CLIENT_OBJECTS) $(GST_HEADERS) $(GST_CORELIB) | ||||
| $(GST_TARGET): $(GST_CLIENT_OBJECTS) $(GST_CORELIB) | ||||
| 	$(CC) $(CFLAGS) -o $(GST_TARGET) $(GST_CLIENT_OBJECTS) $(GST_CORELIB) | ||||
|  | ||||
| # Compile all .c to .o | ||||
| %.o : %.c $(GST_HEADERS) | ||||
| %.o : %.c $(GST_HEADERS) $(GST_INTERNAL_HEADERS) | ||||
| 	$(CC) $(CFLAGS) -o $@ -c $< | ||||
|  | ||||
| run: $(GST_TARGET) | ||||
|   | ||||
| @@ -59,7 +59,7 @@ void debug_repl(FILE *in, FILE *out) { | ||||
|         gst_compiler(&c, &vm); | ||||
|         func.type = GST_NIL; | ||||
|         gst_compiler_usemodule(&c, "std"); | ||||
|         gst_compiler_global(&c, "ans", gst_object_get(vm.rootenv, gst_load_cstring(&vm, "ans"))); | ||||
|         gst_compiler_global(&c, "ans", gst_object_get(vm.rootenv, gst_string_cv(&vm, "ans"))); | ||||
|         func.type = GST_FUNCTION; | ||||
|         func.data.function = gst_compiler_compile(&c, p.value); | ||||
|  | ||||
| @@ -88,7 +88,7 @@ void debug_repl(FILE *in, FILE *out) { | ||||
|             continue; | ||||
|         } else if (out) { | ||||
|             fprintf(out, "%s\n", (char *)gst_to_string(&vm, vm.ret)); | ||||
|             gst_object_put(&vm, vm.rootenv, gst_load_cstring(&vm, "ans"), vm.ret); | ||||
|             gst_object_put(&vm, vm.rootenv, gst_string_cv(&vm, "ans"), vm.ret); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|   | ||||
							
								
								
									
										10
									
								
								core/cache.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								core/cache.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| #ifndef CACHE_H_LVYZMBLR | ||||
| #define CACHE_H_LVYZMBLR | ||||
|  | ||||
| #include <gst/gst.h> | ||||
|  | ||||
| void gst_cache_remove_string(Gst *vm, char *strmem); | ||||
| void gst_cache_remove_tuple(Gst *vm, char *tuplemem); | ||||
| void gst_cache_remove_struct(Gst *vm, char *structmem); | ||||
|  | ||||
| #endif /* end of include guard: CACHE_H_LVYZMBLR */ | ||||
| @@ -3,7 +3,7 @@ | ||||
| GstObject *gst_c_module(Gst *vm, const GstModuleItem *mod) { | ||||
|     GstObject *module = gst_object(vm, 10); | ||||
|     while (mod->name != NULL) { | ||||
|         GstValue key = gst_load_cstring(vm, mod->name); | ||||
|         GstValue key = gst_string_cv(vm, mod->name); | ||||
|         GstValue val; | ||||
|         val.type = GST_CFUNCTION; | ||||
|         val.data.cfunction = mod->data; | ||||
| @@ -19,5 +19,5 @@ void gst_c_register(Gst *vm, const char *packagename, GstObject *mod) { | ||||
|         vm->rootenv = gst_object(vm, 10); | ||||
|     modv.type = GST_OBJECT; | ||||
|     modv.data.object = mod; | ||||
|     gst_object_put(vm, vm->rootenv, gst_load_cstring(vm, packagename), modv); | ||||
|     gst_object_put(vm, vm->rootenv, gst_string_cv(vm, packagename), modv); | ||||
| } | ||||
|   | ||||
| @@ -488,7 +488,7 @@ static Slot compile_assign(GstCompiler *c, FormOptions opts, GstValue left, GstV | ||||
|  | ||||
| /* Compile series of expressions. This compiles the meat of | ||||
|  * function definitions and the inside of do forms. */ | ||||
| static Slot compile_block(GstCompiler *c, FormOptions opts, GstValue *form, uint32_t startIndex) { | ||||
| static Slot compile_block(GstCompiler *c, FormOptions opts, const GstValue *form, uint32_t startIndex) { | ||||
|     GstScope *scope = c->tail; | ||||
|     FormOptions subOpts = form_options_default(); | ||||
|     uint32_t current = startIndex; | ||||
| @@ -542,7 +542,7 @@ static GstFuncDef *compiler_gen_funcdef(GstCompiler *c, uint32_t lastNBytes, uin | ||||
| } | ||||
|  | ||||
| /* Compile a function from a function literal source form */ | ||||
| static Slot compile_function(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| static Slot compile_function(GstCompiler *c, FormOptions opts, const GstValue *form) { | ||||
|     GstScope *scope = c->tail; | ||||
|     GstBuffer *buffer = c->buffer; | ||||
|     uint32_t current = 1; | ||||
| @@ -595,7 +595,7 @@ static Slot compile_function(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| } | ||||
|  | ||||
| /* Branching special */ | ||||
| static Slot compile_if(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| static Slot compile_if(GstCompiler *c, FormOptions opts, const GstValue *form) { | ||||
|     GstScope *scope = c->tail; | ||||
|     GstBuffer *buffer = c->buffer; | ||||
|     FormOptions condOpts = opts; | ||||
| @@ -666,7 +666,7 @@ static Slot compile_if(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| } | ||||
|  | ||||
| /* Try catch special */ | ||||
| static Slot compile_try(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| static Slot compile_try(GstCompiler *c, FormOptions opts, const GstValue *form) { | ||||
|     GstScope *scope = c->tail; | ||||
|     GstBuffer *buffer = c->buffer; | ||||
|     Slot body; | ||||
| @@ -730,7 +730,7 @@ static Slot compile_try(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| } | ||||
|  | ||||
| /* While special */ | ||||
| static Slot compile_while(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| static Slot compile_while(GstCompiler *c, FormOptions opts, const GstValue *form) { | ||||
|     Slot cond; | ||||
|     uint32_t countAtStart = c->buffer->count; | ||||
|     uint32_t countAtJumpDelta; | ||||
| @@ -769,7 +769,7 @@ static Slot compile_while(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| } | ||||
|  | ||||
| /* Do special */ | ||||
| static Slot compile_do(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| static Slot compile_do(GstCompiler *c, FormOptions opts, const GstValue *form) { | ||||
|     Slot ret; | ||||
|     compiler_push_scope(c, 1); | ||||
|     ret = compile_block(c, opts, form, 1); | ||||
| @@ -778,7 +778,7 @@ static Slot compile_do(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| } | ||||
|  | ||||
| /* Quote special - returns its argument as is. */ | ||||
| static Slot compile_quote(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| static Slot compile_quote(GstCompiler *c, FormOptions opts, const GstValue *form) { | ||||
|     GstScope *scope = c->tail; | ||||
|     GstBuffer *buffer = c->buffer; | ||||
|     Slot ret; | ||||
| @@ -801,17 +801,17 @@ static Slot compile_quote(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| } | ||||
|  | ||||
| /* Assignment special */ | ||||
| static Slot compile_var(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| static Slot compile_var(GstCompiler *c, FormOptions opts, const GstValue *form) { | ||||
|     if (gst_tuple_length(form) != 3) | ||||
|         c_error(c, "assignment expects 2 arguments"); | ||||
|     return compile_assign(c, opts, form[1], form[2]); | ||||
| } | ||||
|  | ||||
| /* Define a function type for Special Form helpers */ | ||||
| typedef Slot (*SpecialFormHelper) (GstCompiler *c, FormOptions opts, GstValue *form); | ||||
| typedef Slot (*SpecialFormHelper) (GstCompiler *c, FormOptions opts, const GstValue *form); | ||||
|  | ||||
| /* Dispatch to a special form */ | ||||
| static SpecialFormHelper get_special(GstValue *form) { | ||||
| static SpecialFormHelper get_special(const GstValue *form) { | ||||
|     const uint8_t *name; | ||||
|     if (gst_tuple_length(form) < 1 || form[0].type != GST_STRING) | ||||
|         return NULL; | ||||
| @@ -944,7 +944,7 @@ static Slot compile_object(GstCompiler *c, FormOptions opts, GstObject *obj) { | ||||
| } | ||||
|  | ||||
| /* Compile a form. Checks for special forms and macros. */ | ||||
| static Slot compile_form(GstCompiler *c, FormOptions opts, GstValue *form) { | ||||
| static Slot compile_form(GstCompiler *c, FormOptions opts, const GstValue *form) { | ||||
|     GstScope *scope = c->tail; | ||||
|     GstBuffer *buffer = c->buffer; | ||||
|     SpecialFormHelper helper; | ||||
| @@ -1026,7 +1026,7 @@ void gst_compiler(GstCompiler *c, Gst *vm) { | ||||
|  | ||||
| /* Add a global variable */ | ||||
| void gst_compiler_global(GstCompiler *c, const char *name, GstValue x) { | ||||
|     GstValue sym = gst_load_cstring(c->vm, name); | ||||
|     GstValue sym = gst_string_cv(c->vm, name); | ||||
|     compiler_declare_symbol(c, c->tail, sym); | ||||
|     gst_array_push(c->vm, c->env, x);                 | ||||
| } | ||||
| @@ -1049,7 +1049,7 @@ void gst_compiler_globals(GstCompiler *c, GstObject *env) { | ||||
|  | ||||
| /* Use a module that was loaded into the vm */ | ||||
| void gst_compiler_usemodule(GstCompiler *c, const char *modulename) { | ||||
|     GstValue mod = gst_object_get(c->vm->rootenv, gst_load_cstring(c->vm, modulename)); | ||||
|     GstValue mod = gst_object_get(c->vm->rootenv, gst_string_cv(c->vm, modulename)); | ||||
|     if (mod.type == GST_OBJECT) { | ||||
|         gst_compiler_globals(c, mod.data.object); | ||||
|     } | ||||
|   | ||||
							
								
								
									
										17
									
								
								core/ds.c
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								core/ds.c
									
									
									
									
									
								
							| @@ -53,7 +53,7 @@ void gst_buffer_append(Gst *vm, GstBuffer *buffer, const uint8_t *string, uint32 | ||||
|  | ||||
| /* Convert the buffer to a string */ | ||||
| const uint8_t *gst_buffer_to_string(Gst *vm, GstBuffer *buffer) { | ||||
|     return gst_string_loadbuffer(vm, buffer->data, buffer->count); | ||||
|     return gst_string_b(vm, buffer->data, buffer->count); | ||||
| } | ||||
|  | ||||
| /****/ | ||||
| @@ -132,20 +132,6 @@ GstValue gst_array_peek(GstArray *array) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| /****/ | ||||
| /* Tuple functions */ | ||||
| /****/ | ||||
|  | ||||
| /* Create a new empty tuple of the given size. Expected to be | ||||
|  * mutated immediately */ | ||||
| GstValue *gst_tuple(Gst *vm, uint32_t length) { | ||||
|     char *data = gst_alloc(vm, 2 * sizeof(uint32_t) + length * sizeof(GstValue)); | ||||
|     GstValue *tuple = (GstValue *)(data + (2 * sizeof(uint32_t))); | ||||
|     gst_tuple_length(tuple) = length; | ||||
|     gst_tuple_hash(tuple) = 0; | ||||
|     return tuple; | ||||
| } | ||||
|  | ||||
| /****/ | ||||
| /* Userdata functions */ | ||||
| /****/ | ||||
| @@ -290,3 +276,4 @@ void gst_object_put(Gst *vm, GstObject *o, GstValue key, GstValue value) { | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										22
									
								
								core/gc.c
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								core/gc.c
									
									
									
									
									
								
							| @@ -1,5 +1,5 @@ | ||||
| #include <gst/gst.h> | ||||
| #include "stringcache.h" | ||||
| #include "cache.h" | ||||
|  | ||||
| /* The metadata header associated with an allocated block of memory */ | ||||
| #define gc_header(mem) ((GCMemoryHeader *)(mem) - 1) | ||||
| @@ -102,6 +102,16 @@ void gst_mark(Gst *vm, GstValueUnion x, GstType type) { | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|         case GST_STRUCT: | ||||
|             if (gc_header(gst_struct_raw(x.st))->color != vm->black) { | ||||
|                 uint32_t i, count; | ||||
|                 count = gst_struct_capacity(x.st); | ||||
|                 gc_header(gst_struct_raw(x.st))->color = vm->black; | ||||
|                 for (i = 0; i < count; ++i) | ||||
|                     gst_mark_value(vm, x.st[i]); | ||||
|             } | ||||
|             break; | ||||
|  | ||||
|         case GST_THREAD: | ||||
|             if (gc_header(x.thread)->color != vm->black) { | ||||
|                 GstThread *thread = x.thread; | ||||
| @@ -185,9 +195,13 @@ void gst_sweep(Gst *vm) { | ||||
|             } else { | ||||
|                 vm->blocks = next; | ||||
|             } | ||||
|             /* Remove from string cache */ | ||||
|             if (current->tags & GST_MEMTAG_STRING) { | ||||
|                 gst_stringcache_remove(vm, (uint8_t *)(current + 1) + 2 * sizeof(uint32_t)); | ||||
|             if (current->tags) { | ||||
|                 if (current->tags & GST_MEMTAG_STRING) | ||||
|                     gst_cache_remove_string(vm, (char *)(current + 1)); | ||||
|                 if (current->tags & GST_MEMTAG_STRUCT) | ||||
|                     gst_cache_remove_struct(vm, (char *)(current + 1)); | ||||
|                 if (current->tags & GST_MEMTAG_TUPLE) | ||||
|                     gst_cache_remove_tuple(vm, (char *)(current + 1)); | ||||
|             } | ||||
|             gst_raw_free(current); | ||||
|         } else { | ||||
|   | ||||
							
								
								
									
										361
									
								
								core/ids.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										361
									
								
								core/ids.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,361 @@ | ||||
| #include <gst/gst.h> | ||||
|  | ||||
| /****/ | ||||
| /* Cache */ | ||||
| /****/ | ||||
|  | ||||
| /* Calculate hash for string */ | ||||
| static uint32_t gst_string_calchash(const uint8_t *str, uint32_t len) { | ||||
|     const uint8_t *end = str + len; | ||||
|     uint32_t hash = 5381; | ||||
|     while (str < end) | ||||
|         hash = (hash << 5) + hash + *str++; | ||||
|     return hash; | ||||
| } | ||||
|  | ||||
| /* Calculate hash for tuple (and struct) */ | ||||
| static uint32_t gst_tuple_calchash(const GstValue *tuple, uint32_t len) { | ||||
|     const GstValue *end = tuple + len; | ||||
|     uint32_t hash = 5381; | ||||
|     while (tuple < end) | ||||
|         hash = (hash << 5) + hash + gst_hash(*tuple++); | ||||
|     return hash; | ||||
| } | ||||
|  | ||||
| /* Check if two not necesarrily finalized immutable values | ||||
|  * are equal. Does caching logic */ | ||||
| static int gst_cache_equal(GstValue x, GstValue y) { | ||||
|     uint32_t i, len; | ||||
|     if (x.type != y.type) return 0; | ||||
|     switch (x.type) { | ||||
|     /* Don't bother implemeting equality checks for all types. We only care | ||||
|      * about immutable data structures */ | ||||
|     default: | ||||
|         return 0; | ||||
|     case GST_STRING: | ||||
|         if (gst_string_hash(x.data.string) != gst_string_hash(y.data.string)) return 0; | ||||
|         if (gst_string_length(x.data.string) != gst_string_length(y.data.string)) return 0; | ||||
|         len = gst_string_length(x.data.string); | ||||
|         for (i = 0; i < len; ++i) | ||||
|             if (x.data.string[i] != y.data.string[i]) | ||||
|                 return 0; | ||||
|         return 1; | ||||
|     case GST_STRUCT: | ||||
|         if (gst_struct_hash(x.data.st) != gst_struct_hash(y.data.st)) return 0; | ||||
|         if (gst_struct_length(x.data.st) != gst_struct_length(y.data.st)) return 0; | ||||
|         len = gst_struct_capacity(x.data.st); | ||||
|         for (i = 0; i < len; ++i) | ||||
|             if (!gst_equals(x.data.st[i], y.data.st[i])) | ||||
|                 return 0; | ||||
|         return 1; | ||||
|     case GST_TUPLE: | ||||
|         if (gst_tuple_hash(x.data.tuple) != gst_tuple_hash(y.data.tuple)) return 0; | ||||
|         if (gst_tuple_length(x.data.tuple) != gst_tuple_length(y.data.tuple)) return 0; | ||||
|         len = gst_tuple_length(x.data.tuple); | ||||
|         for (i = 0; i < len; ++i) | ||||
|             if (!gst_equals(x.data.tuple[i], y.data.tuple[i])) | ||||
|                 return 0; | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Find an item in the cache and return its location. | ||||
|  * If the item is not found, return the location | ||||
|  * where one would put it. */ | ||||
| static GstValue *gst_cache_find(Gst *vm, GstValue key, int *success) { | ||||
|     uint32_t bounds[4]; | ||||
|     uint32_t i, j, index; | ||||
|     uint32_t hash = gst_hash(key); | ||||
|     GstValue *firstEmpty = NULL; | ||||
|     index = hash % vm->cache_capacity; | ||||
|     bounds[0] = index; | ||||
|     bounds[1] = vm->cache_capacity; | ||||
|     bounds[2] = 0; | ||||
|     bounds[3] = index; | ||||
|     for (j = 0; j < 4; j += 2) | ||||
|         for (i = bounds[j]; i < bounds[j+1]; ++i) { | ||||
|             GstValue test = vm->cache[i]; | ||||
|             /* Check empty spots */ | ||||
|             if (test.type == GST_NIL) { | ||||
|                 if (firstEmpty == NULL) | ||||
|                     firstEmpty = vm->cache + i; | ||||
|                 goto notfound; | ||||
|             } | ||||
|             /* Check for marked deleted - use booleans as deleted */ | ||||
|             if (test.type == GST_BOOLEAN) { | ||||
|                 if (firstEmpty == NULL) | ||||
|                     firstEmpty = vm->cache + i; | ||||
|                 continue; | ||||
|             } | ||||
|             if (gst_cache_equal(test, key)) { | ||||
|                 /* Replace first deleted */ | ||||
|                 *success = 1; | ||||
|                 if (firstEmpty != NULL) { | ||||
|                     *firstEmpty = test; | ||||
|                     vm->cache[i].type = GST_BOOLEAN; | ||||
|                     return firstEmpty; | ||||
|                 } | ||||
|                 return vm->cache + i; | ||||
|             } | ||||
|         } | ||||
|     notfound: | ||||
|     *success = 0; | ||||
|     return firstEmpty; | ||||
| } | ||||
|  | ||||
| /* Resize the cache. */ | ||||
| static void gst_cache_resize(Gst *vm, uint32_t newCapacity) { | ||||
|     uint32_t i, oldCapacity; | ||||
|     GstValue *oldCache = vm->cache; | ||||
|     GstValue *newCache = gst_raw_calloc(1, newCapacity * sizeof(GstValue)); | ||||
|     if (newCache == NULL) | ||||
|         GST_OUT_OF_MEMORY; | ||||
|     oldCapacity = vm->cache_capacity; | ||||
|     vm->cache = newCache; | ||||
|     vm->cache_capacity = newCapacity; | ||||
|     vm->cache_deleted = 0; | ||||
|     /* Add all of the old strings back */ | ||||
|     for (i = 0; i < oldCapacity; ++i) { | ||||
|         int status; | ||||
|         GstValue *bucket; | ||||
|         GstValue x = oldCache[i]; | ||||
|         if (x.type != GST_NIL && x.type != GST_BOOLEAN) { | ||||
|             bucket = gst_cache_find(vm, x, &status); | ||||
|             if (status || bucket == NULL) { | ||||
|                 /* there was a problem with the algorithm. */ | ||||
|                 break; | ||||
|             } | ||||
|             *bucket = x; | ||||
|         } | ||||
|     } | ||||
|     /* Free the old cache */ | ||||
|     gst_raw_free(oldCache); | ||||
| } | ||||
|  | ||||
| /* Add a value to the cache */ | ||||
| static GstValue gst_cache_add(Gst *vm, GstValue x) { | ||||
|     int status = 0; | ||||
|     GstValue *bucket = gst_cache_find(vm, x, &status); | ||||
|     if (!status) { | ||||
|         if ((vm->cache_count + vm->cache_deleted) * 2 > vm->cache_capacity) { | ||||
|             gst_cache_resize(vm, vm->cache_count * 4);  | ||||
|             bucket = gst_cache_find(vm, x, &status); | ||||
|         } | ||||
|         /* Mark the memory for the gc */ | ||||
|         switch (x.type) { | ||||
|         default: | ||||
|             break; | ||||
|         case GST_STRING: | ||||
|             gst_mem_tag(gst_string_raw(x.data.string), GST_MEMTAG_STRING); | ||||
|             break; | ||||
|         case GST_STRUCT: | ||||
|             gst_mem_tag(gst_struct_raw(x.data.st), GST_MEMTAG_STRUCT); | ||||
|             break; | ||||
|         case GST_TUPLE: | ||||
|             gst_mem_tag(gst_tuple_raw(x.data.tuple), GST_MEMTAG_TUPLE); | ||||
|             break; | ||||
|         } | ||||
|         /* Add x to the cache */ | ||||
|         vm->cache_count++; | ||||
|         *bucket = x; | ||||
|         return x; | ||||
|     } else { | ||||
|         return *bucket; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Remove a value from the cache */ | ||||
| static void gst_cache_remove(Gst *vm, GstValue x) { | ||||
|     int status = 0; | ||||
|     GstValue *bucket = gst_cache_find(vm, x, &status); | ||||
|     if (status) { | ||||
|         vm->cache_count--; | ||||
|         vm->cache_deleted++; | ||||
|         bucket->type = GST_BOOLEAN; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Remove a string from cache (called from gc) */ | ||||
| void gst_cache_remove_string(Gst *vm, char *strmem) { | ||||
|     GstValue x; | ||||
|     x.type = GST_STRING; | ||||
|     x.data.string = (const uint8_t *)(strmem + 2 * sizeof(uint32_t)); | ||||
|     gst_cache_remove(vm, x); | ||||
| } | ||||
|  | ||||
| /* Remove a tuple from cache (called from gc) */ | ||||
| void gst_cache_remove_tuple(Gst *vm, char *tuplemem) { | ||||
|     GstValue x; | ||||
|     x.type = GST_TUPLE; | ||||
|     x.data.tuple = (const GstValue *)(tuplemem + 2 * sizeof(uint32_t)); | ||||
|     gst_cache_remove(vm, x); | ||||
| } | ||||
|  | ||||
| /* Remove a struct from cache (called from gc) */ | ||||
| void gst_cache_remove_struct(Gst *vm, char *structmem) { | ||||
|     GstValue x; | ||||
|     x.type = GST_STRUCT; | ||||
|     x.data.st = (const GstValue *)(structmem + 2 * sizeof(uint32_t)); | ||||
|     gst_cache_remove(vm, x); | ||||
| } | ||||
|  | ||||
| /****/ | ||||
| /* Struct Functions */ | ||||
| /****/ | ||||
|  | ||||
| /* Begin creation of a struct */ | ||||
| GstValue *gst_struct_begin(Gst *vm, uint32_t count) { | ||||
|     char *data = gst_alloc(vm, sizeof(uint32_t) * 2 + 4 * count * sizeof(GstValue)); | ||||
|     GstValue *st = (GstValue *) (data + 2 * sizeof(uint32_t)); | ||||
|     gst_struct_length(st) = count; | ||||
|     return st;  | ||||
| } | ||||
|  | ||||
| /* Put a kv pair into a struct that has not yet been fully constructed. */ | ||||
| void gst_struct_put(GstValue *st, GstValue key, GstValue value) { | ||||
|     uint32_t cap = gst_struct_capacity(st); | ||||
|     uint32_t index = (gst_hash(key) % (cap / 2)) * 2; | ||||
|     uint32_t i; | ||||
|     for (i = index; i < cap; i += 2) { | ||||
|         if (st[i + 1].type == GST_NIL) { | ||||
|             st[i] = key; | ||||
|             st[i + 1] = value; | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|     for (i = 0; i < index; i += 2) { | ||||
|         if (st[i + 1].type == GST_NIL) { | ||||
|             st[i] = key; | ||||
|             st[i + 1] = value; | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|     /* Should not get here if struct was initialized with proper size */ | ||||
| } | ||||
|  | ||||
| /* Finish building a struct */ | ||||
| const GstValue *gst_struct_end(Gst *vm, GstValue *st) { | ||||
|     GstValue cached; | ||||
|     GstValue check; | ||||
|     gst_struct_hash(st) = gst_tuple_calchash(st, gst_struct_capacity(st)); | ||||
|     check.type = GST_STRUCT; | ||||
|     check.data.st = (const GstValue *) st; | ||||
|     cached = gst_cache_add(vm, check); | ||||
|     return cached.data.st; | ||||
| } | ||||
|  | ||||
| /* Get an item from a struct */ | ||||
| GstValue gst_struct_get(const GstValue *st, GstValue key) { | ||||
|     GstValue ret; | ||||
|     uint32_t cap = gst_struct_capacity(st); | ||||
|     uint32_t index = (gst_hash(key) % (cap / 2)) * 2; | ||||
|     uint32_t i; | ||||
|     for (i = index; i < cap; i += 2) { | ||||
|         if (st[i + 1].type == GST_NIL) { | ||||
|             goto notfound; | ||||
|         } else if (gst_equals(st[i], key)) { | ||||
|             return st[i + 1]; | ||||
|         } | ||||
|     } | ||||
|     for (i = 0; i < index; i += 2) { | ||||
|         if (st[i + 1].type == GST_NIL) { | ||||
|             goto notfound; | ||||
|         } else if (gst_equals(st[i], key)) { | ||||
|             return st[i + 1]; | ||||
|         } | ||||
|     } | ||||
|     notfound: | ||||
|     ret.type = GST_NIL; | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| /****/ | ||||
| /* Tuple functions */ | ||||
| /****/ | ||||
|  | ||||
| /* Create a new empty tuple of the given size. Expected to be | ||||
|  * mutated immediately */ | ||||
| GstValue *gst_tuple_begin(Gst *vm, uint32_t length) { | ||||
|     char *data = gst_alloc(vm, 2 * sizeof(uint32_t) + length * sizeof(GstValue)); | ||||
|     GstValue *tuple = (GstValue *)(data + (2 * sizeof(uint32_t))); | ||||
|     gst_tuple_length(tuple) = length; | ||||
|     return tuple; | ||||
| } | ||||
|  | ||||
| /* Finish building a tuple */ | ||||
| const GstValue *gst_tuple_end(Gst *vm, GstValue *tuple) { | ||||
|     GstValue cached; | ||||
|     GstValue check; | ||||
|     gst_tuple_hash(tuple) = gst_tuple_calchash(tuple, gst_tuple_length(tuple)); | ||||
|     check.type = GST_TUPLE; | ||||
|     check.data.tuple = (const GstValue *) tuple; | ||||
|     cached = gst_cache_add(vm, check); | ||||
|     return cached.data.tuple; | ||||
| } | ||||
|  | ||||
| /****/ | ||||
| /* String Functions */ | ||||
| /****/ | ||||
|  | ||||
| /* Begin building a string */ | ||||
| uint8_t *gst_string_begin(Gst *vm, uint32_t length) { | ||||
|     char *data = gst_alloc(vm, 2 * sizeof(uint32_t) + length + 1); | ||||
|     uint8_t *str = (uint8_t *) (data + 2 * sizeof(uint32_t)); | ||||
|     gst_string_length(str) = length; | ||||
|     str[length] = 0; | ||||
|     return str; | ||||
| } | ||||
|  | ||||
| /* Finish building a string */ | ||||
| const uint8_t *gst_string_end(Gst *vm, uint8_t *str) { | ||||
|     GstValue cached; | ||||
|     GstValue check; | ||||
|     gst_string_hash(str) = gst_string_calchash(str, gst_string_length(str)); | ||||
|     check.type = GST_STRING; | ||||
|     check.data.string = (const uint8_t *) str; | ||||
|     cached = gst_cache_add(vm, check); | ||||
|     return cached.data.string; | ||||
|  | ||||
| } | ||||
|  | ||||
| /* Load a buffer as a string */ | ||||
| const uint8_t *gst_string_b(Gst *vm, const uint8_t *buf, uint32_t len) { | ||||
|     GstValue cached; | ||||
|     GstValue check; | ||||
|     uint32_t newbufsize = len + 2 * sizeof(uint32_t) + 1; | ||||
|     uint8_t *str; | ||||
|     /* Ensure enough scratch memory */ | ||||
|     if (vm->scratch_len < newbufsize) { | ||||
|         vm->scratch = gst_alloc(vm, newbufsize); | ||||
|         vm->scratch_len = newbufsize; | ||||
|     } | ||||
|     str = (uint8_t *)(vm->scratch + 2 * sizeof(uint32_t)); | ||||
|     gst_memcpy(str, buf, len); | ||||
|     gst_string_length(str) = len; | ||||
|     gst_string_hash(str) = gst_string_calchash(str, gst_string_length(str)); | ||||
|     str[len] = 0; | ||||
|     check.type = GST_STRING; | ||||
|     check.data.string = (const uint8_t *) str; | ||||
|     cached = gst_cache_add(vm, check); | ||||
|     if (cached.data.string == (const uint8_t *) str) { | ||||
|         vm->scratch_len = 0; | ||||
|         vm->scratch = NULL; | ||||
|     } | ||||
|     return cached.data.string; | ||||
| } | ||||
|  | ||||
| /* Load a c string */ | ||||
| const uint8_t *gst_string_c(Gst *vm, const char *str) { | ||||
|     uint32_t len = 0; | ||||
|     while (str[len]) ++len; | ||||
|     return gst_string_b(vm, (const uint8_t *)str, len); | ||||
| } | ||||
|  | ||||
| /* Load a c string and return it as a GstValue */ | ||||
| GstValue gst_string_cv(Gst *vm, const char *str) { | ||||
|     GstValue ret; | ||||
|     const uint8_t *data = gst_string_c(vm, str); | ||||
|     ret.type = GST_STRING; | ||||
|     ret.data.string = data; | ||||
|     return ret; | ||||
| } | ||||
							
								
								
									
										14
									
								
								core/parse.c
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								core/parse.c
									
									
									
									
									
								
							| @@ -65,11 +65,11 @@ static GstValue quote(GstParser *p, GstValue x) { | ||||
|     /* Load a quote form to get the string literal */ | ||||
|     GstValue tuplev; | ||||
|     GstValue *tuple; | ||||
|     tuple = gst_tuple(p->vm, 2); | ||||
|     tuplev.type = GST_TUPLE; | ||||
|     tuplev.data.tuple = tuple; | ||||
|     tuple[0] = gst_load_cstring(p->vm, "quote"); | ||||
|     tuple = gst_tuple_begin(p->vm, 2); | ||||
|     tuple[0] = gst_string_cv(p->vm, "quote"); | ||||
|     tuple[1] = x; | ||||
|     tuplev.type = GST_TUPLE; | ||||
|     tuplev.data.tuple = gst_tuple_end(p->vm, tuple); | ||||
|     return tuplev; | ||||
| } | ||||
|  | ||||
| @@ -376,9 +376,11 @@ static int form_state(GstParser *p, uint8_t c) { | ||||
|             x.type = GST_ARRAY; | ||||
|             x.data.array = array; | ||||
|         } else if (c == ')') { | ||||
|             GstValue *tup; | ||||
|             tup = gst_tuple_begin(p->vm, array->count); | ||||
|             gst_memcpy(tup, array->data, array->count * sizeof(GstValue)); | ||||
|             x.type = GST_TUPLE; | ||||
|             x.data.tuple = gst_tuple(p->vm, array->count); | ||||
|             gst_memcpy(x.data.tuple, array->data, array->count * sizeof(GstValue)); | ||||
|             x.data.tuple = gst_tuple_end(p->vm, tup); | ||||
|         } else { /* c == '{' */ | ||||
|             uint32_t i; | ||||
|             if (array->count % 2 != 0) { | ||||
|   | ||||
| @@ -78,7 +78,6 @@ static const char *gst_deserialize_impl( | ||||
|     GstValue ret; | ||||
|     ret.type = GST_NIL; | ||||
|     GstValue *buffer; | ||||
|     const uint8_t *bytebuf; | ||||
|     uint32_t length, i; | ||||
|     const char *err; | ||||
|  | ||||
| @@ -137,11 +136,27 @@ static const char *gst_deserialize_impl( | ||||
|             ret.type = GST_STRING; | ||||
|             read_u32(length); | ||||
|             deser_datacheck(length); | ||||
|             ret.data.string = gst_string_loadbuffer(vm, data, length); | ||||
|             ret.data.string = gst_string_b(vm, data, length); | ||||
|             data += length; | ||||
|             gst_array_push(vm, visited, ret); | ||||
|             break; | ||||
|  | ||||
|         case 206: /* Struct */ | ||||
|             ret.type = GST_STRUCT; | ||||
|             read_u32(length); | ||||
|             buffer = gst_struct_begin(vm, length); | ||||
|             for (i = 0; i < length; ++i) { | ||||
|                 GstValue k, v; | ||||
|                 if ((err = gst_deserialize_impl(vm, data, end, &data, visited, &k))) | ||||
|                     return err;  | ||||
|                 if ((err = gst_deserialize_impl(vm, data, end, &data, visited, &v))) | ||||
|                     return err;  | ||||
|                 gst_struct_put(buffer, k, v); | ||||
|             } | ||||
|             ret.data.st = gst_struct_end(vm, buffer); | ||||
|             gst_array_push(vm, visited, ret); | ||||
|             break; | ||||
|  | ||||
|         case 207: /* Buffer */ | ||||
|             ret.type = GST_BYTEBUFFER; | ||||
|             read_u32(length); | ||||
| @@ -172,14 +187,12 @@ static const char *gst_deserialize_impl( | ||||
|         case 209: /* Tuple */ | ||||
|             ret.type = GST_TUPLE; | ||||
|             read_u32(length); | ||||
|             bytebuf = gst_alloc(vm, length * sizeof(GstValue) + 2 * sizeof(uint32_t)); | ||||
|             buffer = (GstValue *)(bytebuf + 2 * sizeof(uint32_t)); | ||||
|             buffer = gst_tuple_begin(vm, length); | ||||
|             for (i = 0; i < length; ++i) | ||||
|                 if ((err = gst_deserialize_impl(vm, data, end, &data, visited, buffer + i))) | ||||
|                     return err; | ||||
|             gst_tuple_hash(buffer) = 0; | ||||
|             gst_tuple_length(buffer) = length; | ||||
|             ret.data.tuple = buffer; | ||||
|             ret.type = GST_TUPLE; | ||||
|             ret.data.tuple = gst_tuple_end(vm, buffer); | ||||
|             gst_array_push(vm, visited, ret); | ||||
|             break; | ||||
|  | ||||
|   | ||||
							
								
								
									
										31
									
								
								core/stl.c
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								core/stl.c
									
									
									
									
									
								
							| @@ -197,7 +197,7 @@ int gst_stl_type(Gst *vm) { | ||||
|         typestr = "funcdef"; | ||||
|         break; | ||||
|     } | ||||
|     gst_c_return(vm, gst_load_cstring(vm, typestr)); | ||||
|     gst_c_return(vm, gst_string_cv(vm, typestr)); | ||||
| } | ||||
|  | ||||
| /* Create array */ | ||||
| @@ -219,12 +219,12 @@ int gst_stl_tuple(Gst *vm) { | ||||
|     uint32_t i; | ||||
|     uint32_t count = gst_count_args(vm); | ||||
|     GstValue ret; | ||||
|     GstValue *tuple= gst_tuple(vm, count); | ||||
|     GstValue *tuple= gst_tuple_begin(vm, count); | ||||
|     for (i = 0; i < count; ++i) { | ||||
|         tuple[i] = gst_arg(vm, i); | ||||
|     } | ||||
|     ret.type = GST_TUPLE; | ||||
|     ret.data.tuple = tuple; | ||||
|     ret.data.tuple = gst_tuple_end(vm, tuple); | ||||
|     gst_c_return(vm, ret); | ||||
| } | ||||
|  | ||||
| @@ -237,7 +237,7 @@ int gst_stl_object(Gst *vm) { | ||||
|     if (count % 2 != 0) { | ||||
|         gst_c_throwc(vm, "expected even number of arguments"); | ||||
|     } | ||||
|     object = gst_object(vm, count); | ||||
|     object = gst_object(vm, count / 2); | ||||
|     for (i = 0; i < count; i += 2) { | ||||
|         gst_object_put(vm, object, gst_arg(vm, i), gst_arg(vm, i + 1)); | ||||
|     } | ||||
| @@ -246,6 +246,24 @@ int gst_stl_object(Gst *vm) { | ||||
|     gst_c_return(vm, ret); | ||||
| } | ||||
|  | ||||
| /* Create struct */ | ||||
| int gst_stl_struct(Gst *vm) { | ||||
|     uint32_t i; | ||||
|     uint32_t count = gst_count_args(vm); | ||||
|     GstValue ret; | ||||
|     GstValue *st; | ||||
|     if (count % 2 != 0) { | ||||
|         gst_c_throwc(vm, "expected even number of arguments"); | ||||
|     } | ||||
|     st = gst_struct_begin(vm, count / 2); | ||||
|     for (i = 0; i < count; i += 2) { | ||||
|         gst_struct_put(st, gst_arg(vm, i), gst_arg(vm, i + 1)); | ||||
|     } | ||||
|     ret.type = GST_STRUCT; | ||||
|     ret.data.st = gst_struct_end(vm, st); | ||||
|     gst_c_return(vm, ret); | ||||
| } | ||||
|  | ||||
| /* Create a buffer */ | ||||
| int gst_stl_buffer(Gst *vm) { | ||||
|     uint32_t i, count; | ||||
| @@ -308,7 +326,6 @@ int gst_stl_rawget(Gst *vm) { | ||||
|  | ||||
| /* Associative rawset */ | ||||
| int gst_stl_rawset(Gst *vm) { | ||||
|     GstValue ret; | ||||
|     uint32_t count; | ||||
|     const char *err; | ||||
|     count = gst_count_args(vm); | ||||
| @@ -319,8 +336,7 @@ int gst_stl_rawset(Gst *vm) { | ||||
|     if (err != NULL) { | ||||
|         gst_c_throwc(vm, err); | ||||
|     } else { | ||||
|         ret.type = GST_NIL; | ||||
|         gst_c_return(vm, ret); | ||||
|         gst_c_return(vm, gst_arg(vm, 0)); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -408,6 +424,7 @@ static const GstModuleItem const std_module[] = { | ||||
|     {"array", gst_stl_array}, | ||||
|     {"tuple", gst_stl_tuple}, | ||||
|     {"object", gst_stl_object}, | ||||
|     {"struct", gst_stl_struct}, | ||||
|     {"buffer", gst_stl_buffer}, | ||||
|     {"strcat", gst_stl_strcat}, | ||||
|     {"print", gst_stl_print}, | ||||
|   | ||||
| @@ -1,14 +0,0 @@ | ||||
| #ifndef GST_STRINGCACHE_defined | ||||
| #define GST_STRINGCACHE_defined | ||||
|  | ||||
| #include <gst/gst.h> | ||||
|  | ||||
| /****/ | ||||
| /* String Cache (move internal) */ | ||||
| /****/ | ||||
|  | ||||
| void gst_stringcache_init(Gst *vm, uint32_t capacity); | ||||
| void gst_stringcache_deinit(Gst *vm); | ||||
| void gst_stringcache_remove(Gst *vm, const uint8_t *str); | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										222
									
								
								core/strings.c
									
									
									
									
									
								
							
							
						
						
									
										222
									
								
								core/strings.c
									
									
									
									
									
								
							| @@ -1,224 +1,4 @@ | ||||
| #include <gst/gst.h> | ||||
| #include "stringcache.h" | ||||
|  | ||||
| /* Dud pointer to serve as deletion marker */ | ||||
| static uint8_t *deleted = (uint8_t *) ""; | ||||
|  | ||||
| /* Check if string and cstring are equal */ | ||||
| /* To check if strings are equal externally, one can | ||||
|  * just use == */ | ||||
| static int gst_cstring_equal(const uint8_t *lhs, const uint8_t *rhs, uint32_t rlen, uint32_t rhash) { | ||||
|     uint32_t lhash, len, i; | ||||
|     /* Check lengths */ | ||||
|     len = gst_string_length(lhs); | ||||
|     if (len != rlen) return 0; | ||||
|     /* Check hashes */ | ||||
|     lhash = gst_string_hash(lhs); | ||||
|     if (lhash != rhash) return 0; | ||||
|     for (i = 0; i < len; ++i) | ||||
|         if (lhs[i] != rhs[i]) | ||||
|             return 0; | ||||
|     return 1; | ||||
| } | ||||
|  | ||||
| /* Simple hash function (djb2) */ | ||||
| static uint32_t gst_string_calchash(const uint8_t *str, uint32_t len) { | ||||
|     const uint8_t *end = str + len; | ||||
|     uint32_t hash = 5381; | ||||
|     while (str < end) | ||||
|         hash = (hash << 5) + hash + *str++; | ||||
|     return hash; | ||||
| } | ||||
|  | ||||
| /* Find a string in the hashtable. Returns null if | ||||
|  * not found. */ | ||||
| static const uint8_t **gst_stringcache_find( | ||||
|         Gst *vm,  | ||||
|         const uint8_t *str, | ||||
|         uint32_t len, | ||||
|         uint32_t hash, | ||||
|         int *success) { | ||||
|     uint32_t bounds[4]; | ||||
|     uint32_t i, j, index; | ||||
|     const uint8_t **firstEmpty = NULL; | ||||
|     index = hash % vm->stringsCapacity; | ||||
|     bounds[0] = index; | ||||
|     bounds[1] = vm->stringsCapacity; | ||||
|     bounds[2] = 0; | ||||
|     bounds[3] = index; | ||||
|     for (j = 0; j < 4; j += 2) | ||||
|         for (i = bounds[j]; i < bounds[j+1]; ++i) { | ||||
|             const uint8_t *testStr = vm->strings[i]; | ||||
|             /* Check empty spots */ | ||||
|             if (testStr == NULL) { | ||||
|                 if (firstEmpty == NULL) | ||||
|                     firstEmpty = vm->strings + i; | ||||
|                 goto notfound; | ||||
|             } | ||||
|             if (testStr == deleted) { | ||||
|                 if (firstEmpty == NULL) | ||||
|                     firstEmpty = vm->strings + i; | ||||
|                 continue; | ||||
|             } | ||||
|             if (gst_cstring_equal(testStr, str, len, hash)) { | ||||
|                 /* Replace first deleted */ | ||||
|                 *success = 1; | ||||
|                 if (firstEmpty != NULL) { | ||||
|                     *firstEmpty = testStr; | ||||
|                     vm->strings[i] = deleted; | ||||
|                     return firstEmpty; | ||||
|                 } | ||||
|                 return vm->strings + i; | ||||
|             } | ||||
|         } | ||||
|     notfound: | ||||
|     *success = 0; | ||||
|     return firstEmpty; | ||||
| } | ||||
|  | ||||
| /* Resize the hashtable. */ | ||||
| static void gst_stringcache_resize(Gst *vm, uint32_t newCapacity) { | ||||
|     uint32_t i, oldCapacity; | ||||
|     const uint8_t **oldCache = vm->strings; | ||||
|     const uint8_t **newCache = gst_raw_calloc(1, newCapacity * sizeof(uint8_t *)); | ||||
|     if (newCache == NULL) | ||||
|         GST_OUT_OF_MEMORY; | ||||
|     oldCapacity = vm->stringsCapacity; | ||||
|     vm->strings = newCache; | ||||
|     vm->stringsCapacity = newCapacity; | ||||
|     vm->stringsDeleted = 0; | ||||
|     /* Add all of the old strings back */ | ||||
|     for (i = 0; i < oldCapacity; ++i) { | ||||
|         int status; | ||||
|         const uint8_t **bucket; | ||||
|         const uint8_t *str = oldCache[i]; | ||||
|         if (str != NULL && str != deleted) { | ||||
|             bucket = gst_stringcache_find(vm, str, | ||||
|                     gst_string_length(str), | ||||
|                     gst_string_hash(str), &status); | ||||
|             if (status || bucket == NULL) { | ||||
|                 /* there was a problem with the algorithm. */ | ||||
|                 break; | ||||
|             } | ||||
|             *bucket = str; | ||||
|         } | ||||
|     } | ||||
|     /* Free the old cache */ | ||||
|     gst_raw_free(oldCache); | ||||
| } | ||||
|  | ||||
| /****/ | ||||
| /* Internal API */ | ||||
| /****/ | ||||
|  | ||||
| /* Initialize the string cache for a vm */ | ||||
| void gst_stringcache_init(Gst *vm, uint32_t capacity) { | ||||
|     vm->strings = gst_raw_calloc(1, capacity * sizeof(uint8_t *)); | ||||
|     if (vm->strings == NULL) | ||||
|         GST_OUT_OF_MEMORY; | ||||
|     vm->stringsCapacity = capacity; | ||||
|     vm->stringsCount = 0; | ||||
|     vm->stringsDeleted = 0; | ||||
| } | ||||
|  | ||||
| /* Deinitialize the stringcache for a vm */ | ||||
| void gst_stringcache_deinit(Gst *vm) { | ||||
|     gst_raw_free(vm->strings); | ||||
|     vm->stringsCapacity = 0; | ||||
|     vm->stringsCount = 0; | ||||
|     vm->stringsDeleted = 0; | ||||
| } | ||||
|  | ||||
| /* Remove a string from the cache */ | ||||
| void gst_stringcache_remove(Gst *vm, const uint8_t *str) { | ||||
|     int status = 0; | ||||
|     const uint8_t **bucket = gst_stringcache_find(vm, str, | ||||
|             gst_string_length(str),  | ||||
|             gst_string_hash(str), | ||||
|             &status); | ||||
|     if (status) { | ||||
|         vm->stringsCount--; | ||||
|         vm->stringsDeleted++; | ||||
|         *bucket = deleted; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /****/ | ||||
| /* Public C API */ | ||||
| /****/ | ||||
|  | ||||
| /* Begin creation of a string */ | ||||
| uint8_t *gst_string_begin(Gst *vm, uint32_t len) { | ||||
|     uint8_t *data = gst_alloc(vm, len + 1 + 2 * sizeof(uint32_t)); | ||||
|     data += 2 * sizeof(uint32_t); | ||||
|     gst_string_length(data) = len; | ||||
|     data[len] = 0; | ||||
|     return data; | ||||
| } | ||||
|  | ||||
| /* Finish building the string. Calculates the hash and deduplicates it */ | ||||
| const uint8_t *gst_string_end(Gst *vm, uint8_t *str) { | ||||
|     int status = 0; | ||||
|     const uint8_t **bucket; | ||||
|     uint32_t hash, len; | ||||
|     len = gst_string_length(str); | ||||
|     hash = gst_string_hash(str) = gst_string_calchash(str, len); | ||||
|     bucket = gst_stringcache_find(vm, str, len, hash, &status); | ||||
|     if (status) { | ||||
|         return *bucket; | ||||
|     } else { | ||||
|         if ((vm->stringsCount + vm->stringsDeleted) * 2 > vm->stringsCapacity) { | ||||
|             gst_stringcache_resize(vm, vm->stringsCount * 4);  | ||||
|             bucket = gst_stringcache_find(vm, str, len, hash, &status); | ||||
|         } | ||||
|         /* Mark the memory as string memory */ | ||||
|         gst_mem_tag(gst_string_raw(str), GST_MEMTAG_STRING); | ||||
|         vm->stringsCount++; | ||||
|         *bucket = str; | ||||
|         return str; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Loads a constant buffer as a string into a gst vm */ | ||||
| const uint8_t *gst_string_loadbuffer(Gst *vm, const uint8_t *buf, uint32_t len) { | ||||
|     int status = 0; | ||||
|     const uint8_t **bucket; | ||||
|     uint32_t hash; | ||||
|     hash = gst_string_calchash(buf, len); | ||||
|     bucket = gst_stringcache_find(vm, buf, len, hash, &status); | ||||
|     if (status) { | ||||
|         return *bucket; | ||||
|     } else { | ||||
|         uint8_t *str; | ||||
|         if ((vm->stringsCount + vm->stringsDeleted) * 2 > vm->stringsCapacity) { | ||||
|             gst_stringcache_resize(vm, vm->stringsCount * 4);  | ||||
|             bucket = gst_stringcache_find(vm, buf, len, hash, &status); | ||||
|         } | ||||
|         vm->stringsCount++; | ||||
|         str = gst_string_begin(vm, len); | ||||
|         gst_memcpy(str, buf, len); | ||||
|         gst_string_hash(str) = hash; | ||||
|         /* Mark the memory as string memory */ | ||||
|         gst_mem_tag(gst_string_raw(str), GST_MEMTAG_STRING); | ||||
|         *bucket = str; | ||||
|         return str; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* Converts a c style string to a gst string */ | ||||
| const uint8_t *gst_cstring_to_string(Gst *vm, const char *cstring) { | ||||
|     uint32_t len = 0; | ||||
|     while (cstring[len]) ++len; | ||||
|     return gst_string_loadbuffer(vm, (const uint8_t *)cstring, len); | ||||
| } | ||||
|  | ||||
| /* Load a c string into a GST string */ | ||||
| GstValue gst_load_cstring(Gst *vm, const char *string) { | ||||
|     GstValue ret; | ||||
|     ret.type = GST_STRING; | ||||
|     ret.data.string = gst_cstring_to_string(vm, string); | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| /* Compares two strings */ | ||||
| int gst_string_compare(const uint8_t *lhs, const uint8_t *rhs) { | ||||
| @@ -230,7 +10,7 @@ int gst_string_compare(const uint8_t *lhs, const uint8_t *rhs) { | ||||
|         if (lhs[i] == rhs[i]) { | ||||
|             continue; | ||||
|         } else if (lhs[i] < rhs[i]) { | ||||
|             return -1; /* x is less then y */ | ||||
|             return -1; /* x is less than y */ | ||||
|         } else { | ||||
|             return 1; /* y is less than x */ | ||||
|         } | ||||
|   | ||||
| @@ -68,14 +68,14 @@ void gst_thread_tuplepack(Gst *vm, GstThread *thread, uint32_t n) { | ||||
|         gst_thread_pushnil(vm, thread, n - size + 1); | ||||
|         stack = thread->data + thread->count; | ||||
|         stack[n].type = GST_TUPLE; | ||||
|         stack[n].data.tuple = gst_tuple(vm, 0); | ||||
|         stack[n].data.tuple = gst_tuple_end(vm, gst_tuple_begin(vm, 0)); | ||||
|     } else { | ||||
|         uint32_t i; | ||||
|         GstValue *tuple = gst_tuple(vm, size - n); | ||||
|         GstValue *tuple = gst_tuple_begin(vm, size - n); | ||||
|         for (i = n; i < size; ++i) | ||||
|             tuple[i - n] = stack[i]; | ||||
|         stack[n].type = GST_TUPLE; | ||||
|         stack[n].data.tuple = tuple; | ||||
|         stack[n].data.tuple = gst_tuple_end(vm, tuple); | ||||
|         gst_frame_size(stack) = n + 1; | ||||
|     } | ||||
| } | ||||
|   | ||||
							
								
								
									
										209
									
								
								core/value.c
									
									
									
									
									
								
							
							
						
						
									
										209
									
								
								core/value.c
									
									
									
									
									
								
							| @@ -13,7 +13,7 @@ static const uint8_t *number_to_string(Gst *vm, GstNumber x) { | ||||
|     uint8_t buf[GST_BUFSIZE]; | ||||
|     /* TODO - not depend on stdio */ | ||||
|     int count = snprintf((char *) buf, GST_BUFSIZE, "%.21g", x); | ||||
|     return gst_string_loadbuffer(vm, buf, (uint32_t) count); | ||||
|     return gst_string_b(vm, buf, (uint32_t) count); | ||||
| } | ||||
|  | ||||
| static const char *HEX_CHARACTERS = "0123456789abcdef"; | ||||
| @@ -44,7 +44,7 @@ static const uint8_t *string_description(Gst *vm, const char *title, void *point | ||||
|         *c++ = HEX(byte & 0xF); | ||||
|     } | ||||
|     *c++ = '>'; | ||||
|     return gst_string_loadbuffer(vm, buf, c - buf); | ||||
|     return gst_string_b(vm, buf, c - buf); | ||||
| } | ||||
|  | ||||
| #undef GST_BUFSIZE | ||||
| @@ -52,52 +52,44 @@ static const uint8_t *string_description(Gst *vm, const char *title, void *point | ||||
| /* Returns a string pointer or NULL if could not allocate memory. */ | ||||
| const uint8_t *gst_to_string(Gst *vm, GstValue x) { | ||||
|     switch (x.type) { | ||||
|         case GST_NIL: | ||||
|             return gst_cstring_to_string(vm, "nil"); | ||||
|         case GST_BOOLEAN: | ||||
|             if (x.data.boolean) { | ||||
|                 return gst_cstring_to_string(vm, "true"); | ||||
|             } else { | ||||
|                 return gst_cstring_to_string(vm, "false"); | ||||
|             } | ||||
|         case GST_NUMBER: | ||||
|             return number_to_string(vm, x.data.number); | ||||
|         case GST_ARRAY: | ||||
|             return string_description(vm, "array", x.data.pointer); | ||||
|         case GST_TUPLE: | ||||
|             return string_description(vm, "tuple", x.data.pointer); | ||||
|         case GST_OBJECT: | ||||
|             return string_description(vm, "object", x.data.pointer); | ||||
|         case GST_STRING: | ||||
|             return x.data.string; | ||||
|         case GST_BYTEBUFFER: | ||||
|             return string_description(vm, "buffer", x.data.pointer); | ||||
|         case GST_CFUNCTION: | ||||
|             return string_description(vm, "cfunction", x.data.pointer); | ||||
|         case GST_FUNCTION: | ||||
|             return string_description(vm, "function", x.data.pointer); | ||||
|         case GST_THREAD: | ||||
|             return string_description(vm, "thread", x.data.pointer); | ||||
|         case GST_USERDATA: | ||||
|             return string_description(vm, "userdata", x.data.pointer); | ||||
|         case GST_FUNCENV: | ||||
|             return string_description(vm, "funcenv", x.data.pointer); | ||||
|         case GST_FUNCDEF: | ||||
|             return string_description(vm, "funcdef", x.data.pointer); | ||||
|     case GST_NIL: | ||||
|         return gst_string_c(vm, "nil"); | ||||
|     case GST_BOOLEAN: | ||||
|         if (x.data.boolean) { | ||||
|             return gst_string_c(vm, "true"); | ||||
|         } else { | ||||
|             return gst_string_c(vm, "false"); | ||||
|         } | ||||
|     case GST_NUMBER: | ||||
|         return number_to_string(vm, x.data.number); | ||||
|     case GST_ARRAY: | ||||
|         return string_description(vm, "array", x.data.pointer); | ||||
|     case GST_TUPLE: | ||||
|         return string_description(vm, "tuple", x.data.pointer); | ||||
|     case GST_STRUCT: | ||||
|         return string_description(vm, "struct", x.data.pointer); | ||||
|     case GST_OBJECT: | ||||
|         return string_description(vm, "object", x.data.pointer); | ||||
|     case GST_STRING: | ||||
|         return x.data.string; | ||||
|     case GST_BYTEBUFFER: | ||||
|         return string_description(vm, "buffer", x.data.pointer); | ||||
|     case GST_CFUNCTION: | ||||
|         return string_description(vm, "cfunction", x.data.pointer); | ||||
|     case GST_FUNCTION: | ||||
|         return string_description(vm, "function", x.data.pointer); | ||||
|     case GST_THREAD: | ||||
|         return string_description(vm, "thread", x.data.pointer); | ||||
|     case GST_USERDATA: | ||||
|         return string_description(vm, "userdata", x.data.pointer); | ||||
|     case GST_FUNCENV: | ||||
|         return string_description(vm, "funcenv", x.data.pointer); | ||||
|     case GST_FUNCDEF: | ||||
|         return string_description(vm, "funcdef", x.data.pointer); | ||||
|     } | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| /* Simple hash function to get tuple hash */ | ||||
| static uint32_t tuple_calchash(GstValue *tuple) { | ||||
|     uint32_t i; | ||||
|     uint32_t count = gst_tuple_length(tuple); | ||||
|     uint32_t hash = 5387; | ||||
|     for (i = 0; i < count; ++i) | ||||
|         hash = (hash << 5) + hash + gst_hash(tuple[i]); | ||||
|     return hash; | ||||
| } | ||||
|  | ||||
| /* Check if two values are equal. This is strict equality with no conversion. */ | ||||
| int gst_equals(GstValue x, GstValue y) { | ||||
|     int result = 0; | ||||
| @@ -105,40 +97,19 @@ int gst_equals(GstValue x, GstValue y) { | ||||
|         result = 0; | ||||
|     } else { | ||||
|         switch (x.type) { | ||||
|             case GST_NIL: | ||||
|                 result = 1; | ||||
|                 break; | ||||
|             case GST_BOOLEAN: | ||||
|                 result = (x.data.boolean == y.data.boolean); | ||||
|                 break; | ||||
|             case GST_NUMBER: | ||||
|                 result = (x.data.number == y.data.number); | ||||
|                 break; | ||||
|             case GST_TUPLE: | ||||
|                 if (x.data.tuple == y.data.tuple) { | ||||
|                     result = 1; | ||||
|                     break; | ||||
|                 } | ||||
|                 if (gst_hash(x) != gst_hash(y) || | ||||
|                         gst_tuple_length(x.data.string) != gst_tuple_length(y.data.string)) { | ||||
|                     result = 0; | ||||
|                     break; | ||||
|                 } | ||||
|                 result = 1; | ||||
|                 { | ||||
|                     uint32_t i; | ||||
|                     for (i = 0; i < gst_tuple_length(x.data.tuple); ++i) { | ||||
|                         if (!gst_equals(x.data.tuple[i], y.data.tuple[i])) { | ||||
|                             result = 0; | ||||
|                             break; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|                 break; | ||||
|             default: | ||||
|                 /* compare pointers */ | ||||
|                 result = (x.data.pointer == y.data.pointer); | ||||
|                 break; | ||||
|         case GST_NIL: | ||||
|             result = 1; | ||||
|             break; | ||||
|         case GST_BOOLEAN: | ||||
|             result = (x.data.boolean == y.data.boolean); | ||||
|             break; | ||||
|         case GST_NUMBER: | ||||
|             result = (x.data.number == y.data.number); | ||||
|             break; | ||||
|         default: | ||||
|             /* compare pointers */ | ||||
|             result = (x.data.pointer == y.data.pointer); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     return result; | ||||
| @@ -148,43 +119,43 @@ int gst_equals(GstValue x, GstValue y) { | ||||
| uint32_t gst_hash(GstValue x) { | ||||
|     uint32_t hash = 0; | ||||
|     switch (x.type) { | ||||
|         case GST_NIL: | ||||
|             hash = 0; | ||||
|             break; | ||||
|         case GST_BOOLEAN: | ||||
|             hash = x.data.boolean; | ||||
|             break; | ||||
|         case GST_NUMBER: | ||||
|             { | ||||
|                 union { | ||||
|                     uint32_t hash; | ||||
|                     GstNumber number; | ||||
|                 } u; | ||||
|                 u.number = x.data.number; | ||||
|                 hash = u.hash; | ||||
|             } | ||||
|             break; | ||||
|             /* String hashes */ | ||||
|         case GST_STRING: | ||||
|             hash = gst_string_hash(x.data.string); | ||||
|             break; | ||||
|         case GST_TUPLE: | ||||
|             if (gst_tuple_hash(x.data.tuple)) | ||||
|                 hash = gst_tuple_hash(x.data.tuple); | ||||
|             else | ||||
|                 hash = gst_tuple_hash(x.data.tuple) = tuple_calchash(x.data.tuple); | ||||
|             break; | ||||
|         default: | ||||
|             /* Cast the pointer */ | ||||
|             { | ||||
|                 union { | ||||
|                     void * pointer; | ||||
|                     uint32_t hash; | ||||
|                 } u; | ||||
|                 u.pointer = x.data.pointer; | ||||
|                 hash = u.hash; | ||||
|             } | ||||
|             break; | ||||
|     case GST_NIL: | ||||
|         hash = 0; | ||||
|         break; | ||||
|     case GST_BOOLEAN: | ||||
|         hash = x.data.boolean; | ||||
|         break; | ||||
|     case GST_NUMBER: | ||||
|         { | ||||
|             union { | ||||
|                 uint32_t hash; | ||||
|                 GstNumber number; | ||||
|             } u; | ||||
|             u.number = x.data.number; | ||||
|             hash = u.hash; | ||||
|         } | ||||
|         break; | ||||
|         /* String hashes */ | ||||
|     case GST_STRING: | ||||
|         hash = gst_string_hash(x.data.string); | ||||
|         break; | ||||
|     case GST_TUPLE: | ||||
|         hash = gst_tuple_hash(x.data.tuple); | ||||
|         break; | ||||
|     case GST_STRUCT: | ||||
|         hash = gst_struct_hash(x.data.st); | ||||
|         break; | ||||
|     default: | ||||
|         /* Cast the pointer */ | ||||
|         { | ||||
|             union { | ||||
|                 void * pointer; | ||||
|                 uint32_t hash; | ||||
|             } u; | ||||
|             u.pointer = x.data.pointer; | ||||
|             hash = u.hash; | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
|     return hash; | ||||
| } | ||||
| @@ -304,6 +275,9 @@ const char *gst_get(GstValue ds, GstValue key, GstValue *out) { | ||||
|         ret.type = GST_NUMBER; | ||||
|         ret.data.number = ds.data.string[index]; | ||||
|         break; | ||||
|     case GST_STRUCT: | ||||
|         ret = gst_struct_get(ds.data.st, key); | ||||
|         break; | ||||
|     case GST_OBJECT: | ||||
|         ret = gst_object_get(ds.data.object, key); | ||||
|         break; | ||||
| @@ -346,7 +320,7 @@ int gst_length(Gst *vm, GstValue x, GstValue *len) { | ||||
|     uint32_t length; | ||||
|     switch (x.type) { | ||||
|         default: | ||||
|             vm->ret = gst_load_cstring(vm, "cannot get length"); | ||||
|             vm->ret = gst_string_cv(vm, "cannot get length"); | ||||
|             return GST_RETURN_ERROR; | ||||
|         case GST_STRING: | ||||
|             length = gst_string_length(x.data.string); | ||||
| @@ -360,6 +334,9 @@ int gst_length(Gst *vm, GstValue x, GstValue *len) { | ||||
|         case GST_TUPLE: | ||||
|             length = gst_tuple_length(x.data.tuple); | ||||
|             break; | ||||
|         case GST_STRUCT: | ||||
|             length = gst_struct_length(x.data.st); | ||||
|             break; | ||||
|         case GST_OBJECT: | ||||
|             length = x.data.object->count; | ||||
|             break; | ||||
|   | ||||
							
								
								
									
										29
									
								
								core/vm.c
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								core/vm.c
									
									
									
									
									
								
							| @@ -1,5 +1,4 @@ | ||||
| #include <gst/gst.h> | ||||
| #include "stringcache.h" | ||||
|  | ||||
| /* Macros for errors in the vm */ | ||||
|  | ||||
| @@ -7,7 +6,7 @@ | ||||
| #define gst_exit(vm, r) return ((vm)->ret = (r), GST_RETURN_OK) | ||||
|  | ||||
| /* Bail from the VM with an error string. */ | ||||
| #define gst_error(vm, e) do { (vm)->ret = gst_load_cstring((vm), (e)); goto vm_error; } while (0) | ||||
| #define gst_error(vm, e) do { (vm)->ret = gst_string_cv((vm), (e)); goto vm_error; } while (0) | ||||
|  | ||||
| /* Crash. Not catchable, unlike error. */ | ||||
| #define gst_crash(vm, e) return ((vm)->crash = (e), GST_RETURN_CRASH) | ||||
| @@ -229,8 +228,9 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) { | ||||
|                 offset = isTCall ? 3 : 4; | ||||
|                 arity = pc[offset - 1]; | ||||
|                 /* Push new frame */ | ||||
|                 if (temp.type != GST_FUNCTION && temp.type != GST_CFUNCTION) | ||||
|                     gst_error(vm, GST_EXPECTED_FUNCTION); | ||||
|                 stack = gst_thread_beginframe(vm, &thread, temp, arity); | ||||
|                 if (stack == NULL) gst_error(vm, "expected function"); | ||||
|                 oldStack = stack - GST_FRAME_SIZE - gst_frame_prevsize(stack); | ||||
|                 /* Write arguments */ | ||||
|                 size = gst_frame_size(stack); | ||||
| @@ -389,11 +389,11 @@ static int gst_continue_size(Gst *vm, uint32_t stackBase) { | ||||
|             { | ||||
|                 uint32_t i; | ||||
|                 uint32_t len = pc[2]; | ||||
|                 GstValue *tuple = gst_tuple(vm, len); | ||||
|                 GstValue *tuple = gst_tuple_begin(vm, len); | ||||
|                 for (i = 0; i < len; ++i) | ||||
|                     tuple[i] = stack[pc[3 + i]]; | ||||
|                 temp.type = GST_TUPLE; | ||||
|                 temp.data.tuple = tuple; | ||||
|                 temp.data.tuple = gst_tuple_end(vm, tuple); | ||||
|                 stack[pc[1]] = temp; | ||||
|                 pc += 3 + len; | ||||
|             } | ||||
| @@ -504,10 +504,16 @@ void gst_init(Gst *vm) { | ||||
|     vm->black = 0; | ||||
|     /* Add thread */ | ||||
|     vm->thread = NULL; | ||||
|     /* Set up string cache */ | ||||
|     gst_stringcache_init(vm, 128); | ||||
|     /* Set up global env */ | ||||
|     vm->rootenv = NULL; | ||||
|     /* Set up scratch memory */ | ||||
|     vm->scratch = NULL; | ||||
|     vm->scratch_len = 0; | ||||
|     /* Set up the cache */ | ||||
|     vm->cache = gst_raw_calloc(1, 128 * sizeof(GstValue)); | ||||
|     vm->cache_capacity = vm->cache == NULL ? 0 : 128; | ||||
|     vm->cache_count = 0; | ||||
|     vm->cache_deleted = 0; | ||||
| } | ||||
|  | ||||
| /* Clear all memory associated with the VM */ | ||||
| @@ -516,5 +522,12 @@ void gst_deinit(Gst *vm) { | ||||
|     vm->thread = NULL; | ||||
|     vm->rootenv = NULL; | ||||
|     vm->ret.type = GST_NIL; | ||||
|     gst_stringcache_deinit(vm); | ||||
|     vm->scratch = NULL; | ||||
|     vm->scratch_len = 0; | ||||
|     /* Deinit the cache */ | ||||
|     gst_raw_free(vm->cache); | ||||
|     vm->cache = NULL; | ||||
|     vm->cache_count = 0; | ||||
|     vm->cache_capacity = 0; | ||||
|     vm->cache_deleted = 0; | ||||
| } | ||||
|   | ||||
| @@ -16,7 +16,7 @@ | ||||
| /* Struct utils */ | ||||
| #define gst_struct_raw(t) ((uint32_t *)(t) - 2) | ||||
| #define gst_struct_length(t) (gst_struct_raw(t)[0]) | ||||
| #define gst_struct_capacity(t) (gst_struct_length(t) * 3) | ||||
| #define gst_struct_capacity(t) (gst_struct_length(t) * 4) | ||||
| #define gst_struct_hash(t) (gst_struct_raw(t)[1]) | ||||
|  | ||||
| /* Memcpy for moving memory */ | ||||
| @@ -78,7 +78,7 @@ | ||||
| #define gst_c_throw(vm, e) do { (vm)->ret = (e); return GST_RETURN_ERROR; } while (0) | ||||
|  | ||||
| /* Throw c string error from a c function */ | ||||
| #define gst_c_throwc(vm, e) gst_c_throw((vm), gst_load_cstring((vm), (e))) | ||||
| #define gst_c_throwc(vm, e) gst_c_throw((vm), gst_string_cv((vm), (e))) | ||||
|  | ||||
| /* Assert from a c function */ | ||||
| #define gst_c_assert(vm, cond, e) do {if (cond) gst_c_throw((vm), (e)); } while (0) | ||||
| @@ -101,6 +101,7 @@ typedef enum GstType { | ||||
|     GST_STRING, | ||||
|     GST_ARRAY, | ||||
|     GST_TUPLE, | ||||
|     GST_STRUCT, | ||||
|     GST_THREAD, | ||||
|     GST_BYTEBUFFER, | ||||
|     GST_FUNCTION, | ||||
| @@ -153,12 +154,12 @@ union GstValueUnion { | ||||
|     GstBuffer *buffer; | ||||
|     GstObject *object; | ||||
|     GstThread *thread; | ||||
|     GstValue *tuple; | ||||
|     const GstValue *tuple; | ||||
|     GstCFunction cfunction; | ||||
|     GstFunction *function; | ||||
|     GstFuncEnv *env; | ||||
|     GstFuncDef *def; | ||||
|     GstValue *st; | ||||
|     const GstValue *st; | ||||
|     const uint8_t *string; | ||||
|     const char *cstring; /* Alias for ease of use from c */ | ||||
|     /* Indirectly used union members */ | ||||
| @@ -264,11 +265,14 @@ struct Gst { | ||||
|     uint32_t memoryInterval; | ||||
|     uint32_t nextCollection; | ||||
|     uint32_t black : 1; | ||||
|     /* String cache */ | ||||
|     const uint8_t **strings; | ||||
|     uint32_t stringsCapacity; | ||||
|     uint32_t stringsCount; | ||||
|     uint32_t stringsDeleted; | ||||
|     /* Immutable value cache */ | ||||
|     GstValue *cache; | ||||
|     uint32_t cache_capacity; | ||||
|     uint32_t cache_count; | ||||
|     uint32_t cache_deleted; | ||||
|     /* Scratch memory */ | ||||
|     char *scratch; | ||||
|     uint32_t scratch_len; | ||||
|     /* Thread */ | ||||
|     GstThread *thread; | ||||
|     /* A GC root */ | ||||
| @@ -345,11 +349,18 @@ void gst_array_ensure(Gst *vm, GstArray *array, uint32_t capacity); | ||||
| void gst_array_push(Gst *vm, GstArray *array, GstValue x); | ||||
| GstValue gst_array_pop(GstArray *array); | ||||
|  | ||||
| /****/ | ||||
| /* Userdata functions */ | ||||
| /****/ | ||||
|  | ||||
| void *gst_userdata(Gst *vm, uint32_t size, GstObject *meta); | ||||
|  | ||||
| /****/ | ||||
| /* Tuple functions */ | ||||
| /****/ | ||||
|  | ||||
| GstValue *gst_tuple(Gst *vm, uint32_t length); | ||||
| GstValue *gst_tuple_begin(Gst *vm, uint32_t length); | ||||
| const GstValue *gst_tuple_end(Gst *vm, GstValue *tuple); | ||||
|  | ||||
| /****/ | ||||
| /* String functions */ | ||||
| @@ -357,16 +368,19 @@ GstValue *gst_tuple(Gst *vm, uint32_t length); | ||||
|  | ||||
| uint8_t *gst_string_begin(Gst *vm, uint32_t len); | ||||
| const uint8_t *gst_string_end(Gst *vm, uint8_t *str); | ||||
| const uint8_t *gst_string_loadbuffer(Gst *vm, const uint8_t *buf, uint32_t len); | ||||
| const uint8_t *gst_cstring_to_string(Gst *vm, const char *cstring); | ||||
| GstValue gst_load_cstring(Gst *vm, const char *string); | ||||
| const uint8_t *gst_string_b(Gst *vm, const uint8_t *buf, uint32_t len); | ||||
| const uint8_t *gst_string_c(Gst *vm, const char *cstring); | ||||
| GstValue gst_string_cv(Gst *vm, const char *string); | ||||
| int gst_string_compare(const uint8_t *lhs, const uint8_t *rhs); | ||||
|  | ||||
| /****/ | ||||
| /* Userdata functions */ | ||||
| /* Struct functions */ | ||||
| /****/ | ||||
|  | ||||
| void *gst_userdata(Gst *vm, uint32_t size, GstObject *meta); | ||||
| GstValue *gst_struct_begin(Gst *vm, uint32_t count); | ||||
| void gst_struct_put(GstValue *st, GstValue key, GstValue value); | ||||
| const GstValue *gst_struct_end(Gst *vm, GstValue *st); | ||||
| GstValue gst_struct_get(const GstValue *st, GstValue key); | ||||
|  | ||||
| /****/ | ||||
| /* Object functions */ | ||||
| @@ -453,6 +467,8 @@ const char *gst_serialize(Gst *vm, GstBuffer *buffer, GstValue x); | ||||
| /****/ | ||||
|  | ||||
| #define GST_MEMTAG_STRING 4 | ||||
| #define GST_MEMTAG_TUPLE 8 | ||||
| #define GST_MEMTAG_STRUCT 16 | ||||
|  | ||||
| void gst_mark_value(Gst *vm, GstValue x); | ||||
| void gst_mark(Gst *vm, GstValueUnion x, GstType type); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose