From: cassowarii <2374677+cassowarii@users.noreply.github.com> Date: Sat, 18 Jul 2026 23:59:20 +0000 (-0700) Subject: split concept of variables vs values. compiler not working yet though X-Git-Url: https://www.git.cassowary.me/gitweb.cgi?a=commitdiff_plain;h=e4fb28073c5601856d7ee3372cdbdb4cd47cfe54;p=sarabande.git split concept of variables vs values. compiler not working yet though --- diff --git a/src/data/closure.c b/src/data/closure.c index 2603382..4029d9b 100644 --- a/src/data/closure.c +++ b/src/data/closure.c @@ -15,8 +15,8 @@ typedef struct sbClosure { GCINFO info; usize num_vars; union { - hRef internal_vars[INLINE_VAR_COUNT]; - hRef *external_vars; + sbVar internal_vars[INLINE_VAR_COUNT]; + sbVar *external_vars; }; } sbClosure; @@ -35,49 +35,46 @@ hClosure sbClosure_create(usize num_vars) { sbClosure *c = sbPool_alloc(&g_closure_pool, &index); c->num_vars = num_vars; if (num_vars > INLINE_VAR_COUNT) { - c->external_vars = calloc(num_vars, sizeof(hRef)); + c->external_vars = calloc(num_vars, sizeof(sbVar)); } return index | FLAG_REAL; } /* set the variable in the closure behind the pointer */ -void sbClosure_set_var(hClosure which, usize index, hVal *what) { +void sbClosure_set_value(hClosure which, usize index, hVal *what) { sbClosure *c = find_closure_by_handle(which); if (c->num_vars <= INLINE_VAR_COUNT) { - sbRef_set_ref(c->internal_vars[index], what); + sbVar_set_value(&c->internal_vars[index], what); } else { - sbRef_set_ref(c->external_vars[index], what); + sbVar_set_value(&c->external_vars[index], what); } } /* set the pointer itself */ -void sbClosure_set_ref(hClosure which, usize index, hVal *what) { - if (what->type != IT_REF) { - PANIC("must pass an indirect variable to be the subject of a closure"); - } +void sbClosure_set_var(hClosure which, usize index, hVar what) { sbClosure *c = find_closure_by_handle(which); if (c->num_vars <= INLINE_VAR_COUNT) { - c->internal_vars[index] = what->ref; + c->internal_vars[index] = sbVar_retain(what); } else { - c->external_vars[index] = what->ref; + c->external_vars[index] = sbVar_retain(what); } } -hVal *sbClosure_get_var(hClosure which, usize index) { +hVal sbClosure_get_value(hClosure which, usize index) { sbClosure *c = find_closure_by_handle(which); if (c->num_vars <= INLINE_VAR_COUNT) { - return sbRef_deref(c->internal_vars[index]); + return sbVar_get_value(&c->internal_vars[index]); } else { - return sbRef_deref(c->external_vars[index]); + return sbVar_get_value(&c->external_vars[index]); } } -hVal sbClosure_get_ref(hClosure which, usize index) { +hVar sbClosure_get_var(hClosure which, usize index) { sbClosure *c = find_closure_by_handle(which); if (c->num_vars <= INLINE_VAR_COUNT) { - return HVREF(c->internal_vars[index]); + return &c->internal_vars[index]; } else { - return HVREF(c->external_vars[index]); + return &c->external_vars[index]; } } diff --git a/src/data/closure.h b/src/data/closure.h index 1bdc995..1acfb8d 100644 --- a/src/data/closure.h +++ b/src/data/closure.h @@ -6,10 +6,10 @@ void sbClosure_sys_deinit(); hClosure sbClosure_create(usize num_vars); -void sbClosure_set_var(hClosure which, usize index, hVal *var); +void sbClosure_set_value(hClosure which, usize index, hVal *var); -void sbClosure_set_ref(hClosure which, usize index, hVal *what); +void sbClosure_set_var(hClosure which, usize index, hVar what); -hVal *sbClosure_get_var(hClosure which, usize index); +hVal sbClosure_get_value(hClosure which, usize index); -hVal sbClosure_get_ref(hClosure which, usize index); +hVar sbClosure_get_var(hClosure which, usize index); diff --git a/src/data/data.h b/src/data/data.h index 9130b59..fce4350 100644 --- a/src/data/data.h +++ b/src/data/data.h @@ -2,6 +2,7 @@ #define __SARABANDE_DATA_H__ #include "data/value.h" +#include "data/variable.h" void data_sys_init(); diff --git a/src/data/hashtable.c b/src/data/hashtable.c index d89b2e5..602ddf1 100644 --- a/src/data/hashtable.c +++ b/src/data/hashtable.c @@ -18,23 +18,24 @@ typedef struct hashtbl { union { struct { hVal keys[INLINE_TABLE_LENGTH]; - hVal values[INLINE_TABLE_LENGTH]; + sbVar values[INLINE_TABLE_LENGTH]; } internal; struct { hVal *keys; - hVal *values; + sbVar *values; } external; }; } hashtbl; static hashtbl *new_tbl(usize initial_size); static hVal *get_key_ptr_for_tbl(hashtbl *t, usize *length_out); -static void get_ptrs_for_tbl(hashtbl *t, hVal **keys, hVal **values); +static void get_ptrs_for_tbl(hashtbl *t, hVal **keys, sbVar **values); static hashtbl *find_tbl_for_handle(hHash handle); static usize set_key(hashtbl *t, hVal *key, hVal *value); -static hVal delete_key(hashtbl *t, hVal *key); +static void delete_key(hashtbl *t, hVal *key); +static hVal delete_key_and_return(hashtbl *t, hVal *key); static void set_hashtbl_size(hashtbl *t, usize new_size, flag rehash_all); -static usize set_key_in_array(hVal *keys, hVal *values, usize length, hVal *key, hVal *value); +static usize set_key_for_rehash(hVal *keys, sbVar *values, usize length, hVal *key, sbVar *value); static usize find_index_by_key(hashtbl *t, hVal *key); void sbHash_sys_init() { @@ -88,19 +89,38 @@ void sbHash_insert(hHash h, hVal *key, hVal *value) { set_key(t, key, value); } -hVal *sbHash_find(hHash h, hVal *key) { +hVal sbHash_find_value(hHash h, hVal *key) { hashtbl *t = find_tbl_for_handle(h); usize index = find_index_by_key(t, key); - hVal *keys, *values; + hVal *keys; + sbVar *values; get_ptrs_for_tbl(t, &keys, &values); if (keys[index].type == IT_NOTHING) { - return NULL; + return HVNOTHING; } else { - return &values[index]; + return sbVar_get_value(&values[index]); } } -hVal *sbHash_find_or_insert(hHash h, hVal *key, hVal *value) { +hVal sbHash_find_lvalue_ref(hHash h, hVal *key) { + hashtbl *t = find_tbl_for_handle(h); + usize index = find_index_by_key(t, key); + hVal *keys; + sbVar *values; + get_ptrs_for_tbl(t, &keys, &values); + return sbVar_get_lvalue_ref(&values[index]); +} + +hVal sbHash_find_rvalue_ref(hHash h, hVal *key) { + hashtbl *t = find_tbl_for_handle(h); + usize index = find_index_by_key(t, key); + hVal *keys; + sbVar *values; + get_ptrs_for_tbl(t, &keys, &values); + return sbVar_get_rvalue_ref(&values[index]); +} + +/*hVal *sbHash_find_or_insert(hHash h, hVal *key, hVal *value) { hashtbl *t = find_tbl_for_handle(h); usize index = find_index_by_key(t, key); hVal *keys, *values; @@ -109,13 +129,18 @@ hVal *sbHash_find_or_insert(hHash h, hVal *key, hVal *value) { values[index] = *value; } return &values[index]; -} +}*/ -void sbHash_delete(hHash h, hVal *key, hVal *value) { +void sbHash_delete(hHash h, hVal *key) { hashtbl *t = find_tbl_for_handle(h); delete_key(t, key); } +hVal sbHash_delete_and_return(hHash h, hVal *key) { + hashtbl *t = find_tbl_for_handle(h); + return delete_key_and_return(t, key); +} + usize sbHash_get_size(hHash h) { hashtbl *t = find_tbl_for_handle(h); return t->n_elems; @@ -131,17 +156,14 @@ static void set_hashtbl_size(hashtbl *t, usize new_size, flag rehash_all) { t->is_inline = 1; } else { hVal *new_keys = calloc(new_size, sizeof(hVal)); - hVal *new_values = calloc(new_size, sizeof(hVal)); + sbVar *new_values = calloc(new_size, sizeof(sbVar)); if (rehash_all) { - hVal *current_keys, *current_values; + hVal *current_keys; + sbVar *current_values; get_ptrs_for_tbl(t, ¤t_keys, ¤t_values); for (usize i = 0; i < t->capacity; i++) { if (current_keys[i].type == IT_NOTHING || current_keys[i].type == ITX_TOMBSTONE) continue; - set_key_in_array(new_keys, new_values, new_size, ¤t_keys[i], ¤t_values[i]); - /* adding a new k/v pair will retain the values, so we need to release them - * from the previous allocation */ - sbV_release(¤t_keys[i]); - sbV_release(¤t_values[i]); + set_key_for_rehash(new_keys, new_values, new_size, ¤t_keys[i], ¤t_values[i]); } /* now that we've migrated all our things to the new version, we can free the old * version (unless it was not alloc'd to begin with) */ @@ -166,7 +188,7 @@ static hVal *get_key_ptr_for_tbl(hashtbl *t, usize *length_out) { } } -static void get_ptrs_for_tbl(hashtbl *t, hVal **keys, hVal **values) { +static void get_ptrs_for_tbl(hashtbl *t, hVal **keys, sbVar **values) { if (t->is_inline) { if (keys) *keys = t->internal.keys; if (values) *values = t->internal.values; @@ -195,7 +217,9 @@ static usize find_index_by_key(hashtbl *t, hVal *key) { return find_key_index_in_array(get_key_ptr_for_tbl(t, NULL), t->capacity, key); } -static usize set_key_in_array(hVal *keys, hVal *values, usize length, hVal *key, hVal *value) { +/* NOTE: This is used for rehashing, so it doesn't update reference counts on values. + * Use set_key for actually retaining refcounts properly. */ +static usize set_key_for_rehash(hVal *keys, sbVar *values, usize length, hVal *key, sbVar *value) { usize index = find_key_index_in_array(keys, length, key); /* now, we either found the current entry for this key, @@ -203,24 +227,19 @@ static usize set_key_in_array(hVal *keys, hVal *values, usize length, hVal *key, if (keys[index].type == IT_NOTHING) { /* key was not here before, so we need to retain the key * as well so it doesn't change out from under us */ - sbV_retain(key); keys[index] = *key; + values[index] = *value; + return index; } else { - /* replacing something that already exists. we can keep - * the key the same, but need to release the previous value. */ - sbV_release(&values[index]); + PANIC("Duplicate key found while rehashing hash table somehow!"); } - - sbV_retain(value); - values[index] = *value; - - return index; } static usize set_key(hashtbl *t, hVal *key, hVal *value) { usize index = find_index_by_key(t, key); - hVal *keys, *values; + hVal *keys; + sbVar *values; get_ptrs_for_tbl(t, &keys, &values); /* now, we either found the current entry for this key, @@ -230,7 +249,6 @@ static usize set_key(hashtbl *t, hVal *key, hVal *value) { * as well so it doesn't change out from under us */ sbV_retain(key); keys[index] = *key; - values[index] = *value; t->used ++; t->n_elems ++; if (t->used >= t->capacity * 3 / 4) { @@ -239,20 +257,33 @@ static usize set_key(hashtbl *t, hVal *key, hVal *value) { } else { /* replacing something that already exists. we can keep * the key the same, but need to release the previous value. */ - sbV_release(&values[index]); + hVal to_replace = sbVar_get_value(&values[index]); + sbV_release(&to_replace); } sbV_retain(value); - values[index] = *value; + values[index] = (sbVar) { .value = *value }; return index; } -static hVal delete_key(hashtbl *t, hVal *key) { +static void delete_key(hashtbl *t, hVal *key) { usize index = find_index_by_key(t, key); - hVal *keys, *values; + hVal *keys; + sbVar *values; + get_ptrs_for_tbl(t, &keys, &values); + hVal to_delete = sbVar_get_value(&values[index]); + sbV_release(&to_delete); + keys[index].type = ITX_TOMBSTONE; + t->n_elems --; +} + +static hVal delete_key_and_return(hashtbl *t, hVal *key) { + usize index = find_index_by_key(t, key); + hVal *keys; + sbVar *values; get_ptrs_for_tbl(t, &keys, &values); - hVal to_return = values[index]; + hVal to_return = sbVar_get_value(&values[index]); keys[index].type = ITX_TOMBSTONE; t->n_elems --; return to_return; diff --git a/src/data/hashtable.h b/src/data/hashtable.h index e5dd026..f60f3bc 100644 --- a/src/data/hashtable.h +++ b/src/data/hashtable.h @@ -22,6 +22,8 @@ void sbHash_insert(hHash h, hVal *key, hVal *value); hVal *sbHash_find_or_insert(hHash h, hVal *key, hVal *value); -void sbHash_delete(hHash h, hVal *key, hVal *value); +void sbHash_delete(hHash h, hVal *key); + +hVal sbHash_delete_and_return(hHash h, hVal *key); usize sbHash_get_size(hHash h); diff --git a/src/data/list.c b/src/data/list.c index df67f67..79419e7 100644 --- a/src/data/list.c +++ b/src/data/list.c @@ -30,37 +30,50 @@ hList sbList_new(usize capacity) { usize index; sbList *l = sbPool_alloc(&g_list_pool, &index); if (capacity < 4) capacity = 4; - sbBuffer_initialize(&l->items, capacity * sizeof(hVal)); + sbBuffer_initialize(&l->items, capacity * sizeof(sbVar)); return index; } -hList sbList_of(usize length, hVal *items) { +hList sbList_of(usize length, hVar items) { usize index; usize capacity = length; sbList *l = sbPool_alloc(&g_list_pool, &index); if (capacity < 4) capacity = 4; - sbBuffer_initialize(&l->items, capacity * sizeof(hVal)); - sbBuffer_set_size(&l->items, length * sizeof(hVal)); - memcpy(l->items.data, items, length * sizeof(hVal)); + sbBuffer_initialize(&l->items, capacity * sizeof(sbVar)); + sbBuffer_set_size(&l->items, length * sizeof(sbVar)); + memcpy(l->items.data, items, length * sizeof(sbVar)); return index; } void sbList_append(hList list, hVal *item) { sbList *l = get_list_by_handle(list); sbV_retain(item); - sbBuffer_append(&l->items, item, sizeof(hVal)); + sbVar new_var = { .value = *item }; + sbBuffer_append(&l->items, &new_var, sizeof(sbVar)); } -hVal *sbList_get_value(hList list, usize *length) { +sbVar *sbList_get_value(hList list, usize *length) { sbList *l = get_list_by_handle(list); - if (length) *length = l->items.size / sizeof(hVal); - return (hVal*)l->items.data; + if (length) *length = l->items.size / sizeof(sbVar); + return (sbVar*)l->items.data; } -hVal *sbList_index(hList list, usize index) { +hVal sbList_index_value(hList list, usize index) { sbList *l = get_list_by_handle(list); - hVal *item = &((hVal*)l->items.data)[index]; - return item; + hVar item = &((sbVar*)l->items.data)[index]; + return sbVar_get_value(item); +} + +hVal sbList_index_lvalue_ref(hList list, usize index) { + sbList *l = get_list_by_handle(list); + hVar item = &((sbVar*)l->items.data)[index]; + return sbVar_get_lvalue_ref(item); +} + +hVal sbList_index_rvalue_ref(hList list, usize index) { + sbList *l = get_list_by_handle(list); + hVar item = &((sbVar*)l->items.data)[index]; + return sbVar_get_rvalue_ref(item); } /* --- */ diff --git a/src/data/list.h b/src/data/list.h index f3da532..cd6d446 100644 --- a/src/data/list.h +++ b/src/data/list.h @@ -6,12 +6,16 @@ void sbList_sys_deinit(); hList sbList_new(usize capacity); -hList sbList_of(usize length, hVal *items); +hList sbList_of(usize length, hVar items); void sbList_append(hList list, hVal *item); -hVal *sbList_get_value(hList list, usize *length); +sbVar *sbList_get_value(hList list, usize *length); -hVal *sbList_index(hList list, usize index); +hVal sbList_index_value(hList list, usize index); + +hVal sbList_index_lvalue_ref(hList list, usize index); + +hVal sbList_index_rvalue_ref(hList list, usize index); void sbList_method(hVm vm); diff --git a/src/data/value.c b/src/data/value.c index de404c7..12d2887 100644 --- a/src/data/value.c +++ b/src/data/value.c @@ -1,5 +1,6 @@ #include "data/value.h" +#include "data/variable.h" #include "data/string.h" #include "data/list.h" #include "data/hashtable.h" @@ -77,6 +78,9 @@ void sbV_retain(const hVal *a) { case IT_INTEGER: sbInteger_retain(a->string); break; + case ITX_HEAPVAR: + sbVar_retain(sbVar_deref(a)); + break; default: /* nothing */ break; @@ -91,6 +95,9 @@ void sbV_release(const hVal *a) { case IT_INTEGER: sbInteger_release(a->string); break; + case ITX_HEAPVAR: + sbVar_release(sbVar_deref(a)); + break; default: /* nothing */ break; diff --git a/src/data/value.h b/src/data/value.h index 6c1a277..d398b24 100644 --- a/src/data/value.h +++ b/src/data/value.h @@ -11,16 +11,17 @@ #define HVSYM(s) ((hVal) { .type = IT_SYMBOL, .symbol = s }) #define HVBOOL(b) ((hVal) { .type = IT_BOOLEAN, .boolean = b }) #define HVLIST(l) ((hVal) { .type = IT_LIST, .list = l }) -#define HVREF(r) ((hVal) { .type = IT_REF, .ref = r }) +#define HVREF(r) ((hVal) { .type = IT_REF, .ptrdata = r }) #define HVNIL ((hVal) { .type = IT_NIL }) #define HVNOTHING ((hVal) {0}) #define HVFUNC(i, c) ((hVal) { .type = i, .closure = c }) #define HVBUILTIN(b) ((hVal) { .type = IT_BUILTIN, .builtin = b }) -#define HVBOUNDMETHOD(m, t) ((hVal) { .type = m | IT_FLAG_BOUND_METHOD, .ref = t }) +#define HVBOUNDMETHOD(m) ((hVal) { .type = m | IT_FLAG_BOUND_METHOD }) #define HVMODULE(m) ((hVal) { .type = IT_MODULE, .module = m }) struct sbVm; struct sbLibTable; +struct sbVar; typedef u64 hHash; typedef u64 hString; @@ -46,9 +47,10 @@ enum intrinsic_type { IT_BUILTIN = -11, // c function IT_MODULE = -12, // builtin module (math, op...) ITX_TOMBSTONE = -13, // + ITX_HEAPVAR = -14 // }; -typedef struct hVal { +typedef struct hval { i64 type; union { hString string; @@ -57,12 +59,12 @@ typedef struct hVal { hList list; hInteger integer; hClosure closure; - hRef ref; u64 boolean; double float_val; sbBuiltinFunc builtin; struct sbLibTable *module; u64 data; + void *ptrdata; }; } hVal; diff --git a/src/data/variable.c b/src/data/variable.c new file mode 100644 index 0000000..a5d793a --- /dev/null +++ b/src/data/variable.c @@ -0,0 +1,106 @@ +#include "common.h" + +#include "gc/gcinfo.h" + +#define VARS_PER_BLOCK 1024 + +typedef struct HeapVar { + GCINFO gcinfo; + hVal value; +} HeapVar; + +/* TODO argle bargle */ +sbPool g_heapvar_pool; + +HeapVar *new_heapvar(hVal *v); + +void sbVar_sys_init() { + sbPool_initialize(&g_heapvar_pool, sizeof(HeapVar), VARS_PER_BLOCK); +} + +hVal sbVar_get_value(hVar v) { + if (v->value.type == ITX_HEAPVAR) { + return ((HeapVar*)v->value.ptrdata)->value; + } else { + return v->value; + } +} + +hVal *sbVar_get_value_ptr(hVar v) { + if (v->value.type == ITX_HEAPVAR) { + return &((HeapVar*)v->value.ptrdata)->value; + } else { + return &v->value; + } +} + +void sbVar_set_value(hVar v, const hVal *new_value) { + /* release whatever was in the slot before */ + sbV_release(&v->value); + sbV_retain(new_value); + if (v->value.type == ITX_HEAPVAR) { + ((HeapVar*)v->value.ptrdata)->value = *new_value; + } else { + v->value = *new_value; + } +} + +/* for stuff like bound methods: we attach a pointer to a heap var to store + * what they're attached to, but don't bother allocating a full variable + * anywhere */ +void sbVar_set_attached_ref(hVal *attach_to, hVal *value) { + HeapVar *stored = new_heapvar(value); + attach_to->ptrdata = stored; +} + +hVal *sbVar_get_attached_ref(const hVal *attached_to) { + return &((HeapVar*)attached_to->ptrdata)->value; +} + +hVal sbVar_get_lvalue_ref(hVar v) { + return HVREF(v); +} + +void sbVar_move_to_heap(hVar v) { + HeapVar *new_entry = new_heapvar(&v->value); + v->value.type = ITX_HEAPVAR; + v->value.ptrdata = new_entry; +} + +hVar sbVar_deref(const hVal *v) { + if (v->type != IT_REF) { + CHECK("Internal error: value is not a pointer to variable"); + } + + /* v is ref */ + return (hVar)v->ptrdata; +} + +sbVar sbVar_retain(hVar v) { + sbVar_move_to_heap(v); + ((HeapVar*)v->value.ptrdata)->gcinfo.refcount ++; + return *v; +} + +void sbVar_release(hVar v) { + if (v->value.type == ITX_HEAPVAR) { + ((HeapVar*)v->value.ptrdata)->gcinfo.refcount --; + } +} + +hVal sbVar_get_rvalue_ref(hVar v) { + if (v->value.type != ITX_HEAPVAR) { + sbVar_move_to_heap(v); + } + + return HVREF(v); +} + +/* --- */ + +HeapVar *new_heapvar(hVal *v) { + HeapVar *new_entry = sbPool_alloc(&g_heapvar_pool, NULL); + new_entry->gcinfo.refcount = 1; + new_entry->value = *v; + return new_entry; +} diff --git a/src/data/variable.h b/src/data/variable.h new file mode 100644 index 0000000..2fab14d --- /dev/null +++ b/src/data/variable.h @@ -0,0 +1,32 @@ +#ifndef __SARABANDE_VARIABLE_H__ +#define __SARABANDE_VARIABLE_H__ + +typedef struct sbVar { + hVal value; +} sbVar; + +typedef sbVar *hVar; + +hVal sbVar_get_value(hVar v); + +hVal *sbVar_get_value_ptr(hVar v); + +void sbVar_set_value(hVar v, const hVal *value); + +hVal sbVar_get_lvalue_ref(hVar v); + +hVal sbVar_get_rvalue_ref(hVar v); + +void sbVar_set_attached_ref(hVal *attach_to, hVal *value); + +hVal *sbVar_get_attached_ref(const hVal *attached_to); + +void sbVar_move_to_heap(hVar v); + +hVar sbVar_deref(const hVal *v); + +sbVar sbVar_retain(hVar v); + +void sbVar_release(hVar v); + +#endif diff --git a/src/lib/lib.c b/src/lib/lib.c index 58a71e7..4fc543d 100644 --- a/src/lib/lib.c +++ b/src/lib/lib.c @@ -136,8 +136,9 @@ void sbLib_resolve_property(hVm vm) { } else { /* it is a method, but it is being called without parameters. * annoyingly, we need to construct a bound version of this method. */ - hRef ref = sbRef_create(target); - sbVm_push_immediate(vm, &HVBOUNDMETHOD(method_name_val->symbol, ref)); + hVal bound_symbol = HVBOUNDMETHOD(method_name_val->symbol); + sbVar_set_attached_ref(&bound_symbol, target); + sbVm_push_immediate(vm, &bound_symbol); } } else { PANIC("invalid method name for type %lld: %s", (long long)target->type, sbSymbol_name(method_name_val->symbol)); diff --git a/src/lib/method/list.c b/src/lib/method/list.c index b252a22..db3eb42 100644 --- a/src/lib/method/list.c +++ b/src/lib/method/list.c @@ -30,10 +30,10 @@ static void push(hVm vm, hVal *list, usize num_params) { static void reverse(hVm vm, hVal *list, usize num_params) { /* TODO maybe mutate in place if no other refs */ usize length; - hVal *elems = sbList_get_value(list->list, &length); + sbVar *elems = sbList_get_value(list->list, &length); hList new_list = sbList_new(length); for (usize i = length - 1; ; i--) { - sbList_append(new_list, &elems[i]); + sbList_append(new_list, sbVar_get_value_ptr(&elems[i])); if (i == 0) break; } sbList_get_value(new_list, &length); @@ -52,13 +52,14 @@ static void join(hVm vm, hVal *list, usize num_params) { delimiter = delimiter_v->string; } usize length; - hVal *elems = sbList_get_value(list->list, &length); + sbVar *elems = sbList_get_value(list->list, &length); hString joined = sbString_new("", 0); for (usize i = 0; i < length; i++) { - if (elems[i].type != IT_STRING) { + hVal *v = sbVar_get_value_ptr(&elems[i]); + if (v->type != IT_STRING) { PANIC("need string to join"); } - joined = sbString_concat(joined, elems[i].string); + joined = sbString_concat(joined, v->string); if (join_with && i < length - 1) { joined = sbString_concat(joined, delimiter); } @@ -119,21 +120,21 @@ sbCFuncStatus list_each_cfunc(hVm vm, flag init) { hVal *iterating_list = sbVm_pop(vm); hVal *loop_func = sbVm_pop(vm); hVal index = HVINT(0); - vm->fp->locals[0] = *iterating_list; - vm->fp->locals[1] = index; - vm->fp->locals[2] = *loop_func; + vm->fp->locals[0].value = *iterating_list; + vm->fp->locals[1].value = index; + vm->fp->locals[2].value = *loop_func; } else { /* loop func must have finished, so remove its result */ sbVm_pop(vm); } - usize current_index = vm->fp->locals[1].integer++; + usize current_index = vm->fp->locals[1].value.integer++; usize length; - hVal *iter_values = sbList_get_value(vm->fp->locals[0].list, &length); + sbVar *iter_values = sbList_get_value(vm->fp->locals[0].value.list, &length); if (current_index < length) { - sbVm_push(vm, &iter_values[current_index]); + sbVm_push(vm, sbVar_get_value_ptr(&iter_values[current_index])); sbVm_push_immediate(vm, &HVINT(1)); - sbVm_call_func(vm, &vm->fp->locals[2]); + sbVm_call_func(vm, sbVar_get_value_ptr(&vm->fp->locals[2])); return CFUNC_NEXT; } else { /* if index was past the end, callback function won't be called, and we'll exit. return nil */ @@ -150,30 +151,29 @@ sbCFuncStatus list_map_cfunc(hVm vm, flag init) { hVal *map_func = sbVm_pop(vm); usize length; sbList_get_value(iterating_list->list, &length); - hVal index = HVINT(0); hVal result = sbV_empty_list(length); - vm->fp->locals[0] = *iterating_list; - vm->fp->locals[1] = index; - vm->fp->locals[2] = *map_func; - vm->fp->locals[3] = result; + vm->fp->locals[0].value = *iterating_list; + vm->fp->locals[1].value = HVINT(0); + vm->fp->locals[2].value = *map_func; + vm->fp->locals[3].value = result; } else { /* get result of map function and append its result to result list */ hVal *mapped = sbVm_pop(vm); - sbList_append(vm->fp->locals[3].list, mapped); + sbList_append(vm->fp->locals[3].value.list, mapped); } - usize current_index = vm->fp->locals[1].integer++; + usize current_index = vm->fp->locals[1].value.integer++; usize length; - hVal *iter_values = sbList_get_value(vm->fp->locals[0].list, &length); + sbVar *iter_values = sbList_get_value(vm->fp->locals[0].value.list, &length); if (current_index < length) { - sbVm_push(vm, &iter_values[current_index]); + sbVm_push(vm, sbVar_get_value_ptr(&iter_values[current_index])); sbVm_push_immediate(vm, &HVINT(1)); - sbVm_call_func(vm, &vm->fp->locals[2]); + sbVm_call_func(vm, &vm->fp->locals[2].value); return CFUNC_NEXT; } else { /* return result list */ - sbVm_push_immediate(vm, &vm->fp->locals[3]); + sbVm_push_immediate(vm, &vm->fp->locals[3].value); return CFUNC_END; } } @@ -189,32 +189,32 @@ sbCFuncStatus list_filter_cfunc(hVm vm, flag init) { hVal index = HVINT(0); hVal result = sbV_empty_list(length); - vm->fp->locals[0] = *iterating_list; - vm->fp->locals[1] = index; - vm->fp->locals[2] = *filter_func; - vm->fp->locals[3] = result; + vm->fp->locals[0].value = *iterating_list; + vm->fp->locals[1].value = index; + vm->fp->locals[2].value = *filter_func; + vm->fp->locals[3].value = result; } else { /* get result of filter function and append element to result if true */ hVal *mapped = sbVm_pop(vm); hVal *element = sbVm_pop(vm); if (!sbV_c_falsy(mapped)) { - sbList_append(vm->fp->locals[3].list, element); + sbList_append(vm->fp->locals[3].value.list, element); } } - usize current_index = vm->fp->locals[1].integer++; + usize current_index = vm->fp->locals[1].value.integer++; usize length; - hVal *iter_values = sbList_get_value(vm->fp->locals[0].list, &length); + sbVar *iter_values = sbList_get_value(vm->fp->locals[0].value.list, &length); if (current_index < length) { /* put current value on stack twice: once as parameter for function, once to save for ourselves */ - sbVm_push(vm, &iter_values[current_index]); - sbVm_push(vm, &iter_values[current_index]); + sbVm_push(vm, sbVar_get_value_ptr(&iter_values[current_index])); + sbVm_push(vm, sbVar_get_value_ptr(&iter_values[current_index])); sbVm_push_immediate(vm, &HVINT(1)); - sbVm_call_func(vm, &vm->fp->locals[2]); + sbVm_call_func(vm, &vm->fp->locals[2].value); return CFUNC_NEXT; } else { /* return result list */ - sbVm_push_immediate(vm, &vm->fp->locals[3]); + sbVm_push_immediate(vm, &vm->fp->locals[3].value); return CFUNC_END; } } @@ -230,29 +230,29 @@ sbCFuncStatus list_reduce_cfunc(hVm vm, flag init) { sbList_get_value(iterating_list->list, &length); hVal index = HVINT(0); - vm->fp->locals[0] = *iterating_list; - vm->fp->locals[1] = index; - vm->fp->locals[2] = *reduce_func; - vm->fp->locals[3] = *result; + vm->fp->locals[0].value = *iterating_list; + vm->fp->locals[1].value = index; + vm->fp->locals[2].value = *reduce_func; + vm->fp->locals[3].value = *result; } else { /* get result of reduce function */ hVal *result = sbVm_pop(vm); - vm->fp->locals[3] = *result; + vm->fp->locals[3].value = *result; } - usize current_index = vm->fp->locals[1].integer++; + usize current_index = vm->fp->locals[1].value.integer++; usize length; - hVal *iter_values = sbList_get_value(vm->fp->locals[0].list, &length); + sbVar *iter_values = sbList_get_value(vm->fp->locals[0].value.list, &length); if (current_index < length) { /* put current result and new value on stack, then call callback function */ - sbVm_push(vm, &vm->fp->locals[3]); - sbVm_push(vm, &iter_values[current_index]); + sbVm_push(vm, &vm->fp->locals[3].value); + sbVm_push(vm, sbVar_get_value_ptr(&iter_values[current_index])); sbVm_push_immediate(vm, &HVINT(2)); - sbVm_call_func(vm, &vm->fp->locals[2]); + sbVm_call_func(vm, &vm->fp->locals[2].value); return CFUNC_NEXT; } else { /* return result */ - sbVm_push_immediate(vm, &vm->fp->locals[3]); + sbVm_push_immediate(vm, &vm->fp->locals[3].value); return CFUNC_END; } } @@ -265,9 +265,9 @@ sbCFuncStatus list_any_cfunc(hVm vm, flag init) { hVal *pred_func = sbVm_pop(vm); hVal index = HVINT(0); - vm->fp->locals[0] = *iterating_list; - vm->fp->locals[1] = index; - vm->fp->locals[2] = *pred_func; + vm->fp->locals[0].value = *iterating_list; + vm->fp->locals[1].value = index; + vm->fp->locals[2].value = *pred_func; } else { /* get result of predicate function */ hVal *mapped = sbVm_pop(vm); @@ -279,14 +279,14 @@ sbCFuncStatus list_any_cfunc(hVm vm, flag init) { } /* haven't found any yet... */ - usize current_index = vm->fp->locals[1].integer++; + usize current_index = vm->fp->locals[1].value.integer++; usize length; - hVal *iter_values = sbList_get_value(vm->fp->locals[0].list, &length); + sbVar *iter_values = sbList_get_value(vm->fp->locals[0].value.list, &length); if (current_index < length) { /* try next element */ - sbVm_push(vm, &iter_values[current_index]); + sbVm_push(vm, sbVar_get_value_ptr(&iter_values[current_index])); sbVm_push_immediate(vm, &HVINT(1)); - sbVm_call_func(vm, &vm->fp->locals[2]); + sbVm_call_func(vm, &vm->fp->locals[2].value); return CFUNC_NEXT; } else { /* no result found */ @@ -303,9 +303,9 @@ sbCFuncStatus list_all_cfunc(hVm vm, flag init) { hVal *pred_func = sbVm_pop(vm); hVal index = HVINT(0); - vm->fp->locals[0] = *iterating_list; - vm->fp->locals[1] = index; - vm->fp->locals[2] = *pred_func; + vm->fp->locals[0].value = *iterating_list; + vm->fp->locals[1].value = index; + vm->fp->locals[2].value = *pred_func; } else { /* get result of predicate function */ hVal *mapped = sbVm_pop(vm); @@ -317,14 +317,14 @@ sbCFuncStatus list_all_cfunc(hVm vm, flag init) { } /* all true so far */ - usize current_index = vm->fp->locals[1].integer++; + usize current_index = vm->fp->locals[1].value.integer++; usize length; - hVal *iter_values = sbList_get_value(vm->fp->locals[0].list, &length); + sbVar *iter_values = sbList_get_value(vm->fp->locals[0].value.list, &length); if (current_index < length) { /* try next element */ - sbVm_push(vm, &iter_values[current_index]); + sbVm_push(vm, sbVar_get_value_ptr(&iter_values[current_index])); sbVm_push_immediate(vm, &HVINT(1)); - sbVm_call_func(vm, &vm->fp->locals[2]); + sbVm_call_func(vm, &vm->fp->locals[2].value); return CFUNC_NEXT; } else { /* all passed */ diff --git a/src/vm/bytecode.h b/src/vm/bytecode.h index b994d95..8bf019e 100644 --- a/src/vm/bytecode.h +++ b/src/vm/bytecode.h @@ -9,19 +9,17 @@ typedef enum sbOpcode { BC_LD_CONST, // push constants[index] to stack BC_LD_CTX, // look up key in context object and push result BC_LD_VAR, // push value onto stack from variable - BC_LD_REF, // push reference value onto stack from variable + BC_LD_LREF, // push lvalue reference onto stack from variable + BC_LD_RREF, // push rvalue reference onto stack from variable BC_LD_UPVAL, // push value onto stack from closure BC_LD_UPREF, // push pointer to closure value onto stack (to close over again) BC_LD_BLK, // push reference to function onto stack - BC_LD_IND, // push value behind pointer variable onto stack BC_LD_NIL, // push nil onto stack BC_LD_TRUE, // push true onto stack BC_LD_FALSE, // push false onto stack BC_ST_VAR, // pop value from stack into variable BC_ST_UPVAL, // pop value from stack into closure - BC_ST_IND, // pop and store as reference (closure/pointer construction) BC_ST_ARG, // decrement TOS and store NOS in variable - BC_ST_ARG_IND, // decrement TOS and store NOS in variable indirectly BC_POP, // pop value from stack BC_NPOP, // pop N values from stack given by top number BC_SWAP, // swap top two values on stack diff --git a/src/vm/exec.c b/src/vm/exec.c index 3ff238c..14df61f 100644 --- a/src/vm/exec.c +++ b/src/vm/exec.c @@ -23,13 +23,11 @@ void print_stack(hVm vm); void sbVm_initialize(hVm vm, usize stacksize, usize rstacksize, flag debugmode) { *vm = (sbVm) {0}; vm->vstack = malloc(stacksize); - vm->xstack = malloc(stacksize); vm->stacksize = stacksize; vm->rstack = malloc(rstacksize); vm->rstacksize = rstacksize; vm->vsp = vm->vstack; - vm->xsp = vm->xstack; vm->rsp = vm->rstack; vm->fp = (sbVmStackFrame*)vm->rstack; @@ -38,7 +36,6 @@ void sbVm_initialize(hVm vm, usize stacksize, usize rstacksize, flag debugmode) void sbVm_deinitialize(hVm vm) { free(vm->vstack); - free(vm->xstack); free(vm->rstack); *vm = (sbVm) {0}; } @@ -183,7 +180,6 @@ void call_bound_method(hVm vm, hVal *to_call) { /* bound method is just a symbol + a closure containing one variable */ hSymbol sym = (hSymbol)(to_call->type & ~IT_FLAG_BOUND_METHOD); - hRef ref = (to_call->ref); /* we should already have parameters, so we just need to line it back up * on the stack and call the method again */ @@ -193,7 +189,7 @@ void call_bound_method(hVm vm, hVal *to_call) { CHECK("bound method call should receive an integer arg count!"); } peek_stack(vm, 0)->integer ++; - push_stack(vm, sbRef_deref(ref)); + push_stack(vm, sbVar_get_attached_ref(to_call)); /* resolve method normally */ sbLib_resolve_method(vm); @@ -201,16 +197,9 @@ void call_bound_method(hVm vm, hVal *to_call) { void return_from_block(hVm vm) { for (usize i = 0; i < vm->fp->num_locals; i++) { - sbV_release(&vm->fp->locals[i]); + sbV_release(&vm->fp->locals[i].value); } - /* move thing that is being returned to the xstack: if we were - * originally returning a local variable, we don't want it to get - * overwritten by a subsequent function call (and if we were - * already returning an immediate value, it does nothing) */ - ((hVal*)(vm->xsp))[-1] = *((hVal**)(vm->vsp))[-1]; - ((hVal**)(vm->vsp))[-1] = &((hVal*)(vm->xsp))[-1]; - sbVmStackFrame *frame = (sbVmStackFrame*)vm->fp; if (frame->return_addr == NULL) { @@ -228,75 +217,40 @@ void debug_print_hv(const hVal *value) { } void store_local(hVm vm, usize local_index, const hVal *value) { - /* release whatever was in the slot before */ - sbV_release(&vm->fp->locals[local_index]); - sbV_retain(value); - vm->fp->locals[local_index] = *value; + sbVar_set_value(&vm->fp->locals[local_index], value); } void push_stack(hVm vm, hVal *value) { - *(hVal**)vm->vsp = value; + *(hVal*)vm->vsp = *value; vm->vsp += sizeof(hVal*); - vm->xsp += sizeof(hVal); } void push_stack_immediate(hVm vm, const hVal *value) { - /* save it on our own stack */ - *(hVal*)vm->xsp = *value; - *(hVal**)vm->vsp = (hVal*)vm->xsp; + *(hVal*)vm->vsp = *value; vm->vsp += sizeof(hVal*); - vm->xsp += sizeof(hVal); } hVal *pop_stack(hVm vm) { vm->vsp -= sizeof(hVal*); - vm->xsp -= sizeof(hVal); - return *(hVal**)vm->vsp; + return (hVal*)vm->vsp; } hVal *npop_stack(hVm vm, usize count) { vm->vsp -= count * sizeof(hVal*); - vm->xsp -= count * sizeof(hVal); - return *(hVal**)vm->vsp; + return (hVal*)vm->vsp; } void swap_stack_top(hVm vm) { - hVal **first_v = &((hVal**)vm->vsp)[-1]; - hVal **second_v = &((hVal**)vm->vsp)[-2]; - hVal *first_x = &((hVal*)vm->xsp)[-1]; - hVal *second_x = &((hVal*)vm->xsp)[-2]; - - /* if we're swapping things that are allocated on the x-stack, - * we have to swap their pointers as well so we don't accidentally - * overwrite what they're pointing to. but if they're pointing - * somewhere else, we don't care */ - - /* x2 x1 &v2 &v1 (might be &x2 &x1)*/ - - hVal xtmp = *second_x; - if (*first_v == first_x) { - /* x2a x1a &v2 &x1a */ - *second_x = *first_x; /* x1b x1a &v2 &x1a */ - *first_v = second_x; /* x1b x1a &v2 &x1b */ - } - - if (*second_v == second_x) { - /* x2a x1a &x2a &v1 */ - *first_x = xtmp; /* x2a x2b &x2a &v1 */ - *second_v = first_x; /* x2a x2b &x2b &v1 */ - } + hVal *first_v = &((hVal*)vm->vsp)[-1]; + hVal *second_v = &((hVal*)vm->vsp)[-2]; - hVal *vtmp = *first_v; /* x2 x1 &v2 &v1 */ - *first_v = *second_v; /* x2 x1 &v2 &v2 */ - *second_v = vtmp; /* x2 x1 &v1 &v2 */ + hVal tmp = *first_v; /* x2 x1 &v2 &v1 */ + *first_v = *second_v; /* x2 x1 &v2 &v2 */ + *second_v = tmp; /* x2 x1 &v1 &v2 */ } hVal *peek_stack(hVm vm, isize offset) { - return ((hVal**)(vm->vsp))[-offset - 1]; -} - -hVal *peek_xstack(hVm vm, isize offset) { - return &((hVal*)(vm->xsp))[-offset - 1]; + return &((hVal*)(vm->vsp))[-offset - 1]; } sbOpcode get_opcode(hVm vm) { @@ -373,6 +327,7 @@ void execute_instruction(hVm vm) { u64 param; usize count; hVal *v, *w, *x, res; + sbVar *vars; switch (op) { case BC_NOP: @@ -395,42 +350,33 @@ void execute_instruction(hVm vm) { break; case BC_LD_VAR: param = get_param(vm); - push_stack(vm, &vm->fp->locals[param]); + res = sbVar_get_value(&vm->fp->locals[param]); + push_stack(vm, &res); break; - case BC_LD_REF: + case BC_LD_LREF: param = get_param(vm); - w = &vm->fp->locals[param]; - if (w->type == IT_NOTHING) { - /* create new ref */ - store_local(vm, param, &HVREF(sbRef_create(&HVNIL))); - w = &vm->fp->locals[param]; - } - push_stack(vm, w); + res = sbVar_get_lvalue_ref(&vm->fp->locals[param]); + push_stack(vm, &res); + break; + case BC_LD_RREF: + param = get_param(vm); + res = sbVar_get_rvalue_ref(&vm->fp->locals[param]); + push_stack(vm, &res); break; case BC_LD_UPVAL: /* Hey, was there upval in there? */ param = get_param(vm); - v = sbClosure_get_var(vm->fp->block_func.closure, param); - push_stack(vm, v); + res = sbClosure_get_value(vm->fp->block_func.closure, param); + push_stack(vm, &res); break; case BC_LD_UPREF: param = get_param(vm); - res = sbClosure_get_ref(vm->fp->block_func.closure, param); - push_stack_immediate(vm, &res); + push_stack(vm, &HVREF(sbClosure_get_var(vm->fp->block_func.closure, param))); break; case BC_LD_BLK: param = get_param(vm); push_stack_immediate(vm, &HVFUNC(param, 0)); break; - case BC_LD_IND: - param = get_param(vm); - v = &vm->fp->locals[param]; - if (v->type != IT_REF) { - CHECK("indirect variables should be of type reference! (%lld)", (long long)v->type); - } - w = sbRef_deref(v->ref); - push_stack(vm, w); - break; case BC_LD_TRUE: push_stack_immediate(vm, &HVBOOL(1)); break; @@ -449,21 +395,7 @@ void execute_instruction(hVm vm) { case BC_ST_UPVAL: param = get_param(vm); v = pop_stack(vm); - sbClosure_set_var(vm->fp->block_func.closure, param, v); - break; - case BC_ST_IND: - param = get_param(vm); - v = &vm->fp->locals[param]; - w = peek_stack(vm, 0); - if (v->type == IT_NOTHING) { - hRef new_ref = sbRef_create(w); - store_local(vm, param, &HVREF(new_ref)); - } else if (v->type == IT_REF) { - sbRef_set_ref(v->ref, w); - } else { - CHECK("indirect variables should be of type reference! (%lld)", (long long)v->type); - } - pop_stack(vm); + sbClosure_set_value(vm->fp->block_func.closure, param, v); break; case BC_ST_ARG: param = get_param(vm); @@ -481,31 +413,6 @@ void execute_instruction(hVm vm) { push_stack_immediate(vm, v); } break; - case BC_ST_ARG_IND: - param = get_param(vm); - x = pop_stack(vm); /* argument count */ - if (x->type != IT_INTEGER) { - /* internal error! this should be generated correctly */ - CHECK("calling convention violation: number of args should be an integer"); - } - - v = &vm->fp->locals[param]; - w = peek_stack(vm, 0); /* argument value */ - if (v->type == IT_NOTHING) { - hRef new_ref = sbRef_create(w); - store_local(vm, param, &HVREF(new_ref)); - } else if (v->type == IT_REF) { - sbRef_set_ref(v->ref, w); - } else { - CHECK("indirect variables should be of type reference! (%lld)", (long long)v->type); - } - pop_stack(vm); - x->integer --; - if (x->integer > 0) { - /* if last integer, don't put the 0 count back on the stack */ - push_stack(vm, x); - } - break; case BC_POP: pop_stack(vm); break; @@ -684,7 +591,7 @@ void execute_instruction(hVm vm) { if (w->type != IT_REF) { CHECK("internal violation: closure should receive a set of reference variables (got %lld)", (long long)w->type); } - sbClosure_set_ref(c, param, w); + sbClosure_set_var(c, param, sbVar_deref(w)); pop_stack(vm); } v->closure = c; @@ -735,9 +642,9 @@ void execute_instruction(hVm vm) { /* internal error! this should be generated correctly */ CHECK("internal violation: LIST_SPILL should receive an integer on top of stack"); } - x = sbList_get_value(v->list, &count); + vars = sbList_get_value(v->list, &count); for (usize i = count - 1; ; i--) { - push_stack(vm, &x[i]); + push_stack(vm, &vars[i].value); if (i == 0) break; } res.integer += count; diff --git a/src/vm/exec.h b/src/vm/exec.h index b3b143e..86e8564 100644 --- a/src/vm/exec.h +++ b/src/vm/exec.h @@ -63,18 +63,16 @@ typedef struct sbVmStackFrame { sbRuntimeCFunc c_func; }; usize num_locals; - hVal locals[]; + sbVar locals[]; } sbVmStackFrame; typedef struct sbVm { u8 *vstack; /* for calculations */ - u8 *xstack; /* parallel to vstack, holds immediate values that are pointed to */ u8 *rstack; /* for locals and return addresses, like FORTH */ const u8 *ip; /* instruction pointer */ sbVmStackFrame *fp; /* frame pointer */ u8 *vsp; /* vstack pointer */ - u8 *xsp; /* xstack pointer */ u8 *rsp; /* rstack pointer */ usize stacksize; /* to detect overflow, save these */ diff --git a/src/vm/operations.c b/src/vm/operations.c index 7626a5c..d299bfe 100644 --- a/src/vm/operations.c +++ b/src/vm/operations.c @@ -127,13 +127,13 @@ hVal sbV_append(hVal *a, hVal *b) { } } -void sbV_index(hVm vm) { +void sbV_index_value(hVm vm) { hVal *a = sbVm_peek(vm, 1); hVal *b = sbVm_peek(vm, 0); if (a->type == IT_LIST && b->type == IT_INTEGER) { sbVm_npop(vm, 2); - hVal *result = sbList_index(a->list, b->integer); - sbVm_push(vm, result); + hVal result = sbList_index_value(a->list, b->integer); + sbVm_push(vm, &result); } else if (a->type == IT_MODULE && b->type == IT_SYMBOL) { sbVm_npop(vm, 2); hVal *result = sbLibTable_find_value(a->module, b->symbol); @@ -154,7 +154,7 @@ hVal sbV_rangeindex(hVal *a, hVal *b, hVal *c) { i64 min = sbInteger_get_value(b->integer); i64 max = sbInteger_get_value(c->integer); if (a->type == IT_LIST) { - hVal *elements = sbList_get_value(a->list, &length); + sbVar *elements = sbList_get_value(a->list, &length); if (min >= max || min >= length || max < 0) { /* backwards or out of range */ return sbV_empty_list(0);