Browse Source

rework bytecode and stacks

Instructions now take their static arguments in the bytecode directly
instead of from the stack. The return address is now moved into a
separate frame stack. That means the only thing in the main stack is now
variable references. That means we can mark every variable which is
currently on the stack during a GC; even variables which aren't referred
to from a namespace.

As a result, a GC can happen before or after any instruction without
having to worry. The VM should also be faster, and the bytecode should
be smaller, due to fewer instructions.
master
Martin Dørum 3 years ago
parent
commit
82c92b26b9
10 changed files with 179 additions and 243 deletions
  1. 35
    67
      include/lang2/bytecode.h
  2. 4
    4
      include/lang2/gen/gen.h
  3. 1
    1
      include/lang2/vm/print.h
  4. 7
    2
      include/lang2/vm/vm.h
  5. 26
    41
      lib/gen/gen.c
  6. 8
    10
      lib/parse/parse.c
  7. 33
    39
      lib/vm/print.c
  8. 55
    70
      lib/vm/vm.c
  9. 1
    1
      test/src/eval.t.c
  10. 9
    8
      test/src/examples.t.c

+ 35
- 67
include/lang2/bytecode.h View File

@@ -11,19 +11,6 @@ enum l2_opcode {
*/
L2_OP_NOP,

/*
* Push a value to the stack.
* Push <word>
*/
L2_OP_PUSH,

/*
* Push a value to the stack.
* Push <word1>
* Push <word2>
*/
L2_OP_PUSH_2,

/*
* Discard the top element from the stack.
* Pop <word>
@@ -53,94 +40,80 @@ enum l2_opcode {
L2_OP_ADD,

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

/*
* Jump relative.
* Pop <word>
* Jump <word> words forwards
* Jump relative; rjmp <count>
* Jump <count> words forwards
*/
L2_OP_RJMP,

/*
* Look up a value from the current stack frame.
* Pop <word>
* Find <val> in stack frame using <word>
* Look up a value from the current stack frame; stack_frame_lookup <key>
* Find <val> in stack frame using <key>
* Push <val>
*/
L2_OP_STACK_FRAME_LOOKUP,

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

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

/*
* Return from a function.
* NSPop
* FSPop
* Pop (discard args array)
* Pop <word>
* Jump to <word>
* Jump to <return address>
*/
L2_OP_RET,

/*
* Allocate an atom from one word.
* Pop <word>
* Alloc integer <var> from <word>
* Put a reference to none at the top of the stack.
* Push 0
*/
L2_OP_ALLOC_NONE,

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

/*
* Allocate a real from two words.
* Pop <high>
* Pop <low>
* Allocate a real from two words; alloc_real <high> <low>
* Alloc real <var> from <high> << 32 | <low>
* Push <var>
*/
L2_OP_ALLOC_REAL,

/*
* Allocate a buffer from static data.
* Pop <word1>
* Pop <word2>
* Alloc buffer <var> with length=<word1>, offset=<word2>
* Allocate a buffer from static data; alloc_buffer_static <length> <offset>
* Alloc buffer <var> with <length> and <offset>
* Push <var>
*/
L2_OP_ALLOC_BUFFER_STATIC,

/*
* Allocate a zeroed buffer.
* Pop <word>
* Alloc buffer <var> with length=<word>
* Push <var>
*/
L2_OP_ALLOC_BUFFER_ZERO,

/*
* Allocate an array.
* Pop <count>
* Pop count times
* Allocate an array; <count>
* Pop <count> times
* Alloc array <var>
* Push <var>
*/
@@ -154,16 +127,14 @@ enum l2_opcode {
L2_OP_ALLOC_NAMESPACE,

/*
* Allocate a function.
* Pop <word>
* Allocate a function; alloc_function <pos>
* Alloc function <var> pointing to location <word>
* Push <var>
*/
L2_OP_ALLOC_FUNCTION,

/*
* Set a namespace's name to a value.
* Pop <key>
* Set a namespace's name to a value; namespace_set <key>
* Read <val>
* Read <ns>
* Assign <val> to <ns[<key>]>
@@ -171,29 +142,26 @@ enum l2_opcode {
L2_OP_NAMESPACE_SET,

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

/*
* Look up a value from an array.
* Pop <key>
* Read <val>
* Read <arr>
* Look up a value from an array; direct_array_lookup <key>
* Pop <val>
* Pop <arr>
* Assign <val> to <arr[<key>]>
*/
L2_OP_DIRECT_ARRAY_LOOKUP,
L2_OP_ARRAY_LOOKUP,

/*
* Set a value in an array.
* Pop <key>
* Set a value in an array; direct_array_set <key>
* Read <arr>
* Push <arr[<key>]>
*/
L2_OP_DIRECT_ARRAY_SET,
L2_OP_ARRAY_SET,

/*
* Halt execution.

+ 4
- 4
include/lang2/gen/gen.h View File

@@ -26,8 +26,8 @@ void l2_gen_halt(struct l2_generator *gen);
void l2_gen_rjmp(struct l2_generator *gen, l2_word len);
void l2_gen_pop(struct l2_generator *gen);
void l2_gen_swap_pop(struct l2_generator *gen);
void l2_gen_push(struct l2_generator *gen, l2_word word);
void l2_gen_ret(struct l2_generator *gen);
void l2_gen_none(struct l2_generator *gen);
void l2_gen_number(struct l2_generator *gen, double num);
void l2_gen_string(struct l2_generator *gen, char **str);
void l2_gen_atom(struct l2_generator *gen, char **ident);
@@ -36,11 +36,11 @@ void l2_gen_array(struct l2_generator *gen, l2_word count);
void l2_gen_namespace(struct l2_generator *gen);
void l2_gen_namespace_set(struct l2_generator *gen, char **ident);
void l2_gen_namespace_lookup(struct l2_generator *gen, char **ident);
void l2_gen_direct_array_lookup(struct l2_generator *gen, int number);
void l2_gen_direct_array_set(struct l2_generator *gen, int number);
void l2_gen_array_lookup(struct l2_generator *gen, int number);
void l2_gen_array_set(struct l2_generator *gen, int number);
void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident);
void l2_gen_stack_frame_set(struct l2_generator *gen, char **ident);
void l2_gen_stack_frame_replace(struct l2_generator *gen, char **ident);
void l2_gen_func_call(struct l2_generator *gen);
void l2_gen_func_call(struct l2_generator *gen, l2_word argc);

#endif

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

@@ -7,7 +7,7 @@ void l2_vm_print_val(struct l2_vm_value *val);
void l2_vm_print_state(struct l2_vm *vm);
void l2_vm_print_heap(struct l2_vm *vm);
void l2_vm_print_stack(struct l2_vm *vm);
void l2_vm_print_nstack(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);

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

@@ -75,6 +75,11 @@ struct l2_vm_namespace {
l2_word data[];
};

struct l2_vm_stack_frame {
l2_word namespace;
l2_word retptr;
};

l2_word l2_vm_namespace_get(struct l2_vm *vm, struct l2_vm_value *ns, l2_word key);
void l2_vm_namespace_set(struct l2_vm_value *ns, l2_word key, l2_word val);
int l2_vm_namespace_replace(struct l2_vm *vm, struct l2_vm_value *ns, l2_word key, l2_word val);
@@ -94,8 +99,8 @@ struct l2_vm {
l2_word stack[1024];
l2_word sptr;

l2_word nstack[1024];
l2_word nsptr;
struct l2_vm_stack_frame fstack[1024];
l2_word fsptr;
};

void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount);

+ 26
- 41
lib/gen/gen.c View File

@@ -36,9 +36,8 @@ void l2_gen_halt(struct l2_generator *gen) {
}

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

void l2_gen_pop(struct l2_generator *gen) {
@@ -49,29 +48,26 @@ void l2_gen_swap_pop(struct l2_generator *gen) {
put(gen, L2_OP_SWAP_POP);
}

void l2_gen_push(struct l2_generator *gen, l2_word word) {
put(gen, L2_OP_PUSH);
put(gen, word);
}

void l2_gen_ret(struct l2_generator *gen) {
put(gen, L2_OP_RET);
}

void l2_gen_none(struct l2_generator *gen) {
put(gen, L2_OP_ALLOC_NONE);
}

void l2_gen_number(struct l2_generator *gen, double num) {
uint64_t n;
memcpy(&n, &num, sizeof(num));
put(gen, L2_OP_PUSH_2);
put(gen, n);
put(gen, n >> 32);
put(gen, L2_OP_ALLOC_REAL);
put(gen, n >> 32);
put(gen, n);
}

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

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

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

gen->pos += aligned / sizeof(l2_word);
@@ -99,30 +94,26 @@ 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_PUSH_2);
put(gen, pos);
put(gen, len);
put(gen, L2_OP_ALLOC_BUFFER_STATIC);
put(gen, len);
put(gen, pos);
} else {
free(*str);
struct l2_generator_string *s = &gen->strings[id - 1];
put(gen, L2_OP_PUSH_2);
put(gen, s->pos);
put(gen, s->length);
put(gen, L2_OP_ALLOC_BUFFER_STATIC);
put(gen, s->length);
put(gen, s->pos);
}
}

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

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

void l2_gen_namespace(struct l2_generator *gen) {
@@ -131,51 +122,45 @@ 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_PUSH);
put(gen, atom_id);
put(gen, L2_OP_NAMESPACE_SET);
put(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_PUSH);
put(gen, atom_id);
put(gen, L2_OP_NAMESPACE_LOOKUP);
put(gen, atom_id);
}

void l2_gen_direct_array_lookup(struct l2_generator *gen, int number) {
put(gen, L2_OP_PUSH);
void l2_gen_array_lookup(struct l2_generator *gen, int number) {
put(gen, L2_OP_ARRAY_LOOKUP);
put(gen, number);
put(gen, L2_OP_DIRECT_ARRAY_LOOKUP);
}

void l2_gen_direct_array_set(struct l2_generator *gen, int number) {
put(gen, L2_OP_PUSH);
void l2_gen_array_set(struct l2_generator *gen, int number) {
put(gen, L2_OP_ARRAY_SET);
put(gen, number);
put(gen, L2_OP_DIRECT_ARRAY_SET);
}

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_PUSH);
put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_LOOKUP);
put(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_PUSH);
put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_SET);
put(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_PUSH);
put(gen, atom_id);
put(gen, L2_OP_STACK_FRAME_REPLACE);
put(gen, atom_id);
}

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

+ 8
- 10
lib/parse/parse.c View File

@@ -101,7 +101,7 @@ static int parse_function_literal_impl(

// All functions must put _something_ on the stack
if (first) {
l2_gen_push(gen, 0);
l2_gen_none(gen);
}

l2_gen_ret(gen);
@@ -119,7 +119,7 @@ static int parse_function_literal(
w.w.write = l2_io_mem_write;
gen->writer.w = &w.w;

// Generates three words; PUSH, 0, RJMP
// Generates two words; RJMP, 0
l2_gen_rjmp(gen, 0);

l2_word pos = gen->pos;
@@ -138,8 +138,8 @@ static int parse_function_literal(

// Due to the earlier gen_rjmp, the second word will be the argument to RJMP.
// Need to set it properly to skip the function body.
// The '- 3' is because we don't skip the PUSH, <count>, RJMP sequence.
ops[1] = opcount - 3;
// The '- 2' is because we don't skip the RJMP, <count> sequence.
ops[1] = opcount - 2;

l2_bufio_put_n(&gen->writer, ops, opcount * sizeof(l2_word));
free(w.mem);
@@ -284,8 +284,7 @@ static int parse_arg_level_expression(
l2_lexer_consume(lexer); // '('
l2_lexer_consume(lexer); // ')'

l2_gen_push(gen, 0);
l2_gen_func_call(gen);
l2_gen_func_call(gen, 0);
} else if (
tok->kind == L2_TOK_PERIOD && tok2->kind == L2_TOK_IDENT &&
tok3->kind == L2_TOK_EQUALS) {
@@ -320,14 +319,14 @@ static int parse_arg_level_expression(
return -1;
}

l2_gen_direct_array_set(gen, number);
l2_gen_array_set(gen, number);
l2_gen_swap_pop(gen);
} else if (tok->kind == L2_TOK_DOT_NUMBER) {
l2_trace_scope("direct array lookup");
int number = tok->v.integer;
l2_lexer_consume(lexer); // dot-number

l2_gen_direct_array_lookup(gen, number);
l2_gen_array_lookup(gen, number);
} else {
break;
}
@@ -351,8 +350,7 @@ static int parse_func_call_after_base(
} while (!tok_is_end(l2_lexer_peek(lexer, 1)));

// The 'argc' previous expressions were arguments, the one before that was the function
l2_gen_push(gen, argc);
l2_gen_func_call(gen);
l2_gen_func_call(gen, argc);

return 0;
}

+ 33
- 39
lib/vm/print.c View File

@@ -78,8 +78,8 @@ void l2_vm_print_state(struct l2_vm *vm) {
l2_vm_print_stack(vm);
printf("Heap:\n");
l2_vm_print_heap(vm);
printf("Namespace Stack:\n");
l2_vm_print_nstack(vm);
printf("Frame Stack:\n");
l2_vm_print_fstack(vm);
}

void l2_vm_print_heap(struct l2_vm *vm) {
@@ -97,9 +97,9 @@ void l2_vm_print_stack(struct l2_vm *vm) {
}
}

void l2_vm_print_nstack(struct l2_vm *vm) {
for (l2_word i = 0; i < vm->nsptr; ++i) {
printf(" %i: %i\n", i, vm->nstack[i]);
void l2_vm_print_fstack(struct l2_vm *vm) {
for (l2_word i = 0; i < vm->fsptr; ++i) {
printf(" %i: %i, ret %i\n", i, vm->fstack[i].namespace, vm->fstack[i].retptr);
}
}

@@ -119,20 +119,6 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) {
printf("NOP\n");
return;

case L2_OP_PUSH:
printf("PUSH ");
print_op_num(ops, opcount, (*ptr)++);
printf("\n");
return;

case L2_OP_PUSH_2:
printf("PUSH2 ");
print_op_num(ops, opcount, (*ptr)++);
printf(" ");
print_op_num(ops, opcount, (*ptr)++);
printf("\n");
return;

case L2_OP_POP:
printf("POP\n");
return;
@@ -150,47 +136,55 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) {
return;

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

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

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

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

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

case L2_OP_RET:
printf("RET\n");
return;

case L2_OP_ALLOC_NONE:
printf("ALLOC_NONE\n");
return;

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

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

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

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

case L2_OP_ALLOC_NAMESPACE:
@@ -198,23 +192,23 @@ void l2_vm_print_op(l2_word *ops, size_t opcount, size_t *ptr) {
return;

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

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

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

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

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

case L2_OP_HALT:

+ 55
- 70
lib/vm/vm.c View File

@@ -71,6 +71,10 @@ 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) {
if (val->extra.ns_parent != 0) {
gc_mark(vm, val->extra.ns_parent);
}

if (val->ns == NULL) {
return;
}
@@ -83,10 +87,6 @@ static void gc_mark_namespace(struct l2_vm *vm, struct l2_vm_value *val) {

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

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

static void gc_free(struct l2_vm *vm, l2_word id) {
@@ -140,7 +140,7 @@ void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) {
vm->opcount = opcount;
vm->iptr = 0;
vm->sptr = 0;
vm->nsptr = 0;
vm->fsptr = 0;

vm->values = NULL;
vm->valuessize = 0;
@@ -156,14 +156,18 @@ void l2_vm_init(struct l2_vm *vm, l2_word *ops, size_t opcount) {
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;
vm->fstack[vm->fsptr].namespace = builtins;
vm->fstack[vm->fsptr].retptr = 0;
vm->fsptr += 1;

// 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->nstack[vm->nsptr++] = root;
vm->fstack[vm->fsptr].namespace = root;
vm->fstack[vm->fsptr].retptr = 0;
vm->fsptr += 1;

// Define a C function variable for every builtin
l2_word id;
@@ -199,10 +203,12 @@ void l2_vm_free(struct l2_vm *vm) {
}

size_t l2_vm_gc(struct l2_vm *vm) {
for (l2_word nsptr = 0; nsptr < vm->nsptr; ++nsptr) {
struct l2_vm_value *val = &vm->values[vm->nstack[nsptr]];
val->flags |= L2_VAL_MARKED;
gc_mark_namespace(vm, val);
for (l2_word sptr = 0; sptr < vm->sptr; ++sptr) {
gc_mark(vm, vm->stack[sptr]);
}

for (l2_word fsptr = 0; fsptr < vm->fsptr; ++fsptr) {
gc_mark(vm, vm->fstack[fsptr].namespace);
}

return gc_sweep(vm);
@@ -222,19 +228,6 @@ void l2_vm_step(struct l2_vm *vm) {
case L2_OP_NOP:
break;

case L2_OP_PUSH:
vm->stack[vm->sptr] = vm->ops[vm->iptr];
vm->sptr += 1;
vm->iptr += 1;
break;

case L2_OP_PUSH_2:
vm->stack[vm->sptr] = vm->ops[vm->iptr];
vm->stack[vm->sptr + 1] = vm->ops[vm->iptr + 1];
vm->sptr += 2;
vm->iptr += 2;
break;

case L2_OP_POP:
vm->sptr -= 1;
break;
@@ -256,7 +249,7 @@ void l2_vm_step(struct l2_vm *vm) {

case L2_OP_FUNC_CALL:
{
l2_word argc = vm->stack[--vm->sptr];
l2_word argc = vm->ops[vm->iptr++];

l2_word arr_id = alloc_val(vm);
vm->values[arr_id].flags = L2_VAL_TYPE_ARRAY;
@@ -288,7 +281,6 @@ void l2_vm_step(struct l2_vm *vm) {
break;
}

vm->stack[vm->sptr++] = vm->iptr;
vm->stack[vm->sptr++] = arr_id;

l2_word ns_id = alloc_val(vm);
@@ -296,40 +288,40 @@ void l2_vm_step(struct l2_vm *vm) {
vm->values[ns_id].extra.ns_parent = func->func.namespace;
vm->values[ns_id].ns = NULL;
vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE;
vm->nstack[vm->nsptr++] = ns_id;
vm->fstack[vm->fsptr].namespace = ns_id;
vm->fstack[vm->fsptr].retptr = vm->iptr;
vm->fsptr += 1;

vm->iptr = func->func.pos;
}
break;

case L2_OP_RJMP:
word = vm->stack[vm->sptr - 1];
vm->sptr -= 1;
vm->iptr += word;
vm->iptr += vm->ops[vm->iptr++];
break;

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

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

case L2_OP_STACK_FRAME_REPLACE:
{
l2_word key = vm->stack[--vm->sptr];
l2_word key = vm->ops[vm->iptr++];
l2_word val = vm->stack[vm->sptr - 1];
struct l2_vm_value *ns = &vm->values[vm->nstack[vm->nsptr - 1]];
struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].namespace];
l2_vm_namespace_replace(vm, ns, key, val); // TODO: error if returns -1
}
break;
@@ -338,34 +330,39 @@ void l2_vm_step(struct l2_vm *vm) {
{
l2_word retval = vm->stack[--vm->sptr];
vm->sptr -= 1; // Discard arguments array
l2_word retaddr = vm->stack[--vm->sptr];
l2_word retptr = vm->fstack[--vm->fsptr].retptr;
vm->stack[vm->sptr++] = retval;
vm->nsptr -= 1; // Pop function stack frame
vm->iptr = retaddr;
vm->iptr = retptr;
}
break;

case L2_OP_ALLOC_NONE:
vm->stack[vm->sptr++] = 0;
break;

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

case L2_OP_ALLOC_REAL:
word = alloc_val(vm);
vm->values[word].flags = L2_VAL_TYPE_REAL;
vm->values[word].real = u32s_to_double(vm->stack[vm->sptr - 1], vm->stack[vm->sptr - 2]);
vm->sptr -= 2;
vm->stack[vm->sptr] = word;
vm->sptr += 1;
{
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->stack[vm->sptr++] = word;
}
break;

case L2_OP_ALLOC_BUFFER_STATIC:
{
word = alloc_val(vm);
l2_word length = vm->stack[--vm->sptr];
l2_word offset = vm->stack[--vm->sptr];
l2_word length = vm->ops[vm->iptr++];
l2_word offset = vm->ops[vm->iptr++];
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;
@@ -377,21 +374,9 @@ void l2_vm_step(struct l2_vm *vm) {
}
break;

case L2_OP_ALLOC_BUFFER_ZERO:
{
word = alloc_val(vm);
l2_word length = vm->stack[--vm->sptr];
vm->values[word].flags = L2_VAL_TYPE_BUFFER;
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;
}
break;

case L2_OP_ALLOC_ARRAY:
{
l2_word count = vm->stack[--vm->sptr];
l2_word count = vm->ops[vm->iptr++];
l2_word arr_id = alloc_val(vm);
struct l2_vm_value *arr = &vm->values[arr_id];
arr->flags = L2_VAL_TYPE_ARRAY;
@@ -424,15 +409,15 @@ void l2_vm_step(struct l2_vm *vm) {
case L2_OP_ALLOC_FUNCTION:
word = alloc_val(vm);
vm->values[word].flags = L2_VAL_TYPE_FUNCTION;
vm->values[word].func.pos = vm->stack[--vm->sptr];
vm->values[word].func.namespace = vm->nstack[vm->nsptr - 1];
vm->values[word].func.pos = vm->ops[vm->iptr++];
vm->values[word].func.namespace = vm->fstack[vm->fsptr - 1].namespace;
vm->stack[vm->sptr] = word;
vm->sptr += 1;
break;

case L2_OP_NAMESPACE_SET:
{
l2_word key = vm->stack[--vm->sptr];
l2_word key = vm->ops[vm->iptr++];
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);
@@ -441,24 +426,24 @@ void l2_vm_step(struct l2_vm *vm) {

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

case L2_OP_DIRECT_ARRAY_LOOKUP:
case L2_OP_ARRAY_LOOKUP:
{
l2_word key = vm->stack[--vm->sptr];
l2_word key = vm->ops[vm->iptr++];
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];
}
break;

case L2_OP_DIRECT_ARRAY_SET:
case L2_OP_ARRAY_SET:
{
l2_word key = vm->stack[--vm->sptr];
l2_word key = vm->ops[vm->iptr++];
l2_word val = vm->stack[vm->sptr - 1];
l2_word arr = vm->stack[vm->sptr - 2];
// TODO: Error if out of bounds or incorrect type

+ 1
- 1
test/src/eval.t.c View File

@@ -13,7 +13,7 @@ static struct l2_vm vm;

static struct l2_vm_value *var_lookup(const char *name) {
l2_word atom_id = l2_strset_get(&gen.atomset, name);
l2_word id = l2_vm_namespace_get(&vm, &vm.values[vm.nstack[1]], atom_id);
l2_word id = l2_vm_namespace_get(&vm, &vm.values[vm.fstack[1].namespace], atom_id);
return &vm.values[id];
}


+ 9
- 8
test/src/examples.t.c View File

@@ -110,8 +110,11 @@ static void check_impl(const char *name) {
l2_vm_init(&vm, (l2_word *)bytecode.mem, bytecode.len / sizeof(l2_word));
vm.std_output = &output.w;

l2_vm_run(&vm);
l2_vm_gc(&vm);
// Run a GC after every instruction to uncover potential GC issues
while (vm.ops[vm.iptr] != L2_OP_HALT) {
l2_vm_step(&vm);
l2_vm_gc(&vm);
}

l2_vm_free(&vm);
free(bytecode.mem);
@@ -122,15 +125,13 @@ static void check_impl(const char *name) {

#define check(name) do { \
snow_fail_update(); \
check_impl(name); \
test(name) { check_impl(name); } \
} while (0)

describe(exaples) {
test("examples") {
check("namespaces.l2");
check("arrays.l2");
check("functions.l2");
}
check("namespaces.l2");
check("arrays.l2");
check("functions.l2");

if (error_message != NULL) {
free(error_message);

Loading…
Cancel
Save