Lots of changes with long commit message again

1. (list ...)
2. string-* functions
3. (native str) to resolve native functions at runtime
4. Memory fuckups in compiler core unit loading
5. Now can call non-identifiers in compiler
This commit is contained in:
Mark Poliakov 2021-04-09 00:18:48 +03:00
parent e15327e2e5
commit 91961bcec5
20 changed files with 403 additions and 83 deletions

View File

@ -9,6 +9,7 @@ VM_OBJS=$(O)/vm/main.o \
$(O)/vm/stack.o \ $(O)/vm/stack.o \
$(O)/vm/error.o \ $(O)/vm/error.o \
$(O)/vm/debug.o \ $(O)/vm/debug.o \
$(O)/vm/libcore.o \
$(O)/core/vector.o \ $(O)/core/vector.o \
$(O)/core/hash.o $(O)/core/hash.o
COMPILER_OBJS=$(O)/compiler/main.o \ COMPILER_OBJS=$(O)/compiler/main.o \

View File

@ -9,6 +9,17 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
static void emit_rev_cons(struct function *fn,
struct context *ctx,
struct node *args) {
if (null_q(args)) {
return;
}
emit_rev_cons(fn, ctx, cdr(args));
emit(fn, ctx, car(args));
emit_insn(fn, OP(OP_CONS, 0));
}
int emit_builtin_syntax(struct function *fn, int emit_builtin_syntax(struct function *fn,
struct context *ctx, struct context *ctx,
const char *name, const char *name,
@ -154,6 +165,10 @@ int emit_builtin_syntax(struct function *fn,
cond_jmp = vector_ref(&fn->bytecode, cond_jmp_loc); cond_jmp = vector_ref(&fn->bytecode, cond_jmp_loc);
*cond_jmp |= (end_loc - cond_jmp_loc) & 0xFFFFFF; *cond_jmp |= (end_loc - cond_jmp_loc) & 0xFFFFFF;
return 0; return 0;
} else if (!strcmp(name, "list")) {
emit_insn(fn, OP(OP_LDNIL, 0));
emit_rev_cons(fn, ctx, tail);
return 0;
} else if (!strcmp(name, "use") || } else if (!strcmp(name, "use") ||
!strcmp(name, "export")) { !strcmp(name, "export")) {
// Ignore // Ignore

View File

@ -22,6 +22,11 @@ void emit_function(struct context *ctx, struct function *fn) {
struct unit *root = ctx->root; struct unit *root = ctx->root;
assert(ctx->owner == fn); assert(ctx->owner == fn);
fn->argc = 0;
for (struct node *node = fn->args; node; node = cdr(node)) {
++fn->argc;
}
// Pass 0 - extract global scope // Pass 0 - extract global scope
for (struct node *node = body; node; node = cdr(node)) { for (struct node *node = body; node; node = cdr(node)) {
struct node *expr = car(node); struct node *expr = car(node);
@ -124,6 +129,7 @@ void emit(struct function *fn, struct context *ctx, struct node *expr) {
return; return;
} }
struct node *n0; struct node *n0;
size_t index;
int c0; int c0;
switch (expr->type) { switch (expr->type) {
@ -135,11 +141,8 @@ void emit(struct function *fn, struct context *ctx, struct node *expr) {
fprintf(stderr, "Call to nil\n"); fprintf(stderr, "Call to nil\n");
abort(); abort();
} }
if (n0->type != N_IDENT) {
fprintf(stderr, "TODO non-identifier calls\n");
abort();
}
if (n0->type == N_IDENT) {
// Try builtin syntax construct // Try builtin syntax construct
if (emit_builtin_syntax(fn, ctx, n0->n_ident, cdr(expr)) == 0) { if (emit_builtin_syntax(fn, ctx, n0->n_ident, cdr(expr)) == 0) {
return; return;
@ -156,11 +159,21 @@ void emit(struct function *fn, struct context *ctx, struct node *expr) {
// call // call
emit_call(fn, ctx, n0->n_ident); emit_call(fn, ctx, n0->n_ident);
return; return;
} else {
c0 = emit_arg_list(fn, ctx, expr->n_cons.cdr);
emit(fn, ctx, n0);
emit_insn(fn, OP(OP_CALL, 0));
return;
}
case N_STRING:
assert(unit_insert_string(ctx->root, expr->n_string, &index) == 0);
emit_insn(fn, OP(OP_LDS, index));
return;
case N_INTEGER: case N_INTEGER:
if (expr->n_integer < 0x7FFFFF && expr->n_integer > -0x7FFFFF) { if (expr->n_integer < 0x7FFFFF && expr->n_integer > -0x7FFFFF) {
emit_insn(fn, OP(OP_LDI, expr->n_integer)); emit_insn(fn, OP(OP_LDI, expr->n_integer));
} else { } else {
printf("ldc ...\n"); assert(0 && "TODO constant pool lmao");
} }
return; return;
case N_IDENT: case N_IDENT:

View File

@ -6,7 +6,8 @@
enum node_type { enum node_type {
N_CONS, N_CONS,
N_IDENT, N_IDENT,
N_INTEGER N_INTEGER,
N_STRING
}; };
struct node { struct node {
@ -16,6 +17,7 @@ struct node {
struct node *car, *cdr; struct node *car, *cdr;
} n_cons; } n_cons;
char *n_ident; char *n_ident;
char *n_string;
intmax_t n_integer; intmax_t n_integer;
}; };
}; };
@ -40,6 +42,10 @@ static inline int integer_q(struct node *n) {
return n && n->type == N_INTEGER; return n && n->type == N_INTEGER;
} }
static inline int string_q(struct node *n) {
return n && n->type == N_STRING;
}
static inline struct node *car(struct node *n) { static inline struct node *car(struct node *n) {
assert(pair_q(n)); assert(pair_q(n));
return n->n_cons.car; return n->n_cons.car;
@ -62,6 +68,7 @@ static inline struct node *cddr(struct node *n) {
return cdr(cdr(n)); return cdr(cdr(n));
} }
struct node *string_from_owned(char *ptr);
struct node *cons(struct node *a, struct node *b); struct node *cons(struct node *a, struct node *b);
struct node *ident(const char *i); struct node *ident(const char *i);
struct node *integer(intmax_t v); struct node *integer(intmax_t v);

View File

@ -35,6 +35,7 @@ struct ext_unit {
struct function { struct function {
size_t index; size_t index;
size_t local_count; size_t local_count;
size_t argc;
struct node *args, *body; struct node *args, *body;
struct vector bytecode; struct vector bytecode;
}; };
@ -47,6 +48,7 @@ struct export {
struct unit { struct unit {
struct context global; struct context global;
struct vector strtab;
struct vector functions; struct vector functions;
struct vector exports; struct vector exports;
struct vector ext_refs; struct vector ext_refs;
@ -59,5 +61,6 @@ struct function *unit_lambda(struct unit *u);
int unit_ext_load(struct unit *self, const char *unit); int unit_ext_load(struct unit *self, const char *unit);
int ctx_lookup_name(struct context *ctx, const char *name, int *kind, size_t *index); int ctx_lookup_name(struct context *ctx, const char *name, int *kind, size_t *index);
int unit_lookup_global(struct unit *unit, const char *name, size_t *index); int unit_lookup_global(struct unit *unit, const char *name, size_t *index);
int unit_insert_string(struct unit *unit, const char *text, size_t *index);
void emit_insn(struct function *fn, uint32_t insn); void emit_insn(struct function *fn, uint32_t insn);

View File

@ -47,8 +47,10 @@ static void write_unit(FILE *fp, struct unit *u) {
hdr.func_table_size = u->functions.size; hdr.func_table_size = u->functions.size;
for (size_t i = 0; i < u->functions.size; ++i) { for (size_t i = 0; i < u->functions.size; ++i) {
struct function *fn = vector_ref(&u->functions, i); struct function *fn = vector_ref(&u->functions, i);
offset += sizeof(struct bin_func_entry) + fn->bytecode.size; offset += sizeof(struct bin_func_entry) + fn->bytecode.size * sizeof(uint32_t);
} }
hdr.string_table_offset = offset;
hdr.string_table_size = u->strtab.size;
fwrite(&hdr, 1, sizeof(struct bin_header), fp); fwrite(&hdr, 1, sizeof(struct bin_header), fp);
for (size_t i = 0; i < u->ext_units.size; ++i) { for (size_t i = 0; i < u->ext_units.size; ++i) {
@ -77,16 +79,19 @@ static void write_unit(FILE *fp, struct unit *u) {
for (size_t i = 0; i < u->functions.size; ++i) { for (size_t i = 0; i < u->functions.size; ++i) {
struct function *fn = vector_ref(&u->functions, i); struct function *fn = vector_ref(&u->functions, i);
struct bin_func_entry bin_func; struct bin_func_entry bin_func;
size_t argc = 0; bin_func.argc = fn->argc;
for (struct node *arg = fn->args; arg; arg = cdr(arg)) {
++argc;
}
bin_func.argc = argc;
bin_func.local_count = fn->local_count; bin_func.local_count = fn->local_count;
bin_func.len = fn->bytecode.size * sizeof(uint32_t); bin_func.len = fn->bytecode.size * sizeof(uint32_t);
fwrite(&bin_func, 1, sizeof(struct bin_func_entry), fp); fwrite(&bin_func, 1, sizeof(struct bin_func_entry), fp);
fwrite(fn->bytecode.data, 1, fn->bytecode.size * sizeof(uint32_t), fp); fwrite(fn->bytecode.data, 1, fn->bytecode.size * sizeof(uint32_t), fp);
} }
for (size_t i = 0; i < u->strtab.size; ++i) {
char **ref = vector_ref(&u->strtab, i);
const char *str = *ref;
uint32_t len = strlen(str);
fwrite(&len, 1, sizeof(uint32_t), fp);
fwrite(str, 1, len + 1, fp);
}
} }
int main(int argc, char **argv) { int main(int argc, char **argv) {

View File

@ -5,6 +5,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h> #include <stdio.h>
struct node *string_from_owned(char *ptr) {
struct node *n = malloc(sizeof(struct node));
n->type = N_STRING;
n->n_string = ptr;
return n;
}
struct node *cons(struct node *a, struct node *b) { struct node *cons(struct node *a, struct node *b) {
struct node *n = malloc(sizeof(struct node)); struct node *n = malloc(sizeof(struct node));
n->type = N_CONS; n->type = N_CONS;
@ -57,6 +64,9 @@ void vm_print(const struct node *node, int depth) {
case N_INTEGER: case N_INTEGER:
printf("%zd", node->n_integer); printf("%zd", node->n_integer);
break; break;
case N_STRING:
printf("\"%s\"", node->n_string);
break;
case N_CONS: case N_CONS:
if (!depth) { if (!depth) {
printf("("); printf("(");

View File

@ -202,6 +202,39 @@ int vm_parse(struct vm_parser *in, struct node **out) {
buf[i] = 0; buf[i] = 0;
*out = ident(buf); *out = ident(buf);
return 0; return 0;
} else if (ch == '"') {
char *buf;
size_t cap, len;
cap = 32;
len = 0;
buf = malloc(cap);
if (!buf) {
return -ENOMEM;
}
assert(in->pop(in) == ch);
while (1) {
ch = in->peek(in);
if (!ch) {
return -EINVAL;
}
assert(ch != '\\' && "Not implemented");
assert(in->pop(in) == ch);
if (ch == '"') {
break;
}
if (len == cap - 1) {
cap += 32;
buf = realloc(buf, cap);
assert(buf);
}
buf[len++] = ch;
}
buf[len] = 0;
*out = string_from_owned(buf);
return 0;
} }
fprintf(stderr, "Unrecognized character: #%c (%d)\n", ch, ch); fprintf(stderr, "Unrecognized character: #%c (%d)\n", ch, ch);

View File

@ -9,13 +9,17 @@
#include <stdio.h> #include <stdio.h>
static struct ext_unit_entry u_core_entries[] = { static struct ext_unit_entry u_core_entries[] = {
{ "println" },
{ "print" }, { "print" },
{ "file-open" }, { "putc" },
{ "file-read" },
{ "file-write" }, { "string-new" },
{ "file-close" }, { "string-length" },
{ "file-seek" }, { "string-ref" },
{ "exit" } { "string-set!" },
{ "string-append" },
{ "native" },
}; };
void unit_init(struct unit *u) { void unit_init(struct unit *u) {
@ -27,6 +31,7 @@ void unit_init(struct unit *u) {
vector_init(&u->ext_refs, sizeof(struct ext_ref)); vector_init(&u->ext_refs, sizeof(struct ext_ref));
vector_init(&u->ext_units, sizeof(struct ext_unit)); vector_init(&u->ext_units, sizeof(struct ext_unit));
vector_init(&u->exports, sizeof(struct export)); vector_init(&u->exports, sizeof(struct export));
vector_init(&u->strtab, sizeof(char *));
} }
void ctx_init(struct context *ctx, struct context *parent) { void ctx_init(struct context *ctx, struct context *parent) {
@ -128,9 +133,13 @@ static int parse_exports(FILE *fp, struct ext_unit *unit) {
int unit_ext_load(struct unit *self, const char *name) { int unit_ext_load(struct unit *self, const char *name) {
if (!strcmp(name, "core")) { if (!strcmp(name, "core")) {
struct ext_unit *unit = vector_append(&self->ext_units); struct ext_unit *unit = vector_append(&self->ext_units);
unit->exports.size = sizeof(u_core_entries) / sizeof(u_core_entries[0]); vector_init(&unit->exports, sizeof(struct ext_unit_entry));
unit->exports.cap = unit->exports.size; for (size_t i = 0; i < sizeof(u_core_entries) / sizeof(u_core_entries[0]); ++i) {
unit->exports.data = u_core_entries; struct ext_unit_entry *from, *to;
from = &u_core_entries[i];
to = vector_append(&unit->exports);
memcpy(to, from, sizeof(struct ext_unit_entry));
}
strcpy(unit->name, name); strcpy(unit->name, name);
return 0; return 0;
} }
@ -148,6 +157,20 @@ int unit_ext_load(struct unit *self, const char *name) {
return -ENOENT; return -ENOENT;
} }
int unit_insert_string(struct unit *unit, const char *text, size_t *index) {
// TODO find identical strings?
*index = unit->strtab.size;
char **ref = vector_append(&unit->strtab);
if (!ref) {
return -ENOMEM;
}
*ref = strdup(text);
if (!*ref) {
return -ENOMEM;
}
return 0;
}
// TODO external references // TODO external references
int ctx_lookup_name(struct context *ctx, const char *name, int *kind, size_t *index) { int ctx_lookup_name(struct context *ctx, const char *name, int *kind, size_t *index) {
// 1. Lookup local // 1. Lookup local

View File

@ -16,6 +16,8 @@ struct bin_header {
uint32_t export_table_size; uint32_t export_table_size;
uint32_t func_table_offset; uint32_t func_table_offset;
uint32_t func_table_size; uint32_t func_table_size;
uint32_t string_table_offset;
uint32_t string_table_size;
}; };
struct bin_unit_entry { struct bin_unit_entry {

View File

@ -21,6 +21,7 @@
#define OP_LDC 0x30 #define OP_LDC 0x30
#define OP_LDNIL 0x31 #define OP_LDNIL 0x31
#define OP_LDI 0x32 #define OP_LDI 0x32
#define OP_LDS 0x33
#define OP_CAR 0x40 #define OP_CAR 0x40
#define OP_CDR 0x41 #define OP_CDR 0x41

View File

@ -1,15 +1,11 @@
(use core) (use core)
(define (f2 x) (define (string-chars s)
(define (f1 x y) (define len (string-length s))
(define (f0 x y z) (define out nil)
(+ x y z) (while (/= len 0)
(setq len (- len 1))
(setq out (cons (string-ref s len) out))
) )
out
(f0 x y 1)
) )
(f1 x 2)
)
(print (f2 3))

4
vm/include/libcore.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
struct vm_unit_info;
int load_core(struct vm_unit_info *info);

View File

@ -21,6 +21,7 @@ struct vm_func_entry {
struct vm_unit { struct vm_unit {
struct vector ref_table; struct vector ref_table;
struct vector functions; struct vector functions;
struct vector strtab;
uint64_t *global_pool; uint64_t *global_pool;
size_t global_pool_size; size_t global_pool_size;
@ -28,6 +29,7 @@ struct vm_unit {
int is_loaded; int is_loaded;
}; };
char **unit_add_string(struct vm_unit *u);
struct vm_func_entry *unit_add_function(struct vm_unit *u); struct vm_func_entry *unit_add_function(struct vm_unit *u);
struct vm_ref_entry *unit_add_ref(struct vm_unit *u); struct vm_ref_entry *unit_add_ref(struct vm_unit *u);
void unit_free(struct vm_unit *u); void unit_free(struct vm_unit *u);

View File

@ -11,6 +11,7 @@ enum vm_type {
VT_CONS, VT_CONS,
VT_STRING, VT_STRING,
VT_FUNC, VT_FUNC,
VT_CFUNC,
}; };
struct vm_value { struct vm_value {
@ -24,6 +25,7 @@ struct vm_value {
size_t lib_index, fn_index; size_t lib_index, fn_index;
} v_func; } v_func;
struct vm_string v_string; struct vm_string v_string;
uintptr_t v_cfunc;
}; };
}; };
@ -31,6 +33,10 @@ static inline int ref_q(uint64_t w) {
return (w & FLAG_REF) != 0; return (w & FLAG_REF) != 0;
} }
static inline int integer_q(uint64_t w) {
return !(w & FLAG_REF);
}
static inline int null_q(uint64_t w) { static inline int null_q(uint64_t w) {
return w == FLAG_REF; return w == FLAG_REF;
} }
@ -40,6 +46,10 @@ static inline struct vm_value *getref(uint64_t w) {
return (struct vm_value *) (w << 1); return (struct vm_value *) (w << 1);
} }
static inline int string_q(uint64_t w) {
return !null_q(w) && ref_q(w) && getref(w)->type == VT_STRING;
}
static inline int cons_q(uint64_t w) { static inline int cons_q(uint64_t w) {
if (ref_q(w)) { if (ref_q(w)) {
return null_q(w) || getref(w)->type == VT_CONS; return null_q(w) || getref(w)->type == VT_CONS;
@ -52,6 +62,10 @@ static inline int func_q(uint64_t w) {
return ref_q(w) && !null_q(w) && getref(w)->type == VT_FUNC; return ref_q(w) && !null_q(w) && getref(w)->type == VT_FUNC;
} }
static inline int cfunc_q(uint64_t w) {
return ref_q(w) && !null_q(w) && getref(w)->type == VT_CFUNC;
}
static inline int pair_q(uint64_t w) { static inline int pair_q(uint64_t w) {
return ref_q(w) && (!null_q(w) && getref(w)->type == VT_CONS); return ref_q(w) && (!null_q(w) && getref(w)->type == VT_CONS);
} }
@ -76,5 +90,6 @@ void vm_value_free(struct vm_value *val);
struct vm_value *vm_cons(uint64_t w0, uint64_t w1); struct vm_value *vm_cons(uint64_t w0, uint64_t w1);
struct vm_value *vm_makestr(const char *str); struct vm_value *vm_makestr(const char *str);
struct vm_value *vm_func(size_t lib_index, size_t fn_index); struct vm_value *vm_func(size_t lib_index, size_t fn_index);
struct vm_value *vm_cfunc(uintptr_t address);
void vm_print(FILE *dst, uint64_t w); void vm_print(FILE *dst, uint64_t w);

137
vm/libcore.c Normal file
View File

@ -0,0 +1,137 @@
#include "vmstate.h"
#include "vmval.h"
#include "error.h"
#include "load.h"
#include "unit.h"
#include <string.h>
#define ARG(name) \
uint64_t name; \
if ((res = vm_pop(vm, &name)) != 0) { \
return res; \
}
#define ARG_INTEGER(name) \
int64_t name; \
if ((res = vm_pop_integer(vm, &name)) != 0) { \
return res; \
}
// I/O stuff
static int c_print(struct vm *vm) {
int res;
ARG(w);
if (string_q(w)) {
fputs(getref(w)->v_string.data, stdout);
} else {
vm_print(stdout, w);
}
vm_unref(w);
return 0;
}
static int c_println(struct vm *vm) {
int res;
if ((res = c_print(vm)) != 0) {
return res;
}
putc('\n', stdout);
return 0;
}
static int c_putc(struct vm *vm) {
int res;
ARG_INTEGER(c);
putc(c, stdout);
return 0;
}
// String stuff
static int c_string_length(struct vm *vm) {
int res;
ARG(w);
if (!string_q(w)) {
return -ERR_OPERAND_TYPE;
}
struct vm_value *v = getref(w);
size_t len = vm_strlen(&v->v_string);
vm_value_unref(v);
return vm_push_integer(vm, len);
}
static int c_string_ref(struct vm *vm) {
int res;
ARG(s);
ARG_INTEGER(i);
if (!string_q(s)) {
return -ERR_OPERAND_TYPE;
}
struct vm_value *v = getref(s);
char c;
if (i < 0 || (size_t) i >= vm_strlen(&v->v_string)) {
vm_value_unref(v);
return -ERR_RANGE;
}
c = v->v_string.data[i];
vm_value_unref(v);
return vm_push_integer(vm, c);
}
static int c_extra_func(struct vm *vm) {
int res;
ARG(w);
printf("Runtime-resolved function was called!\n");
vm_unref(w);
return 0;
}
static int c_native(struct vm *vm) {
int res;
ARG(w);
if (!string_q(w)) {
return -ERR_OPERAND_TYPE;
}
struct vm_value *name = getref(w);
struct vm_value *sym;
if (!strcmp(name->v_string.data, "extra-func")) {
sym = vm_cfunc((uintptr_t) c_extra_func);
} else {
return -ERR_SYMBOL_UNDEFINED;
}
vm_value_unref(name);
vm_value_ref(sym);
vm_push_ref(vm, sym);
return 0;
}
static struct vm_export_entry c_unit_core_exports[] = {
{ 1, { (uintptr_t) c_println }, "println" },
{ 1, { (uintptr_t) c_print }, "print" },
{ 1, { (uintptr_t) c_putc }, "putc" },
//{ 1, { (uintptr_t) c_string_length }, "string-new" },
{ 1, { (uintptr_t) c_string_length }, "string-length" },
{ 1, { (uintptr_t) c_string_ref }, "string-ref" },
//{ 1, { (uintptr_t) c_string_length }, "string-ref" },
{ 1, { (uintptr_t) c_native }, "native" },
};
int load_core(struct vm_unit_info *info) {
struct vm_export_entry *ent;
assert(info);
vector_init(&info->exports, sizeof(struct vm_export_entry));
for (size_t i = 0; i < sizeof(c_unit_core_exports) / sizeof(struct vm_export_entry); ++i) {
ent = vector_append(&info->exports);
if (!ent) {
return -ERR_OUT_OF_MEMORY;
}
memcpy(ent, &c_unit_core_exports[i], sizeof(struct vm_export_entry));
}
info->unit = NULL;
info->index = 0xFFFFFFFF;
return 0;
}

View File

@ -10,41 +10,9 @@
#include "load.h" #include "load.h"
#include "unit.h" #include "unit.h"
#include "vmstate.h" #include "vmstate.h"
#include "libcore.h"
#include "vmval.h" #include "vmval.h"
static int c_print(struct vm *vm) {
uint64_t w;
int res;
if ((res = vm_pop(vm, &w)) != 0) {
return res;
}
vm_print(stdout, w);
printf("\n");
vm_unref(w);
return 0;
}
static struct vm_export_entry c_unit_core_exports[] = {
{ 1, { (uintptr_t) c_print }, "print" }
};
static int load_core(struct vm_unit_info *info) {
struct vm_export_entry *ent;
assert(info);
vector_init(&info->exports, sizeof(struct vm_export_entry));
for (size_t i = 0; i < sizeof(c_unit_core_exports) / sizeof(struct vm_export_entry); ++i) {
ent = vector_append(&info->exports);
if (!ent) {
return -ERR_OUT_OF_MEMORY;
}
memcpy(ent, &c_unit_core_exports[i], sizeof(struct vm_export_entry));
}
info->unit = NULL;
info->index = 0xFFFFFFFF;
return 0;
}
static FILE *unit_try_open_in(const char *paths, const char *name) { static FILE *unit_try_open_in(const char *paths, const char *name) {
const char *head; const char *head;
char path[256]; char path[256];
@ -183,6 +151,28 @@ static int vm_load_refs(struct vm_unit *unit,
return 0; return 0;
} }
static int vm_load_strings(struct vm_unit *unit,
struct bin_header *hdr,
FILE *fp) {
uint32_t len;
fseek(fp, hdr->string_table_offset, SEEK_SET);
for (size_t i = 0; i < hdr->string_table_size; ++i) {
// TODO optimize this crap
char **ref = unit_add_string(unit);
if (!ref) {
return -ERR_OUT_OF_MEMORY;
}
fread(&len, 1, sizeof(uint32_t), fp);
*ref = malloc(len + 1);
if (!*ref) {
return -ERR_OUT_OF_MEMORY;
}
fread(*ref, 1, len + 1, fp);
}
return 0;
}
static int vm_load_exports(struct vm_unit_info *info, static int vm_load_exports(struct vm_unit_info *info,
struct bin_header *hdr, struct bin_header *hdr,
FILE *fp) { FILE *fp) {
@ -244,6 +234,10 @@ int vm_load_unit_file(struct vm *vm,
} }
} }
if ((res = vm_load_strings(unit, &hdr, fp)) != 0) {
return res;
}
if (info) { if (info) {
info->unit = unit; info->unit = unit;
} }

View File

@ -12,6 +12,10 @@ struct vm_func_entry *unit_add_function(struct vm_unit *u) {
return vector_append(&u->functions); return vector_append(&u->functions);
} }
char **unit_add_string(struct vm_unit *u) {
return vector_append(&u->strtab);
}
void unit_free(struct vm_unit *u) { void unit_free(struct vm_unit *u) {
struct vm_func_entry *func; struct vm_func_entry *func;
@ -21,6 +25,11 @@ void unit_free(struct vm_unit *u) {
free(func->bytecode); free(func->bytecode);
} }
vector_free(&u->functions); vector_free(&u->functions);
for (size_t i = 0; i < u->strtab.size; ++i) {
char **ref = vector_ref(&u->strtab, i);
free(*ref);
}
vector_free(&u->strtab);
for (size_t i = 0; i < u->global_pool_size; ++i) { for (size_t i = 0; i < u->global_pool_size; ++i) {
vm_unref(u->global_pool[i]); vm_unref(u->global_pool[i]);

View File

@ -95,6 +95,7 @@ struct vm_unit *vm_add_unit(struct vm *vm, size_t global_pool_size) {
vector_init(&unit->ref_table, sizeof(struct vm_ref_entry)); vector_init(&unit->ref_table, sizeof(struct vm_ref_entry));
vector_init(&unit->functions, sizeof(struct vm_func_entry)); vector_init(&unit->functions, sizeof(struct vm_func_entry));
vector_init(&unit->strtab, sizeof(char *));
return unit; return unit;
} }
@ -152,10 +153,20 @@ static uint64_t *vm_arg_ref(struct vm *vm, size_t index) {
} }
int vm_call_ref(struct vm *vm, struct vm_value *ref) { int vm_call_ref(struct vm *vm, struct vm_value *ref) {
if (ref->type != VT_FUNC) { switch (ref->type) {
case VT_CFUNC:
{
int (*func) (struct vm *) = (void *) ref->v_cfunc;
if (!func) {
return -ERR_OPERAND_TYPE; return -ERR_OPERAND_TYPE;
} }
return func(vm);
}
case VT_FUNC:
return vm_call_unit_index(vm, ref->v_func.lib_index, ref->v_func.fn_index); return vm_call_unit_index(vm, ref->v_func.lib_index, ref->v_func.fn_index);
default:
return -ERR_OPERAND_TYPE;
}
} }
static int vm_read_ext_ref(struct vm *vm, struct vm_ref_entry *ref, uint64_t *w) { static int vm_read_ext_ref(struct vm *vm, struct vm_ref_entry *ref, uint64_t *w) {
@ -265,6 +276,21 @@ int vm_eval_step(struct vm *vm) {
vm_unref(w0); vm_unref(w0);
vm_unref(w1); vm_unref(w1);
return res; return res;
case OP_NEQ:
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
return res;
}
if ((res = stack_pop(&vm->data_stack, &w1)) != 0) {
return res;
}
if (ref_q(w0) || ref_q(w1)) {
// TODO what do?
return -ERR_OPERAND_TYPE;
}
res = vm_push_bool(vm, w0 != w1);
vm_unref(w0);
vm_unref(w1);
return res;
// //
case OP_LDNIL: case OP_LDNIL:
return stack_push(&vm->data_stack, FLAG_REF); return stack_push(&vm->data_stack, FLAG_REF);
@ -345,6 +371,17 @@ int vm_eval_step(struct vm *vm) {
v0 = vm_func(vm->lp, i0); v0 = vm_func(vm->lp, i0);
vm_value_ref(v0); vm_value_ref(v0);
return vm_push_ref(vm, v0); return vm_push_ref(vm, v0);
case OP_LDS:
i0 = opcode & 0xFFFFFF;
if (i0 >= unit->strtab.size) {
return -ERR_RANGE;
}
{
char **ref = vector_ref(&unit->strtab, i0);
v0 = vm_makestr(*ref);
vm_value_ref(v0);
return vm_push_ref(vm, v0);
}
case OP_STL: case OP_STL:
i0 = opcode & 0xFFFFFF; i0 = opcode & 0xFFFFFF;
if (i0 >= func->local_count) { if (i0 >= func->local_count) {
@ -386,7 +423,7 @@ int vm_eval_step(struct vm *vm) {
if ((res = vm_read_ext_ref(vm, r0, &w0)) != 0) { if ((res = vm_read_ext_ref(vm, r0, &w0)) != 0) {
return res; return res;
} }
if (!func_q(w0)) { if (!ref_q(w0) || null_q(w0)) {
return -ERR_OPERAND_TYPE; return -ERR_OPERAND_TYPE;
} }
return vm_call_ref(vm, getref(w0)); return vm_call_ref(vm, getref(w0));
@ -397,7 +434,7 @@ int vm_eval_step(struct vm *vm) {
return -ERR_RANGE; return -ERR_RANGE;
} }
w0 = unit->global_pool[i0]; w0 = unit->global_pool[i0];
if (!func_q(w0)) { if (!ref_q(w0) || null_q(w0)) {
return -ERR_OPERAND_TYPE; return -ERR_OPERAND_TYPE;
} }
return vm_call_ref(vm, getref(w0)); return vm_call_ref(vm, getref(w0));
@ -405,7 +442,7 @@ int vm_eval_step(struct vm *vm) {
if ((res = stack_pop(&vm->data_stack, &w0)) != 0) { if ((res = stack_pop(&vm->data_stack, &w0)) != 0) {
return res; return res;
} }
if (!func_q(w0)) { if (!ref_q(w0) || null_q(w0)) {
return -ERR_OPERAND_TYPE; return -ERR_OPERAND_TYPE;
} }
res = vm_call_ref(vm, getref(w0)); res = vm_call_ref(vm, getref(w0));

View File

@ -34,6 +34,9 @@ static void vm_print_ref(FILE *fp, struct vm_value *value, int cdepth) {
fprintf(fp, ")"); fprintf(fp, ")");
} }
break; break;
case VT_CFUNC:
fprintf(fp, "<native function 0x%zx>", value->v_cfunc);
break;
case VT_FUNC: case VT_FUNC:
fprintf(fp, "<function %zu:%zu>", value->v_func.lib_index, value->v_func.fn_index); fprintf(fp, "<function %zu:%zu>", value->v_func.lib_index, value->v_func.fn_index);
break; break;
@ -73,6 +76,7 @@ void vm_value_free(struct vm_value *v) {
break; break;
case VT_STRING: case VT_STRING:
// TODO // TODO
break;
default: default:
break; break;
} }
@ -100,6 +104,15 @@ int vm_value_unref(struct vm_value *v) {
} }
} }
struct vm_value *vm_cfunc(uintptr_t ptr) {
struct vm_value *v = vm_value_create(VT_CFUNC);
if (!v) {
return NULL;
}
v->v_cfunc = ptr;
return v;
}
struct vm_value *vm_cons(uint64_t w0, uint64_t w1) { struct vm_value *vm_cons(uint64_t w0, uint64_t w1) {
struct vm_value *v = vm_value_create(VT_CONS); struct vm_value *v = vm_value_create(VT_CONS);
if (!v) { if (!v) {