mirror of
https://github.com/nunuhara/xsystem4.git
synced 2026-10-05 05:17:59 +03:00
Initial delegates implementation
This isn't very well tested yet, but it runs Rance 01 up to the first HLL error.
This commit is contained in:
@@ -62,6 +62,7 @@ bool page_index_valid(int index);
|
||||
bool string_index_valid(int index);
|
||||
|
||||
struct page *heap_get_page(int index);
|
||||
struct page *heap_get_delegate_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);
|
||||
|
||||
+26
-4
@@ -29,14 +29,15 @@ enum page_type {
|
||||
GLOBAL_PAGE,
|
||||
LOCAL_PAGE,
|
||||
STRUCT_PAGE,
|
||||
ARRAY_PAGE
|
||||
ARRAY_PAGE,
|
||||
DELEGATE_PAGE,
|
||||
};
|
||||
|
||||
#define NR_PAGE_TYPES (ARRAY_PAGE+1)
|
||||
|
||||
/*
|
||||
* A page is an ordered collection of variables. Pages are used to implement
|
||||
* global and local variables, structures and arrays as follows,
|
||||
* global and local variables, structures, arrays and delegates as follows:
|
||||
*
|
||||
* Global variables: all global variables are stored in a single global page.
|
||||
*
|
||||
@@ -48,15 +49,28 @@ enum page_type {
|
||||
* Arrays: each array object is backed by a page storing its members.
|
||||
* Multi-dimensional arrays are implemented as a tree of pages (meaning the
|
||||
* whole array is NOT contiguous in memory).
|
||||
*
|
||||
* Delegates: each delegate object is backed by a page storing object/function
|
||||
* pairs.
|
||||
*/
|
||||
struct page {
|
||||
enum page_type type;
|
||||
// Value of `index`:
|
||||
// ----------------
|
||||
// GLOBAL_PAGE: unused
|
||||
// LOCAL_PAGE: function index
|
||||
// STRUCT_PAGE: struct index
|
||||
// ARRAY_PAGE: array data type (e.g. for AIN_ARRAY_STRING, AIN_STRING)
|
||||
// DELEGATE_PAGE: unused
|
||||
union {
|
||||
int index;
|
||||
enum ain_data_type a_type;
|
||||
};
|
||||
int struct_type; // for array pages
|
||||
int rank; // for array pages
|
||||
// array-specific metadata
|
||||
struct {
|
||||
int struct_type;
|
||||
int rank;
|
||||
} array;
|
||||
int nr_vars;
|
||||
union vm_value values[];
|
||||
};
|
||||
@@ -115,4 +129,12 @@ void array_sort(struct page *page, int compare_fno);
|
||||
int array_find(struct page *page, int start, int end, union vm_value v, int compare_fno);
|
||||
void array_reverse(struct page *page);
|
||||
|
||||
// delegates
|
||||
struct page *delegate_new_from_method(int obj, int fun);
|
||||
int delegate_numof(struct page *page);
|
||||
struct page *delegate_plusa(struct page *dst, struct page *add);
|
||||
struct page *delegate_minusa(struct page *dst, struct page *minus);
|
||||
struct page *delegate_clear(struct page *page);
|
||||
void delegate_get(struct page *page, int i, int *obj_out, int *fun_out);
|
||||
|
||||
#endif /* SYSTEM4_PAGE_H */
|
||||
|
||||
+8
-8
@@ -162,16 +162,16 @@ sexp sexp_page_get_a_type (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
return sexp_make_integer(ctx, ((struct page*)sexp_cpointer_value(x))->a_type);
|
||||
}
|
||||
|
||||
sexp sexp_page_get_struct_type (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
sexp sexp_page_get__page_struct_type (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
if (! (sexp_pointerp(x) && (sexp_pointer_tag(x) == sexp_unbox_fixnum(sexp_opcode_arg1_type(self)))))
|
||||
return sexp_type_exception(ctx, self, sexp_unbox_fixnum(sexp_opcode_arg1_type(self)), x);
|
||||
return sexp_make_integer(ctx, ((struct page*)sexp_cpointer_value(x))->struct_type);
|
||||
return sexp_make_integer(ctx, ((struct page*)sexp_cpointer_value(x))->_page_struct_type);
|
||||
}
|
||||
|
||||
sexp sexp_page_get_rank (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
sexp sexp_page_get__page_rank (sexp ctx, sexp self, sexp_sint_t n, sexp x) {
|
||||
if (! (sexp_pointerp(x) && (sexp_pointer_tag(x) == sexp_unbox_fixnum(sexp_opcode_arg1_type(self)))))
|
||||
return sexp_type_exception(ctx, self, sexp_unbox_fixnum(sexp_opcode_arg1_type(self)), x);
|
||||
return sexp_make_integer(ctx, ((struct page*)sexp_cpointer_value(x))->rank);
|
||||
return sexp_make_integer(ctx, ((struct page*)sexp_cpointer_value(x))->_page_rank);
|
||||
}
|
||||
|
||||
|
||||
@@ -290,8 +290,8 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
|
||||
tmp = sexp_string_to_symbol(ctx, name);
|
||||
sexp_env_define(ctx, env, tmp, sexp_page_type_obj);
|
||||
sexp_type_slots(sexp_page_type_obj) = SEXP_NULL;
|
||||
sexp_push(ctx, sexp_type_slots(sexp_page_type_obj), sexp_intern(ctx, "rank", -1));
|
||||
sexp_push(ctx, sexp_type_slots(sexp_page_type_obj), sexp_intern(ctx, "struct_type", -1));
|
||||
sexp_push(ctx, sexp_type_slots(sexp_page_type_obj), sexp_intern(ctx, "_page_rank", -1));
|
||||
sexp_push(ctx, sexp_type_slots(sexp_page_type_obj), sexp_intern(ctx, "_page_struct_type", -1));
|
||||
sexp_push(ctx, sexp_type_slots(sexp_page_type_obj), sexp_intern(ctx, "a_type", -1));
|
||||
sexp_push(ctx, sexp_type_slots(sexp_page_type_obj), sexp_intern(ctx, "nr_vars", -1));
|
||||
sexp_push(ctx, sexp_type_slots(sexp_page_type_obj), sexp_intern(ctx, "index", -1));
|
||||
@@ -301,13 +301,13 @@ sexp sexp_init_library (sexp ctx, sexp self, sexp_sint_t n, sexp env, const char
|
||||
tmp = sexp_make_type_predicate(ctx, name, sexp_page_type_obj);
|
||||
name = sexp_intern(ctx, "page?", 5);
|
||||
sexp_env_define(ctx, env, name, tmp);
|
||||
op = sexp_define_foreign(ctx, env, "array-rank", 1, sexp_page_get_rank);
|
||||
op = sexp_define_foreign(ctx, env, "array-rank", 1, sexp_page_get__page_rank);
|
||||
if (sexp_opcodep(op)) {
|
||||
sexp_opcode_return_type(op) = sexp_make_fixnum(SEXP_FIXNUM);
|
||||
sexp_opcode_arg1_type(op) = sexp_make_fixnum(sexp_type_tag(sexp_page_type_obj));
|
||||
}
|
||||
if (sexp_vectorp(sexp_type_getters(sexp_page_type_obj))) sexp_vector_set(sexp_type_getters(sexp_page_type_obj), SEXP_FIVE, op);
|
||||
op = sexp_define_foreign(ctx, env, "array-struct-type", 1, sexp_page_get_struct_type);
|
||||
op = sexp_define_foreign(ctx, env, "array-struct-type", 1, sexp_page_get__page_struct_type);
|
||||
if (sexp_opcodep(op)) {
|
||||
sexp_opcode_return_type(op) = sexp_make_fixnum(SEXP_FIXNUM);
|
||||
sexp_opcode_arg1_type(op) = sexp_make_fixnum(sexp_type_tag(sexp_page_type_obj));
|
||||
|
||||
+2
-2
@@ -63,8 +63,8 @@
|
||||
(int nr_vars page-nr-vars)
|
||||
|
||||
(int a_type array-data-type)
|
||||
(int struct_type array-struct-type)
|
||||
(int rank array-rank))
|
||||
(int _page_struct_type array-struct-type)
|
||||
(int _page_rank array-rank))
|
||||
|
||||
(define-c-union vm_value
|
||||
predicate: vm-value?
|
||||
|
||||
@@ -111,6 +111,8 @@ static const char *variable_name(struct page *page, int varno)
|
||||
return ain->structures[page->index].members[varno].name;
|
||||
case ARRAY_PAGE:
|
||||
return "array member";
|
||||
case DELEGATE_PAGE:
|
||||
return "delegate member";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
@@ -217,6 +219,10 @@ static struct page *frame_page(int i)
|
||||
return get_page(call_stack[call_stack_ptr - (i+1)].page_slot);
|
||||
}
|
||||
|
||||
// XXX: chibi-ffi doesn't support anonymous structs
|
||||
#define _page_struct_type array.struct_type
|
||||
#define _page_rank array.rank
|
||||
|
||||
// autogenerated with `chibi-ffi src/debug-ffi.stub`
|
||||
#include "debug-ffi.c"
|
||||
|
||||
|
||||
@@ -356,7 +356,7 @@ static int find_walk_data(struct page *array, int map_no, struct dgn *dgn)
|
||||
{
|
||||
if (!array)
|
||||
return WALK_DATA_BROKEN;
|
||||
if (array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->rank != 1)
|
||||
if (array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->array.rank != 1)
|
||||
VM_ERROR("Not a flat integer array");
|
||||
|
||||
int ptr = 0;
|
||||
|
||||
@@ -222,6 +222,14 @@ struct string *heap_get_string(int index)
|
||||
return heap[index].s;
|
||||
}
|
||||
|
||||
struct page *heap_get_delegate_page(int index)
|
||||
{
|
||||
struct page *page = heap_get_page(index);
|
||||
if (!page || page->type != DELEGATE_PAGE)
|
||||
VM_ERROR("Not a delegate page: %d", index);
|
||||
return page;
|
||||
}
|
||||
|
||||
void heap_set_page(int slot, struct page *page)
|
||||
{
|
||||
#ifdef DEBUG_HEAP
|
||||
|
||||
+2
-2
@@ -99,7 +99,7 @@ static void Bitarray_GetArray(int bitSet, struct page **page)
|
||||
return;
|
||||
|
||||
struct page *array = *page;
|
||||
if (!array || array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->rank != 1)
|
||||
if (!array || array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->array.rank != 1)
|
||||
ERROR("Not an flat integer array");
|
||||
|
||||
int n = (arrays[bitSet].size + 31) / 32;
|
||||
@@ -117,7 +117,7 @@ static void Bitarray_SetArray(int bitSet, struct page **page)
|
||||
return;
|
||||
|
||||
struct page *array = *page;
|
||||
if (!array || array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->rank != 1)
|
||||
if (!array || array->type != ARRAY_PAGE || array->a_type != AIN_ARRAY_INT || array->array.rank != 1)
|
||||
ERROR("Not an flat integer array");
|
||||
|
||||
int n = (arrays[bitSet].size + 31) / 32;
|
||||
|
||||
+5
-5
@@ -122,9 +122,9 @@ void iarray_write_array(struct iarray_writer *w, struct page *page)
|
||||
assert(page->type == ARRAY_PAGE);
|
||||
|
||||
struct ain_type t = {
|
||||
.data = page->rank > 1 ? page->a_type : array_type(page->a_type),
|
||||
.struc = page->struct_type,
|
||||
.rank = page->rank - 1
|
||||
.data = page->array.rank > 1 ? page->a_type : array_type(page->a_type),
|
||||
.struc = page->array.struct_type,
|
||||
.rank = page->array.rank - 1
|
||||
};
|
||||
|
||||
iarray_write(w, page->nr_vars);
|
||||
@@ -230,8 +230,8 @@ struct page *iarray_read_array(struct iarray_reader *r, struct ain_type *t)
|
||||
|
||||
int nr_vars = iarray_read(r);
|
||||
struct page *page = alloc_page(ARRAY_PAGE, t->data, nr_vars);
|
||||
page->struct_type = t->struc;
|
||||
page->rank = t->rank;
|
||||
page->array.struct_type = t->struc;
|
||||
page->array.rank = t->rank;
|
||||
|
||||
for (int i = 0; i < nr_vars; i++) {
|
||||
page->values[i].i = iarray_read_member(r, &next_t);
|
||||
|
||||
+123
-17
@@ -29,7 +29,8 @@ static const char *pagetype_strtab[] = {
|
||||
[GLOBAL_PAGE] = "GLOBAL_PAGE",
|
||||
[LOCAL_PAGE] = "LOCAL_PAGE",
|
||||
[STRUCT_PAGE] = "STRUCT_PAGE",
|
||||
[ARRAY_PAGE] = "ARRAY_PAGE"
|
||||
[ARRAY_PAGE] = "ARRAY_PAGE",
|
||||
[DELEGATE_PAGE] = "DELEGATE_PAGE",
|
||||
};
|
||||
|
||||
const char *pagetype_string(enum page_type type)
|
||||
@@ -168,10 +169,19 @@ enum ain_data_type variable_type(struct page *page, int varno, int *struct_type,
|
||||
return ain->structures[page->index].members[varno].type.data;
|
||||
case ARRAY_PAGE:
|
||||
if (struct_type)
|
||||
*struct_type = page->struct_type;
|
||||
*struct_type = page->array.struct_type;
|
||||
if (array_rank)
|
||||
*array_rank = page->rank - 1;
|
||||
return page->rank > 1 ? page->a_type : array_type(page->a_type);
|
||||
*array_rank = page->array.rank - 1;
|
||||
return page->array.rank > 1 ? page->a_type : array_type(page->a_type);
|
||||
case DELEGATE_PAGE:
|
||||
if (varno % 2 == 0) {
|
||||
if (struct_type && page->values[varno].i >= 0)
|
||||
*struct_type = heap_get_page(page->values[varno].i)->index;
|
||||
if (array_rank)
|
||||
*array_rank = -1;
|
||||
return AIN_STRUCT;
|
||||
}
|
||||
return AIN_VOID;
|
||||
}
|
||||
return AIN_VOID;
|
||||
}
|
||||
@@ -207,8 +217,7 @@ struct page *copy_page(struct page *src)
|
||||
if (!src)
|
||||
return NULL;
|
||||
struct page *dst = alloc_page(src->type, src->index, src->nr_vars);
|
||||
dst->struct_type = src->struct_type;
|
||||
dst->rank = src->rank;
|
||||
dst->array = src->array;
|
||||
|
||||
for (int i = 0; i < src->nr_vars; i++) {
|
||||
dst->values[i] = vm_copy(src->values[i], variable_type(src, i, NULL, NULL));
|
||||
@@ -282,8 +291,8 @@ struct page *alloc_array(int rank, union vm_value *dimensions, enum ain_data_typ
|
||||
data_type = unref_array_type(data_type);
|
||||
enum ain_data_type type = array_type(data_type);
|
||||
struct page *page = alloc_page(ARRAY_PAGE, data_type, dimensions->i);
|
||||
page->struct_type = struct_type;
|
||||
page->rank = rank;
|
||||
page->array.struct_type = struct_type;
|
||||
page->array.rank = rank;
|
||||
|
||||
for (int i = 0; i < dimensions->i; i++) {
|
||||
if (rank == 1) {
|
||||
@@ -311,7 +320,7 @@ struct page *realloc_array(struct page *src, int rank, union vm_value *dimension
|
||||
return alloc_array(rank, dimensions, data_type, struct_type, init_structs);
|
||||
if (src->type != ARRAY_PAGE)
|
||||
VM_ERROR("Not an array");
|
||||
if (src->rank != rank)
|
||||
if (src->array.rank != rank)
|
||||
VM_ERROR("Attempt to reallocate array with different rank");
|
||||
if (!dimensions->i) {
|
||||
delete_page_vars(src);
|
||||
@@ -354,7 +363,7 @@ int array_numof(struct page *page, int rank)
|
||||
{
|
||||
if (!page)
|
||||
return 0;
|
||||
if (rank < 1 || rank > page->rank)
|
||||
if (rank < 1 || rank > page->array.rank)
|
||||
return 0;
|
||||
if (rank == 1) {
|
||||
return page->nr_vars;
|
||||
@@ -379,7 +388,7 @@ void array_copy(struct page *dst, int dst_i, struct page *src, int src_i, int n)
|
||||
VM_ERROR("Out of bounds array access");
|
||||
if (!array_index_ok(dst, dst_i + n - 1) || !array_index_ok(src, src_i + n - 1))
|
||||
VM_ERROR("Out of bounds array access");
|
||||
if (dst->rank != 1 || src->rank != 1)
|
||||
if (dst->array.rank != 1 || src->array.rank != 1)
|
||||
VM_ERROR("Tried to copy to/from a multi-dimensional array");
|
||||
if (dst->a_type != src->a_type)
|
||||
VM_ERROR("Array types do not match");
|
||||
@@ -420,12 +429,12 @@ struct page *array_pushback(struct page *dst, union vm_value v, enum ain_data_ty
|
||||
if (dst) {
|
||||
if (dst->type != ARRAY_PAGE)
|
||||
VM_ERROR("Not an array");
|
||||
if (dst->rank != 1)
|
||||
if (dst->array.rank != 1)
|
||||
VM_ERROR("Tried pushing to a multi-dimensional array");
|
||||
|
||||
int index = dst->nr_vars;
|
||||
union vm_value dims[1] = { (union vm_value) { .i = index + 1 } };
|
||||
dst = realloc_array(dst, 1, dims, dst->a_type, dst->struct_type, false);
|
||||
dst = realloc_array(dst, 1, dims, dst->a_type, dst->array.struct_type, false);
|
||||
variable_set(dst, index, array_type(data_type), v);
|
||||
} else {
|
||||
union vm_value dims[1] = { (union vm_value) { .i = 1 } };
|
||||
@@ -441,11 +450,11 @@ struct page *array_popback(struct page *dst)
|
||||
return NULL;
|
||||
if (dst->type != ARRAY_PAGE)
|
||||
VM_ERROR("Not an array");
|
||||
if (dst->rank != 1)
|
||||
if (dst->array.rank != 1)
|
||||
VM_ERROR("Tried popping from a multi-dimensional array");
|
||||
|
||||
union vm_value dims[1] = { (union vm_value) { .i = dst->nr_vars - 1 } };
|
||||
dst = realloc_array(dst, 1, dims, dst->a_type, dst->struct_type, false);
|
||||
dst = realloc_array(dst, 1, dims, dst->a_type, dst->array.struct_type, false);
|
||||
return dst;
|
||||
}
|
||||
|
||||
@@ -456,7 +465,7 @@ struct page *array_erase(struct page *page, int i, bool *success)
|
||||
return NULL;
|
||||
if (page->type != ARRAY_PAGE)
|
||||
VM_ERROR("Not an array");
|
||||
if (page->rank != 1)
|
||||
if (page->array.rank != 1)
|
||||
VM_ERROR("Tried erasing from a multi-dimensional array");
|
||||
if (!array_index_ok(page, i))
|
||||
return page;
|
||||
@@ -488,7 +497,7 @@ struct page *array_insert(struct page *page, int i, union vm_value v, enum ain_d
|
||||
}
|
||||
if (page->type != ARRAY_PAGE)
|
||||
VM_ERROR("Not an array");
|
||||
if (page->rank != 1)
|
||||
if (page->array.rank != 1)
|
||||
VM_ERROR("Tried inserting into a multi-dimensional array");
|
||||
|
||||
// NOTE: you cannot insert at the end of an array due to how i is clamped
|
||||
@@ -576,3 +585,100 @@ void array_reverse(struct page *page)
|
||||
page->values[end] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
struct page *delegate_new_from_method(int obj, int fun)
|
||||
{
|
||||
struct page *page = alloc_page(DELEGATE_PAGE, 0, 2);
|
||||
page->values[0].i = obj;
|
||||
page->values[1].i = fun;
|
||||
if (obj >= 0) {
|
||||
heap_ref(obj);
|
||||
}
|
||||
return page;
|
||||
}
|
||||
|
||||
int delegate_numof(struct page *page)
|
||||
{
|
||||
if (page->type != DELEGATE_PAGE)
|
||||
VM_ERROR("Not a delegate");
|
||||
return page->nr_vars / 2;
|
||||
}
|
||||
|
||||
struct page *delegate_plusa(struct page *dst, struct page *add)
|
||||
{
|
||||
if (dst->type != DELEGATE_PAGE || add->type != DELEGATE_PAGE)
|
||||
VM_ERROR("Not a delegate");
|
||||
|
||||
// FIXME: duplicate checking needed?
|
||||
int new_vars = dst->nr_vars + add->nr_vars;
|
||||
dst = xrealloc(dst, sizeof(struct page) + sizeof(union vm_value) * new_vars);
|
||||
for (int i = 0; i < add->nr_vars; i += 2) {
|
||||
if (add->values[i].i >= 0) {
|
||||
heap_ref(add->values[i].i);
|
||||
}
|
||||
dst->values[dst->nr_vars+i+0].i = add->values[i+0].i;
|
||||
dst->values[dst->nr_vars+i+1].i = add->values[i+1].i;
|
||||
}
|
||||
dst->nr_vars = new_vars;
|
||||
return dst;
|
||||
}
|
||||
|
||||
struct page *delegate_minusa(struct page *dst, struct page *minus)
|
||||
{
|
||||
if (dst->type != DELEGATE_PAGE || minus->type != DELEGATE_PAGE)
|
||||
VM_ERROR("Not a delegate");
|
||||
|
||||
// set matching obj/fun pairs to -1/-1
|
||||
int removed = 0;
|
||||
for (int i = 0; i < minus->nr_vars; i += 2) {
|
||||
for (int j = 0; j < dst->nr_vars; j += 2) {
|
||||
if (minus->values[i].i == dst->values[j].i && minus->values[i+1].i == dst->values[j+1].i) {
|
||||
if (dst->values[j].i >= 0)
|
||||
heap_unref(dst->values[j].i);
|
||||
dst->values[j].i = -1;
|
||||
dst->values[j+1].i = -1;
|
||||
removed++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// shift values to fill in gaps
|
||||
for (int i = 0, p = 0; i < dst->nr_vars; i += 2) {
|
||||
if (dst->values[i].i == -1 && dst->values[i+1].i == -1)
|
||||
continue;
|
||||
if (p < i) {
|
||||
dst->values[p+0].i = dst->values[i+0].i;
|
||||
dst->values[p+1].i = dst->values[i+1].i;
|
||||
}
|
||||
p += 2;
|
||||
}
|
||||
dst->nr_vars -= removed;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
struct page *delegate_clear(struct page *page)
|
||||
{
|
||||
if (page->type != DELEGATE_PAGE)
|
||||
VM_ERROR("Not a delegate");
|
||||
for (int i = 0; i < page->nr_vars; i += 2) {
|
||||
if (page->values[i].i >= 0)
|
||||
heap_unref(page->values[i].i);
|
||||
page->values[i].i = -1;
|
||||
page->values[i+1].i = -1;
|
||||
}
|
||||
page->index = 0;
|
||||
page->nr_vars = 0;
|
||||
return page;
|
||||
}
|
||||
|
||||
void delegate_get(struct page *page, int i, int *obj_out, int *fun_out)
|
||||
{
|
||||
if (page->type != DELEGATE_PAGE)
|
||||
VM_ERROR("Not a delegate");
|
||||
if (i*2 >= page->nr_vars)
|
||||
VM_ERROR("Invalid delegate index: %d", i);
|
||||
*obj_out = page->values[i*2].i;
|
||||
*fun_out = page->values[i*2+1].i;
|
||||
}
|
||||
|
||||
+4
-4
@@ -66,8 +66,8 @@ static cJSON *resume_page_to_json(struct page *page)
|
||||
cJSON_AddStringToObject(json, "type", page_type_strtab[page->type]);
|
||||
cJSON_AddNumberToObject(json, "subtype", page->index);
|
||||
if (page->type == ARRAY_PAGE) {
|
||||
cJSON_AddNumberToObject(json, "struct-type", page->struct_type);
|
||||
cJSON_AddNumberToObject(json, "rank", page->rank);
|
||||
cJSON_AddNumberToObject(json, "struct-type", page->array.struct_type);
|
||||
cJSON_AddNumberToObject(json, "rank", page->array.rank);
|
||||
}
|
||||
|
||||
cJSON *values = cJSON_CreateArray();
|
||||
@@ -200,8 +200,8 @@ static void load_page(int slot, cJSON *json)
|
||||
|
||||
// allocate page
|
||||
struct page *page = alloc_page(page_type, subtype->valueint, cJSON_GetArraySize(values));
|
||||
page->struct_type = struct_type;
|
||||
page->rank = rank;
|
||||
page->array.struct_type = struct_type;
|
||||
page->array.rank = rank;
|
||||
|
||||
// init page variables
|
||||
int i = 0;
|
||||
|
||||
@@ -78,6 +78,12 @@ int32_t call_stack_ptr = 0;
|
||||
struct ain *ain;
|
||||
size_t instr_ptr = 0;
|
||||
|
||||
static struct {
|
||||
struct page *page;
|
||||
int index;
|
||||
int nr_functions;
|
||||
} current_delegate;
|
||||
|
||||
// Read the opcode at ADDR.
|
||||
static int16_t get_opcode(size_t addr)
|
||||
{
|
||||
@@ -2007,6 +2013,106 @@ static enum opcode execute_instruction(enum opcode opcode)
|
||||
stack_push(i < get_argument(1) || i >= get_argument(2));
|
||||
break;
|
||||
}
|
||||
//case DG_ADD:
|
||||
//case DG_SET:
|
||||
case DG_CALL: { // DG_TYPE, ADDR
|
||||
int dg = get_argument(0);
|
||||
if (dg < 0 || dg >= ain->nr_delegates)
|
||||
VM_ERROR("Invalid delegate index");
|
||||
int obj, fun;
|
||||
delegate_get(current_delegate.page, current_delegate.index, &obj, &fun);
|
||||
// pop previous return value
|
||||
if (ain->delegates[dg].return_type.data != AIN_VOID) {
|
||||
stack_pop();
|
||||
}
|
||||
// call function
|
||||
vm_call(fun, obj);
|
||||
if (++current_delegate.index >= current_delegate.nr_functions) {
|
||||
// clear delegate state
|
||||
current_delegate.page = NULL;
|
||||
current_delegate.index = 0;
|
||||
current_delegate.nr_functions = 0;
|
||||
// jump to addr
|
||||
instr_ptr = get_argument(1);
|
||||
} else {
|
||||
// continue to next instruction
|
||||
instr_ptr += 10;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case DG_NUMOF: {
|
||||
stack_push(delegate_numof(heap_get_page(stack_pop().i)));
|
||||
break;
|
||||
}
|
||||
//case DG_EXIST:
|
||||
//case DG_ERASE:
|
||||
case DG_CLEAR: {
|
||||
int slot = stack_pop().i;
|
||||
if (!slot)
|
||||
break;
|
||||
heap_set_page(slot, delegate_clear(heap_get_delegate_page(slot)));
|
||||
break;
|
||||
}
|
||||
case DG_COPY: {
|
||||
stack_push(vm_copy_page(heap_get_delegate_page(stack_pop().i)));
|
||||
break;
|
||||
}
|
||||
case DG_ASSIGN: {
|
||||
int set_i = stack_pop().i;
|
||||
int dst_i = stack_pop().i;
|
||||
struct page *set = heap_get_delegate_page(set_i);
|
||||
delete_page(dst_i);
|
||||
heap_set_page(dst_i, copy_page(set));
|
||||
stack_push(set_i);
|
||||
break;
|
||||
}
|
||||
case DG_PLUSA: {
|
||||
int add_i = stack_pop().i;
|
||||
int dst_i = stack_pop().i;
|
||||
struct page *add = heap_get_delegate_page(add_i);
|
||||
struct page *dst = heap_get_delegate_page(dst_i);
|
||||
heap_set_page(dst_i, delegate_plusa(dst, add));
|
||||
stack_push(add_i);
|
||||
break;
|
||||
}
|
||||
case DG_MINUSA: {
|
||||
int minus_i = stack_pop().i;
|
||||
int dst_i = stack_pop().i;
|
||||
struct page *minus = heap_get_delegate_page(minus_i);
|
||||
struct page *dst = heap_get_delegate_page(dst_i);
|
||||
heap_set_page(dst_i, delegate_minusa(dst, minus));
|
||||
stack_push(minus_i);
|
||||
break;
|
||||
}
|
||||
case DG_POP: {
|
||||
heap_unref(stack_pop().i);
|
||||
break;
|
||||
}
|
||||
case DG_NEW_FROM_METHOD: {
|
||||
int fun = stack_pop().i;
|
||||
int obj = stack_pop().i;
|
||||
stack_push(heap_alloc_page(delegate_new_from_method(obj, fun)));
|
||||
break;
|
||||
}
|
||||
case DG_CALLBEGIN: { // DG_TYPE
|
||||
int dg = get_argument(0);
|
||||
if (dg < 0 || dg >= ain->nr_delegates)
|
||||
VM_ERROR("Invalid delegate index");
|
||||
struct page *page = heap_get_page(stack_pop().i);
|
||||
if (page->type != DELEGATE_PAGE)
|
||||
VM_ERROR("Not a delegate");
|
||||
current_delegate.page = page;
|
||||
current_delegate.index = 0;
|
||||
current_delegate.nr_functions = delegate_numof(page);
|
||||
// XXX: If the delegate has a return value, we push a dummy value
|
||||
// so that DG_CALL can replace it
|
||||
if (ain->delegates[dg].return_type.data != AIN_VOID) {
|
||||
stack_push(0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
//case DG_NEW:
|
||||
//case DG_STR_TO_METHOD:
|
||||
// -- NOOPs ---
|
||||
case FUNC:
|
||||
break;
|
||||
@@ -2168,10 +2274,14 @@ static void describe_page(struct page *page)
|
||||
free(u);
|
||||
break;
|
||||
case ARRAY_PAGE:
|
||||
u = sjis2utf(ain_strtype(ain, page->a_type, page->struct_type), 0);
|
||||
u = sjis2utf(ain_strtype(ain, page->a_type, page->array.struct_type), 0);
|
||||
sys_message("ARRAY_PAGE: %s\n", u);
|
||||
free(u);
|
||||
break;
|
||||
case DELEGATE_PAGE:
|
||||
// TODO: list function names
|
||||
sys_message("DELEGATE_PAGE\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
Submodule subprojects/libsys4 updated: a3976458d4...cbdf4ae8ab
Reference in New Issue
Block a user