1 /* accel.c: Glulxe code for accelerated functions
2 Designed by Andrew Plotkin <erkyrath@eblong.com>
3 http://eblong.com/zarf/glulx/index.html
9 /* Git passes along function arguments in reverse order. To make our lives
12 #define ARG(argv, argc, ix) (argv[(argc-1)-ix])
14 #define ARG(argv, argc, ix) (argv[ix])
17 /* Any function can be called with any number of arguments. This macro
18 lets us snarf a given argument, or zero if it wasn't supplied. */
19 #define ARG_IF_GIVEN(argv, argc, ix) ((argc > ix) ? (ARG(argv, argc, ix)) : 0)
21 static void accel_error(char *msg);
22 static glui32 func_1_z__region(glui32 argc, glui32 *argv);
23 static glui32 func_2_cp__tab(glui32 argc, glui32 *argv);
24 static glui32 func_3_ra__pr(glui32 argc, glui32 *argv);
25 static glui32 func_4_rl__pr(glui32 argc, glui32 *argv);
26 static glui32 func_5_oc__cl(glui32 argc, glui32 *argv);
27 static glui32 func_6_rv__pr(glui32 argc, glui32 *argv);
28 static glui32 func_7_op__pr(glui32 argc, glui32 *argv);
30 static int obj_in_class(glui32 obj);
31 static glui32 get_prop(glui32 obj, glui32 id);
33 /* Parameters, set by @accelparam. */
34 static glui32 classes_table = 0; /* class object array */
35 static glui32 indiv_prop_start = 0; /* first individual prop ID */
36 static glui32 class_metaclass = 0; /* "Class" class object */
37 static glui32 object_metaclass = 0; /* "Object" class object */
38 static glui32 routine_metaclass = 0; /* "Routine" class object */
39 static glui32 string_metaclass = 0; /* "String" class object */
40 static glui32 self = 0; /* address of global "self" */
41 static glui32 num_attr_bytes = 0; /* number of attributes / 8 */
42 static glui32 cpv__start = 0; /* array of common prop defaults */
44 typedef struct accelentry_struct {
46 acceleration_func func;
47 struct accelentry_struct *next;
50 #define ACCEL_HASH_SIZE (511)
52 static accelentry_t **accelentries = NULL;
59 acceleration_func accel_find_func(glui32 index)
62 case 0: return NULL; /* 0 always means no acceleration */
63 case 1: return func_1_z__region;
64 case 2: return func_2_cp__tab;
65 case 3: return func_3_ra__pr;
66 case 4: return func_4_rl__pr;
67 case 5: return func_5_oc__cl;
68 case 6: return func_6_rv__pr;
69 case 7: return func_7_op__pr;
74 acceleration_func accel_get_func(glui32 addr)
82 bucknum = (addr % ACCEL_HASH_SIZE);
83 for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) {
84 if (ptr->addr == addr)
90 void accel_set_func(glui32 index, glui32 addr)
95 acceleration_func new_func = NULL;
97 /* Check the Glulx type identifier byte. */
98 functype = Mem1(addr);
99 if (functype != 0xC0 && functype != 0xC1) {
100 fatal_error_i("Attempt to accelerate non-function.", addr);
104 accelentries = (accelentry_t **)glulx_malloc(ACCEL_HASH_SIZE
105 * sizeof(accelentry_t *));
107 fatal_error("Cannot malloc acceleration table.");
108 for (bucknum=0; bucknum<ACCEL_HASH_SIZE; bucknum++)
109 accelentries[bucknum] = NULL;
112 new_func = accel_find_func(index);
114 bucknum = (addr % ACCEL_HASH_SIZE);
115 for (ptr = accelentries[bucknum]; ptr; ptr = ptr->next) {
116 if (ptr->addr == addr)
121 return; /* no need for a new entry */
123 ptr = (accelentry_t *)glulx_malloc(sizeof(accelentry_t));
125 fatal_error("Cannot malloc acceleration entry.");
128 ptr->next = accelentries[bucknum];
129 accelentries[bucknum] = ptr;
132 ptr->func = new_func;
135 void accel_set_param(glui32 index, glui32 val)
138 case 0: classes_table = val; break;
139 case 1: indiv_prop_start = val; break;
140 case 2: class_metaclass = val; break;
141 case 3: object_metaclass = val; break;
142 case 4: routine_metaclass = val; break;
143 case 5: string_metaclass = val; break;
144 case 6: self = val; break;
145 case 7: num_attr_bytes = val; break;
146 case 8: cpv__start = val; break;
150 static void accel_error(char *msg)
157 static int obj_in_class(glui32 obj)
159 /* This checks whether obj is contained in Class, not whether
160 it is a member of Class. */
161 return (Mem4(obj + 13 + num_attr_bytes) == class_metaclass);
164 static glui32 get_prop(glui32 obj, glui32 id)
170 if (id & 0xFFFF0000) {
171 cla = Mem4(classes_table+((id & 0xFFFF) * 4));
172 ARG(call_argv, 2, 0) = obj;
173 ARG(call_argv, 2, 1) = cla;
174 if (func_5_oc__cl(2, call_argv) == 0)
181 ARG(call_argv, 2, 0) = obj;
182 ARG(call_argv, 2, 1) = id;
183 prop = func_2_cp__tab(2, call_argv);
187 if (obj_in_class(obj) && (cla == 0)) {
188 if ((id < indiv_prop_start) || (id >= indiv_prop_start+8))
192 if (Mem4(self) != obj) {
193 if (Mem1(prop + 9) & 1)
199 static glui32 func_1_z__region(glui32 argc, glui32 *argv)
207 addr = ARG(argv, argc, 0);
220 if (tb >= 0x70 && tb <= 0x7F && addr >= ramstart) {
226 static glui32 func_2_cp__tab(glui32 argc, glui32 *argv)
232 obj = ARG_IF_GIVEN(argv, argc, 0);
233 id = ARG_IF_GIVEN(argv, argc, 1);
235 if (func_1_z__region(1, &obj) != 1) {
236 accel_error("[** Programming error: tried to find the \".\" of (something) **]");
240 otab = Mem4(obj + 16);
246 /* @binarysearch id 2 otab 10 max 0 0 res; */
247 return binary_search(id, 2, otab, 10, max, 0, 0);
250 static glui32 func_3_ra__pr(glui32 argc, glui32 *argv)
256 obj = ARG_IF_GIVEN(argv, argc, 0);
257 id = ARG_IF_GIVEN(argv, argc, 1);
259 prop = get_prop(obj, id);
263 return Mem4(prop + 4);
266 static glui32 func_4_rl__pr(glui32 argc, glui32 *argv)
272 obj = ARG_IF_GIVEN(argv, argc, 0);
273 id = ARG_IF_GIVEN(argv, argc, 1);
275 prop = get_prop(obj, id);
279 return 4 * Mem2(prop + 2);
282 static glui32 func_5_oc__cl(glui32 argc, glui32 *argv)
286 glui32 zr, prop, inlist, inlistlen, jx;
288 obj = ARG_IF_GIVEN(argv, argc, 0);
289 cla = ARG_IF_GIVEN(argv, argc, 1);
291 zr = func_1_z__region(1, &obj);
293 return (cla == string_metaclass) ? 1 : 0;
295 return (cla == routine_metaclass) ? 1 : 0;
299 if (cla == class_metaclass) {
300 if (obj_in_class(obj))
302 if (obj == class_metaclass)
304 if (obj == string_metaclass)
306 if (obj == routine_metaclass)
308 if (obj == object_metaclass)
312 if (cla == object_metaclass) {
313 if (obj_in_class(obj))
315 if (obj == class_metaclass)
317 if (obj == string_metaclass)
319 if (obj == routine_metaclass)
321 if (obj == object_metaclass)
325 if ((cla == string_metaclass) || (cla == routine_metaclass))
328 if (!obj_in_class(cla)) {
329 accel_error("[** Programming error: tried to apply 'ofclass' with non-class **]");
333 prop = get_prop(obj, 2);
337 inlist = Mem4(prop + 4);
341 inlistlen = Mem2(prop + 2);
342 for (jx = 0; jx < inlistlen; jx++) {
343 if (Mem4(inlist + (4 * jx)) == cla)
349 static glui32 func_6_rv__pr(glui32 argc, glui32 *argv)
354 id = ARG_IF_GIVEN(argv, argc, 1);
356 addr = func_3_ra__pr(argc, argv);
359 if ((id > 0) && (id < indiv_prop_start))
360 return Mem4(cpv__start + (4 * id));
362 accel_error("[** Programming error: tried to read (something) **]");
369 static glui32 func_7_op__pr(glui32 argc, glui32 *argv)
375 obj = ARG_IF_GIVEN(argv, argc, 0);
376 id = ARG_IF_GIVEN(argv, argc, 1);
378 zr = func_1_z__region(1, &obj);
380 /* print is INDIV_PROP_START+6 */
381 if (id == indiv_prop_start+6)
383 /* print_to_array is INDIV_PROP_START+7 */
384 if (id == indiv_prop_start+7)
389 /* call is INDIV_PROP_START+5 */
390 return ((id == indiv_prop_start+5) ? 1 : 0);
395 if ((id >= indiv_prop_start) && (id < indiv_prop_start+8)) {
396 if (obj_in_class(obj))
400 return ((func_3_ra__pr(argc, argv)) ? 1 : 0);