diff --git a/src/resume.c b/src/resume.c index 086fb85..99d4357 100644 --- a/src/resume.c +++ b/src/resume.c @@ -114,6 +114,8 @@ static cJSON *funcall_to_json(struct function_call *call) cJSON_AddNumberToObject(json, "return-address", call->return_address); cJSON_AddNumberToObject(json, "local-page", call->page_slot); cJSON_AddNumberToObject(json, "struct-page", call->struct_page); + if (call->delegate >= 0) + cJSON_AddNumberToObject(json, "delegate", call->delegate); return json; } @@ -266,8 +268,20 @@ static void alloc_heap_slot(int slot) heap_free_ptr++; } +struct delegate_list { + int *slots; + int n; +}; + +void delegate_list_add(struct delegate_list *list, int slot) +{ + list->slots = xrealloc_array(list->slots, list->n, list->n+1, sizeof(int)); + list->slots[list->n++] = slot; +} + static void load_heap(cJSON *json) { + struct delegate_list delegates = {0}; delete_heap(); cJSON *item; @@ -287,6 +301,8 @@ static void load_heap(cJSON *json) load_string(slot, value); } else if (cJSON_IsObject(value)) { load_page(slot, value); + if (heap[slot].page->type == DELEGATE_PAGE) + delegate_list_add(&delegates, slot); } else if (cJSON_IsNull(value)) { heap[slot].type = VM_PAGE; heap[slot].page = NULL; @@ -294,6 +310,13 @@ static void load_heap(cJSON *json) invalid_save_data("Invalid heap data"); } } + + for (int i = 0; i < delegates.n; i++) { + int slot = delegates.slots[i]; + struct page *page = heap_get_delegate_page(slot); + vm_register_delegate_structs(page, slot); + } + free(delegates.slots); } static void load_call_stack(cJSON *json) @@ -302,11 +325,13 @@ static void load_call_stack(cJSON *json) cJSON *item; cJSON_ArrayForEach(item, json) { type_check(cJSON_Object, item); + cJSON *delegate = cJSON_GetObjectItem(item, "delegate"); call_stack[call_stack_ptr++] = (struct function_call) { .fno = type_check(cJSON_Number, cJSON_GetObjectItem(item, "function"))->valueint, .return_address = type_check(cJSON_Number, cJSON_GetObjectItem(item, "return-address"))->valueint, .page_slot = type_check(cJSON_Number, cJSON_GetObjectItem(item, "local-page"))->valueint, - .struct_page = type_check(cJSON_Number, cJSON_GetObjectItem(item, "struct-page"))->valueint + .struct_page = type_check(cJSON_Number, cJSON_GetObjectItem(item, "struct-page"))->valueint, + .delegate = delegate ? type_check(cJSON_Number, delegate)->valueint : -1 }; } } diff --git a/src/vm.c b/src/vm.c index e8f9eac..2773ec7 100644 --- a/src/vm.c +++ b/src/vm.c @@ -239,7 +239,7 @@ int vm_copy_page(struct page *page) return slot; } -static void register_delegate_structs(struct page *dg, int dg_i) +void vm_register_delegate_structs(struct page *dg, int dg_i) { for (int i = 0; i < dg->nr_vars; i += 2) { if (dg->values[i].i < 0) @@ -254,7 +254,7 @@ int vm_copy_delegate_page(int dg_i) int slot = vm_copy_page(page); if (page) { - register_delegate_structs(page, slot); + vm_register_delegate_structs(page, slot); } return slot; @@ -316,7 +316,8 @@ static void scenario_call(int slot) .call_address = instr_ptr, .return_address = VM_RETURN, .page_slot = slot, - .struct_page = -1 + .struct_page = -1, + .delegate = -1, }; call_stack_ptr = 1; instr_ptr = ain->functions[fno].address; @@ -340,7 +341,8 @@ static int _function_call(int fno, int return_address) .call_address = instr_ptr, .return_address = return_address, .page_slot = slot, - .struct_page = -1 + .struct_page = -1, + .delegate = -1, }; // initialize local variables for (int i = f->nr_args; i < f->nr_vars; i++) { @@ -378,10 +380,8 @@ static void method_call(int fno, int return_address) static void vm_execute(void); -static void delegate_call(int dg_no) +static void delegate_call(int dg_no, int return_address) { - size_t saved_ip = instr_ptr; - // stack: [arg0, ..., dg_page, dg_index] int dg_page = stack_peek(1).i; int dg_index = stack_peek(0).i; @@ -389,7 +389,7 @@ static void delegate_call(int dg_no) int obj, fun; delegate_get(dg_page, dg_index, &obj, &fun); - int slot = _function_call(fun, VM_RETURN); + int slot = _function_call(fun, return_address); // copy arguments into local page struct ain_function_type *dg = &ain->delegates[dg_no]; @@ -399,8 +399,7 @@ static void delegate_call(int dg_no) } call_stack[call_stack_ptr-1].struct_page = obj; - vm_execute(); - instr_ptr = saved_ip; + call_stack[call_stack_ptr-1].delegate = dg_no; } void vm_call(int fno, int struct_page) @@ -420,6 +419,14 @@ static void function_return(void) { heap_unref(call_stack[call_stack_ptr-1].page_slot); instr_ptr = call_stack[call_stack_ptr-1].return_address; + if (call_stack[call_stack_ptr-1].delegate >= 0) { + const int dg = call_stack[call_stack_ptr-1].delegate; + if (ain->delegates[dg].return_type.data != AIN_VOID) { + stack[stack_ptr-2].i++; + } else { + stack[stack_ptr-1].i++; + } + } call_stack_ptr--; } @@ -2134,13 +2141,7 @@ static enum opcode execute_instruction(enum opcode opcode) if (ain->delegates[dg].return_type.data != AIN_VOID) { stack_pop(); } - delegate_call(dg); - if (ain->delegates[dg].return_type.data != AIN_VOID) { - stack[stack_ptr-2].i++; - } else { - stack[stack_ptr-1].i++; - } - instr_ptr += 10; + delegate_call(dg, instr_ptr + instruction_width(DG_CALL)); } else { // call finished: clean up stack and jump to return address union vm_value r; @@ -2196,7 +2197,7 @@ static enum opcode execute_instruction(enum opcode opcode) struct page *new_dg = copy_page(set); delete_page(dst_i); heap_set_page(dst_i, new_dg); - register_delegate_structs(new_dg, dst_i); + vm_register_delegate_structs(new_dg, dst_i); stack_push(set_i); break; } diff --git a/subprojects/libsys4 b/subprojects/libsys4 index 918fc7d..22fdbf0 160000 --- a/subprojects/libsys4 +++ b/subprojects/libsys4 @@ -1 +1 @@ -Subproject commit 918fc7d0c1d35cdfc3c2a694bb14e5971a8df95b +Subproject commit 22fdbf0b4b63704818abdee3c8af7574ddc0e10e