Implement various SH_ instructions

Implement various shorthand instructions introduced in Alice 2010. This
is enough to get through the first scene in Haru Urare.
This commit is contained in:
Nunuhara Cabbage
2021-05-09 20:53:32 -07:00
parent 74230869ae
commit 2365fb3a01
6 changed files with 368 additions and 44 deletions
+2
View File
@@ -63,6 +63,8 @@ bool string_index_valid(int index);
struct page *heap_get_page(int index);
struct string *heap_get_string(int index);
void heap_set_page(int slot, struct page *page);
void heap_string_assign(int slot, struct string *string);
void heap_struct_assign(int lval, int rval);
int32_t heap_alloc_page(struct page *page);
int32_t heap_alloc_string(struct string *s);
+20
View File
@@ -61,6 +61,26 @@ struct page {
union vm_value values[];
};
static inline union vm_value page_get_var(struct page *page, int i)
{
#ifdef DEBUG_HEAP
if (i < 0 || i >= page->nr_vars)
VM_ERROR("Invalid page index: %d", i);
#endif
return page->values[i];
}
static inline void _page_set_var(struct page *page, int i, union vm_value v)
{
#ifdef DEBUG_HEAP
if (i < 0 || i >= page->nr_vars)
VM_ERROR("Invalid page index: %d", i);
#endif
page->values[i] = v;
}
#define page_set_var(page, i, v) _page_set_var(page, i, vm_value_cast(v))
// variables
union vm_value variable_initval(enum ain_data_type type);
void variable_fini(union vm_value v, enum ain_data_type type);
+40
View File
@@ -222,9 +222,49 @@ struct string *heap_get_string(int index)
void heap_set_page(int slot, struct page *page)
{
#ifdef DEBUG_HEAP
if (!page_index_valid(slot))
VM_ERROR("Invalid page index: %d", index);
#endif
heap[slot].page = page;
}
void heap_string_assign(int slot, struct string *string)
{
#ifdef DEBUG_HEAP
if (!string_index_valid(slot))
VM_ERROR("Tried to assign string to non-string slot");
#endif
if (heap[slot].s) {
free_string(heap[slot].s);
}
heap[slot].s = string_ref(string);
}
void heap_struct_assign(int lval, int rval)
{
if (lval == -1)
VM_ERROR("Assignment to null-pointer");
if (lval == rval)
return;
#ifdef DEBUG_HEAP
if (!page_index_valid(lval))
VM_ERROR("Invalid page index: %d", lval);
if (!page_index_valid(rval))
VM_ERROR("Invalid page index: %d", rval);
if (heap[lval].page && heap[lval].page->type != STRUCT_PAGE)
VM_ERROR("SR_ASSIGN to non-struct page");
if (heap[rval].page && heap[rval].page->type != STRUCT_PAGE)
VM_ERROR("SR_ASSIGN from non-struct page");
if (heap[lval].page && heap[rval].page && heap[lval].page->index != heap[rval].page->index)
VM_ERROR("SR_ASSIGN with different struct types");
#endif
if (heap[lval].page) {
delete_page(lval);
}
heap_set_page(lval, copy_page(heap[rval].page));
}
int32_t heap_alloc_string(struct string *s)
{
int slot = heap_alloc_slot(VM_STRING);
+1 -1
View File
@@ -191,7 +191,7 @@ void delete_page_vars(struct page *page)
void delete_page(int slot)
{
struct page *page = heap[slot].page;
struct page *page = heap_get_page(slot);
if (page->type == STRUCT_PAGE) {
delete_struct(page->index, slot);
}
+304 -42
View File
@@ -22,6 +22,7 @@
#include <time.h>
#include <errno.h>
#include <setjmp.h>
#include <assert.h>
#include <SDL.h> // for system.MsgBox
#include "system4.h"
@@ -158,9 +159,19 @@ static int32_t struct_page_slot(void)
return call_stack[call_stack_ptr-1].struct_page;
}
static union vm_value *struct_page(void)
static struct page *struct_page(void)
{
return heap[struct_page_slot()].page->values;
return heap[struct_page_slot()].page;
}
static union vm_value member_get(int varno)
{
return struct_page()->values[varno];
}
static void member_set(int varno, int32_t value)
{
struct_page()->values[varno].i = value;
}
static union vm_value stack_peek(int n)
@@ -221,10 +232,10 @@ union vm_value vm_copy(union vm_value v, enum ain_data_type type)
{
switch (type) {
case AIN_STRING:
return (union vm_value) { .i = vm_string_ref(heap[v.i].s) };
return (union vm_value) { .i = vm_string_ref(heap_get_string(v.i)) };
case AIN_STRUCT:
case AIN_ARRAY_TYPE:
return (union vm_value) { .i = vm_copy_page(heap[v.i].page) };
return (union vm_value) { .i = vm_copy_page(heap_get_page(v.i)) };
case AIN_REF_TYPE:
heap_ref(v.i);
return v;
@@ -360,7 +371,7 @@ static void system_call(enum syscall_code code)
case SYS_GLOBAL_SAVE: { // system.GlobalSave(string szKeyName, string szFileName)
int filename = stack_pop().i;
int keyname = stack_pop().i;
stack_push(save_globals(heap[keyname].s->text, heap[filename].s->text));
stack_push(save_globals(heap_get_string(keyname)->text, heap_get_string(filename)->text));
heap_unref(filename);
heap_unref(keyname);
break;
@@ -368,7 +379,7 @@ static void system_call(enum syscall_code code)
case SYS_GLOBAL_LOAD: { // system.GlobalLoad(string szKeyName, string szFileName)
int filename = stack_pop().i;
int keyname = stack_pop().i;
stack_push(load_globals(heap[keyname].s->text, heap[filename].s->text, NULL, NULL));
stack_push(load_globals(heap_get_string(keyname)->text, heap_get_string(filename)->text, NULL, NULL));
heap_unref(filename);
heap_unref(keyname);
break;
@@ -407,7 +418,7 @@ static void system_call(enum syscall_code code)
SDL_MESSAGEBOX_INFORMATION,
NULL,
"xsystem4",
str->text,
utf,
SDL_arraysize(buttons),
buttons,
NULL
@@ -434,7 +445,7 @@ static void system_call(enum syscall_code code)
case SYS_RESUME_LOAD: {
int filename_slot = stack_pop().i;
int key_slot = stack_pop().i;
vm_load_image(heap[key_slot].s->text, heap[filename_slot].s->text);
vm_load_image(heap_get_string(key_slot)->text, heap_get_string(filename_slot)->text);
//heap_unref(stack_pop().i);
//heap_unref(stack_pop().i);
stack_pop();
@@ -444,7 +455,7 @@ static void system_call(enum syscall_code code)
}
case SYS_EXISTS_FILE: { // system.ExistsFile(string szFileName)
int str = stack_pop().i;
char *path = unix_path(heap[str].s->text);
char *path = unix_path(heap_get_string(str)->text);
stack_push(file_exists(path));
heap_unref(str);
free(path);
@@ -498,7 +509,7 @@ static void system_call(enum syscall_code code)
}
case SYS_EXISTS_SAVE_FILE: {
int slot = stack_pop().i;
char *path = savedir_path(heap[slot].s->text);
char *path = savedir_path(heap_get_string(slot)->text);
stack_push(file_exists(path));
heap_unref(slot);
free(path);
@@ -538,7 +549,9 @@ static void system_call(enum syscall_code code)
int filename = stack_pop().i;
int keyname = stack_pop().i;
// FIXME: free ref'd array if allocated
heap_set_page(comment, vm_load_image_comments(heap[keyname].s->text, heap[filename].s->text, &success));
heap_set_page(comment, vm_load_image_comments(heap_get_string(keyname)->text,
heap_get_string(filename)->text,
&success));
heap_unref(filename);
heap_unref(keyname);
stack_push(success);
@@ -560,7 +573,10 @@ static void system_call(enum syscall_code code)
int groupname = stack_pop().i;
int filename = stack_pop().i;
int keyname = stack_pop().i;
stack_push(save_group(heap[keyname].s->text, heap[filename].s->text, heap[groupname].s->text, &n->i));
stack_push(save_group(heap_get_string(keyname)->text,
heap_get_string(filename)->text,
heap_get_string(groupname)->text,
&n->i));
heap_unref(groupname);
heap_unref(filename);
heap_unref(keyname);
@@ -571,7 +587,10 @@ static void system_call(enum syscall_code code)
int groupname = stack_pop().i;
int filename = stack_pop().i;
int keyname = stack_pop().i;
stack_push(load_globals(heap[keyname].s->text, heap[filename].s->text, heap[groupname].s->text, &n->i));
stack_push(load_globals(heap_get_string(keyname)->text,
heap_get_string(filename)->text,
heap_get_string(groupname)->text,
&n->i));
heap_unref(groupname);
heap_unref(filename);
heap_unref(keyname);
@@ -579,21 +598,21 @@ static void system_call(enum syscall_code code)
}
case SYS_DELETE_SAVE_FILE: { // system.DeleteSaveFile(string szFileName)
int filename = stack_pop().i;
stack_push(delete_save_file(heap[filename].s->text));
stack_push(delete_save_file(heap_get_string(filename)->text));
heap_unref(filename);
break;
}
case SYS_EXIST_FUNC: { // system.ExistFunc(string szFuncName)
int funcname = stack_pop().i;
stack_push(ain_get_function(ain, heap[funcname].s->text) > 0);
stack_push(ain_get_function(ain, heap_get_string(funcname)->text) > 0);
heap_unref(funcname);
break;
}
case SYS_COPY_SAVE_FILE: { // system.CopySaveFile(string szDestFileName, string szSourceFileName)
int src = stack_pop().i;
int dst = stack_pop().i;
char *u_src = savedir_path(heap[src].s->text);
char *u_dst = savedir_path(heap[dst].s->text);
char *u_src = savedir_path(heap_get_string(src)->text);
char *u_dst = savedir_path(heap_get_string(dst)->text);
stack_push(file_copy(u_src, u_dst));
free(u_src);
free(u_dst);
@@ -744,7 +763,7 @@ static enum opcode execute_instruction(enum opcode opcode)
break;
}
case SH_STRUCTREF: { // VARNO
stack_push(struct_page()[get_argument(0)]);
stack_push(member_get(get_argument(0)));
break;
}
case SH_LOCALASSIGN: { // VARNO, VALUE
@@ -777,9 +796,9 @@ static enum opcode execute_instruction(enum opcode opcode)
int src_var = stack_pop().i;
int src_page = stack_pop().i;
int dst_var = stack_pop().i;
int dst_page = stack_pop().i;
heap[dst_page].page->values[dst_var].i = src_page;
heap[dst_page].page->values[dst_var+1].i = src_var;
struct page *dst = heap_get_page(stack_pop().i);
page_set_var(dst, dst_var, src_page);
page_set_var(dst, dst_var+1, src_var);
stack_push(src_page);
stack_push(src_var);
break;
@@ -842,7 +861,7 @@ static enum opcode execute_instruction(enum opcode opcode)
// XXX: I am GUESSING that the VM pre-allocates the scenario function's
// local page here. It certainly pushes what appears to be a page
// index to the stack.
stack_push(alloc_scenario_page(heap[str].s->text));
stack_push(alloc_scenario_page(heap_get_string(str)->text));
heap_unref(str);
break;
}
@@ -883,7 +902,7 @@ static enum opcode execute_instruction(enum opcode opcode)
}
case STRSWITCH: {
int str = stack_pop().i;
exec_strswitch(get_argument(0), heap[str].s);
exec_strswitch(get_argument(0), heap_get_string(str));
heap_unref(str);
break;
}
@@ -892,8 +911,8 @@ static enum opcode execute_instruction(enum opcode opcode)
int file = stack_pop().i; // filename
int expr = stack_pop().i; // expression
if (!stack_pop().i) {
char *filename = sjis2utf(heap[file].s->text, heap[file].s->size);
char *value = sjis2utf(heap[expr].s->text, heap[expr].s->size);
char *filename = sjis2utf(heap_get_string(file)->text, heap[file].s->size);
char *value = sjis2utf(heap_get_string(expr)->text, heap[expr].s->size);
sys_message("Assertion failed at %s:%d: %s\n", filename, line, value);
free(filename);
free(value);
@@ -1285,17 +1304,14 @@ static enum opcode execute_instruction(enum opcode opcode)
case S_REF: {
// Dereference a reference to a string
int str = stack_pop_var()->i;
stack_push_string(string_ref(heap[str].s));
stack_push_string(string_ref(heap_get_string(str)));
break;
}
//case S_REFREF: // ???: why/how is this different from regular REFREF?
case S_ASSIGN: { // A = B
int rval = stack_peek(0).i;
int lval = stack_peek(1).i;
if (heap[lval].s) {
free_string(heap[lval].s);
}
heap[lval].s = string_ref(heap[rval].s);
heap_string_assign(lval, heap_get_string(rval));
// remove A from the stack, but leave B
stack_set(1, rval);
stack_pop();
@@ -1315,7 +1331,7 @@ static enum opcode execute_instruction(enum opcode opcode)
int b = stack_pop().i;
int a = stack_pop().i;
// TODO: can use string_append here?
stack_push_string(string_concatenate(heap[a].s, heap[b].s));
stack_push_string(string_concatenate(heap_get_string(a), heap_get_string(b)));
heap_unref(a);
heap_unref(b);
break;
@@ -1364,18 +1380,18 @@ static enum opcode execute_instruction(enum opcode opcode)
}
case S_LENGTH: {
int str = stack_pop_var()->i;
stack_push(sjis_count_char(heap[str].s->text));
stack_push(sjis_count_char(heap_get_string(str)->text));
break;
}
case S_LENGTH2: {
int str = stack_pop().i;
stack_push(sjis_count_char(heap[str].s->text));
stack_push(sjis_count_char(heap_get_string(str)->text));
heap_unref(str);
break;
}
case S_LENGTHBYTE: {
int str = stack_pop_var()->i;
stack_push(heap[str].s->size);
stack_push(heap_get_string(str)->size);
break;
}
case S_EMPTY: {
@@ -1449,7 +1465,7 @@ static enum opcode execute_instruction(enum opcode opcode)
//int functype = stack_pop().i;
stack_pop();
int str = stack_pop().i;
stack_pop_var()->i = get_function_by_name(heap[str].s->text);
stack_pop_var()->i = get_function_by_name(heap_get_string(str)->text);
stack_push(str);
break;
}
@@ -1457,7 +1473,7 @@ static enum opcode execute_instruction(enum opcode opcode)
case C_REF: {
int i = stack_pop().i;
int str = stack_pop().i;
stack_push(string_get_char(heap[str].s, i));
stack_push(string_get_char(heap_get_string(str), i));
break;
}
case C_ASSIGN: {
@@ -1483,12 +1499,7 @@ static enum opcode execute_instruction(enum opcode opcode)
stack_pop(); // struct type
int rval = stack_pop().i;
int lval = stack_pop().i;
if (lval == -1)
VM_ERROR("Assignment to null-pointer");
if (heap[lval].page) {
delete_page(lval);
}
heap_set_page(lval, copy_page(heap[rval].page));
heap_struct_assign(lval, rval);
stack_push(rval);
break;
}
@@ -1620,6 +1631,257 @@ static enum opcode execute_instruction(enum opcode opcode)
array_reverse(heap[array].page);
break;
}
//
// -- Shorthand Instructions (added in Alice 2010) ---
//
case SH_SR_ASSIGN: {
int rval = stack_pop_var()->i;
int lval = stack_pop().i;
heap_struct_assign(lval, rval);
break;
}
case SH_MEM_ASSIGN_LOCAL: {
member_set(get_argument(0), local_get(get_argument(1)).i);
break;
}
case A_NUMOF_GLOB_1: {
int array = global_get(get_argument(0)).i;
stack_push(array_numof(heap_get_page(array), 1));
break;
}
case A_NUMOF_STRUCT_1: {
int array = member_get(get_argument(0)).i;
stack_push(array_numof(heap_get_page(array), 1));
break;
}
case SH_MEM_ASSIGN_IMM: {
member_set(get_argument(0), get_argument(1));
break;
}
case SH_LOCALREFREF: {
stack_push(local_get(get_argument(0)));
stack_push(local_get(get_argument(0)+1));
break;
}
case SH_IF_LOC_LT_IMM: {
if (local_get(get_argument(0)).i < get_argument(1))
instr_ptr = get_argument(2);
else
instr_ptr += instruction_width(SH_IF_LOC_LT_IMM);
break;
}
case SH_IF_LOC_GE_IMM: {
if (local_get(get_argument(0)).i >= get_argument(1))
instr_ptr = get_argument(2);
else
instr_ptr += instruction_width(SH_IF_LOC_GE_IMM);
break;
}
case SH_LOCREF_ASSIGN_MEM: {
struct page *page = heap_get_page(local_get(get_argument(0)).i);
int index = local_get(get_argument(0)+1).i;
page_set_var(page, index, member_get(get_argument(1)));
break;
}
case PAGE_REF: {
struct page *page = heap_get_page(stack_pop().i);
stack_push(page_get_var(page, get_argument(0)));
break;
}
case SH_GLOBAL_ASSIGN_LOCAL: {
global_set(get_argument(0), local_get(get_argument(1)), true);
break;
}
case SH_LOCAL_ASSIGN_STRUCTREF: {
local_set(get_argument(0), member_get(get_argument(1)).i);
break;
}
case SH_IF_STRUCTREF_NE_LOCALREF: {
if (member_get(get_argument(0)).i != local_get(get_argument(1)).i)
instr_ptr = get_argument(2);
else
instr_ptr += instruction_width(SH_IF_STRUCTREF_NE_LOCALREF);
break;
}
case SH_IF_STRUCTREF_GT_IMM: {
if (member_get(get_argument(0)).i > get_argument(1))
instr_ptr = get_argument(2);
else
instr_ptr += instruction_width(SH_IF_STRUCTREF_GT_IMM);
break;
}
case SH_STRUCTREF_CALLMETHOD_NO_PARAM: {
int memb_page = member_get(get_argument(0)).i;
function_call(get_argument(1), instr_ptr + instruction_width(SH_STRUCTREF_CALLMETHOD_NO_PARAM));
call_stack[call_stack_ptr-1].struct_page = memb_page;
break;
}
case SH_STRUCTREF2: {
int memb = member_get(get_argument(0)).i;
stack_push(page_get_var(heap_get_page(memb), get_argument(1)));
break;
}
case SH_STRUCTREF2_CALLMETHOD_NO_PARAM: {
int memb1 = member_get(get_argument(0)).i;
int memb2 = page_get_var(heap_get_page(memb1), get_argument(1)).i;
function_call(get_argument(2), instr_ptr + instruction_width(SH_STRUCTREF2_CALLMETHOD_NO_PARAM));
call_stack[call_stack_ptr-1].struct_page = memb2;
break;
}
case SH_IF_STRUCTREF_Z: {
if (!member_get(get_argument(0)).i)
instr_ptr = get_argument(1);
else
instr_ptr += instruction_width(SH_IF_STRUCTREF_Z);
break;
}
case SH_IF_STRUCT_A_NOT_EMPTY: {
int array = member_get(get_argument(0)).i;
if (heap_get_page(array))
instr_ptr = get_argument(1);
else
instr_ptr += instruction_width(SH_IF_STRUCT_A_NOT_EMPTY);
break;
}
case SH_IF_LOC_GT_IMM: {
if (local_get(get_argument(0)).i > get_argument(1))
instr_ptr = get_argument(2);
else
instr_ptr += instruction_width(SH_IF_LOC_GT_IMM);
break;
}
case SH_IF_STRUCTREF_NE_IMM: {
if (member_get(get_argument(0)).i != get_argument(1))
instr_ptr = get_argument(2);
else
instr_ptr += instruction_width(SH_IF_STRUCTREF_NE_IMM);
break;
}
case THISCALLMETHOD_NOPARAM: {
int this_page = struct_page_slot();
function_call(get_argument(0), instr_ptr + instruction_width(THISCALLMETHOD_NOPARAM));
call_stack[call_stack_ptr-1].struct_page = this_page;
break;
}
case SH_IF_LOC_NE_IMM: {
if (local_get(get_argument(0)).i != get_argument(1))
instr_ptr = get_argument(2);
else
instr_ptr += instruction_width(SH_IF_LOC_NE_IMM);
break;
}
case SH_IF_STRUCTREF_EQ_IMM: {
if (member_get(get_argument(0)).i == get_argument(1))
instr_ptr = get_argument(2);
else
instr_ptr += instruction_width(SH_IF_STRUCTREF_EQ_IMM);
break;
}
case SH_GLOBAL_ASSIGN_IMM: {
global_set(get_argument(0), (union vm_value) { .i = get_argument(1) }, false);
break;
}
case SH_LOCALSTRUCT_ASSIGN_IMM: {
struct page *page = heap_get_page(local_get(get_argument(0)).i);
page_set_var(page, get_argument(1), get_argument(2));
break;
}
case SH_STRUCT_A_PUSHBACK_LOCAL_STRUCT: {
int struct_type;
int array = member_get(get_argument(0)).i;
union vm_value val = vm_copy(local_get(get_argument(1)), AIN_STRUCT);
enum ain_data_type data_type = variable_type(struct_page(), get_argument(0), &struct_type, NULL);
heap_set_page(array, array_pushback(heap_get_page(array), val, data_type, struct_type));
break;
}
case SH_LOCAL_A_PUSHBACK_LOCAL_STRUCT: {
int struct_type;
int array = local_get(get_argument(0)).i;
union vm_value val = vm_copy(local_get(get_argument(1)), AIN_STRUCT);
enum ain_data_type data_type = variable_type(local_page(), get_argument(0), &struct_type, NULL);
heap_set_page(array, array_pushback(heap_get_page(array), val, data_type, struct_type));
break;
}
case SH_IF_SREF_NE_STR0: {
struct string *a = heap_get_string(stack_pop_var()->i);
struct string *b = ain->strings[get_argument(0)];
if (strcmp(a->text, b->text))
instr_ptr = get_argument(1);
else
instr_ptr += instruction_width(SH_IF_SREF_NE_STR0);
break;
}
case SH_S_ASSIGN_REF: {
int rval = stack_pop_var()->i;
int lval = stack_pop().i;
heap_string_assign(lval, heap_get_string(rval));
break;
}
case SH_LOCALSREF_EQ_STR0: {
struct string *a = heap_get_string(local_get(get_argument(0)).i);
struct string *b = ain->strings[get_argument(1)];
stack_push(!strcmp(a->text, b->text));
break;
}
case SH_LOCALSREF_NE_STR0: {
struct string *a = heap_get_string(local_get(get_argument(0)).i);
struct string *b = ain->strings[get_argument(1)];
stack_push(!!strcmp(a->text, b->text));
break;
}
case SH_STRUCT_SR_REF: {
int sr = member_get(get_argument(0)).i;
stack_push(vm_copy_page(heap_get_page(sr)));
// NOTE: argument 1 (struct type) not used
break;
}
case SH_STRUCT_S_REF: {
int str = member_get(get_argument(0)).i;
stack_push_string(string_ref(heap_get_string(str)));
break;
}
case S_REF2: {
struct page *page = heap_get_page(stack_pop().i);
struct string *s = heap_get_string(page_get_var(page, get_argument(0)).i);
stack_push_string(string_ref(s));
break;
}
case SH_LOCAL_S_REF: {
int str = local_get(get_argument(0)).i;
stack_push_string(string_ref(heap_get_string(str)));
break;
}
case SH_LOCAL_APUSHBACK_LOCALSREF: {
int array = local_get(get_argument(0)).i;
union vm_value val = vm_copy(local_get(get_argument(1)), AIN_STRING);
heap_set_page(array, array_pushback(heap_get_page(array), val, AIN_ARRAY_STRING, -1));
break;
}
case SH_S_ASSIGN_STR0: {
int lval = stack_pop().i;
heap_string_assign(lval, ain->strings[get_argument(0)]);
break;
}
case SH_SASSIGN_LOCALSREF: {
int lval = stack_pop().i;
struct string *rval = heap_get_string(local_get(get_argument(0)).i);
heap_string_assign(lval, rval);
break;
}
case SH_STRUCTREF_SASSIGN_LOCALSREF: {
int lval = member_get(get_argument(0)).i;
int rval = local_get(get_argument(1)).i;
heap_string_assign(lval, heap_get_string(rval));
break;
}
case SH_LOCALSREF_EMPTY: {
stack_push(!heap_get_string(local_get(get_argument(0)).i)->size);
break;
}
case SH_STRUCTSREF_EMPTY: {
stack_push(!heap_get_string(member_get(get_argument(0)).i)->size);
break;
}
// -- NOOPs ---
case FUNC:
break;