Преглед на файлове

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 години
родител
ревизия
82c92b26b9
променени са 10 файла, в които са добавени 179 реда и са изтрити 243 реда
  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 Целия файл

@@ -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 Целия файл

@@ -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 Целия файл

@@ -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 Целия файл

@@ -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 Целия файл

@@ -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 Целия файл

@@ -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 Целия файл

@@ -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 Целия файл

@@ -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 Целия файл

@@ -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 Целия файл

@@ -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…
Отказ
Запис