Przeglądaj źródła

builtin stuff, and reorganized l2_vm_value

master
Martin Dørum 3 lat temu
rodzic
commit
2bf2b4a88f

+ 5
- 0
include/lang2/builtins.x.h Wyświetl plik

@@ -0,0 +1,5 @@
// X macro: Define a macro named X, then include this file, then undef X.

#ifdef X
X("print", l2_builtin_print);
#endif

+ 6
- 0
include/lang2/vm/builtins.h Wyświetl plik

@@ -0,0 +1,6 @@
#include "vm.h"

#define X(name, f) \
l2_word f(struct l2_vm *vm, struct l2_vm_array *args);
#include "../builtins.x.h"
#undef X

+ 33
- 15
include/lang2/vm/vm.h Wyświetl plik

@@ -10,32 +10,51 @@ struct l2_vm;
struct l2_vm_array;
typedef l2_word (*l2_vm_cfunction)(struct l2_vm *vm, struct l2_vm_array *args);

enum l2_value_type {
L2_VAL_TYPE_NONE,
L2_VAL_TYPE_INTEGER,
L2_VAL_TYPE_REAL,
L2_VAL_TYPE_BUFFER,
L2_VAL_TYPE_ARRAY,
L2_VAL_TYPE_NAMESPACE,
L2_VAL_TYPE_FUNCTION,
L2_VAL_TYPE_CFUNCTION,
};

enum l2_value_flags {
L2_VAL_MARKED = 1 << 6,
L2_VAL_CONST = 1 << 7,
};

// The smallest size an l2_vm_value can be is 16 bytes on common platforms.
// Pointers are 8 bytes, and since we need to store _at least_ 1 pointer +
// 1 byte for flags, it's going to be padded up to 16 bytes anyways.
// Might as well store some useful extra info in here.
struct l2_vm_value {
enum l2_value_flags {
L2_VAL_TYPE_NONE,
L2_VAL_TYPE_INTEGER,
L2_VAL_TYPE_REAL,
L2_VAL_TYPE_BUFFER,
L2_VAL_TYPE_ARRAY,
L2_VAL_TYPE_NAMESPACE,
L2_VAL_TYPE_FUNCTION,
L2_VAL_TYPE_CFUNCTION,
L2_VAL_MARKED = 1 << 7,
L2_VAL_CONST = 1 << 8,
} flags;
// Byte 0: 4 bytes
union {
l2_word ns_parent;
} extra;

// Byte 4: 1 byte, 3 bytes padding
uint8_t flags;

// Byte 8: 8 bytes
union {
int64_t integer;
double real;
struct l2_vm_buffer *buffer;
struct l2_vm_array *array;
struct l2_vm_namespace *ns;
struct {
l2_word pos;
l2_word namespace;
} func;
l2_vm_cfunction cfunc;
void *data;
};
};

#define l2_vm_value_type(val) ((val)->flags & 0x0f)
#define l2_vm_value_type(val) ((enum l2_value_type)((val)->flags & 0x0f))

struct l2_vm_buffer {
size_t len;
@@ -49,7 +68,6 @@ struct l2_vm_array {
};

struct l2_vm_namespace {
l2_word parent;
size_t len;
size_t size;
l2_word mask;

+ 6
- 0
lib/gen/gen.c Wyświetl plik

@@ -13,6 +13,12 @@ void l2_gen_init(struct l2_generator *gen, struct l2_io_writer *w) {
gen->strings = NULL;
gen->pos = 0;
l2_bufio_writer_init(&gen->writer, w);

// Register atoms for all builtins
#define X(name, f) \
l2_strset_put_copy(&gen->atomset, name);
#include "builtins.x.h"
#undef X
}

void l2_gen_flush(struct l2_generator *gen) {

+ 8
- 0
lib/vm/builtins.c Wyświetl plik

@@ -0,0 +1,8 @@
#include "vm/builtins.h"

#include <stdio.h>

l2_word l2_builtin_print(struct l2_vm *vm, struct l2_vm_array *args) {
printf("hey this is test\n");
return 0;
}

+ 5
- 6
lib/vm/namespace.c Wyświetl plik

@@ -100,17 +100,16 @@ static l2_word get(struct l2_vm_namespace *ns, l2_word key) {

void l2_vm_namespace_set(struct l2_vm_value *v, l2_word key, l2_word val) {
if (val == 0) {
del(v->data, key);
del(v->ns, key);
} else {
v->data = set(v->data, key, val);
v->ns = set(v->ns, key, val);
}
}

l2_word l2_vm_namespace_get(struct l2_vm *vm, struct l2_vm_value *v, l2_word key) {
struct l2_vm_namespace *ns = v->data;
l2_word ret = get(ns, key);
if (ret == 0 && ns != NULL && ns->parent != 0) {
return l2_vm_namespace_get(vm, &vm->values[ns->parent], key);
l2_word ret = get(v->ns, key);
if (ret == 0 && v->extra.ns_parent != 0) {
return l2_vm_namespace_get(vm, &vm->values[v->extra.ns_parent], key);
}

return ret;

+ 21
- 19
lib/vm/print.c Wyświetl plik

@@ -4,7 +4,8 @@
#include <string.h>

void l2_vm_print_val(struct l2_vm_value *val) {
switch (val->flags & 0x0f) {

switch (l2_vm_value_type(val)) {
case L2_VAL_TYPE_NONE:
printf("NONE\n");
break;
@@ -19,48 +20,45 @@ void l2_vm_print_val(struct l2_vm_value *val) {

case L2_VAL_TYPE_ARRAY:
{
if (val->data == NULL) {
if (val->array == NULL) {
printf("ARRAY, empty\n");
return;
}

struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
printf("ARRAY, len %zu\n", arr->len);
for (size_t i = 0; i < arr->len; ++i) {
printf(" %zu: %u\n", i, arr->data[i]);
printf("ARRAY, len %zu\n", val->array->len);
for (size_t i = 0; i < val->array->len; ++i) {
printf(" %zu: %u\n", i, val->array->data[i]);
}
}
break;

case L2_VAL_TYPE_BUFFER:
{
if (val->data == NULL) {
if (val->buffer == NULL) {
printf("BUFFER, empty\n");
return;
}

struct l2_vm_buffer *buf = (struct l2_vm_buffer *)val->data;
printf("BUFFER, len %zu\n", buf->len);
for (size_t i = 0; i < buf->len; ++i) {
printf(" %zu: %c\n", i, buf->data[i]);
printf("BUFFER, len %zu\n", val->buffer->len);
for (size_t i = 0; i < val->buffer->len; ++i) {
printf(" %zu: %c\n", i, val->buffer->data[i]);
}
}
break;

case L2_VAL_TYPE_NAMESPACE:
{
if (val->data == NULL) {
printf("NAMESPACE, empty\n");
if (val->ns == NULL) {
printf("NAMESPACE, empty, parent %u\n", val->extra.ns_parent);
return;
}

struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
printf("NAMESPACE, len %zu, parent %u\n", ns->len, ns->parent);
for (size_t i = 0; i < ns->size; ++i) {
l2_word key = ns->data[i];
l2_word val = ns->data[ns->size + i];
printf("NAMESPACE, len %zu, parent %u\n", val->ns->len, val->extra.ns_parent);
for (size_t i = 0; i < val->ns->size; ++i) {
l2_word key = val->ns->data[i];
l2_word v = val->ns->data[val->ns->size + i];
if (key == 0 || key == ~(l2_word)0) continue;
printf(" %u: %u\n", key, val);
printf(" %u: %u\n", key, v);
}
}
break;
@@ -68,6 +66,10 @@ void l2_vm_print_val(struct l2_vm_value *val) {
case L2_VAL_TYPE_FUNCTION:
printf("FUNCTION, pos %u, ns %u\n", val->func.pos, val->func.namespace);
break;

case L2_VAL_TYPE_CFUNCTION:
printf("C FUNCTION, %p\n", val->cfunc);
break;
}
}


+ 52
- 31
lib/vm/vm.c Wyświetl plik

@@ -1,9 +1,10 @@
#include "vm/vm.h"

#include <string.h>

#include <stdio.h>

#include "vm/builtins.h"

static l2_word alloc_val(struct l2_vm *vm) {
size_t id = l2_bitset_set_next(&vm->valueset);
if (id >= vm->valuessize) {
@@ -57,33 +58,31 @@ static void gc_mark(struct l2_vm *vm, l2_word id) {
}

static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val) {
if (val->data == NULL) {
if (val->array == NULL) {
return;
}

struct l2_vm_array *arr = (struct l2_vm_array *)val->data;
for (size_t i = 0; i < arr->len; ++i) {
gc_mark(vm, arr->data[i]);
for (size_t i = 0; i < val->array->len; ++i) {
gc_mark(vm, val->array->data[i]);
}
}

static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val) {
if (val->data == NULL) {
if (val->ns == NULL) {
return;
}

struct l2_vm_namespace *ns = (struct l2_vm_namespace *)val->data;
for (size_t i = 0; i < ns->size; ++i) {
l2_word key = ns->data[i];
for (size_t i = 0; i < val->ns->size; ++i) {
l2_word key = val->ns->data[i];
if (key == 0 || key == ~(l2_word)0) {
continue;
}

gc_mark(vm, ns->data[ns->size + i]);
gc_mark(vm, val->ns->data[val->ns->size + i]);
}

if (ns->parent != 0) {
gc_mark(vm, ns->parent);
if (val->extra.ns_parent != 0) {
gc_mark(vm, val->extra.ns_parent);
}
}

@@ -91,11 +90,15 @@ static void gc_free(struct l2_vm *vm, l2_word id) {
struct l2_vm_value *val = &vm->values[id];
l2_bitset_unset(&vm->valueset, id);

// Don't need to do anything more; the next round of GC will free
// whichever values were only referenced by the array
int typ = l2_vm_value_type(val);
if (typ == L2_VAL_TYPE_ARRAY || typ == L2_VAL_TYPE_BUFFER || typ == L2_VAL_TYPE_NAMESPACE) {
free(val->data);
// Don't need to do anything more; the next round of GC will free
// whichever values were only referenced by the array
free(val->array);
} else if (typ == L2_VAL_TYPE_BUFFER) {
free(val->buffer);
} else if (typ == L2_VAL_TYPE_NAMESPACE) {
free(val->ns);
}
}

@@ -135,12 +138,30 @@ void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) {
l2_word none_id = alloc_val(vm);
vm->values[none_id].flags = L2_VAL_TYPE_NONE | L2_VAL_CONST;

// Need to allocate a builtins namespace
l2_word builtins = alloc_val(vm);
vm->values[builtins].extra.ns_parent = 0;
vm->values[builtins].ns = NULL; // Will be allocated on first insert
vm->values[builtins].flags = L2_VAL_TYPE_NAMESPACE;
vm->nstack[vm->nsptr++] = builtins;

// Need to allocate a root namespace
l2_word root = alloc_val(vm);
vm->values[root].extra.ns_parent = builtins;
vm->values[root].ns = NULL;
vm->values[root].flags = L2_VAL_TYPE_NAMESPACE;
vm->values[root].data = NULL; // Will be allocated on first insert
vm->nstack[vm->nsptr] = root;
vm->nsptr += 1;
vm->nstack[vm->nsptr++] = root;

// Define a C function variable for every builtin
l2_word id;
l2_word key = 1;
#define X(name, f) \
id = alloc_val(vm); \
vm->values[id].flags = L2_VAL_TYPE_CFUNCTION; \
vm->values[id].cfunc = f; \
l2_vm_namespace_set(&vm->values[builtins], key++, id);
#include "builtins.x.h"
#undef X
}

void l2_vm_free(struct l2_vm *vm) {
@@ -216,9 +237,9 @@ void l2_vm_step(struct l2_vm *vm) {

l2_word arr_id = alloc_val(vm);
vm->values[arr_id].flags = L2_VAL_TYPE_ARRAY;
vm->values[arr_id].data = malloc(
vm->values[arr_id].array = malloc(
sizeof(struct l2_vm_array) + sizeof(l2_word) * argc);
struct l2_vm_array *arr = vm->values[arr_id].data;
struct l2_vm_array *arr = vm->values[arr_id].array;
arr->len = argc;
arr->size = argc;

@@ -227,7 +248,7 @@ void l2_vm_step(struct l2_vm *vm) {
arr->data[i] = vm->stack[vm->sptr + i];
}

enum l2_value_flags typ = l2_vm_value_type(func);
enum l2_value_type typ = l2_vm_value_type(func);

// C functions are called differently from language functions
if (typ == L2_VAL_TYPE_CFUNCTION) {
@@ -245,10 +266,9 @@ void l2_vm_step(struct l2_vm *vm) {
vm->stack[vm->sptr++] = arr_id;

l2_word ns_id = alloc_val(vm);
vm->values[ns_id].extra.ns_parent = ns_id;
vm->values[ns_id].ns = NULL;
vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE;
vm->values[ns_id].data = calloc(1, sizeof(struct l2_vm_namespace));
struct l2_vm_namespace *ns = vm->values[ns_id].data;
ns->parent = func->func.namespace;
vm->nstack[vm->nsptr++] = ns_id;

vm->iptr = func->func.pos;
@@ -331,10 +351,10 @@ void l2_vm_step(struct l2_vm *vm) {
l2_word length = vm->stack[--vm->sptr];
l2_word offset = vm->stack[--vm->sptr];
vm->values[word].flags = L2_VAL_TYPE_BUFFER;
vm->values[word].data = malloc(sizeof(struct l2_vm_buffer) + length);
((struct l2_vm_buffer *)vm->values[word].data)->len = length;
vm->values[word].buffer = malloc(sizeof(struct l2_vm_buffer) + length);
vm->values[word].buffer->len = length;
memcpy(
(unsigned char *)vm->values[word].data + sizeof(struct l2_vm_buffer),
(unsigned char *)vm->values[word].buffer + sizeof(struct l2_vm_buffer),
vm->ops + offset, length);
vm->stack[vm->sptr] = word;
vm->sptr += 1;
@@ -346,8 +366,8 @@ void l2_vm_step(struct l2_vm *vm) {
word = alloc_val(vm);
l2_word length = vm->stack[--vm->sptr];
vm->values[word].flags = L2_VAL_TYPE_BUFFER;
vm->values[word].data = calloc(1, sizeof(struct l2_vm_buffer) + length);
((struct l2_vm_buffer *)vm->values[word].data)->len = length;
vm->values[word].buffer = calloc(1, sizeof(struct l2_vm_buffer) + length);
vm->values[word].buffer->len = length;
vm->stack[vm->sptr] = word;
vm->sptr += 1;
}
@@ -356,7 +376,7 @@ void l2_vm_step(struct l2_vm *vm) {
case L2_OP_ALLOC_ARRAY:
word = alloc_val(vm);
vm->values[word].flags = L2_VAL_TYPE_ARRAY;
vm->values[word].data = NULL; // Will be allocated on first insert
vm->values[word].array = NULL; // Will be allocated on first insert
vm->stack[vm->sptr] = word;
vm->sptr += 1;
break;
@@ -364,7 +384,8 @@ void l2_vm_step(struct l2_vm *vm) {
case L2_OP_ALLOC_NAMESPACE:
word = alloc_val(vm);
vm->values[word].flags = L2_VAL_TYPE_NAMESPACE;
vm->values[word].data = NULL; // Will be allocated on first insert
vm->values[word].extra.ns_parent = 0;
vm->values[word].ns = NULL; // Will be allocated on first insert
vm->stack[vm->sptr] = word;
vm->sptr += 1;
break;

Ładowanie…
Anuluj
Zapisz