1
0
mirror of https://github.com/janet-lang/janet synced 2026-06-01 10:12:16 +00:00

More work on nanbox implementation.

This commit is contained in:
Calvin Rose
2017-11-29 15:17:56 -05:00
parent b568a6bc88
commit eceb6e5a77
16 changed files with 161 additions and 119 deletions
+3 -2
View File
@@ -60,12 +60,13 @@ void dst_array_ensure(DstArray *array, int32_t capacity) {
/* Set the count of an array. Extend with nil if needed. */
void dst_array_setcount(DstArray *array, int32_t count) {
if (count < 0)
return;
if (count > array->count) {
dst_array_ensure(array, count + 1);
dst_memempty(array->data + array->count, count - array->count);
}
if (count > 0)
array->count = count;
array->count = count;
}
/* Push a value to the top of the array */
+1 -1
View File
@@ -172,7 +172,7 @@ static void dst_mark_funcdef(DstFuncDef *def) {
for (i = 0; i < count; ++i) {
DstValue v = def->constants[i];
/* Funcdefs use nil literals to store other funcdefs */
if (v.type == DST_NIL) {
if (dst_checktype(v, DST_NIL)) {
dst_mark_funcdef((DstFuncDef *) dst_unwrap_pointer(v));
} else {
dst_mark(v);
+58 -59
View File
@@ -319,13 +319,14 @@ void dst_short_description_b(DstBuffer *buffer, DstValue x) {
}
}
/* Helper structure for stringifying deeply nested structures */
/* Helper structure for stringifying nested structures */
typedef struct DstPrinter DstPrinter;
struct DstPrinter {
DstBuffer buffer;
DstTable seen;
uint32_t flags;
int64_t next;
uint32_t state;
int32_t next;
int32_t indent;
int32_t indent_size;
int32_t token_line_limit;
@@ -399,7 +400,7 @@ static void dst_print_hashtable_inner(DstPrinter *p, const DstValue *data, int32
dst_buffer_push_u8(&p->buffer, '\n');
p->indent++;
for (i = 0; i < cap; i += 2) {
if (dst_checktype(data[i], DST_NIL)) {
if (!dst_checktype(data[i], DST_NIL)) {
dst_print_indent(p);
dst_description_helper(p, data[i]);
dst_buffer_push_u8(&p->buffer, ' ');
@@ -412,7 +413,7 @@ static void dst_print_hashtable_inner(DstPrinter *p, const DstValue *data, int32
} else {
int isfirst = 1;
for (i = 0; i < cap; i += 2) {
if (dst_checktype(data[i], DST_NIL)) {
if (!dst_checktype(data[i], DST_NIL)) {
if (isfirst)
isfirst = 0;
else
@@ -462,52 +463,57 @@ static void dst_print_seq_inner(DstPrinter *p, const DstValue *data, int32_t len
/* Static debug print helper */
static void dst_description_helper(DstPrinter *p, DstValue x) {
const char *open;
const char *close;
int32_t len, cap;
const DstValue *data;
DstValue check;
p->depth--;
DstValue check = dst_table_get(&p->seen, x);
switch (dst_type(x)) {
default:
if (p->flags & DST_PRINTFLAG_COLORIZE) {
dst_buffer_push_cstring(&p->buffer, dst_type_colors[dst_type(x)]);
dst_short_description_b(&p->buffer, x);
dst_buffer_push_cstring(&p->buffer, "\x1B[0m");
} else {
dst_short_description_b(&p->buffer, x);
}
p->depth++;
return;
case DST_STRUCT:
open = "{"; close = "}";
break;
case DST_TABLE:
open = "@{"; close = "}";
break;
case DST_TUPLE:
open = "("; close = ")";
break;
case DST_ARRAY:
open = "["; close = "]";
break;
}
if (!p->state) {
dst_table_init(&p->seen, 10);
p->state = 1;
}
check = dst_table_get(&p->seen, x);
if (dst_checktype(check, DST_INTEGER)) {
dst_buffer_push_cstring(&p->buffer, "<cycle ");
integer_to_string_b(&p->buffer, dst_unwrap_integer(check));
dst_buffer_push_cstring(&p->buffer, ">");
} else {
const char *open;
const char *close;
int32_t len, cap;
const DstValue *data;
switch (dst_type(x)) {
default:
if (p->flags & DST_PRINTFLAG_COLORIZE) {
dst_buffer_push_cstring(&p->buffer, dst_type_colors[dst_type(x)]);
dst_short_description_b(&p->buffer, x);
dst_buffer_push_cstring(&p->buffer, "\x1B[0m");
} else {
dst_short_description_b(&p->buffer, x);
}
p->depth++;
return;
case DST_STRUCT:
open = "{"; close = "}";
break;
case DST_TABLE:
open = "@{"; close = "}";
break;
case DST_TUPLE:
open = "("; close = ")";
break;
case DST_ARRAY:
open = "["; close = "]";
break;
}
dst_table_put(&p->seen, x, dst_wrap_integer(p->next++));
dst_buffer_push_cstring(&p->buffer, open);
if (p->depth == 0) {
dst_buffer_push_cstring(&p->buffer, "...");
} else if (dst_hashtable_view(x, &data, &len, &cap)) {
dst_print_hashtable_inner(p, data, len, cap);
} else if (dst_seq_view(x, &data, &len)) {
dst_print_seq_inner(p, data, len);
}
dst_buffer_push_cstring(&p->buffer, close);
return;
}
dst_table_put(&p->seen, x, dst_wrap_integer(p->next++));
dst_buffer_push_cstring(&p->buffer, open);
if (p->depth == 0) {
dst_buffer_push_cstring(&p->buffer, "...");
} else if (dst_hashtable_view(x, &data, &len, &cap)) {
dst_print_hashtable_inner(p, data, len, cap);
} else if (dst_seq_view(x, &data, &len)) {
dst_print_seq_inner(p, data, len);
}
dst_buffer_push_cstring(&p->buffer, close);
/* Remove from seen as we know that printing completes, we
* can print in multiple times and we know we are not recursing */
dst_table_remove(&p->seen, x);
@@ -530,16 +536,16 @@ const uint8_t *dst_description(DstValue x) {
const uint8_t *ret;
dst_printer_defaults(&printer);
printer.state = 0;
dst_buffer_init(&printer.buffer, 0);
dst_table_init(&printer.seen, 10);
/* Only print description up to a depth of 4 */
dst_description_helper(&printer, x);
ret = dst_string(printer.buffer.data, printer.buffer.count);
dst_buffer_deinit(&printer.buffer);
dst_table_deinit(&printer.seen);
if (printer.state)
dst_table_deinit(&printer.seen);
return ret;
}
@@ -564,6 +570,7 @@ const uint8_t *dst_formatc(const char *format, ...) {
const uint8_t *ret;
DstPrinter printer;
DstBuffer *bufp = &printer.buffer;
printer.state = 0;
/* Calculate length */
while (format[len]) len++;
@@ -607,13 +614,10 @@ const uint8_t *dst_formatc(const char *format, ...) {
case 'c':
dst_buffer_push_u8(bufp, va_arg(args, int64_t));
break;
case 'p':
case 'v':
{
dst_printer_defaults(&printer);
dst_table_init(&printer.seen, 10);
/* Only print description up to a depth of 4 */
dst_description_helper(&printer, va_arg(args, DstValue));
dst_table_deinit(&printer.seen);
break;
}
case 'q':
@@ -629,14 +633,7 @@ const uint8_t *dst_formatc(const char *format, ...) {
}
case 'V':
{
const uint8_t *str = dst_short_description(va_arg(args, DstValue));
dst_buffer_push_bytes(bufp, str, dst_string_length(str));
break;
}
case 'v':
{
const uint8_t *str = dst_description(va_arg(args, DstValue));
dst_buffer_push_bytes(bufp, str, dst_string_length(str));
dst_short_description_b(bufp, va_arg(args, DstValue));
break;
}
}
@@ -648,6 +645,8 @@ const uint8_t *dst_formatc(const char *format, ...) {
ret = dst_string(printer.buffer.data, printer.buffer.count);
dst_buffer_deinit(&printer.buffer);
if (printer.state)
dst_table_deinit(&printer.seen);
return ret;
}
+23 -20
View File
@@ -22,6 +22,8 @@
#include <dst/dst.h>
#define dst_struct_maphash(cap, hash) (((uint32_t)(hash) % (cap)) & 0xFFFFFFFE);
/* Begin creation of a struct */
DstValue *dst_struct_begin(int32_t count) {
/* This expression determines size of structs. It must be a pure
@@ -30,10 +32,11 @@ DstValue *dst_struct_begin(int32_t count) {
* sizeof(int32_t) * 2 + 2 * count * sizeof(DstValue). Adding more space
* ensures that structs are less likely to have hash collisions. If more space
* is added or s is changed, change the macro dst_struct_capacity in internal.h */
size_t s = sizeof(int32_t) * 2 + 4 * count * sizeof(DstValue);
int32_t capacity = 4 * count;
size_t s = sizeof(int32_t) * 2 + (capacity * sizeof(DstValue));
char *data = dst_alloc(DST_MEMORY_STRUCT, s);
memset(data, 0, s);
DstValue *st = (DstValue *) (data + 2 * sizeof(int32_t));
dst_memempty(st, capacity);
dst_struct_length(st) = count;
/* Use the hash storage space as a counter to see how many items
* were successfully added. If this number is not equal to the
@@ -46,13 +49,13 @@ DstValue *dst_struct_begin(int32_t count) {
/* Find an item in a struct */
static const DstValue *dst_struct_find(const DstValue *st, DstValue key) {
int32_t cap = dst_struct_capacity(st);
int32_t index = (dst_hash(key) % cap) & (~1);
int32_t index = dst_struct_maphash(cap, dst_hash(key));
int32_t i;
for (i = index; i < cap; i += 2)
if (st[i].type == DST_NIL || dst_equals(st[i], key))
if (dst_checktype(st[i], DST_NIL) || dst_equals(st[i], key))
return st + i;
for (i = 0; i < index; i += 2)
if (st[i].type == DST_NIL || dst_equals(st[i], key))
if (dst_checktype(st[i], DST_NIL) || dst_equals(st[i], key))
return st + i;
return NULL;
}
@@ -63,10 +66,10 @@ static const DstValue *dst_struct_find(const DstValue *st, DstValue key) {
void dst_struct_put(DstValue *st, DstValue key, DstValue value) {
int32_t cap = dst_struct_capacity(st);
int32_t hash = dst_hash(key);
int32_t index = (hash % cap) & (~1);
int32_t index = dst_struct_maphash(cap, hash);
int32_t i, j, dist;
int32_t bounds[4] = {index, cap, 0, index};
if (key.type == DST_NIL || value.type == DST_NIL) return;
if (dst_checktype(key, DST_NIL) || dst_checktype(value, DST_NIL)) return;
/* Avoid extra items */
if (dst_struct_hash(st) == dst_struct_length(st)) return;
for (dist = 0, j = 0; j < 4; j += 2)
@@ -75,7 +78,7 @@ void dst_struct_put(DstValue *st, DstValue key, DstValue value) {
int32_t otherhash;
int32_t otherindex, otherdist;
/* We found an empty slot, so just add key and value */
if (st[i].type == DST_NIL) {
if (dst_checktype(st[i], DST_NIL)) {
st[i] = key;
st[i + 1] = value;
/* Update the temporary count */
@@ -88,7 +91,7 @@ void dst_struct_put(DstValue *st, DstValue key, DstValue value) {
* with different order have the same internal layout, and therefor
* will compare properly - i.e., {1 2 3 4} should equal {3 4 1 2}. */
otherhash = dst_hash(st[i]);
otherindex = (otherhash % cap) & (~1);
otherindex = dst_struct_maphash(cap, otherhash);
otherdist = (i + cap - otherindex) % cap;
if (dist < otherdist)
status = -1;
@@ -131,27 +134,25 @@ const DstValue *dst_struct_end(DstValue *st) {
DstValue *newst;
realCount = 0;
for (i = 0; i < dst_struct_capacity(st); i += 2) {
realCount += st[i].type != DST_NIL;
realCount += dst_checktype(st[i], DST_NIL) ? 1 : 0;
}
newst = dst_struct_begin(realCount);
for (i = 0; i < dst_struct_capacity(st); i += 2) {
if (st[i].type != DST_NIL) {
if (!dst_checktype(st[i], DST_NIL)) {
dst_struct_put(newst, st[i], st[i + 1]);
}
}
st = newst;
}
dst_struct_hash(st) = 0;
dst_struct_hash(st) = dst_array_calchash(st, dst_struct_capacity(st));
return (const DstValue *)st;
}
/* Get an item from a struct */
DstValue dst_struct_get(const DstValue *st, DstValue key) {
const DstValue *bucket = dst_struct_find(st, key);
if (!bucket || bucket[0].type == DST_NIL) {
DstValue ret;
ret.type = DST_NIL;
return ret;
if (NULL == bucket || dst_checktype(*bucket, DST_NIL)) {
return dst_wrap_nil();
} else {
return bucket[1];
}
@@ -161,16 +162,16 @@ DstValue dst_struct_get(const DstValue *st, DstValue key) {
DstValue dst_struct_next(const DstValue *st, DstValue key) {
const DstValue *bucket, *end;
end = st + dst_struct_capacity(st);
if (key.type == DST_NIL) {
if (dst_checktype(key, DST_NIL)) {
bucket = st;
} else {
bucket = dst_struct_find(st, key);
if (!bucket || bucket[0].type == DST_NIL)
if (NULL == bucket || dst_checktype(*bucket, DST_NIL))
return dst_wrap_nil();
bucket += 2;
}
for (; bucket < end; bucket += 2) {
if (bucket[0].type != DST_NIL)
if (!dst_checktype(bucket[0], DST_NIL))
return bucket[0];
}
return dst_wrap_nil();
@@ -181,7 +182,7 @@ DstTable *dst_struct_to_table(const DstValue *st) {
DstTable *table = dst_table(dst_struct_capacity(st));
int32_t i;
for (i = 0; i < dst_struct_capacity(st); i += 2) {
if (st[i].type != DST_NIL) {
if (!dst_checktype(st[i], DST_NIL)) {
dst_table_put(table, st[i], st[i + 1]);
}
}
@@ -235,3 +236,5 @@ int dst_struct_compare(const DstValue *lhs, const DstValue *rhs) {
}
return 0;
}
#undef dst_struct_maphash
+5 -5
View File
@@ -64,13 +64,13 @@ static const uint8_t **dst_symcache_findmem(
int32_t len,
int32_t hash,
int *success) {
int32_t bounds[4];
int32_t i, j, index;
uint32_t bounds[4];
uint32_t i, j, index;
const uint8_t **firstEmpty = NULL;
/* We will search two ranges - index to the end,
* and 0 to the index. */
index = hash % dst_vm_cache_capacity;
index = (uint32_t)hash % dst_vm_cache_capacity;
bounds[0] = index;
bounds[1] = dst_vm_cache_capacity;
bounds[2] = 0;
@@ -110,8 +110,8 @@ static const uint8_t **dst_symcache_findmem(
dst_symcache_findmem((str), dst_string_length(str), dst_string_hash(str), (success))
/* Resize the cache. */
static void dst_cache_resize(int32_t newCapacity) {
int32_t i, oldCapacity;
static void dst_cache_resize(uint32_t newCapacity) {
uint32_t i, oldCapacity;
const uint8_t **oldCache = dst_vm_cache;
const uint8_t **newCache = calloc(1, newCapacity * sizeof(const uint8_t **));
if (newCache == NULL) {
+1 -1
View File
@@ -109,7 +109,7 @@ int dst_sys_get(DstValue *argv, int32_t argn) {
ds = argv[0];
for (i = 1; i < argn; i++) {
ds = dst_get(ds, argv[i]);
if (ds.type == DST_NIL)
if (dst_checktype(ds, DST_NIL))
break;
}
dst_vm_fiber->ret = ds;
+7 -3
View File
@@ -22,11 +22,13 @@
#include <dst/dst.h>
#define dst_table_maphash(cap, hash) (((uint32_t)(hash) % (cap)) & 0xFFFFFFFE)
/* Initialize a table */
DstTable *dst_table_init(DstTable *table, int32_t capacity) {
DstValue *data;
if (capacity < 2) capacity = 2;
data = calloc(sizeof(DstValue), capacity);
data = (DstValue *) dst_memalloc_empty(capacity);
if (NULL == data) {
DST_OUT_OF_MEMORY;
}
@@ -51,7 +53,7 @@ DstTable *dst_table(int32_t capacity) {
/* Find the bucket that contains the given key. Will also return
* bucket where key should go if not in the table. */
static DstValue *dst_table_find(DstTable *t, DstValue key) {
int32_t index = (dst_hash(key) % t->capacity) & (~1);
int32_t index = dst_table_maphash(t->capacity, dst_hash(key));
int32_t i, j;
int32_t start[2], end[2];
start[0] = index; end[0] = t->capacity;
@@ -74,7 +76,7 @@ static DstValue *dst_table_find(DstTable *t, DstValue key) {
/* Resize the dictionary table. */
static void dst_table_rehash(DstTable *t, int32_t size) {
DstValue *olddata = t->data;
DstValue *newdata = calloc(sizeof(DstValue), size);
DstValue *newdata = (DstValue *) dst_memalloc_empty(size);
if (NULL == newdata) {
DST_OUT_OF_MEMORY;
}
@@ -179,3 +181,5 @@ const DstValue *dst_table_to_struct(DstTable *t) {
}
return dst_struct_end(st);
}
#undef dst_table_maphash
+3 -3
View File
@@ -30,12 +30,12 @@ DstValue *dst_tuple_begin(int32_t length) {
char *data = dst_alloc(DST_MEMORY_TUPLE, 2 * sizeof(int32_t) + length * sizeof(DstValue));
DstValue *tuple = (DstValue *)(data + (2 * sizeof(int32_t)));
dst_tuple_length(tuple) = length;
dst_tuple_hash(tuple) = 0;
return tuple;
}
/* Finish building a tuple */
const DstValue *dst_tuple_end(DstValue *tuple) {
dst_tuple_hash(tuple) = dst_array_calchash(tuple, dst_tuple_length(tuple));
return (const DstValue *)tuple;
}
@@ -53,14 +53,14 @@ int dst_tuple_equal(const DstValue *lhs, const DstValue *rhs) {
int32_t rlen = dst_tuple_length(rhs);
int32_t lhash = dst_tuple_hash(lhs);
int32_t rhash = dst_tuple_hash(rhs);
if (llen != rlen)
return 0;
if (lhash == 0)
lhash = dst_tuple_hash(lhs) = dst_array_calchash(lhs, llen);
if (rhash == 0)
rhash = dst_tuple_hash(rhs) = dst_array_calchash(rhs, rlen);
if (lhash != rhash)
return 0;
if (llen != rlen)
return 0;
for (index = 0; index < llen; index++) {
if (!dst_equals(lhs[index], rhs[index]))
return 0;
+2 -10
View File
@@ -73,18 +73,10 @@ int32_t dst_hash(DstValue x) {
hash = dst_string_hash(dst_unwrap_string(x));
break;
case DST_TUPLE:
if (0 == dst_tuple_hash(dst_unwrap_tuple(x)))
hash = dst_tuple_hash(dst_unwrap_tuple(x)) =
dst_array_calchash(dst_unwrap_tuple(x), dst_tuple_length(dst_unwrap_tuple(x)));
else
hash = dst_tuple_hash(dst_unwrap_tuple(x));
hash = dst_tuple_hash(dst_unwrap_tuple(x));
break;
case DST_STRUCT:
if (0 == dst_struct_hash(dst_unwrap_struct(x)))
hash = dst_struct_hash(dst_unwrap_struct(x)) =
dst_array_calchash(dst_unwrap_struct(x), dst_struct_capacity(dst_unwrap_struct(x)));
else
hash = dst_struct_hash(dst_unwrap_struct(x));
hash = dst_struct_hash(dst_unwrap_struct(x));
break;
default:
if (sizeof(double) == sizeof(void *)) {
+27 -5
View File
@@ -24,7 +24,7 @@
#ifdef DST_NANBOX
void *dst_nanbox_to_pointer(dst_t x) {
void *dst_nanbox_to_pointer(DstValue x) {
/* We need to do this shift to keep the higher bits of the pointer
* the same as bit 47 as required by the x86 architecture. We may save
* an instruction if we do x.u64 & DST_NANBOX_POINTERBITS, but this 0s
@@ -41,6 +41,14 @@ DstValue dst_nanbox_from_pointer(void *p, uint64_t tagmask) {
return ret;
}
DstValue dst_nanbox_from_cpointer(const void *p, uint64_t tagmask) {
DstValue ret;
ret.cpointer = p;
ret.u64 &= DST_NANBOX_POINTERBITS;
ret.u64 |= tagmask;
return ret;
}
DstValue dst_nanbox_from_double(double d) {
DstValue ret;
ret.real = d;
@@ -51,13 +59,23 @@ DstValue dst_nanbox_from_double(double d) {
}
DstValue dst_nanbox_from_bits(uint64_t bits) {
dst_t ret;
DstValue ret;
ret.u64 = bits;
return ret;
}
void dst_nanbox_memempty(DstValue *mem, uint32_t count) {
uint32_t i;
void *dst_nanbox_memalloc_empty(int32_t count) {
int32_t i;
void *mem = malloc(count * sizeof(DstValue));
DstValue *mmem = (DstValue *)mem;
for (i = 0; i < count; i++) {
mmem[i] = dst_wrap_nil();
}
return mem;
}
void dst_nanbox_memempty(DstValue *mem, int32_t count) {
int32_t i;
for (i = 0; i < count; i++) {
mem[i] = dst_wrap_nil();
}
@@ -74,24 +92,28 @@ void dst_nanbox_memempty(DstValue *mem, uint32_t count) {
DstValue dst_wrap_nil() {
DstValue y;
y.type = DST_NIL;
y.as.u64 = 0;
return y;
}
DstValue dst_wrap_true() {
DstValue y;
y.type = DST_TRUE;
y.as.u64 = 0;
return y;
}
DstValue dst_wrap_false() {
DstValue y;
y.type = DST_TRUE;
y.type = DST_FALSE;
y.as.u64 = 0;
return y;
}
DstValue dst_wrap_boolean(int x) {
DstValue y;
y.type = x ? DST_TRUE : DST_FALSE;
y.as.u64 = 0;
return y;
}