blob: 9a64801b1030784c976a9969d9a6e1ebd0d2cc30 [file] [log] [blame]
swissChili8cfb7c42021-04-18 21:17:58 -07001/* -*- mode:c -*- */
2
swissChilica107a02021-04-14 12:07:30 -07003#include "compiler.h"
swissChilif3e7f182021-04-20 13:57:22 -07004#include "lib/std.h"
swissChili53472e82021-05-08 16:06:32 -07005#include "plat/plat.h"
swissChiliddc97542021-07-04 11:47:42 -07006#include "gc.h"
swissChilica107a02021-04-14 12:07:30 -07007
8#include <dasm_proto.h>
9#include <dasm_x86.h>
10
swissChili923b5362021-05-09 20:31:43 -070011#include <stdlib.h>
12#include <string.h>
13
swissChili53472e82021-05-08 16:06:32 -070014#define value_size sizeof(value_t)
swissChilica107a02021-04-14 12:07:30 -070015
16|.arch x86;
17
18|.macro setup, nvars;
swissChili74348422021-07-04 13:23:24 -070019|->function_start:
swissChilica107a02021-04-14 12:07:30 -070020| push ebp;
21| mov ebp, esp;
swissChili8cfb7c42021-04-18 21:17:58 -070022| sub esp, (value_size * nvars);
swissChilica107a02021-04-14 12:07:30 -070023|.endmacro;
24
25|.macro cleanup;
26| mov esp, ebp;
27| pop ebp;
28| ret;
29|.endmacro;
30
swissChili67bdf282021-06-06 18:46:08 -070031|.macro local_var, index;
32|.endmacro;
33
swissChilica107a02021-04-14 12:07:30 -070034dasm_State *d;
35unsigned int npc = 8;
36
swissChili9e57da42021-06-15 22:22:46 -070037|.macro run_gc;
swissChilie9fec8b2021-06-22 13:59:33 -070038| mov eax, esp;
swissChili9e57da42021-06-15 22:22:46 -070039| push ebp;
swissChilie9fec8b2021-06-22 13:59:33 -070040| push eax;
swissChili9e57da42021-06-15 22:22:46 -070041| mov eax, _do_gc;
42| call eax;
43|.endmacro;
swissChili6d6525e2021-06-15 21:20:53 -070044
swissChili53472e82021-05-08 16:06:32 -070045struct function *find_function(struct environment *env, char *name)
swissChilica107a02021-04-14 12:07:30 -070046{
47 struct function *f = env->first;
48
swissChili53472e82021-05-08 16:06:32 -070049 while (strcmp(f->name, name) != 0)
swissChilica107a02021-04-14 12:07:30 -070050 {
swissChili53472e82021-05-08 16:06:32 -070051 if (f->prev)
swissChilica107a02021-04-14 12:07:30 -070052 f = f->prev;
53 else
54 return NULL;
55 }
56
57 return f;
58}
59
swissChili67bdf282021-06-06 18:46:08 -070060unsigned int local_alloc(struct local *local)
61{
62 for (int i = 0; i < local->num_stack_slots; i++)
63 {
64 if (local->stack_slots[i] == false)
65 {
66 local->stack_slots[i] = true;
67
68 if (i >= local->num_stack_entries)
69 local->num_stack_entries++;
70
71 return i;
72 }
73 }
74
75 int old_size = local->num_stack_slots;
76 local->num_stack_slots += 4;
77 local->stack_slots = realloc(local->stack_slots, local->num_stack_slots * sizeof(bool));
78 // unreadable: set the remaining slots to unused
79 memset(local->stack_slots + old_size, 0, local->num_stack_slots - old_size);
80 local->stack_slots[old_size] = true;
81
82 return old_size;
83}
84
85void local_free(struct local *local, unsigned int slot)
86{
87 local->stack_slots[slot] = false;
88}
89
swissChilif1ba8c12021-07-02 18:45:38 -070090struct dasm_State *compile_function(value_t args, enum namespace namespace,
swissChiliddc97542021-07-04 11:47:42 -070091 struct environment *env, struct local *local_out,
swissChili74348422021-07-04 13:23:24 -070092 struct local *local_parent, int *nargs, char *name)
swissChilif1ba8c12021-07-02 18:45:38 -070093{
94 dasm_State *d;
95 dasm_State **Dst = &d;
96
97 |.section code;
98 dasm_init(&d, DASM_MAXSECTION);
99
100 |.globals lbl_;
101 void *labels[lbl__MAX];
102 dasm_setupglobal(&d, labels, lbl__MAX);
103
104 |.actionlist lisp_actions;
105 dasm_setup(&d, lisp_actions);
106
107 struct local local;
108 local.parent = NULL;
109 local.first = NULL;
110 local.num_vars = 0;
111 local.npc = 8;
112 local.nextpc = 0;
113 local.stack_slots = malloc(sizeof(bool) * 4);
114 memset(local.stack_slots, 0, sizeof(bool) * 4);
115 local.num_stack_slots = 4;
116 local.num_stack_entries = 0;
swissChiliddc97542021-07-04 11:47:42 -0700117 local.num_closure_slots = 0;
118 local.parent = local_parent;
swissChili74348422021-07-04 13:23:24 -0700119 local.current_function_name = name;
swissChilif1ba8c12021-07-02 18:45:38 -0700120
121 dasm_growpc(&d, local.npc);
122
swissChilif1ba8c12021-07-02 18:45:38 -0700123 value_t arglist = car(args);
124 value_t body = cdr(args);
125
swissChili74348422021-07-04 13:23:24 -0700126 local.num_args = length(arglist);
127
swissChilif1ba8c12021-07-02 18:45:38 -0700128 value_t a = arglist;
129 for (int i = 0; !nilp(a); a = cdr(a), i++)
130 {
131 if (!symbolp(car(a)))
132 {
133 err("defun argument must be a symbol");
134 }
135
136 add_variable(&local, V_ARGUMENT, (char *)(car(a) ^ SYMBOL_TAG), i);
137 }
138
139 for (value_t body_ = body; !nilp(body_); body_ = cdr(body_))
140 {
141 walk_and_alloc(&local, car(body_));
142 }
143
144 | setup (local.num_stack_entries);
145
146 memset(local.stack_slots, 0, local.num_stack_slots * sizeof(bool));
147 local.num_stack_entries = 0;
148
149 for (; !nilp(body); body = cdr(body))
150 {
151 compile_expression(env, &local, car(body), Dst);
152 }
153
154 | cleanup;
155
156 if (local_out)
157 *local_out = local;
158
159 if (nargs)
160 *nargs = length(arglist);
161
162 return d;
swissChiliddc97542021-07-04 11:47:42 -0700163
164 // TODO: local leaks memory! free variables too, not just stack slots (in
165 // two places). Add a free_local() function that does this.
swissChilif1ba8c12021-07-02 18:45:38 -0700166}
167
swissChili53472e82021-05-08 16:06:32 -0700168void compile_tl(value_t val, struct environment *env)
swissChilica107a02021-04-14 12:07:30 -0700169{
swissChili53472e82021-05-08 16:06:32 -0700170 if (!listp(val))
171 err("Top level must be a list");
swissChilica107a02021-04-14 12:07:30 -0700172
swissChili53472e82021-05-08 16:06:32 -0700173 value_t form = car(val);
174 value_t args = cdr(val);
175
swissChili2999dd12021-07-02 14:19:53 -0700176 if (symstreq(form, "defun") || symstreq(form, "defmacro"))
swissChili8fc5e2f2021-04-22 13:45:10 -0700177 {
swissChili2999dd12021-07-02 14:19:53 -0700178 enum namespace namespace = NS_FUNCTION;
179
180 if (symstreq(form, "defmacro"))
181 namespace = NS_MACRO;
182
swissChili8fc5e2f2021-04-22 13:45:10 -0700183 struct local local;
swissChilif1ba8c12021-07-02 18:45:38 -0700184 int nargs;
swissChili74348422021-07-04 13:23:24 -0700185 char *name = (char *)(car(args) ^ SYMBOL_TAG);
186 dasm_State *d = compile_function(cdr(args), namespace, env, &local, NULL, &nargs, name);
swissChilia820dea2021-05-09 16:46:55 -0700187
swissChili74348422021-07-04 13:23:24 -0700188 add_function(env, name, link(&d),
swissChilif1ba8c12021-07-02 18:45:38 -0700189 nargs, namespace);
swissChili8fc5e2f2021-04-22 13:45:10 -0700190
swissChili53472e82021-05-08 16:06:32 -0700191 dasm_free(&d);
swissChili67bdf282021-06-06 18:46:08 -0700192 free(local.stack_slots);
193 }
194}
195
196void walk_and_alloc(struct local *local, value_t body)
197{
198 if (!listp(body))
199 return;
200
201 value_t args = cdr(body);
202
203 if (symstreq(car(body), "let1"))
204 {
205 int slot = local_alloc(local);
206
207 value_t expr = cdr(args);
swissChilif1ba8c12021-07-02 18:45:38 -0700208 for (; !nilp(expr); expr = cdr(expr))
209 {
swissChiliddc97542021-07-04 11:47:42 -0700210 walk_and_alloc(local, car(expr));
swissChilif1ba8c12021-07-02 18:45:38 -0700211 }
swissChili67bdf282021-06-06 18:46:08 -0700212
213 local_free(local, slot);
214 }
swissChilif1ba8c12021-07-02 18:45:38 -0700215 else if (symstreq(car(body), "lambda"))
216 {
217 // We don't want to walk the lambda because it's another function. When
218 // the lambda is compiled it will be walked.
219 return;
220 }
swissChili67bdf282021-06-06 18:46:08 -0700221 else
222 {
223 for (; !nilp(args); args = cdr(args))
224 {
225 walk_and_alloc(local, car(args));
226 }
swissChili8fc5e2f2021-04-22 13:45:10 -0700227 }
228}
229
swissChili53472e82021-05-08 16:06:32 -0700230struct environment compile_all(struct istream *is)
swissChili8fc5e2f2021-04-22 13:45:10 -0700231{
swissChilib8fd4712021-06-23 15:32:04 -0700232 unsigned char pool = make_pool();
233 unsigned char pop = push_pool(pool);
234
swissChili8fc5e2f2021-04-22 13:45:10 -0700235 value_t val;
swissChilif3e7f182021-04-20 13:57:22 -0700236 struct environment env;
237 env.first = NULL;
swissChili53472e82021-05-08 16:06:32 -0700238 load_std(&env);
239
240 while (read1(is, &val))
swissChili8fc5e2f2021-04-22 13:45:10 -0700241 {
swissChili53472e82021-05-08 16:06:32 -0700242 compile_tl(val, &env);
swissChili8fc5e2f2021-04-22 13:45:10 -0700243 }
swissChilif3e7f182021-04-20 13:57:22 -0700244
swissChilib8fd4712021-06-23 15:32:04 -0700245 pop_pool(pop);
246
swissChili8fc5e2f2021-04-22 13:45:10 -0700247 return env;
swissChilica107a02021-04-14 12:07:30 -0700248}
swissChilib3ca4fb2021-04-20 10:33:00 -0700249
swissChili53472e82021-05-08 16:06:32 -0700250int nextpc(struct local *local, dasm_State **Dst)
swissChilib3ca4fb2021-04-20 10:33:00 -0700251{
swissChili53472e82021-05-08 16:06:32 -0700252 int n = local->nextpc++;
253 if (n > local->npc)
254 {
255 local->npc += 16;
256 dasm_growpc(Dst, local->npc);
257 }
258 return n;
259}
260
swissChili6b47b6d2021-06-30 22:08:55 -0700261void compile_backquote(struct environment *env, struct local *local,
262 value_t val, dasm_State **Dst)
263{
264 if (!listp(val))
265 {
266 | mov eax, (val);
267 }
268 else
269 {
270 value_t fsym = car(val),
271 args = cdr(val);
272 int nargs = length(args);
273
274 // TODO
275 }
276}
277
swissChiliddc97542021-07-04 11:47:42 -0700278void compile_variable(struct variable *v, dasm_State *Dst)
279{
280 switch (v->type)
281 {
282 case V_ARGUMENT:
283 | mov eax, dword [ebp + (value_size * (v->number + 2))];
284 break;
285 case V_BOUND:
286 | mov eax, dword [ebp - ((v->number + 1) * value_size)];
287 break;
288 case V_FREE:
289 // edi is the closure context pointer
290 | mov eax, dword [edi + (v->number * value_size)];
291 break;
292 default:
293 err("Sorry, can only access V_ARGUMENT, V_FREE and V_BOUND variables for now :(");
294 }
295}
296
swissChili53472e82021-05-08 16:06:32 -0700297void compile_expression(struct environment *env, struct local *local,
298 value_t val, dasm_State **Dst)
299{
300 if (symstreq(val, "nil"))
301 {
302 | mov eax, (nil);
303 }
swissChili923b5362021-05-09 20:31:43 -0700304 else if (symstreq(val, "t"))
305 {
306 | mov eax, (t);
307 }
308 else if (integerp(val) || stringp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700309 {
310 | mov eax, val;
311 }
swissChili53472e82021-05-08 16:06:32 -0700312 else if (listp(val))
swissChilib3ca4fb2021-04-20 10:33:00 -0700313 {
swissChili53472e82021-05-08 16:06:32 -0700314 value_t fsym = car(val);
315 value_t args = cdr(val);
316 int nargs = length(args);
swissChilib3ca4fb2021-04-20 10:33:00 -0700317
swissChili53472e82021-05-08 16:06:32 -0700318 if (!symbolp(fsym))
swissChilif3e7f182021-04-20 13:57:22 -0700319 {
swissChili53472e82021-05-08 16:06:32 -0700320 err("function name must be a symbol");
swissChilif3e7f182021-04-20 13:57:22 -0700321 }
322
swissChili53472e82021-05-08 16:06:32 -0700323 if (symstreq(fsym, "if"))
swissChilib3ca4fb2021-04-20 10:33:00 -0700324 {
swissChili53472e82021-05-08 16:06:32 -0700325 if (nargs < 2 || nargs > 3)
326 err("Must give at least 2 arguments to if");
swissChilib3ca4fb2021-04-20 10:33:00 -0700327
swissChili53472e82021-05-08 16:06:32 -0700328 compile_expression(env, local, car(args), Dst);
329 int false_label = nextpc(local, Dst),
330 after_label = nextpc(local, Dst);
331
332 // result is in eax
333 | cmp eax, (nil);
334 | je =>false_label;
335
336 compile_expression(env, local, elt(args, 1), Dst);
swissChilia820dea2021-05-09 16:46:55 -0700337 | jmp =>after_label;
swissChili923b5362021-05-09 20:31:43 -0700338 |=>false_label:;
swissChili53472e82021-05-08 16:06:32 -0700339 if (nargs == 3)
340 compile_expression(env, local, elt(args, 2), Dst);
341 |=>after_label:
342 }
swissChili67bdf282021-06-06 18:46:08 -0700343 else if (symstreq(fsym, "let1"))
344 {
345 if (nargs < 2)
346 {
347 err("Must give at least 2 arguments to let1");
348 }
349 value_t binding = car(args);
350 value_t rest = cdr(args);
351
352 if (length(binding) != 2)
353 {
354 err("Binding list in let1 must contain exactly two entries");
355 }
356
357 value_t name = car(binding);
358 value_t value = car(cdr(binding));
359
360 compile_expression(env, local, value, Dst);
361
362 int i = local_alloc(local);
363
364 add_variable(local, V_BOUND, (char *)(name ^ SYMBOL_TAG), i);
365
366 | mov dword [ebp - ((i + 1) * value_size)], eax;
367
368 for (; !nilp(rest); rest = cdr(rest))
369 {
370 compile_expression(env, local, car(rest), Dst);
371 }
372
373 local_free(local, i);
374 }
swissChilie9fec8b2021-06-22 13:59:33 -0700375 else if (symstreq(fsym, "gc"))
376 {
377 if (nargs)
378 {
379 err("gc takes no arguments");
380 }
381
382 | run_gc;
383 }
swissChili6b47b6d2021-06-30 22:08:55 -0700384 else if (symstreq(fsym, "quote"))
385 {
386 if (nargs != 1)
387 err("quote should take exactly 1 argument");
388
389 // Simple!
390 | mov eax, (car(args));
391 }
392 else if (symstreq(fsym, "backquote"))
393 {
394 if (nargs != 1)
395 err("backquote should take exactly 1 argument");
396
397 compile_backquote(env, local, car(args), Dst);
398 }
swissChili74348422021-07-04 13:23:24 -0700399 else if (symstreq(fsym, "function"))
400 {
401 if (nargs != 1)
402 {
403 err("function should take exactly 1 argument");
404 }
405
406 if (!symbolp(car(args)))
407 {
408 err("argument to function should be a symbol resolvable at compile time");
409 }
410
411 struct function *f = find_function(env, (char *)(car(args) ^ SYMBOL_TAG));
412 value_t closure = create_closure(f->code_ptr, f->nargs, 0);
413
414 | mov eax, (closure);
415 }
swissChili6b47b6d2021-06-30 22:08:55 -0700416 else if (symstreq(fsym, "list"))
417 {
418 | push (nil);
419
420 for (int i = nargs - 1; i >= 0; i--)
421 {
422 compile_expression(env, local, elt(args, i), Dst);
423
424 // push the ith item
425 | push eax;
426 // cons the top two stack items
427 | mov ebx, (cons);
428 | call ebx;
429 // remove the stack items from use
430 | add esp, (2 * value_size);
431 // put the new thing on the stack
432 | push eax;
433 }
434
435 | pop eax;
436 }
swissChiliddc97542021-07-04 11:47:42 -0700437 else if (symstreq(fsym, "lambda"))
438 {
439 // Compile the function with this as the parent scope
440 struct local new_local;
441 int nargs_out;
swissChili74348422021-07-04 13:23:24 -0700442 dasm_State *d = compile_function(args, NS_ANONYMOUS, env, &new_local, local, &nargs_out, "recurse");
swissChiliddc97542021-07-04 11:47:42 -0700443
444 // Link the function
445 void *func_ptr = link(&d);
446
447 // Create a closure object with the correct number of captures at
448 // runtime
swissChiliddc97542021-07-04 11:47:42 -0700449 | push (new_local.num_closure_slots);
450 | push (nargs_out);
451 | push (func_ptr);
swissChili74348422021-07-04 13:23:24 -0700452 | mov ebx, (create_closure);
swissChiliddc97542021-07-04 11:47:42 -0700453 | call ebx;
454 | add esp, 12;
455
456 // Walk the generated local scope for V_FREE variables, since each
457 // of these exists in our scope (or higher), evaluate it and set it
458 // as a member of the lambda capture.
459
460 for (struct variable *var = new_local.first; var; var = var->prev)
461 {
462 if (var->type == V_FREE)
463 {
464 // Closure in eax
465 | push eax;
466 // Variable now in eax
467 compile_variable(find_variable(local, var->name), Dst);
468 | push eax;
469
swissChiliddc97542021-07-04 11:47:42 -0700470 // The capture offset
471 | push (var->number);
swissChili74348422021-07-04 13:23:24 -0700472 | mov ebx, (set_closure_capture_variable);
swissChiliddc97542021-07-04 11:47:42 -0700473 | call ebx;
474 // Skip the value and index
475 | add esp, 8;
476 // Pop the closure back in to eax
477 | pop eax;
478 }
479 }
480
481 // Closure is still in eax
482
483 dasm_free(&d);
484 free(new_local.stack_slots);
485 }
swissChili53472e82021-05-08 16:06:32 -0700486 else
487 {
swissChili74348422021-07-04 13:23:24 -0700488 char *name = (char *)(fsym ^ SYMBOL_TAG);
489 struct function *func = find_function(env, name);
490
491 bool is_recursive = false;
492 int nargs_needed = 0;
swissChili53472e82021-05-08 16:06:32 -0700493
swissChili74348422021-07-04 13:23:24 -0700494 if (symstreq(fsym, local->current_function_name))
swissChilif1ba8c12021-07-02 18:45:38 -0700495 {
swissChili74348422021-07-04 13:23:24 -0700496 is_recursive = true;
497 nargs_needed = local->num_args;
498 }
499 else
500 {
501 if (func == NULL)
502 {
503 fprintf(stderr, "Function call: %s at %s:%d\n", name, cons_file(val), cons_line(val));
504 err("Function undefined");
505 }
506
507 nargs_needed = func->nargs;
508 }
509
510 if (nargs != nargs_needed)
511 {
512 fprintf(stderr, "Function call: %s at %s:%d, want %d args but given %d\n",
513 name, cons_file(val), cons_line(val), nargs_needed, nargs);
swissChili53472e82021-05-08 16:06:32 -0700514 err("wrong number of args");
swissChilif1ba8c12021-07-02 18:45:38 -0700515 }
swissChili53472e82021-05-08 16:06:32 -0700516
swissChili74348422021-07-04 13:23:24 -0700517 if (is_recursive || func->namespace == NS_FUNCTION)
swissChili53472e82021-05-08 16:06:32 -0700518 {
swissChili2999dd12021-07-02 14:19:53 -0700519 for (int i = length(args) - 1; i >= 0; i--)
520 {
521 compile_expression(env, local, elt(args, i), Dst);
522 | push eax;
523 }
swissChili74348422021-07-04 13:23:24 -0700524
525 if (is_recursive)
526 {
527 | call ->function_start;
528 }
529 else
530 {
531 | mov ebx, (func->code_addr);
532 | call ebx;
533 }
swissChili2999dd12021-07-02 14:19:53 -0700534 | add esp, (nargs * value_size);
535 // result in eax
536 }
537 else if (func->namespace == NS_MACRO)
538 {
539 value_t expanded_to = call_list(func, args);
540
swissChili2999dd12021-07-02 14:19:53 -0700541 compile_expression(env, local, expanded_to, Dst);
542 }
swissChili53472e82021-05-08 16:06:32 -0700543 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700544 }
swissChili923b5362021-05-09 20:31:43 -0700545 else if (symbolp(val))
546 {
swissChili923b5362021-05-09 20:31:43 -0700547 struct variable *v = find_variable(local, (char *)(val ^ SYMBOL_TAG));
548
549 if (!v)
swissChilie9fec8b2021-06-22 13:59:33 -0700550 {
551 fprintf(stderr, "var: %s\n", (char *)(val ^ SYMBOL_TAG));
swissChili923b5362021-05-09 20:31:43 -0700552 err("Variable unbound");
swissChilie9fec8b2021-06-22 13:59:33 -0700553 }
swissChili923b5362021-05-09 20:31:43 -0700554
swissChiliddc97542021-07-04 11:47:42 -0700555 compile_variable(v, Dst);
swissChili923b5362021-05-09 20:31:43 -0700556 }
swissChilib3ca4fb2021-04-20 10:33:00 -0700557}
swissChilif3e7f182021-04-20 13:57:22 -0700558
swissChili53472e82021-05-08 16:06:32 -0700559void compile_expr_to_func(struct environment *env, char *name, value_t val,
560 dasm_State **Dst)
swissChilif3e7f182021-04-20 13:57:22 -0700561{
562 | setup 0;
563
564 struct local local;
swissChili53472e82021-05-08 16:06:32 -0700565 compile_expression(env, &local, val, Dst);
566
swissChilif3e7f182021-04-20 13:57:22 -0700567 | cleanup;
568
swissChili2999dd12021-07-02 14:19:53 -0700569 add_function(env, name, link(Dst), 0, NS_FUNCTION);
swissChilif3e7f182021-04-20 13:57:22 -0700570}
swissChili923b5362021-05-09 20:31:43 -0700571
572struct variable *add_variable(struct local *local, enum var_type type,
573 char *name, int number)
574{
575 struct variable *var = malloc(sizeof(struct variable));
576 var->prev = local->first;
577 var->type = type;
578 var->name = name;
579 var->number = number;
580
581 local->first = var;
582
583 return var;
584}
585
586void destroy_local(struct local *local)
587{
588 for (struct variable *v = local->first; v;)
589 {
590 struct variable *t = v;
591 v = v->prev;
592 free(t);
593 }
594}
595
596struct variable *find_variable(struct local *local, char *name)
597{
598 struct variable *v = local->first;
599
600 for (; v && strcmp(v->name, name) != 0; v = v->prev)
601 {}
602
swissChiliddc97542021-07-04 11:47:42 -0700603 if (!v)
604 {
605 if (local->parent)
606 {
607 v = find_variable(local->parent, name);
608
609 if (v)
610 {
611 // We found this in a parent scope, add it as a V_FREE variable to skip the search.
612 v = add_variable(local, V_FREE, name, local->num_closure_slots++);
613 }
614 }
615 }
swissChili923b5362021-05-09 20:31:43 -0700616 return v;
617}
swissChili2999dd12021-07-02 14:19:53 -0700618
swissChiliddc97542021-07-04 11:47:42 -0700619extern value_t _call_list(void *addr, value_t list, value_t *edi);
swissChili2999dd12021-07-02 14:19:53 -0700620
621value_t call_list(struct function *func, value_t list)
622{
swissChiliddc97542021-07-04 11:47:42 -0700623 return _call_list(func->code_ptr, list, NULL);
624}
625
626value_t call_list_closure(struct closure *c, value_t list)
627{
628 return _call_list(c->function, list, c->data);
swissChili2999dd12021-07-02 14:19:53 -0700629}