Browse Source

better bytecode format

master
Martin Dørum 7 months ago
parent
commit
0acbfd77f0
9 changed files with 252 additions and 203 deletions
  1. 5
    7
      cmd/main.c
  2. 28
    28
      include/lang2/bytecode.h
  3. 1
    1
      include/lang2/loader.h
  4. 2
    2
      include/lang2/vm/print.h
  5. 3
    3
      include/lang2/vm/vm.h
  6. 82
    50
      lib/gen/gen.c
  7. 14
    39
      lib/loader.c
  8. 59
    35
      lib/vm/print.c
  9. 58
    38
      lib/vm/vm.c

+ 5
- 7
cmd/main.c View File

@@ -61,7 +61,7 @@ static void step_through(struct l2_vm *vm) {
while (!vm->halted) {
size_t iptr = vm->iptr;
printf("\n======\n\n(%d) Will run instr: ", vm->iptr);
l2_vm_print_op(vm->ops, vm->opcount, &iptr);
l2_vm_print_op(vm->ops, vm->opslen, &iptr);
if (fgets(buf, sizeof(buf), stdin) == NULL) {
break;
}
@@ -125,9 +125,9 @@ static void repl() {
l2_vm_init(&vm, NULL, 0);
} else if (w.len > 0) {
vm.ops = w.mem;
vm.opcount = w.len / sizeof(l2_word);
vm.opslen = w.len;

while (vm.iptr < vm.opcount) {
while (vm.iptr < vm.opslen) {
l2_vm_step(&vm);
}

@@ -264,9 +264,7 @@ int main(int argc, char **argv) {
}

if (do_serialize_bytecode) {
l2_bc_serialize(
outbc, bytecode_writer.mem,
bytecode_writer.len / sizeof(l2_word));
l2_bc_serialize(outbc, bytecode_writer.mem, bytecode_writer.len);
}

if (do_print_bytecode || do_print_tokens || do_serialize_bytecode) {
@@ -275,7 +273,7 @@ int main(int argc, char **argv) {
}

struct l2_vm vm;
l2_vm_init(&vm, bytecode_writer.mem, bytecode_writer.len / sizeof(l2_word));
l2_vm_init(&vm, bytecode_writer.mem, bytecode_writer.len);

if (do_step) {
step_through(&vm);

+ 28
- 28
include/lang2/bytecode.h View File

@@ -5,7 +5,7 @@

typedef uint32_t l2_word;

#define l2_bytecode_version 1
#define l2_bytecode_version 2

enum l2_opcode {
/*
@@ -42,14 +42,14 @@ enum l2_opcode {
L2_OP_ADD,

/*
* Call a function; func_call <argc>
* Call a function; func_call <argc:u4>
* Pop <argc> times
* Pop <func>
* Push array with args
* Call <func>
* (Before returning, the function will push a return value onto the stack)
*/
L2_OP_FUNC_CALL,
L2_OP_FUNC_CALL_U4,

/*
* Call an infix function
@@ -62,31 +62,31 @@ enum l2_opcode {
L2_OP_FUNC_CALL_INFIX,

/*
* Jump relative; rjmp <count>
* Jump relative; rjmp <count:u4>
* Jump <count> words forwards
*/
L2_OP_RJMP,
L2_OP_RJMP_U4,

/*
* Look up a value from the current stack frame; stack_frame_lookup <key>
* Look up a value from the current stack frame; stack_frame_lookup <key:u4>
* Find <val> in stack frame using <key>
* Push <val>
*/
L2_OP_STACK_FRAME_LOOKUP,
L2_OP_STACK_FRAME_LOOKUP_U4,

/*
* Set a value in the current stack frame; stack_frame_set <key>
* Set a value in the current stack frame; stack_frame_set <key:u4>
* Read <val>
* Assign <val> to stack frame at <key>
*/
L2_OP_STACK_FRAME_SET,
L2_OP_STACK_FRAME_SET_U4,

/*
* Replace a value on the stack; stack_frame_replace <key>
* Replace a value on the stack; stack_frame_replace <key:U4>
* Read <val>
* Assign <val> to stack frame at <key>
*/
L2_OP_STACK_FRAME_REPLACE,
L2_OP_STACK_FRAME_REPLACE_U4,

/*
* Return from a function.
@@ -105,33 +105,33 @@ enum l2_opcode {
L2_OP_ALLOC_NONE,

/*
* Allocate an atom from one word; alloc_atom <word>
* Allocate an atom from one word; alloc_atom <word:u4>
* Alloc atom <var> from <word>
* Push <var>
*/
L2_OP_ALLOC_ATOM,
L2_OP_ALLOC_ATOM_U4,

/*
* Allocate a real from two words; alloc_real <high> <low>
* Alloc real <var> from <high> << 32 | <low>
* Allocate a real from two words; alloc_real <double:u8>
* Alloc real <var> from <double>
* Push <var>
*/
L2_OP_ALLOC_REAL,
L2_OP_ALLOC_REAL_D8,

/*
* Allocate a buffer from static data; alloc_buffer_static <length> <offset>
* Allocate a buffer from static data; alloc_buffer_static <length:u4> <offset:u4>
* Alloc buffer <var> with <length> and <offset>
* Push <var>
*/
L2_OP_ALLOC_BUFFER_STATIC,
L2_OP_ALLOC_BUFFER_STATIC_U4,

/*
* Allocate an array; <count>
* Allocate an array; <count:u4>
* Pop <count> times
* Alloc array <var>
* Push <var>
*/
L2_OP_ALLOC_ARRAY,
L2_OP_ALLOC_ARRAY_U4,

/*
* Allocate an integer->value map.
@@ -141,33 +141,33 @@ enum l2_opcode {
L2_OP_ALLOC_NAMESPACE,

/*
* Allocate a function; alloc_function <pos>
* Allocate a function; alloc_function <pos:u4>
* Alloc function <var> pointing to location <word>
* Push <var>
*/
L2_OP_ALLOC_FUNCTION,
L2_OP_ALLOC_FUNCTION_U4,

/*
* Set a namespace's name to a value; namespace_set <key>
* Set a namespace's name to a value; namespace_set <key:u4>
* Read <val>
* Read <ns>
* Assign <val> to <ns[<key>]>
*/
L2_OP_NAMESPACE_SET,
L2_OP_NAMESPACE_SET_U4,

/*
* Lookup a value from a namespace; namespace_lookup <key>
* Lookup a value from a namespace; namespace_lookup <key:u4>
* Pop <ns>
* Push <ns[<key>]>
*/
L2_OP_NAMESPACE_LOOKUP,
L2_OP_NAMESPACE_LOOKUP_U4,

/*
* Look up a value from an array; array_lookup <key>
* Look up a value from an array; array_lookup <key:u4>
* Pop <arr>
* Push <arr[<key>]>
*/
L2_OP_ARRAY_LOOKUP,
L2_OP_ARRAY_LOOKUP_U4,

/*
* Set a value in an array; array_set <key>

+ 1
- 1
include/lang2/loader.h View File

@@ -6,7 +6,7 @@

#include <stdio.h>

int l2_bc_serialize(FILE *outf, l2_word *data, size_t len);
int l2_bc_serialize(FILE *outf, unsigned char *data, size_t len);
int l2_bc_load(FILE *inf, struct l2_io_writer *w);

#endif

+ 2
- 2
include/lang2/vm/print.h View File

@@ -9,7 +9,7 @@ void l2_vm_print_heap(struct l2_vm *vm);
void l2_vm_print_stack(struct l2_vm *vm);
void l2_vm_print_fstack(struct l2_vm *vm);

void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr);
void l2_vm_print_bytecode(l2_word *ops, size_t opcount);
void l2_vm_print_op(unsigned char *ops, size_t opcount, size_t *ptr);
void l2_vm_print_bytecode(unsigned char *ops, size_t opcount);

#endif

+ 3
- 3
include/lang2/vm/vm.h View File

@@ -97,8 +97,8 @@ int l2_vm_namespace_replace(struct l2_vm *vm, struct l2_vm_value *ns, l2_word ke
struct l2_vm {
int halted;
int gc_scheduled;
l2_word *ops;
size_t opcount;
unsigned char *ops;
size_t opslen;
l2_word iptr;

struct l2_io_writer *std_output;
@@ -118,7 +118,7 @@ struct l2_vm {
l2_word gc_start;
};

void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount);
void l2_vm_init(struct l2_vm *vm, unsigned char *ops, size_t opslen);
l2_word l2_vm_alloc(struct l2_vm *vm, enum l2_value_type typ, enum l2_value_flags flags);
l2_word l2_vm_error(struct l2_vm *vm, const char *fmt, ...);
l2_word l2_vm_type_error(struct l2_vm *vm, struct l2_vm_value *val);

+ 82
- 50
lib/gen/gen.c View File

@@ -1,12 +1,45 @@
#include "gen/gen.h"

#include <string.h>

#include "bytecode.h"

static void put(struct l2_generator *gen, l2_word word) {
l2_bufio_put_n(&gen->writer, &word, sizeof(word));
static void put(struct l2_generator *gen, unsigned char ch) {
l2_bufio_put(&gen->writer, ch);
gen->pos += 1;
}

static void put_u4le(struct l2_generator *gen, l2_word word) {
char data[4] = {
(word >> 0) & 0xff,
(word >> 8) & 0xff,
(word >> 16) & 0xff,
(word >> 24) & 0xff,
};

l2_bufio_put_n(&gen->writer, data, 4);
gen->pos += 4;
}

static void put_d8le(struct l2_generator *gen, double num) {
uint64_t integer;
memcpy(&integer, &num, 8);

char data[8] = {
(integer >> 0) & 0xff,
(integer >> 8) & 0xff,
(integer >> 16) & 0xff,
(integer >> 24) & 0xff,
(integer >> 32) & 0xff,
(integer >> 40) & 0xff,
(integer >> 48) & 0xff,
(integer >> 56) & 0xff,
};

l2_bufio_put_n(&gen->writer, data, 8);
gen->pos += 8;
}

void l2_gen_init(struct l2_generator *gen, struct l2_io_writer *w) {
l2_strset_init(&gen->atomset);
l2_strset_init(&gen->stringset);
@@ -39,8 +72,8 @@ void l2_gen_halt(struct l2_generator *gen) {
}

void l2_gen_rjmp(struct l2_generator *gen, l2_word len) {
put(gen, L2_OP_RJMP);
put(gen, len);
put(gen, L2_OP_RJMP_U4);
put_u4le(gen, len);
}

void l2_gen_discard(struct l2_generator *gen) {
@@ -62,21 +95,20 @@ void l2_gen_none(struct l2_generator *gen) {
void l2_gen_number(struct l2_generator *gen, double num) {
uint64_t n;
memcpy(&n, &num, sizeof(num));
put(gen, L2_OP_ALLOC_REAL);
put(gen, n >> 32);
put(gen, n);
put(gen, L2_OP_ALLOC_REAL_D8);
put_d8le(gen, num);
}

void l2_gen_atom(struct l2_generator *gen, char **str) {
size_t id = l2_strset_put(&gen->atomset, str);
put(gen, L2_OP_ALLOC_ATOM);
put(gen, id);
put(gen, L2_OP_ALLOC_ATOM_U4);
put_u4le(gen, id);
}

void l2_gen_atom_copy(struct l2_generator *gen, char *str) {
size_t id = l2_strset_put_copy(&gen->atomset, str);
put(gen, L2_OP_ALLOC_ATOM);
put(gen, id);
put(gen, L2_OP_ALLOC_ATOM_U4);
put_u4le(gen, id);
}

void l2_gen_string(struct l2_generator *gen, char **str) {
@@ -88,8 +120,8 @@ void l2_gen_string(struct l2_generator *gen, char **str) {
aligned += sizeof(l2_word) - (aligned % sizeof(l2_word));
}

put(gen, L2_OP_RJMP);
put(gen, aligned / sizeof(l2_word));
put(gen, L2_OP_RJMP_U4);
put_u4le(gen, aligned / sizeof(l2_word));
l2_word pos = gen->pos;

gen->pos += aligned / sizeof(l2_word);
@@ -103,15 +135,15 @@ void l2_gen_string(struct l2_generator *gen, char **str) {
gen->strings[id - 1].length = len;
gen->strings[id - 1].pos = pos;

put(gen, L2_OP_ALLOC_BUFFER_STATIC);
put(gen, len);
put(gen, pos);
put(gen, L2_OP_ALLOC_BUFFER_STATIC_U4);
put_u4le(gen, len);
put_u4le(gen, pos);
} else {
free(*str);
struct l2_generator_string *s = &gen->strings[id - 1];
put(gen, L2_OP_ALLOC_BUFFER_STATIC);
put(gen, s->length);
put(gen, s->pos);
put(gen, L2_OP_ALLOC_BUFFER_STATIC_U4);
put_u4le(gen, s->length);
put_u4le(gen, s->pos);
}
}

@@ -122,20 +154,20 @@ void l2_gen_string_copy(struct l2_generator *gen, char *str) {
l2_gen_string(gen, &s);
} else {
struct l2_generator_string *s = &gen->strings[id - 1];
put(gen, L2_OP_ALLOC_BUFFER_STATIC);
put(gen, s->length);
put(gen, s->pos);
put(gen, L2_OP_ALLOC_BUFFER_STATIC_U4);
put_u4le(gen, s->length);
put_u4le(gen, s->pos);
}
}

void l2_gen_function(struct l2_generator *gen, l2_word pos) {
put(gen, L2_OP_ALLOC_FUNCTION);
put(gen, pos);
put(gen, L2_OP_ALLOC_FUNCTION_U4);
put_u4le(gen, pos);
}

void l2_gen_array(struct l2_generator *gen, l2_word count) {
put(gen, L2_OP_ALLOC_ARRAY);
put(gen, count);
put(gen, L2_OP_ALLOC_ARRAY_U4);
put_u4le(gen, count);
}

void l2_gen_namespace(struct l2_generator *gen) {
@@ -144,31 +176,31 @@ void l2_gen_namespace(struct l2_generator *gen) {

void l2_gen_namespace_set(struct l2_generator *gen, char **ident) {
size_t atom_id = l2_strset_put(&gen->atomset, ident);
put(gen, L2_OP_NAMESPACE_SET);
put(gen, atom_id);
put(gen, L2_OP_NAMESPACE_SET_U4);
put_u4le(gen, atom_id);
}

void l2_gen_namespace_set_copy(struct l2_generator *gen, char *ident) {
size_t atom_id = l2_strset_put_copy(&gen->atomset, ident);
put(gen, L2_OP_NAMESPACE_SET);
put(gen, atom_id);
put(gen, L2_OP_NAMESPACE_SET_U4);
put_u4le(gen, atom_id);
}

void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident) {
size_t atom_id = l2_strset_put(&gen->atomset, ident);
put(gen, L2_OP_NAMESPACE_LOOKUP);
put(gen, atom_id);
put(gen, L2_OP_NAMESPACE_LOOKUP_U4);
put_u4le(gen, atom_id);
}

void l2_gen_namespace_lookup_copy(struct l2_generator *gen, char *ident) {
size_t atom_id = l2_strset_put_copy(&gen->atomset, ident);
put(gen, L2_OP_NAMESPACE_LOOKUP);
put(gen, atom_id);
put(gen, L2_OP_NAMESPACE_LOOKUP_U4);
put_u4le(gen, atom_id);
}

void l2_gen_array_lookup(struct l2_generator *gen, int number) {
put(gen, L2_OP_ARRAY_LOOKUP);
put(gen, number);
put(gen, L2_OP_ARRAY_LOOKUP_U4);
put_u4le(gen, number);
}

void l2_gen_array_set(struct l2_generator *gen, int number) {
@@ -186,43 +218,43 @@ void l2_gen_dynamic_set(struct l2_generator *gen) {

void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident) {
size_t atom_id = l2_strset_put(&gen->atomset, ident);
put(gen, L2_OP_STACK_FRAME_LOOKUP);
put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_LOOKUP_U4);
put_u4le(gen, atom_id);
}

void l2_gen_stack_frame_lookup_copy(struct l2_generator *gen, char *ident) {
size_t atom_id = l2_strset_put_copy(&gen->atomset, ident);
put(gen, L2_OP_STACK_FRAME_LOOKUP);
put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_LOOKUP_U4);
put_u4le(gen, atom_id);
}

void l2_gen_stack_frame_set(struct l2_generator *gen, char **ident) {
size_t atom_id = l2_strset_put(&gen->atomset, ident);
put(gen, L2_OP_STACK_FRAME_SET);
put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_SET_U4);
put_u4le(gen, atom_id);
}

void l2_gen_stack_frame_set_copy(struct l2_generator *gen, char *ident) {
size_t atom_id = l2_strset_put_copy(&gen->atomset, ident);
put(gen, L2_OP_STACK_FRAME_SET);
put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_SET_U4);
put_u4le(gen, atom_id);
}

void l2_gen_stack_frame_replace(struct l2_generator *gen, char **ident) {
size_t atom_id = l2_strset_put(&gen->atomset, ident);
put(gen, L2_OP_STACK_FRAME_REPLACE);
put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_REPLACE_U4);
put_u4le(gen, atom_id);
}

void l2_gen_stack_frame_replace_copy(struct l2_generator *gen, char *ident) {
size_t atom_id = l2_strset_put_copy(&gen->atomset, ident);
put(gen, L2_OP_STACK_FRAME_REPLACE);
put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_REPLACE_U4);
put_u4le(gen, atom_id);
}

void l2_gen_func_call(struct l2_generator *gen, l2_word argc) {
put(gen, L2_OP_FUNC_CALL);
put(gen, argc);
put(gen, L2_OP_FUNC_CALL_U4);
put_u4le(gen, argc);
}

void l2_gen_func_call_infix(struct l2_generator *gen) {

+ 14
- 39
lib/loader.c View File

@@ -2,7 +2,7 @@

#include <stdint.h>

int l2_bc_serialize(FILE *outf, l2_word *data, size_t len) {
int l2_bc_serialize(FILE *outf, unsigned char *data, size_t len) {
char header[4] = { 0x1b, 0x6c, 0x32, 0x63 };
if (fwrite(header, 1, 4, outf) < 4) {
fprintf(stderr, "Write error\n");
@@ -12,35 +12,21 @@ int l2_bc_serialize(FILE *outf, l2_word *data, size_t len) {
uint32_t version = l2_bytecode_version;

unsigned char version_buf[4] = {
(version & 0xff000000ull) >> 24,
(version & 0x00ff0000ull) >> 16,
(version & 0x0000ff00ull) >> 8,
(version & 0x000000ffull) >> 0,
(version >> 0) & 0xff,
(version >> 8) & 0xff,
(version >> 16) & 0xff,
(version >> 24) & 0xff,
};
if (fwrite(version_buf, 1, 4, outf) < 4) {
fprintf(stderr, "Write error\n");
return -1;
}

struct l2_io_file_writer w = {
.w.write = l2_io_file_write,
.f = outf,
};

struct l2_bufio_writer writer;
l2_bufio_writer_init(&writer, &w.w);

unsigned char word_buf[4];
for (size_t i = 0; i < len; ++i) {
uint32_t word = data[i];
word_buf[0] = (word & 0xff000000ull) >> 24;
word_buf[1] = (word & 0x00ff0000ull) >> 16;
word_buf[2] = (word & 0x0000ff00ull) >> 8;
word_buf[3] = (word & 0x000000ffull) >> 0;
l2_bufio_put_n(&writer, word_buf, 4);
if (fwrite(data, 1, len, outf) < len) {
fprintf(stderr, "Write error\n");
return -1;
}

l2_bufio_flush(&writer);
return 0;
}

@@ -54,10 +40,10 @@ int l2_bc_load(FILE *inf, struct l2_io_writer *w) {
}

uint32_t version = 0 |
((uint32_t)version_buf[0]) << 24 |
((uint32_t)version_buf[1]) << 16 |
((uint32_t)version_buf[2]) << 8 |
((uint32_t)version_buf[3]) << 0;
((uint32_t)version_buf[0]) << 0 |
((uint32_t)version_buf[1]) << 8 |
((uint32_t)version_buf[2]) << 16 |
((uint32_t)version_buf[3]) << 24;
if (version != l2_bytecode_version) {
fprintf(
stderr, "Version mismatch! Bytecode file uses bytecode version %i"
@@ -66,26 +52,15 @@ int l2_bc_load(FILE *inf, struct l2_io_writer *w) {
return -1;
}

struct l2_bufio_writer writer;
l2_bufio_writer_init(&writer, w);

// Must be divisible by 4
unsigned char buffer[4096];

while (1) {
size_t n = fread(buffer, 1, sizeof(buffer), inf);
if (n < 4) {
l2_bufio_flush(&writer);
if (n == 0) {
return 0;
}

for (size_t i = 0; i < n; i += 4) {
l2_word word = 0 |
((uint32_t)buffer[i + 0]) << 24 |
((uint32_t)buffer[i + 1]) << 16 |
((uint32_t)buffer[i + 2]) << 8 |
((uint32_t)buffer[i + 3]) << 0;
l2_bufio_put_n(&writer, &word, 4);
}
w->write(w, buffer, n);
}
}

+ 59
- 35
lib/vm/print.c View File

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

void l2_vm_print_val(struct l2_vm_value *val) {
static l2_word read_u4le(unsigned char *ops, size_t *ptr) {
unsigned char *data = &ops[*ptr];
l2_word ret =
(l2_word)data[0] |
(l2_word)data[1] << 8 |
(l2_word)data[2] << 16 |
(l2_word)data[3] << 24;
*ptr += 4;
return ret;
}

static double read_d8le(unsigned char *ops, size_t *ptr) {
unsigned char *data = &ops[*ptr];
uint64_t integer = 0 |
(uint64_t)data[0] |
(uint64_t)data[1] << 8 |
(uint64_t)data[2] << 16 |
(uint64_t)data[3] << 24 |
(uint64_t)data[4] << 32 |
(uint64_t)data[5] << 40 |
(uint64_t)data[6] << 48 |
(uint64_t)data[7] << 56;

double num;
memcpy(&num, &integer, 8);
*ptr += 8;
return num;
}

void l2_vm_print_val(struct l2_vm_value *val) {
switch (l2_vm_value_type(val)) {
case L2_VAL_TYPE_NONE:
printf("NONE\n");
@@ -114,7 +142,7 @@ void l2_vm_print_fstack(struct l2_vm *vm) {
}
}

void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) {
void l2_vm_print_op(unsigned char *ops, size_t opcount, size_t *ptr) {
enum l2_opcode opcode = (enum l2_opcode)ops[(*ptr)++];

switch (opcode) {
@@ -138,28 +166,28 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) {
printf("ADD\n");
return;

case L2_OP_FUNC_CALL:
printf("FUNC_CALL %08x\n", ops[(*ptr)++]);
case L2_OP_FUNC_CALL_U4:
printf("FUNC_CALL %08x\n", read_u4le(ops, ptr));
return;

case L2_OP_FUNC_CALL_INFIX:
printf("FUNC_CALL_INFIX\n");
return;

case L2_OP_RJMP:
printf("RJMP %08x\n", ops[(*ptr)++]);
case L2_OP_RJMP_U4:
printf("RJMP %08x\n", read_u4le(ops, ptr));
return;

case L2_OP_STACK_FRAME_LOOKUP:
printf("STACK_FRAME_LOOKUP %08x\n", ops[(*ptr)++]);
case L2_OP_STACK_FRAME_LOOKUP_U4:
printf("STACK_FRAME_LOOKUP %08x\n", read_u4le(ops, ptr));
return;

case L2_OP_STACK_FRAME_SET:
printf("STACK_FRAME_SET %08x\n", ops[(*ptr)++]);
case L2_OP_STACK_FRAME_SET_U4:
printf("STACK_FRAME_SET %08x\n", read_u4le(ops, ptr));
return;

case L2_OP_STACK_FRAME_REPLACE:
printf("STACK_FRAME_REPLACE %08x\n", ops[(*ptr)++]);
case L2_OP_STACK_FRAME_REPLACE_U4:
printf("STACK_FRAME_REPLACE %08x\n", read_u4le(ops, ptr));
return;

case L2_OP_RET:
@@ -170,52 +198,48 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) {
printf("ALLOC_NONE\n");
return;

case L2_OP_ALLOC_ATOM:
printf("ALLOC_ATOM %08x\n", ops[(*ptr)++]);
case L2_OP_ALLOC_ATOM_U4:
printf("ALLOC_ATOM %08x\n", read_u4le(ops, ptr));
return;

case L2_OP_ALLOC_REAL:
{
l2_word w1 = ops[(*ptr)++];
l2_word w2 = ops[(*ptr)++];
printf("ALLOC_REAL %08x %08x\n", w1, w2);
}
case L2_OP_ALLOC_REAL_D8:
printf("ALLOC_REAL %f\n", read_d8le(ops, ptr));
return;

case L2_OP_ALLOC_BUFFER_STATIC:
case L2_OP_ALLOC_BUFFER_STATIC_U4:
{
l2_word w1 = ops[(*ptr)++];
l2_word w2 = ops[(*ptr)++];
l2_word w1 = read_u4le(ops, ptr);
l2_word w2 = read_u4le(ops, ptr);;
printf("ALLOC_BUFFER_STATIC %08x %08x\n", w1, w2);
}
return;

case L2_OP_ALLOC_ARRAY:
printf("ALLOC_ARRAY %08x\n", ops[(*ptr)++]);
case L2_OP_ALLOC_ARRAY_U4:
printf("ALLOC_ARRAY_U4 %08x\n", read_u4le(ops, ptr));
return;

case L2_OP_ALLOC_NAMESPACE:
printf("ALLOC_NAMESPACE\n");
return;

case L2_OP_ALLOC_FUNCTION:
printf("ALLOC_FUNCTION %08x\n", ops[(*ptr)++]);
case L2_OP_ALLOC_FUNCTION_U4:
printf("ALLOC_FUNCTION_U4 %08x\n", read_u4le(ops, ptr));
return;

case L2_OP_NAMESPACE_SET:
printf("NAMESPACE_SET %08x\n", ops[(*ptr)++]);
case L2_OP_NAMESPACE_SET_U4:
printf("NAMESPACE_SET_U4 %08x\n", read_u4le(ops, ptr));
return;

case L2_OP_NAMESPACE_LOOKUP:
printf("NAMESPACE_LOOKUP %08x\n", ops[(*ptr)++]);
case L2_OP_NAMESPACE_LOOKUP_U4:
printf("NAMESPACE_LOOKUP_U4 %08x\n", read_u4le(ops, ptr));
return;

case L2_OP_ARRAY_LOOKUP:
printf("ARRAY_LOOKUP %08x\n", ops[(*ptr)++]);
case L2_OP_ARRAY_LOOKUP_U4:
printf("ARRAY_LOOKUP_U4 %08x\n", read_u4le(ops, ptr));
return;

case L2_OP_ARRAY_SET:
printf("ARRAY_SET %08x\n", ops[(*ptr)++]);
printf("ARRAY_SET %08x\n", read_u4le(ops, ptr));
return;

case L2_OP_DYNAMIC_LOOKUP:
@@ -241,7 +265,7 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) {
printf("\n");
}

void l2_vm_print_bytecode(l2_word *ops, size_t opcount) {
void l2_vm_print_bytecode(unsigned char *ops, size_t opcount) {
size_t ptr = 0;
while (ptr < opcount) {
printf("%04zu ", ptr);

+ 58
- 38
lib/vm/vm.c View File

@@ -31,13 +31,6 @@ static l2_word alloc_val(struct l2_vm *vm) {
return (l2_word)id;
}

static double u32s_to_double(uint32_t high, uint32_t low) {
double d;
uint64_t num = (uint64_t)high << 32 | (uint64_t)low;
memcpy(&d, &num, sizeof(num));
return d;
}

static void gc_mark_array(struct l2_vm *vm, struct l2_vm_value *val);
static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val);

@@ -149,7 +142,7 @@ const char *l2_value_type_name(enum l2_value_type typ) {
return "(unknown)";
}

void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) {
void l2_vm_init(struct l2_vm *vm, unsigned char *ops, size_t opslen) {
if (!stdio_inited) {
std_output.w.write = l2_io_file_write;
std_output.f = stdout;
@@ -164,7 +157,7 @@ void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) {
vm->halted = 0;
vm->gc_scheduled = 0;
vm->ops = ops;
vm->opcount = opcount;
vm->opslen = opslen;
vm->iptr = 0;
vm->sptr = 0;
vm->fsptr = 0;
@@ -375,6 +368,35 @@ static void call_func(
vm->iptr = func->func.pos;
}

static l2_word read_u4le(struct l2_vm *vm) {
unsigned char *data = &vm->ops[vm->iptr];
l2_word ret =
(l2_word)data[0] |
(l2_word)data[1] << 8 |
(l2_word)data[2] << 16 |
(l2_word)data[3] << 24;
vm->iptr += 4;
return ret;
}

static double read_d8le(struct l2_vm *vm) {
unsigned char *data = &vm->ops[vm->iptr];
uint64_t integer = 0 |
(uint64_t)data[0] |
(uint64_t)data[1] << 8 |
(uint64_t)data[2] << 16 |
(uint64_t)data[3] << 24 |
(uint64_t)data[4] << 32 |
(uint64_t)data[5] << 40 |
(uint64_t)data[6] << 48 |
(uint64_t)data[7] << 56;

double num;
memcpy(&num, &integer, 8);
vm->iptr += 8;
return num;
}

void l2_vm_step(struct l2_vm *vm) {
enum l2_opcode opcode = (enum l2_opcode)vm->ops[vm->iptr++];

@@ -410,9 +432,9 @@ void l2_vm_step(struct l2_vm *vm) {
vm->sptr -= 1;
break;

case L2_OP_FUNC_CALL:
case L2_OP_FUNC_CALL_U4:
{
l2_word argc = vm->ops[vm->iptr++];
l2_word argc = read_u4le(vm);
vm->sptr -= argc;
l2_word *argv = vm->stack + vm->sptr;

@@ -421,30 +443,30 @@ void l2_vm_step(struct l2_vm *vm) {
}
break;

case L2_OP_RJMP:
vm->iptr += vm->ops[vm->iptr] + 1;
case L2_OP_RJMP_U4:
vm->iptr += read_u4le(vm) + 1;
break;

case L2_OP_STACK_FRAME_LOOKUP:
case L2_OP_STACK_FRAME_LOOKUP_U4:
{
l2_word key = vm->ops[vm->iptr++];
l2_word key = read_u4le(vm);
struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns];
vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, ns, key);
}
break;

case L2_OP_STACK_FRAME_SET:
case L2_OP_STACK_FRAME_SET_U4:
{
l2_word key = vm->ops[vm->iptr++];
l2_word key = read_u4le(vm);
l2_word val = vm->stack[vm->sptr - 1];
struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns];
l2_vm_namespace_set(ns, key, val);
}
break;

case L2_OP_STACK_FRAME_REPLACE:
case L2_OP_STACK_FRAME_REPLACE_U4:
{
l2_word key = vm->ops[vm->iptr++];
l2_word key = read_u4le(vm);
l2_word val = vm->stack[vm->sptr - 1];
struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns];
l2_vm_namespace_replace(vm, ns, key, val); // TODO: error if returns -1
@@ -467,29 +489,27 @@ void l2_vm_step(struct l2_vm *vm) {
vm->stack[vm->sptr++] = 0;
break;

case L2_OP_ALLOC_ATOM:
case L2_OP_ALLOC_ATOM_U4:
word = alloc_val(vm);
vm->values[word].flags = L2_VAL_TYPE_ATOM;
vm->values[word].atom = vm->ops[vm->iptr++];
vm->values[word].atom = read_u4le(vm);
vm->stack[vm->sptr++] = word;
break;

case L2_OP_ALLOC_REAL:
case L2_OP_ALLOC_REAL_D8:
{
word = alloc_val(vm);
l2_word high = vm->ops[vm->iptr++];
l2_word low = vm->ops[vm->iptr++];
vm->values[word].flags = L2_VAL_TYPE_REAL;
vm->values[word].real = u32s_to_double(high, low);
vm->values[word].real = read_d8le(vm);
vm->stack[vm->sptr++] = word;
}
break;

case L2_OP_ALLOC_BUFFER_STATIC:
case L2_OP_ALLOC_BUFFER_STATIC_U4:
{
word = alloc_val(vm);
l2_word length = vm->ops[vm->iptr++];
l2_word offset = vm->ops[vm->iptr++];
l2_word length = read_u4le(vm);
l2_word offset = read_u4le(vm);
vm->values[word].flags = L2_VAL_TYPE_BUFFER;
vm->values[word].buffer = malloc(sizeof(struct l2_vm_buffer) + length);
vm->values[word].buffer->len = length;
@@ -501,9 +521,9 @@ void l2_vm_step(struct l2_vm *vm) {
}
break;

case L2_OP_ALLOC_ARRAY:
case L2_OP_ALLOC_ARRAY_U4:
{
l2_word count = vm->ops[vm->iptr++];
l2_word count = read_u4le(vm);
l2_word arr_id = alloc_val(vm);
struct l2_vm_value *arr = &vm->values[arr_id];
arr->flags = L2_VAL_TYPE_ARRAY;
@@ -533,35 +553,35 @@ void l2_vm_step(struct l2_vm *vm) {
vm->sptr += 1;
break;

case L2_OP_ALLOC_FUNCTION:
case L2_OP_ALLOC_FUNCTION_U4:
word = alloc_val(vm);
vm->values[word].flags = L2_VAL_TYPE_FUNCTION;
vm->values[word].func.pos = vm->ops[vm->iptr++];
vm->values[word].func.pos = read_u4le(vm);
vm->values[word].func.ns = vm->fstack[vm->fsptr - 1].ns;
vm->stack[vm->sptr] = word;
vm->sptr += 1;
break;

case L2_OP_NAMESPACE_SET:
case L2_OP_NAMESPACE_SET_U4:
{
l2_word key = vm->ops[vm->iptr++];
l2_word key = read_u4le(vm);
l2_word val = vm->stack[vm->sptr - 1];
l2_word ns = vm->stack[vm->sptr - 2];
l2_vm_namespace_set(&vm->values[ns], key, val);
}
break;

case L2_OP_NAMESPACE_LOOKUP:
case L2_OP_NAMESPACE_LOOKUP_U4:
{
l2_word key = vm->ops[vm->iptr++];
l2_word key = read_u4le(vm);
l2_word ns = vm->stack[--vm->sptr];
vm->stack[vm->sptr++] = l2_vm_namespace_get(vm, &vm->values[ns], key);
}
break;

case L2_OP_ARRAY_LOOKUP:
case L2_OP_ARRAY_LOOKUP_U4:
{
l2_word key = vm->ops[vm->iptr++];
l2_word key = read_u4le(vm);
l2_word arr = vm->stack[--vm->sptr];
// TODO: Error if out of bounds or incorrect type
vm->stack[vm->sptr++] = vm->values[arr].array->data[key];

Loading…
Cancel
Save