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;
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];
}
}
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);
#define __SARABANDE_DATA_H__
#include "data/value.h"
+#include "data/variable.h"
void data_sys_init();
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() {
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;
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;
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) */
}
}
-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;
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,
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,
* 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) {
} 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;
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);
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);
}
/* --- */
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);
#include "data/value.h"
+#include "data/variable.h"
#include "data/string.h"
#include "data/list.h"
#include "data/hashtable.h"
case IT_INTEGER:
sbInteger_retain(a->string);
break;
+ case ITX_HEAPVAR:
+ sbVar_retain(sbVar_deref(a));
+ break;
default:
/* nothing */
break;
case IT_INTEGER:
sbInteger_release(a->string);
break;
+ case ITX_HEAPVAR:
+ sbVar_release(sbVar_deref(a));
+ break;
default:
/* nothing */
break;
#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;
IT_BUILTIN = -11, // c function
IT_MODULE = -12, // builtin module (math, op...)
ITX_TOMBSTONE = -13, // <hashtable_tombstone>
+ ITX_HEAPVAR = -14 // <hVar_moved_to_heap>
};
-typedef struct hVal {
+typedef struct hval {
i64 type;
union {
hString string;
hList list;
hInteger integer;
hClosure closure;
- hRef ref;
u64 boolean;
double float_val;
sbBuiltinFunc builtin;
struct sbLibTable *module;
u64 data;
+ void *ptrdata;
};
} hVal;
--- /dev/null
+#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;
+}
--- /dev/null
+#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
} 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));
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);
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);
}
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 */
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;
}
}
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;
}
}
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;
}
}
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);
}
/* 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 */
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);
}
/* 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 */
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
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;
void sbVm_deinitialize(hVm vm) {
free(vm->vstack);
- free(vm->xstack);
free(vm->rstack);
*vm = (sbVm) {0};
}
/* 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 */
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);
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) {
}
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) {
u64 param;
usize count;
hVal *v, *w, *x, res;
+ sbVar *vars;
switch (op) {
case BC_NOP:
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;
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);
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;
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;
/* 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;
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 */
}
}
-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);
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);