| L2_OP_RJMP_U4, | L2_OP_RJMP_U4, | ||||
| L2_OP_RJMP_U1, | 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> | * Look up a value from the current stack frame; stack_frame_lookup <key> | ||||
| * Find <val> in stack frame using <key> | * Find <val> in stack frame using <key> |
| void l2_gen_array_set(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_lookup(struct l2_generator *gen); | ||||
| void l2_gen_dynamic_set(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(struct l2_generator *gen, char **ident); | ||||
| void l2_gen_stack_frame_lookup_copy(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); | void l2_gen_stack_frame_set(struct l2_generator *gen, char **ident); |
| l2_word ns; | l2_word ns; | ||||
| l2_word sptr; | l2_word sptr; | ||||
| l2_word retptr; | l2_word retptr; | ||||
| l2_word args; | |||||
| }; | }; | ||||
| l2_word l2_vm_namespace_get(struct l2_vm *vm, struct l2_vm_value *ns, l2_word key); | l2_word l2_vm_namespace_get(struct l2_vm *vm, struct l2_vm_value *ns, l2_word key); |
| put(gen, L2_OP_DYNAMIC_SET); | 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) { | void l2_gen_stack_frame_lookup(struct l2_generator *gen, char **ident) { | ||||
| size_t atom_id = l2_strset_put(&gen->atomset, ident); | size_t atom_id = l2_strset_put(&gen->atomset, ident); | ||||
| if (atom_id <= 0xff) { | if (atom_id <= 0xff) { |
| l2_trace_scope("function literal"); | l2_trace_scope("function literal"); | ||||
| // '{' and EOL already skipped by parse_object_or_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; | int first = 1; | ||||
| while (1) { | while (1) { | ||||
| if (l2_token_get_kind(l2_lexer_peek(lexer, 1)) == L2_TOK_CLOSE_BRACE) { | if (l2_token_get_kind(l2_lexer_peek(lexer, 1)) == L2_TOK_CLOSE_BRACE) { | ||||
| l2_trace_scope("ident"); | l2_trace_scope("ident"); | ||||
| l2_trace("ident '%s'", l2_token_get_str(tok)); | l2_trace("ident '%s'", l2_token_get_str(tok)); | ||||
| struct l2_token_value ident = l2_token_extract_val(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 { | } 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) { | } else if (l2_token_get_kind(tok) == L2_TOK_NUMBER) { | ||||
| l2_trace_scope("number literal"); | l2_trace_scope("number literal"); |
| void l2_vm_print_fstack(struct l2_vm *vm) { | void l2_vm_print_fstack(struct l2_vm *vm) { | ||||
| for (l2_word i = 0; i < vm->fsptr; ++i) { | 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); | |||||
| } | } | ||||
| } | } | ||||
| printf("RJMP %u\n", read_u1le(ops, ptr)); | printf("RJMP %u\n", read_u1le(ops, ptr)); | ||||
| return; | return; | ||||
| case L2_OP_STACK_FRAME_GET_ARGS: | |||||
| printf("STACK_FRAME_GET_ARGS\n"); | |||||
| return; | |||||
| case L2_OP_STACK_FRAME_LOOKUP_U4: | case L2_OP_STACK_FRAME_LOOKUP_U4: | ||||
| printf("STACK_FRAME_LOOKUP %u\n", read_u4le(ops, ptr)); | printf("STACK_FRAME_LOOKUP %u\n", read_u4le(ops, ptr)); | ||||
| return; | return; |
| vm->fstack[vm->fsptr].ns = builtins; | vm->fstack[vm->fsptr].ns = builtins; | ||||
| vm->fstack[vm->fsptr].retptr = 0; | vm->fstack[vm->fsptr].retptr = 0; | ||||
| vm->fstack[vm->fsptr].sptr = 0; | vm->fstack[vm->fsptr].sptr = 0; | ||||
| vm->fstack[vm->fsptr].args = 0; | |||||
| vm->fsptr += 1; | vm->fsptr += 1; | ||||
| // Need to allocate a root namespace | // Need to allocate a root namespace | ||||
| vm->fstack[vm->fsptr].ns = root; | vm->fstack[vm->fsptr].ns = root; | ||||
| vm->fstack[vm->fsptr].retptr = ~(l2_word)0; | vm->fstack[vm->fsptr].retptr = ~(l2_word)0; | ||||
| vm->fstack[vm->fsptr].sptr = 0; | vm->fstack[vm->fsptr].sptr = 0; | ||||
| vm->fstack[vm->fsptr].args = 0; | |||||
| vm->fsptr += 1; | vm->fsptr += 1; | ||||
| // None is always at 0 | // None is always at 0 | ||||
| // builtins live, and they aren't sweeped anyways | // builtins live, and they aren't sweeped anyways | ||||
| for (l2_word fsptr = 1; fsptr < vm->fsptr; ++fsptr) { | for (l2_word fsptr = 1; fsptr < vm->fsptr; ++fsptr) { | ||||
| gc_mark(vm, vm->fstack[fsptr].ns); | gc_mark(vm, vm->fstack[fsptr].ns); | ||||
| gc_mark(vm, vm->fstack[fsptr].args); | |||||
| } | } | ||||
| return gc_sweep(vm); | return gc_sweep(vm); | ||||
| } | } | ||||
| static void call_func_with_args(struct l2_vm *vm, l2_word func_id, l2_word args_id) { | 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); | l2_word ns_id = alloc_val(vm); | ||||
| struct l2_vm_value *func = &vm->values[func_id]; // func might be stale after alloc_val | 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; | vm->values[ns_id].extra.ns_parent = func->func.ns; | ||||
| vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE; | vm->values[ns_id].flags = L2_VAL_TYPE_NAMESPACE; | ||||
| vm->fstack[vm->fsptr].ns = ns_id; | vm->fstack[vm->fsptr].ns = ns_id; | ||||
| vm->fstack[vm->fsptr].retptr = vm->iptr; | 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->fsptr += 1; | ||||
| vm->iptr = func->func.pos; | 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 | // The 'call_func' function assumes that all relevant values have been popped off | ||||
| case L2_OP_RJMP_U1: { X(read_u1le); } break; | case L2_OP_RJMP_U1: { X(read_u1le); } break; | ||||
| #undef X | #undef X | ||||
| case L2_OP_STACK_FRAME_GET_ARGS: | |||||
| vm->stack[vm->sptr++] = vm->fstack[vm->fsptr - 1].args; | |||||
| break; | |||||
| #define X(read) \ | #define X(read) \ | ||||
| l2_word key = read(vm); \ | l2_word key = read(vm); \ | ||||
| struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; \ | struct l2_vm_value *ns = &vm->values[vm->fstack[vm->fsptr - 1].ns]; \ |