mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-09-25 00:17:56 +03:00
Fix ResumeSave/ResumeLoad bugs with delegates
When loading a delegate, the stored objects must be registered to it. Also, delegate_call cannot use vm_execute because the VM cannot be resumed from such a state. Incidentally, this means that ResumeSave cannot be called from within a constructor/destructor (since they also use vm_execute), but this is probably not a problem.
This commit is contained in:
+26
-1
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+1
-1
Submodule subprojects/libsys4 updated: 918fc7d0c1...22fdbf0b4b
Reference in New Issue
Block a user