@@ -69,6 +69,11 @@ enum l2_opcode { | |||
L2_OP_RJMP_U4, | |||
L2_OP_RJMP_U1, | |||
/* Get the arguments array from the stack frame | |||
* Push <arguments array> | |||
*/ | |||
L2_OP_STACK_FRAME_GET_ARGS, | |||
/* | |||
* Look up a value from the current stack frame; stack_frame_lookup <key> | |||
* Find <val> in stack frame using <key> |
@@ -45,6 +45,7 @@ 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_dynamic_lookup(struct l2_generator *gen); | |||
void l2_gen_dynamic_set(struct l2_generator *gen); | |||
void l2_gen_stack_frame_get_args(struct l2_generator *gen); | |||
void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident); | |||
void l2_gen_stack_frame_lookup_copy(struct l2_generator *gen, char *ident); | |||
void l2_gen_stack_frame_set(struct l2_generator *gen, char **ident); |
@@ -99,6 +99,7 @@ struct l2_vm_stack_frame { | |||
l2_word ns; | |||
l2_word sptr; | |||
l2_word retptr; | |||
l2_word args; | |||
}; | |||
l2_word l2_vm_namespace_get(struct l2_vm *vm, struct l2_vm_value *ns, l2_word key); |
@@ -289,6 +289,10 @@ void l2_gen_dynamic_set(struct l2_generator *gen) { | |||
put(gen, L2_OP_DYNAMIC_SET); | |||
} | |||
void l2_gen_stack_frame_get_args(struct l2_generator *gen) { | |||
put(gen, L2_OP_STACK_FRAME_GET_ARGS); | |||
} | |||
void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident) { | |||
size_t atom_id = l2_strset_put(&gen->atomset, ident); | |||
if (atom_id <= 0xff) { |
@@ -105,10 +105,6 @@ static int parse_function_literal_impl( | |||
l2_trace_scope("function literal"); | |||
// '{' and EOL already skipped by parse_object_or_function_literal | |||
// The arguments array will be at the top of the stack | |||
char *ident = "$"; | |||
l2_gen_stack_frame_set_copy(gen, ident); | |||
int first = 1; | |||
while (1) { | |||
if (l2_token_get_kind(l2_lexer_peek(lexer, 1)) == L2_TOK_CLOSE_BRACE) { | |||
@@ -258,12 +254,17 @@ static int parse_arg_level_expression_base( | |||
l2_trace_scope("ident"); | |||
l2_trace("ident '%s'", l2_token_get_str(tok)); | |||
struct l2_token_value ident = l2_token_extract_val(tok); | |||
l2_lexer_consume(lexer); // ident | |||
if (ident.flags & L2_TOK_SMALL) { | |||
l2_gen_stack_frame_lookup_copy(gen, ident.strbuf); | |||
if (strcmp(l2_token_get_str(tok), "$") == 0) { | |||
l2_lexer_consume(lexer); // ident | |||
l2_gen_stack_frame_get_args(gen); | |||
} else { | |||
l2_gen_stack_frame_lookup(gen, &ident.str); | |||
l2_lexer_consume(lexer); // ident | |||
if (ident.flags & L2_TOK_SMALL) { | |||
l2_gen_stack_frame_lookup_copy(gen, ident.strbuf); | |||
} else { | |||
l2_gen_stack_frame_lookup(gen, &ident.str); | |||
} | |||
} | |||
} else if (l2_token_get_kind(tok) == L2_TOK_NUMBER) { | |||
l2_trace_scope("number literal"); |
@@ -145,8 +145,9 @@ void l2_vm_print_stack(struct l2_vm *vm) { | |||
void l2_vm_print_fstack(struct l2_vm *vm) { | |||
for (l2_word i = 0; i < vm->fsptr; ++i) { | |||
printf(" %i: %i, ret %i, stack base %u\n", | |||
i, vm->fstack[i].ns, (int)vm->fstack[i].retptr, vm->fstack[i].sptr); | |||
printf(" %i: %i, ret %i, stack base %u, args %u\n", | |||
i, vm->fstack[i].ns, (int)vm->fstack[i].retptr, | |||
vm->fstack[i].sptr, vm->fstack[i].args); | |||
} | |||
} | |||
@@ -192,6 +193,10 @@ void l2_vm_print_op(unsigned char *ops, size_t opcount, size_t *ptr) { | |||
printf("RJMP %u\n", read_u1le(ops, ptr)); | |||
return; | |||
case L2_OP_STACK_FRAME_GET_ARGS: | |||
printf("STACK_FRAME_GET_ARGS\n"); | |||
return; | |||
case L2_OP_STACK_FRAME_LOOKUP_U4: | |||
printf("STACK_FRAME_LOOKUP %u\n", read_u4le(ops, ptr)); | |||
return; |
@@ -230,6 +230,7 @@ void l2_vm_init(struct l2_vm *vm, unsigned char *ops, size_t opslen) { | |||
vm->fstack[vm->fsptr].ns = builtins; | |||
vm->fstack[vm->fsptr].retptr = 0; | |||
vm->fstack[vm->fsptr].sptr = 0; | |||
vm->fstack[vm->fsptr].args = 0; | |||
vm->fsptr += 1; | |||
// Need to allocate a root namespace | |||
@@ -240,6 +241,7 @@ void l2_vm_init(struct l2_vm *vm, unsigned char *ops, size_t opslen) { | |||
vm->fstack[vm->fsptr].ns = root; | |||
vm->fstack[vm->fsptr].retptr = ~(l2_word)0; | |||
vm->fstack[vm->fsptr].sptr = 0; | |||
vm->fstack[vm->fsptr].args = 0; | |||
vm->fsptr += 1; | |||
// None is always at 0 | |||
@@ -341,6 +343,7 @@ size_t l2_vm_gc(struct l2_vm *vm) { | |||
// builtins live, and they aren't sweeped anyways | |||
for (l2_word fsptr = 1; fsptr < vm->fsptr; ++fsptr) { | |||
gc_mark(vm, vm->fstack[fsptr].ns); | |||
gc_mark(vm, vm->fstack[fsptr].args); | |||
} | |||
return gc_sweep(vm); | |||
@@ -444,9 +447,6 @@ static void after_func_return(struct l2_vm *vm) { | |||
} | |||
static void call_func_with_args(struct l2_vm *vm, l2_word func_id, l2_word args_id) { | |||
l2_word stack_base = vm->sptr; | |||
vm->stack[vm->sptr++] = args_id; | |||
l2_word ns_id = alloc_val(vm); | |||
struct l2_vm_value *func = &vm->values[func_id]; // func might be stale after alloc_val | |||
vm->values[ns_id].extra.ns_parent = func->func.ns; | |||
@@ -454,10 +454,17 @@ static void call_func_with_args(struct l2_vm *vm, l2_word func_id, l2_word args_ | |||
vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE; | |||
vm->fstack[vm->fsptr].ns = ns_id; | |||
vm->fstack[vm->fsptr].retptr = vm->iptr; | |||
vm->fstack[vm->fsptr].sptr = stack_base; | |||
vm->fstack[vm->fsptr].sptr = vm->sptr; | |||
vm->fstack[vm->fsptr].args = args_id; | |||
vm->fsptr += 1; | |||
vm->iptr = func->func.pos; | |||
// We need one value as a buffer between the previous stack frame and the new. | |||
// This is mostly due to the way continuations are handled. | |||
// This wouldn't be necessary if continuations were stored in the stack | |||
// frame struct rather than as a value on the stack. | |||
vm->stack[vm->sptr++] = vm->knone; | |||
} | |||
// The 'call_func' function assumes that all relevant values have been popped off | |||
@@ -596,6 +603,10 @@ void l2_vm_step(struct l2_vm *vm) { | |||
case L2_OP_RJMP_U1: { X(read_u1le); } break; | |||
#undef X | |||
case L2_OP_STACK_FRAME_GET_ARGS: | |||
vm->stack[vm->sptr++] = vm->fstack[vm->fsptr - 1].args; | |||
break; | |||
#define X(read) \ | |||
l2_word key = read(vm); \ | |||
struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; \ |