1
/* accel.c: Glulxe code for accelerated functions
2
Designed by Andrew Plotkin <erkyrath@eblong.com>
3
http://eblong.com/zarf/glulx/index.html
10
#define glulx_malloc malloc
12
/* Git passes along function arguments in reverse order. To make our lives
15
#define ARG(argv, argc, ix) (argv[(argc-1)-ix])
17
#define ARG(argv, argc, ix) (argv[ix])
20
/* Any function can be called with any number of arguments. This macro
21
lets us snarf a given argument, or zero if it wasn't supplied. */
22
#define ARG_IF_GIVEN(argv, argc, ix) ((argc > ix) ? (ARG(argv, argc, ix)) : 0)
24
static void accel_error(char *msg);
25
static glui32 func_1_z__region(glui32 argc, glui32 *argv);
26
static glui32 func_2_cp__tab(glui32 argc, glui32 *argv);
27
static glui32 func_3_ra__pr(glui32 argc, glui32 *argv);
28
static glui32 func_4_rl__pr(glui32 argc, glui32 *argv);
29
static glui32 func_5_oc__cl(glui32 argc, glui32 *argv);
30
static glui32 func_6_rv__pr(glui32 argc, glui32 *argv);
31
static glui32 func_7_op__pr(glui32 argc, glui32 *argv);
33
static int obj_in_class(glui32 obj);
34
static glui32 get_prop(glui32 obj, glui32 id);
36
/* Parameters, set by @accelparam. */
37
static glui32 classes_table = 0; /* class object array */
38
static glui32 indiv_prop_start = 0; /* first individual prop ID */
39
static glui32 class_metaclass = 0; /* "Class" class object */
40
static glui32 object_metaclass = 0; /* "Object" class object */
41
static glui32 routine_metaclass = 0; /* "Routine" class object */
42
static glui32 string_metaclass = 0; /* "String" class object */
43
static glui32 self = 0; /* address of global "self" */
44
static glui32 num_attr_bytes = 0; /* number of attributes / 8 */
45
static glui32 cpv__start = 0; /* array of common prop defaults */
47
typedef struct accelentry_struct {
49
acceleration_func func;
50
struct accelentry_struct *next;
53
#define ACCEL_HASH_SIZE (511)
55
static accelentry_t **accelentries = NULL;
62
acceleration_func accel_find_func(glui32 index)
65
case 0: return NULL; /* 0 always means no acceleration */
66
case 1: return func_1_z__region;
67
case 2: return func_2_cp__tab;
68
case 3: return func_3_ra__pr;
69
case 4: return func_4_rl__pr;
70
case 5: return func_5_oc__cl;
71
case 6: return func_6_rv__pr;
72
case 7: return func_7_op__pr;
77
acceleration_func accel_get_func(glui32 addr)
85
bucknum = (addr % ACCEL_HASH_SIZE);
86
for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) {
87
if (ptr->addr == addr)
93
void accel_set_func(glui32 index, glui32 addr)
98
acceleration_func new_func = NULL;
100
/* Check the Glulx type identifier byte. */
101
functype = memRead8(addr);
102
if (functype != 0xC0 && functype != 0xC1) {
103
fatalError("Attempt to accelerate non-function.");
107
accelentries = (accelentry_t **)glulx_malloc(ACCEL_HASH_SIZE
108
* sizeof(accelentry_t *));
110
fatalError("Cannot malloc acceleration table.");
111
for (bucknum=0; bucknum<ACCEL_HASH_SIZE; bucknum++)
112
accelentries[bucknum] = NULL;
115
new_func = accel_find_func(index);
117
bucknum = (addr % ACCEL_HASH_SIZE);
118
for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) {
119
if (ptr->addr == addr)
124
return; /* no need for a new entry */
126
ptr = (accelentry_t *)glulx_malloc(sizeof(accelentry_t));
128
fatalError("Cannot malloc acceleration entry.");
131
ptr->next = accelentries[bucknum];
132
accelentries[bucknum] = ptr;
135
ptr->func = new_func;
138
void accel_set_param(glui32 index, glui32 val)
141
case 0: classes_table = val; break;
142
case 1: indiv_prop_start = val; break;
143
case 2: class_metaclass = val; break;
144
case 3: object_metaclass = val; break;
145
case 4: routine_metaclass = val; break;
146
case 5: string_metaclass = val; break;
147
case 6: self = val; break;
148
case 7: num_attr_bytes = val; break;
149
case 8: cpv__start = val; break;
153
static void accel_error(char *msg)
160
static int obj_in_class(glui32 obj)
162
/* This checks whether obj is contained in Class, not whether
163
it is a member of Class. */
164
return (memRead32(obj + 13 + num_attr_bytes) == class_metaclass);
167
static glui32 get_prop(glui32 obj, glui32 id)
173
if (id & 0xFFFF0000) {
174
cla = memRead32(classes_table+((id & 0xFFFF) * 4));
175
ARG(call_argv, 2, 0) = obj;
176
ARG(call_argv, 2, 1) = cla;
177
if (func_5_oc__cl(2, call_argv) == 0)
184
ARG(call_argv, 2, 0) = obj;
185
ARG(call_argv, 2, 1) = id;
186
prop = func_2_cp__tab(2, call_argv);
190
if (obj_in_class(obj) && (cla == 0)) {
191
if ((id < indiv_prop_start) || (id >= indiv_prop_start+8))
195
if (memRead32(self) != obj) {
196
if (memRead8(prop + 9) & 1)
202
static glui32 func_1_z__region(glui32 argc, glui32 *argv)
210
addr = ARG(argv, argc, 0);
223
if (tb >= 0x70 && tb <= 0x7F && addr >= gRamStart) {
229
static glui32 func_2_cp__tab(glui32 argc, glui32 *argv)
235
obj = ARG_IF_GIVEN(argv, argc, 0);
236
id = ARG_IF_GIVEN(argv, argc, 1);
238
if (func_1_z__region(1, &obj) != 1) {
239
accel_error("[** Programming error: tried to find the \".\" of (something) **]");
243
otab = memRead32(obj + 16);
247
max = memRead32(otab);
249
/* @binarysearch id 2 otab 10 max 0 0 res; */
250
return git_binary_search(id, 2, otab, 10, max, 0, 0);
253
static glui32 func_3_ra__pr(glui32 argc, glui32 *argv)
259
obj = ARG_IF_GIVEN(argv, argc, 0);
260
id = ARG_IF_GIVEN(argv, argc, 1);
262
prop = get_prop(obj, id);
266
return memRead32(prop + 4);
269
static glui32 func_4_rl__pr(glui32 argc, glui32 *argv)
275
obj = ARG_IF_GIVEN(argv, argc, 0);
276
id = ARG_IF_GIVEN(argv, argc, 1);
278
prop = get_prop(obj, id);
282
return 4 * memRead16(prop + 2);
285
static glui32 func_5_oc__cl(glui32 argc, glui32 *argv)
289
glui32 zr, prop, inlist, inlistlen, jx;
291
obj = ARG_IF_GIVEN(argv, argc, 0);
292
cla = ARG_IF_GIVEN(argv, argc, 1);
294
zr = func_1_z__region(1, &obj);
296
return (cla == string_metaclass) ? 1 : 0;
298
return (cla == routine_metaclass) ? 1 : 0;
302
if (cla == class_metaclass) {
303
if (obj_in_class(obj))
305
if (obj == class_metaclass)
307
if (obj == string_metaclass)
309
if (obj == routine_metaclass)
311
if (obj == object_metaclass)
315
if (cla == object_metaclass) {
316
if (obj_in_class(obj))
318
if (obj == class_metaclass)
320
if (obj == string_metaclass)
322
if (obj == routine_metaclass)
324
if (obj == object_metaclass)
328
if ((cla == string_metaclass) || (cla == routine_metaclass))
331
if (!obj_in_class(cla)) {
332
accel_error("[** Programming error: tried to apply 'ofclass' with non-class **]");
336
prop = get_prop(obj, 2);
340
inlist = memRead32(prop + 4);
344
inlistlen = memRead16(prop + 2);
345
for (jx = 0; jx < inlistlen; jx++) {
346
if (memRead32(inlist + (4 * jx)) == cla)
352
static glui32 func_6_rv__pr(glui32 argc, glui32 *argv)
357
id = ARG_IF_GIVEN(argv, argc, 1);
359
addr = func_3_ra__pr(argc, argv);
362
if ((id > 0) && (id < indiv_prop_start))
363
return memRead32(cpv__start + (4 * id));
365
accel_error("[** Programming error: tried to read (something) **]");
369
return memRead32(addr);
372
static glui32 func_7_op__pr(glui32 argc, glui32 *argv)
378
obj = ARG_IF_GIVEN(argv, argc, 0);
379
id = ARG_IF_GIVEN(argv, argc, 1);
381
zr = func_1_z__region(1, &obj);
383
/* print is INDIV_PROP_START+6 */
384
if (id == indiv_prop_start+6)
386
/* print_to_array is INDIV_PROP_START+7 */
387
if (id == indiv_prop_start+7)
392
/* call is INDIV_PROP_START+5 */
393
return ((id == indiv_prop_start+5) ? 1 : 0);
398
if ((id >= indiv_prop_start) && (id < indiv_prop_start+8)) {
399
if (obj_in_class(obj))
403
return ((func_3_ra__pr(argc, argv)) ? 1 : 0);