More precise stack marking.
[bpt/guile.git] / libguile / vm.c
1 /* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
17 */
18
19 #if HAVE_CONFIG_H
20 # include <config.h>
21 #endif
22
23 #include <stdlib.h>
24 #include <alloca.h>
25 #include <alignof.h>
26 #include <string.h>
27 #include <stdint.h>
28
29 #ifdef HAVE_SYS_MMAN_H
30 #include <sys/mman.h>
31 #endif
32
33 #include "libguile/bdw-gc.h"
34 #include <gc/gc_mark.h>
35
36 #include "_scm.h"
37 #include "control.h"
38 #include "frames.h"
39 #include "instructions.h"
40 #include "loader.h"
41 #include "programs.h"
42 #include "vm.h"
43 #include "vm-builtins.h"
44
45 #include "private-gc.h" /* scm_getenv_int */
46
47 static int vm_default_engine = SCM_VM_REGULAR_ENGINE;
48
49 /* Unfortunately we can't snarf these: snarfed things are only loaded up from
50 (system vm vm), which might not be loaded before an error happens. */
51 static SCM sym_vm_run;
52 static SCM sym_vm_error;
53 static SCM sym_keyword_argument_error;
54 static SCM sym_regular;
55 static SCM sym_debug;
56
57 /* The VM has a number of internal assertions that shouldn't normally be
58 necessary, but might be if you think you found a bug in the VM. */
59 #define VM_ENABLE_ASSERTIONS
60
61 /* #define VM_ENABLE_PARANOID_ASSERTIONS */
62
63 /* Size in SCM objects of the stack reserve. The reserve is used to run
64 exception handling code in case of a VM stack overflow. */
65 #define VM_STACK_RESERVE_SIZE 512
66
67
68 \f
69 /*
70 * VM Continuation
71 */
72
73 void
74 scm_i_vm_cont_print (SCM x, SCM port, scm_print_state *pstate)
75 {
76 scm_puts_unlocked ("#<vm-continuation ", port);
77 scm_uintprint (SCM_UNPACK (x), 16, port);
78 scm_puts_unlocked (">", port);
79 }
80
81 /* In theory, a number of vm instances can be active in the call trace, and we
82 only want to reify the continuations of those in the current continuation
83 root. I don't see a nice way to do this -- ideally it would involve dynwinds,
84 and previous values of the *the-vm* fluid within the current continuation
85 root. But we don't have access to continuation roots in the dynwind stack.
86 So, just punt for now, we just capture the continuation for the current VM.
87
88 While I'm on the topic, ideally we could avoid copying the C stack if the
89 continuation root is inside VM code, and call/cc was invoked within that same
90 call to vm_run; but that's currently not implemented.
91 */
92 SCM
93 scm_i_vm_capture_stack (SCM *stack_base, SCM *fp, SCM *sp, scm_t_uint32 *ra,
94 scm_t_dynstack *dynstack, scm_t_uint32 flags)
95 {
96 struct scm_vm_cont *p;
97
98 p = scm_gc_malloc (sizeof (*p), "capture_vm_cont");
99 p->stack_size = sp - stack_base + 1;
100 p->stack_base = scm_gc_malloc (p->stack_size * sizeof (SCM),
101 "capture_vm_cont");
102 p->ra = ra;
103 p->sp = sp;
104 p->fp = fp;
105 memcpy (p->stack_base, stack_base, (sp + 1 - stack_base) * sizeof (SCM));
106 p->reloc = p->stack_base - stack_base;
107 p->dynstack = dynstack;
108 p->flags = flags;
109 return scm_cell (scm_tc7_vm_cont, (scm_t_bits)p);
110 }
111
112 static void
113 vm_return_to_continuation (struct scm_vm *vp, SCM cont, size_t n, SCM *argv)
114 {
115 struct scm_vm_cont *cp;
116 SCM *argv_copy;
117
118 argv_copy = alloca (n * sizeof(SCM));
119 memcpy (argv_copy, argv, n * sizeof(SCM));
120
121 cp = SCM_VM_CONT_DATA (cont);
122
123 if (vp->stack_size < cp->stack_size + n + 3)
124 scm_misc_error ("vm-engine", "not enough space to reinstate continuation",
125 scm_list_1 (cont));
126
127 vp->sp = cp->sp;
128 vp->fp = cp->fp;
129 memcpy (vp->stack_base, cp->stack_base, cp->stack_size * sizeof (SCM));
130
131 {
132 size_t i;
133
134 /* Push on an empty frame, as the continuation expects. */
135 for (i = 0; i < 3; i++)
136 {
137 vp->sp++;
138 *vp->sp = SCM_BOOL_F;
139 }
140
141 /* Push the return values. */
142 for (i = 0; i < n; i++)
143 {
144 vp->sp++;
145 *vp->sp = argv_copy[i];
146 }
147 vp->ip = cp->ra;
148 }
149 }
150
151 static struct scm_vm * thread_vm (scm_i_thread *t);
152 SCM
153 scm_i_capture_current_stack (void)
154 {
155 scm_i_thread *thread;
156 struct scm_vm *vp;
157
158 thread = SCM_I_CURRENT_THREAD;
159 vp = thread_vm (thread);
160
161 return scm_i_vm_capture_stack (vp->stack_base, vp->fp, vp->sp, vp->ip,
162 scm_dynstack_capture_all (&thread->dynstack),
163 0);
164 }
165
166 static void vm_dispatch_apply_hook (struct scm_vm *vp) SCM_NOINLINE;
167 static void vm_dispatch_push_continuation_hook (struct scm_vm *vp) SCM_NOINLINE;
168 static void vm_dispatch_pop_continuation_hook (struct scm_vm *vp, SCM *old_fp) SCM_NOINLINE;
169 static void vm_dispatch_next_hook (struct scm_vm *vp) SCM_NOINLINE;
170 static void vm_dispatch_abort_hook (struct scm_vm *vp) SCM_NOINLINE;
171 static void vm_dispatch_restore_continuation_hook (struct scm_vm *vp) SCM_NOINLINE;
172
173 static void
174 vm_dispatch_hook (struct scm_vm *vp, int hook_num, SCM *argv, int n)
175 {
176 SCM hook;
177 struct scm_frame c_frame;
178 scm_t_cell *frame;
179 int saved_trace_level;
180
181 hook = vp->hooks[hook_num];
182
183 if (SCM_LIKELY (scm_is_false (hook))
184 || scm_is_null (SCM_HOOK_PROCEDURES (hook)))
185 return;
186
187 saved_trace_level = vp->trace_level;
188 vp->trace_level = 0;
189
190 /* Allocate a frame object on the stack. This is more efficient than calling
191 `scm_c_make_frame ()' to allocate on the heap, but it forces hooks to not
192 capture frame objects.
193
194 At the same time, procedures such as `frame-procedure' make sense only
195 while the stack frame represented by the frame object is visible, so it
196 seems reasonable to limit the lifetime of frame objects. */
197
198 c_frame.stack_holder = vp;
199 c_frame.fp_offset = vp->fp - vp->stack_base;
200 c_frame.sp_offset = vp->sp - vp->stack_base;
201 c_frame.ip = vp->ip;
202
203 /* Arrange for FRAME to be 8-byte aligned, like any other cell. */
204 frame = alloca (sizeof (*frame) + 8);
205 frame = (scm_t_cell *) ROUND_UP ((scm_t_uintptr) frame, 8UL);
206
207 frame->word_0 = SCM_PACK (scm_tc7_frame | (SCM_VM_FRAME_KIND_VM << 8));
208 frame->word_1 = SCM_PACK_POINTER (&c_frame);
209
210 if (n == 0)
211 {
212 SCM args[1];
213
214 args[0] = SCM_PACK_POINTER (frame);
215 scm_c_run_hookn (hook, args, 1);
216 }
217 else if (n == 1)
218 {
219 SCM args[2];
220
221 args[0] = SCM_PACK_POINTER (frame);
222 args[1] = argv[0];
223 scm_c_run_hookn (hook, args, 2);
224 }
225 else
226 {
227 SCM args = SCM_EOL;
228
229 while (n--)
230 args = scm_cons (argv[n], args);
231 scm_c_run_hook (hook, scm_cons (SCM_PACK_POINTER (frame), args));
232 }
233
234 vp->trace_level = saved_trace_level;
235 }
236
237 static void
238 vm_dispatch_apply_hook (struct scm_vm *vp)
239 {
240 return vm_dispatch_hook (vp, SCM_VM_APPLY_HOOK, NULL, 0);
241 }
242 static void vm_dispatch_push_continuation_hook (struct scm_vm *vp)
243 {
244 return vm_dispatch_hook (vp, SCM_VM_PUSH_CONTINUATION_HOOK, NULL, 0);
245 }
246 static void vm_dispatch_pop_continuation_hook (struct scm_vm *vp, SCM *old_fp)
247 {
248 return vm_dispatch_hook (vp, SCM_VM_POP_CONTINUATION_HOOK,
249 &SCM_FRAME_LOCAL (old_fp, 1),
250 SCM_FRAME_NUM_LOCALS (old_fp, vp->sp) - 1);
251 }
252 static void vm_dispatch_next_hook (struct scm_vm *vp)
253 {
254 return vm_dispatch_hook (vp, SCM_VM_NEXT_HOOK, NULL, 0);
255 }
256 static void vm_dispatch_abort_hook (struct scm_vm *vp)
257 {
258 return vm_dispatch_hook (vp, SCM_VM_ABORT_CONTINUATION_HOOK,
259 &SCM_FRAME_LOCAL (vp->fp, 1),
260 SCM_FRAME_NUM_LOCALS (vp->fp, vp->sp) - 1);
261 }
262 static void vm_dispatch_restore_continuation_hook (struct scm_vm *vp)
263 {
264 return vm_dispatch_hook (vp, SCM_VM_RESTORE_CONTINUATION_HOOK, NULL, 0);
265 }
266
267 static void
268 vm_abort (struct scm_vm *vp, SCM tag,
269 size_t nstack, SCM *stack_args, SCM tail, SCM *sp,
270 scm_i_jmp_buf *current_registers) SCM_NORETURN;
271
272 static void
273 vm_abort (struct scm_vm *vp, SCM tag,
274 size_t nstack, SCM *stack_args, SCM tail, SCM *sp,
275 scm_i_jmp_buf *current_registers)
276 {
277 size_t i;
278 ssize_t tail_len;
279 SCM *argv;
280
281 tail_len = scm_ilength (tail);
282 if (tail_len < 0)
283 scm_misc_error ("vm-engine", "tail values to abort should be a list",
284 scm_list_1 (tail));
285
286 argv = alloca ((nstack + tail_len) * sizeof (SCM));
287 for (i = 0; i < nstack; i++)
288 argv[i] = stack_args[i];
289 for (; i < nstack + tail_len; i++, tail = scm_cdr (tail))
290 argv[i] = scm_car (tail);
291
292 /* FIXME: NULLSTACK (SCM_VM_DATA (vp)->sp - sp) */
293 vp->sp = sp;
294
295 scm_c_abort (vp, tag, nstack + tail_len, argv, current_registers);
296 }
297
298 static void
299 vm_reinstate_partial_continuation (struct scm_vm *vp, SCM cont,
300 size_t n, SCM *argv,
301 scm_t_dynstack *dynstack,
302 scm_i_jmp_buf *registers)
303 {
304 struct scm_vm_cont *cp;
305 SCM *argv_copy, *base;
306 scm_t_ptrdiff reloc;
307 size_t i;
308
309 argv_copy = alloca (n * sizeof(SCM));
310 memcpy (argv_copy, argv, n * sizeof(SCM));
311
312 cp = SCM_VM_CONT_DATA (cont);
313 base = SCM_FRAME_LOCALS_ADDRESS (vp->fp);
314 reloc = cp->reloc + (base - cp->stack_base);
315
316 #define RELOC(scm_p) \
317 (((SCM *) (scm_p)) + reloc)
318
319 if ((base - vp->stack_base) + cp->stack_size + n + 1 > vp->stack_size)
320 scm_misc_error ("vm-engine",
321 "not enough space to instate partial continuation",
322 scm_list_1 (cont));
323
324 memcpy (base, cp->stack_base, cp->stack_size * sizeof (SCM));
325
326 /* now relocate frame pointers */
327 {
328 SCM *fp;
329 for (fp = RELOC (cp->fp);
330 SCM_FRAME_LOWER_ADDRESS (fp) > base;
331 fp = SCM_FRAME_DYNAMIC_LINK (fp))
332 SCM_FRAME_SET_DYNAMIC_LINK (fp, RELOC (SCM_FRAME_DYNAMIC_LINK (fp)));
333 }
334
335 vp->sp = base - 1 + cp->stack_size;
336 vp->fp = RELOC (cp->fp);
337 vp->ip = cp->ra;
338
339 /* Push the arguments. */
340 for (i = 0; i < n; i++)
341 {
342 vp->sp++;
343 *vp->sp = argv_copy[i];
344 }
345
346 /* The prompt captured a slice of the dynamic stack. Here we wind
347 those entries onto the current thread's stack. We also have to
348 relocate any prompts that we see along the way. */
349 {
350 scm_t_bits *walk;
351
352 for (walk = SCM_DYNSTACK_FIRST (cp->dynstack);
353 SCM_DYNSTACK_TAG (walk);
354 walk = SCM_DYNSTACK_NEXT (walk))
355 {
356 scm_t_bits tag = SCM_DYNSTACK_TAG (walk);
357
358 if (SCM_DYNSTACK_TAG_TYPE (tag) == SCM_DYNSTACK_TYPE_PROMPT)
359 scm_dynstack_wind_prompt (dynstack, walk, reloc, registers);
360 else
361 scm_dynstack_wind_1 (dynstack, walk);
362 }
363 }
364 #undef RELOC
365 }
366
367 \f
368 /*
369 * VM Error Handling
370 */
371
372 static void vm_error (const char *msg, SCM arg) SCM_NORETURN;
373 static void vm_error_bad_instruction (scm_t_uint32 inst) SCM_NORETURN SCM_NOINLINE;
374 static void vm_error_unbound (SCM proc, SCM sym) SCM_NORETURN SCM_NOINLINE;
375 static void vm_error_unbound_fluid (SCM proc, SCM fluid) SCM_NORETURN SCM_NOINLINE;
376 static void vm_error_not_a_variable (const char *func_name, SCM x) SCM_NORETURN SCM_NOINLINE;
377 static void vm_error_apply_to_non_list (SCM x) SCM_NORETURN SCM_NOINLINE;
378 static void vm_error_kwargs_length_not_even (SCM proc) SCM_NORETURN SCM_NOINLINE;
379 static void vm_error_kwargs_invalid_keyword (SCM proc, SCM obj) SCM_NORETURN SCM_NOINLINE;
380 static void vm_error_kwargs_unrecognized_keyword (SCM proc, SCM kw) SCM_NORETURN SCM_NOINLINE;
381 static void vm_error_too_many_args (int nargs) SCM_NORETURN SCM_NOINLINE;
382 static void vm_error_wrong_num_args (SCM proc) SCM_NORETURN SCM_NOINLINE;
383 static void vm_error_wrong_type_apply (SCM proc) SCM_NORETURN SCM_NOINLINE;
384 static void vm_error_stack_overflow (struct scm_vm *vp) SCM_NORETURN SCM_NOINLINE;
385 static void vm_error_stack_underflow (void) SCM_NORETURN SCM_NOINLINE;
386 static void vm_error_improper_list (SCM x) SCM_NORETURN SCM_NOINLINE;
387 static void vm_error_not_a_pair (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
388 static void vm_error_not_a_bytevector (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
389 static void vm_error_not_a_struct (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
390 static void vm_error_no_values (void) SCM_NORETURN SCM_NOINLINE;
391 static void vm_error_not_enough_values (void) SCM_NORETURN SCM_NOINLINE;
392 static void vm_error_wrong_number_of_values (scm_t_uint32 expected) SCM_NORETURN SCM_NOINLINE;
393 static void vm_error_continuation_not_rewindable (SCM cont) SCM_NORETURN SCM_NOINLINE;
394 static void vm_error_bad_wide_string_length (size_t len) SCM_NORETURN SCM_NOINLINE;
395
396 static void
397 vm_error (const char *msg, SCM arg)
398 {
399 scm_throw (sym_vm_error,
400 scm_list_3 (sym_vm_run, scm_from_latin1_string (msg),
401 SCM_UNBNDP (arg) ? SCM_EOL : scm_list_1 (arg)));
402 abort(); /* not reached */
403 }
404
405 static void
406 vm_error_bad_instruction (scm_t_uint32 inst)
407 {
408 vm_error ("VM: Bad instruction: ~s", scm_from_uint32 (inst));
409 }
410
411 static void
412 vm_error_unbound (SCM proc, SCM sym)
413 {
414 scm_error_scm (scm_misc_error_key, proc,
415 scm_from_latin1_string ("Unbound variable: ~s"),
416 scm_list_1 (sym), SCM_BOOL_F);
417 }
418
419 static void
420 vm_error_unbound_fluid (SCM proc, SCM fluid)
421 {
422 scm_error_scm (scm_misc_error_key, proc,
423 scm_from_latin1_string ("Unbound fluid: ~s"),
424 scm_list_1 (fluid), SCM_BOOL_F);
425 }
426
427 static void
428 vm_error_not_a_variable (const char *func_name, SCM x)
429 {
430 scm_error (scm_arg_type_key, func_name, "Not a variable: ~S",
431 scm_list_1 (x), scm_list_1 (x));
432 }
433
434 static void
435 vm_error_apply_to_non_list (SCM x)
436 {
437 scm_error (scm_arg_type_key, "apply", "Apply to non-list: ~S",
438 scm_list_1 (x), scm_list_1 (x));
439 }
440
441 static void
442 vm_error_kwargs_length_not_even (SCM proc)
443 {
444 scm_error_scm (sym_keyword_argument_error, proc,
445 scm_from_latin1_string ("Odd length of keyword argument list"),
446 SCM_EOL, SCM_BOOL_F);
447 }
448
449 static void
450 vm_error_kwargs_invalid_keyword (SCM proc, SCM obj)
451 {
452 scm_error_scm (sym_keyword_argument_error, proc,
453 scm_from_latin1_string ("Invalid keyword"),
454 SCM_EOL, scm_list_1 (obj));
455 }
456
457 static void
458 vm_error_kwargs_unrecognized_keyword (SCM proc, SCM kw)
459 {
460 scm_error_scm (sym_keyword_argument_error, proc,
461 scm_from_latin1_string ("Unrecognized keyword"),
462 SCM_EOL, scm_list_1 (kw));
463 }
464
465 static void
466 vm_error_too_many_args (int nargs)
467 {
468 vm_error ("VM: Too many arguments", scm_from_int (nargs));
469 }
470
471 static void
472 vm_error_wrong_num_args (SCM proc)
473 {
474 scm_wrong_num_args (proc);
475 }
476
477 static void
478 vm_error_wrong_type_apply (SCM proc)
479 {
480 scm_error (scm_arg_type_key, NULL, "Wrong type to apply: ~S",
481 scm_list_1 (proc), scm_list_1 (proc));
482 }
483
484 static void
485 vm_error_stack_overflow (struct scm_vm *vp)
486 {
487 if (vp->stack_limit < vp->stack_base + vp->stack_size)
488 /* There are VM_STACK_RESERVE_SIZE bytes left. Make them available so
489 that `throw' below can run on this VM. */
490 vp->stack_limit = vp->stack_base + vp->stack_size;
491 else
492 /* There is no space left on the stack. FIXME: Do something more
493 sensible here! */
494 abort ();
495 vm_error ("VM: Stack overflow", SCM_UNDEFINED);
496 }
497
498 static void
499 vm_error_stack_underflow (void)
500 {
501 vm_error ("VM: Stack underflow", SCM_UNDEFINED);
502 }
503
504 static void
505 vm_error_improper_list (SCM x)
506 {
507 vm_error ("Expected a proper list, but got object with tail ~s", x);
508 }
509
510 static void
511 vm_error_not_a_pair (const char *subr, SCM x)
512 {
513 scm_wrong_type_arg_msg (subr, 1, x, "pair");
514 }
515
516 static void
517 vm_error_not_a_bytevector (const char *subr, SCM x)
518 {
519 scm_wrong_type_arg_msg (subr, 1, x, "bytevector");
520 }
521
522 static void
523 vm_error_not_a_struct (const char *subr, SCM x)
524 {
525 scm_wrong_type_arg_msg (subr, 1, x, "struct");
526 }
527
528 static void
529 vm_error_no_values (void)
530 {
531 vm_error ("Zero values returned to single-valued continuation",
532 SCM_UNDEFINED);
533 }
534
535 static void
536 vm_error_not_enough_values (void)
537 {
538 vm_error ("Too few values returned to continuation", SCM_UNDEFINED);
539 }
540
541 static void
542 vm_error_wrong_number_of_values (scm_t_uint32 expected)
543 {
544 vm_error ("Wrong number of values returned to continuation (expected ~a)",
545 scm_from_uint32 (expected));
546 }
547
548 static void
549 vm_error_continuation_not_rewindable (SCM cont)
550 {
551 vm_error ("Unrewindable partial continuation", cont);
552 }
553
554 static void
555 vm_error_bad_wide_string_length (size_t len)
556 {
557 vm_error ("VM: Bad wide string length: ~S", scm_from_size_t (len));
558 }
559
560
561 \f
562
563 static SCM vm_boot_continuation;
564 static SCM vm_builtin_apply;
565 static SCM vm_builtin_values;
566 static SCM vm_builtin_abort_to_prompt;
567 static SCM vm_builtin_call_with_values;
568 static SCM vm_builtin_call_with_current_continuation;
569
570 static const scm_t_uint32 vm_boot_continuation_code[] = {
571 SCM_PACK_OP_24 (halt, 0)
572 };
573
574 static const scm_t_uint32 vm_builtin_apply_code[] = {
575 SCM_PACK_OP_24 (assert_nargs_ge, 3),
576 SCM_PACK_OP_24 (tail_apply, 0), /* proc in r1, args from r2 */
577 };
578
579 static const scm_t_uint32 vm_builtin_values_code[] = {
580 SCM_PACK_OP_24 (return_values, 0) /* vals from r1 */
581 };
582
583 static const scm_t_uint32 vm_builtin_abort_to_prompt_code[] = {
584 SCM_PACK_OP_24 (assert_nargs_ge, 2),
585 SCM_PACK_OP_24 (abort, 0), /* tag in r1, vals from r2 */
586 /* FIXME: Partial continuation should capture caller regs. */
587 SCM_PACK_OP_24 (return_values, 0) /* vals from r1 */
588 };
589
590 static const scm_t_uint32 vm_builtin_call_with_values_code[] = {
591 SCM_PACK_OP_24 (assert_nargs_ee, 3),
592 SCM_PACK_OP_24 (alloc_frame, 7),
593 SCM_PACK_OP_12_12 (mov, 6, 1),
594 SCM_PACK_OP_24 (call, 6), SCM_PACK_OP_ARG_8_24 (0, 1),
595 SCM_PACK_OP_12_12 (mov, 0, 2),
596 SCM_PACK_OP_24 (tail_call_shuffle, 7)
597 };
598
599 static const scm_t_uint32 vm_builtin_call_with_current_continuation_code[] = {
600 SCM_PACK_OP_24 (assert_nargs_ee, 2),
601 SCM_PACK_OP_24 (call_cc, 0)
602 };
603
604
605 static SCM
606 scm_vm_builtin_ref (unsigned idx)
607 {
608 switch (idx)
609 {
610 #define INDEX_TO_NAME(builtin, BUILTIN, req, opt, rest) \
611 case SCM_VM_BUILTIN_##BUILTIN: return vm_builtin_##builtin;
612 FOR_EACH_VM_BUILTIN(INDEX_TO_NAME)
613 #undef INDEX_TO_NAME
614 default: abort();
615 }
616 }
617
618 SCM scm_sym_apply;
619 static SCM scm_sym_values;
620 static SCM scm_sym_abort_to_prompt;
621 static SCM scm_sym_call_with_values;
622 static SCM scm_sym_call_with_current_continuation;
623
624 SCM
625 scm_vm_builtin_name_to_index (SCM name)
626 #define FUNC_NAME "builtin-name->index"
627 {
628 SCM_VALIDATE_SYMBOL (1, name);
629
630 #define NAME_TO_INDEX(builtin, BUILTIN, req, opt, rest) \
631 if (scm_is_eq (name, scm_sym_##builtin)) \
632 return scm_from_uint (SCM_VM_BUILTIN_##BUILTIN);
633 FOR_EACH_VM_BUILTIN(NAME_TO_INDEX)
634 #undef NAME_TO_INDEX
635
636 return SCM_BOOL_F;
637 }
638 #undef FUNC_NAME
639
640 SCM
641 scm_vm_builtin_index_to_name (SCM index)
642 #define FUNC_NAME "builtin-index->name"
643 {
644 unsigned idx;
645
646 SCM_VALIDATE_UINT_COPY (1, index, idx);
647
648 switch (idx)
649 {
650 #define INDEX_TO_NAME(builtin, BUILTIN, req, opt, rest) \
651 case SCM_VM_BUILTIN_##BUILTIN: return scm_sym_##builtin;
652 FOR_EACH_VM_BUILTIN(INDEX_TO_NAME)
653 #undef INDEX_TO_NAME
654 default: return SCM_BOOL_F;
655 }
656 }
657 #undef FUNC_NAME
658
659 static void
660 scm_init_vm_builtins (void)
661 {
662 scm_c_define_gsubr ("builtin-name->index", 1, 0, 0,
663 scm_vm_builtin_name_to_index);
664 scm_c_define_gsubr ("builtin-index->name", 1, 0, 0,
665 scm_vm_builtin_index_to_name);
666 }
667
668 SCM
669 scm_i_call_with_current_continuation (SCM proc)
670 {
671 return scm_call_1 (vm_builtin_call_with_current_continuation, proc);
672 }
673
674 \f
675 /*
676 * VM
677 */
678
679 #define VM_MIN_STACK_SIZE (1024)
680 #define VM_DEFAULT_STACK_SIZE (256 * 1024)
681 static size_t vm_stack_size = VM_DEFAULT_STACK_SIZE;
682
683 static void
684 initialize_default_stack_size (void)
685 {
686 int size = scm_getenv_int ("GUILE_STACK_SIZE", vm_stack_size);
687 if (size >= VM_MIN_STACK_SIZE)
688 vm_stack_size = size;
689 }
690
691 #define VM_NAME vm_regular_engine
692 #define VM_USE_HOOKS 0
693 #define FUNC_NAME "vm-regular-engine"
694 #include "vm-engine.c"
695 #undef FUNC_NAME
696 #undef VM_USE_HOOKS
697 #undef VM_NAME
698
699 #define VM_NAME vm_debug_engine
700 #define VM_USE_HOOKS 1
701 #define FUNC_NAME "vm-debug-engine"
702 #include "vm-engine.c"
703 #undef FUNC_NAME
704 #undef VM_USE_HOOKS
705 #undef VM_NAME
706
707 typedef SCM (*scm_t_vm_engine) (scm_i_thread *current_thread, struct scm_vm *vp,
708 scm_i_jmp_buf *registers, int resume);
709
710 static const scm_t_vm_engine vm_engines[SCM_VM_NUM_ENGINES] =
711 { vm_regular_engine, vm_debug_engine };
712
713 static SCM*
714 allocate_stack (size_t size)
715 #define FUNC_NAME "make_vm"
716 {
717 void *ret;
718
719 if (size >= ((size_t) -1) / sizeof (SCM))
720 abort ();
721
722 size *= sizeof (SCM);
723
724 #if HAVE_SYS_MMAN_H
725 ret = mmap (NULL, size, PROT_READ | PROT_WRITE,
726 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
727 if (ret == MAP_FAILED)
728 SCM_SYSERROR;
729 #else
730 ret = malloc (size);
731 if (!ret)
732 SCM_SYSERROR;
733 #endif
734
735 return (SCM *) ret;
736 }
737 #undef FUNC_NAME
738
739 static void
740 free_stack (SCM *stack, size_t size)
741 {
742 size *= sizeof (SCM);
743
744 #if HAVE_SYS_MMAN_H
745 munmap (stack, size);
746 #else
747 free (stack);
748 #endif
749 }
750
751 static struct scm_vm *
752 make_vm (void)
753 #define FUNC_NAME "make_vm"
754 {
755 int i;
756 struct scm_vm *vp;
757
758 vp = scm_gc_malloc (sizeof (struct scm_vm), "vm");
759
760 vp->stack_size= vm_stack_size;
761 vp->stack_base = allocate_stack (vp->stack_size);
762 vp->stack_limit = vp->stack_base + vp->stack_size - VM_STACK_RESERVE_SIZE;
763 vp->ip = NULL;
764 vp->sp = vp->stack_base - 1;
765 vp->fp = NULL;
766 vp->engine = vm_default_engine;
767 vp->trace_level = 0;
768 for (i = 0; i < SCM_VM_NUM_HOOKS; i++)
769 vp->hooks[i] = SCM_BOOL_F;
770
771 return vp;
772 }
773 #undef FUNC_NAME
774
775 /* Mark the VM stack region between its base and its current top. */
776 struct GC_ms_entry *
777 scm_i_vm_mark_stack (struct scm_vm *vp, struct GC_ms_entry *mark_stack_ptr,
778 struct GC_ms_entry *mark_stack_limit)
779 {
780 SCM *sp, *fp;
781
782 for (fp = vp->fp, sp = vp->sp; fp; fp = SCM_FRAME_DYNAMIC_LINK (fp))
783 {
784 for (; sp >= &SCM_FRAME_LOCAL (fp, 0); sp--)
785 {
786 SCM elt = *sp;
787 if (SCM_NIMP (elt))
788 mark_stack_ptr = GC_MARK_AND_PUSH ((GC_word *) elt,
789 mark_stack_ptr, mark_stack_limit,
790 NULL);
791 }
792 sp = SCM_FRAME_PREVIOUS_SP (fp);
793 }
794
795 return mark_stack_ptr;
796 }
797
798 /* Free the VM stack, as this thread is exiting. */
799 void
800 scm_i_vm_free_stack (struct scm_vm *vp)
801 {
802 free_stack (vp->stack_base, vp->stack_size);
803 vp->stack_base = vp->stack_limit = NULL;
804 vp->stack_size = 0;
805 }
806
807 static struct scm_vm *
808 thread_vm (scm_i_thread *t)
809 {
810 if (SCM_UNLIKELY (!t->vp))
811 t->vp = make_vm ();
812
813 return t->vp;
814 }
815
816 struct scm_vm *
817 scm_the_vm (void)
818 {
819 return thread_vm (SCM_I_CURRENT_THREAD);
820 }
821
822 SCM
823 scm_call_n (SCM proc, SCM *argv, size_t nargs)
824 {
825 scm_i_thread *thread;
826 struct scm_vm *vp;
827 SCM *base;
828 ptrdiff_t base_frame_size;
829 /* Cached variables. */
830 scm_i_jmp_buf registers; /* used for prompts */
831 size_t i;
832
833 thread = SCM_I_CURRENT_THREAD;
834 vp = thread_vm (thread);
835
836 SCM_CHECK_STACK;
837
838 /* Check that we have enough space: 3 words for the boot
839 continuation, 3 + nargs for the procedure application, and 3 for
840 setting up a new frame. */
841 base_frame_size = 3 + 3 + nargs + 3;
842 vp->sp += base_frame_size;
843 if (vp->sp >= vp->stack_limit)
844 vm_error_stack_overflow (vp);
845 base = vp->sp + 1 - base_frame_size;
846
847 /* Since it's possible to receive the arguments on the stack itself,
848 shuffle up the arguments first. */
849 for (i = nargs; i > 0; i--)
850 base[6 + i - 1] = argv[i - 1];
851
852 /* Push the boot continuation, which calls PROC and returns its
853 result(s). */
854 base[0] = SCM_PACK (vp->fp); /* dynamic link */
855 base[1] = SCM_PACK (vp->ip); /* ra */
856 base[2] = vm_boot_continuation;
857 vp->fp = &base[2];
858 vp->ip = (scm_t_uint32 *) vm_boot_continuation_code;
859
860 /* The pending call to PROC. */
861 base[3] = SCM_PACK (vp->fp); /* dynamic link */
862 base[4] = SCM_PACK (vp->ip); /* ra */
863 base[5] = proc;
864 vp->fp = &base[5];
865 vp->sp = &SCM_FRAME_LOCAL (vp->fp, nargs);
866
867 {
868 int resume = SCM_I_SETJMP (registers);
869
870 if (SCM_UNLIKELY (resume))
871 /* Non-local return. */
872 vm_dispatch_abort_hook (vp);
873
874 return vm_engines[vp->engine](thread, vp, &registers, resume);
875 }
876 }
877
878 /* Scheme interface */
879
880 #define VM_DEFINE_HOOK(n) \
881 { \
882 struct scm_vm *vp; \
883 vp = scm_the_vm (); \
884 if (scm_is_false (vp->hooks[n])) \
885 vp->hooks[n] = scm_make_hook (SCM_I_MAKINUM (1)); \
886 return vp->hooks[n]; \
887 }
888
889 SCM_DEFINE (scm_vm_apply_hook, "vm-apply-hook", 0, 0, 0,
890 (void),
891 "")
892 #define FUNC_NAME s_scm_vm_apply_hook
893 {
894 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK);
895 }
896 #undef FUNC_NAME
897
898 SCM_DEFINE (scm_vm_push_continuation_hook, "vm-push-continuation-hook", 0, 0, 0,
899 (void),
900 "")
901 #define FUNC_NAME s_scm_vm_push_continuation_hook
902 {
903 VM_DEFINE_HOOK (SCM_VM_PUSH_CONTINUATION_HOOK);
904 }
905 #undef FUNC_NAME
906
907 SCM_DEFINE (scm_vm_pop_continuation_hook, "vm-pop-continuation-hook", 0, 0, 0,
908 (void),
909 "")
910 #define FUNC_NAME s_scm_vm_pop_continuation_hook
911 {
912 VM_DEFINE_HOOK (SCM_VM_POP_CONTINUATION_HOOK);
913 }
914 #undef FUNC_NAME
915
916 SCM_DEFINE (scm_vm_next_hook, "vm-next-hook", 0, 0, 0,
917 (void),
918 "")
919 #define FUNC_NAME s_scm_vm_next_hook
920 {
921 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK);
922 }
923 #undef FUNC_NAME
924
925 SCM_DEFINE (scm_vm_abort_continuation_hook, "vm-abort-continuation-hook", 0, 0, 0,
926 (void),
927 "")
928 #define FUNC_NAME s_scm_vm_abort_continuation_hook
929 {
930 VM_DEFINE_HOOK (SCM_VM_ABORT_CONTINUATION_HOOK);
931 }
932 #undef FUNC_NAME
933
934 SCM_DEFINE (scm_vm_restore_continuation_hook, "vm-restore-continuation-hook", 0, 0, 0,
935 (void),
936 "")
937 #define FUNC_NAME s_scm_vm_restore_continuation_hook
938 {
939 VM_DEFINE_HOOK (SCM_VM_RESTORE_CONTINUATION_HOOK);
940 }
941 #undef FUNC_NAME
942
943 SCM_DEFINE (scm_vm_trace_level, "vm-trace-level", 0, 0, 0,
944 (void),
945 "")
946 #define FUNC_NAME s_scm_vm_trace_level
947 {
948 return scm_from_int (scm_the_vm ()->trace_level);
949 }
950 #undef FUNC_NAME
951
952 SCM_DEFINE (scm_set_vm_trace_level_x, "set-vm-trace-level!", 1, 0, 0,
953 (SCM level),
954 "")
955 #define FUNC_NAME s_scm_set_vm_trace_level_x
956 {
957 scm_the_vm ()->trace_level = scm_to_int (level);
958 return SCM_UNSPECIFIED;
959 }
960 #undef FUNC_NAME
961
962 \f
963 /*
964 * VM engines
965 */
966
967 static int
968 symbol_to_vm_engine (SCM engine, const char *FUNC_NAME)
969 {
970 if (scm_is_eq (engine, sym_regular))
971 return SCM_VM_REGULAR_ENGINE;
972 else if (scm_is_eq (engine, sym_debug))
973 return SCM_VM_DEBUG_ENGINE;
974 else
975 SCM_MISC_ERROR ("Unknown VM engine: ~a", scm_list_1 (engine));
976 }
977
978 static SCM
979 vm_engine_to_symbol (int engine, const char *FUNC_NAME)
980 {
981 switch (engine)
982 {
983 case SCM_VM_REGULAR_ENGINE:
984 return sym_regular;
985 case SCM_VM_DEBUG_ENGINE:
986 return sym_debug;
987 default:
988 /* ? */
989 SCM_MISC_ERROR ("Unknown VM engine: ~a",
990 scm_list_1 (scm_from_int (engine)));
991 }
992 }
993
994 SCM_DEFINE (scm_vm_engine, "vm-engine", 0, 0, 0,
995 (void),
996 "")
997 #define FUNC_NAME s_scm_vm_engine
998 {
999 return vm_engine_to_symbol (scm_the_vm ()->engine, FUNC_NAME);
1000 }
1001 #undef FUNC_NAME
1002
1003 void
1004 scm_c_set_vm_engine_x (int engine)
1005 #define FUNC_NAME "set-vm-engine!"
1006 {
1007 if (engine < 0 || engine >= SCM_VM_NUM_ENGINES)
1008 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1009 scm_list_1 (scm_from_int (engine)));
1010
1011 scm_the_vm ()->engine = engine;
1012 }
1013 #undef FUNC_NAME
1014
1015 SCM_DEFINE (scm_set_vm_engine_x, "set-vm-engine!", 1, 0, 0,
1016 (SCM engine),
1017 "")
1018 #define FUNC_NAME s_scm_set_vm_engine_x
1019 {
1020 scm_c_set_vm_engine_x (symbol_to_vm_engine (engine, FUNC_NAME));
1021 return SCM_UNSPECIFIED;
1022 }
1023 #undef FUNC_NAME
1024
1025 void
1026 scm_c_set_default_vm_engine_x (int engine)
1027 #define FUNC_NAME "set-default-vm-engine!"
1028 {
1029 if (engine < 0 || engine >= SCM_VM_NUM_ENGINES)
1030 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1031 scm_list_1 (scm_from_int (engine)));
1032
1033 vm_default_engine = engine;
1034 }
1035 #undef FUNC_NAME
1036
1037 SCM_DEFINE (scm_set_default_vm_engine_x, "set-default-vm-engine!", 1, 0, 0,
1038 (SCM engine),
1039 "")
1040 #define FUNC_NAME s_scm_set_default_vm_engine_x
1041 {
1042 scm_c_set_default_vm_engine_x (symbol_to_vm_engine (engine, FUNC_NAME));
1043 return SCM_UNSPECIFIED;
1044 }
1045 #undef FUNC_NAME
1046
1047 /* FIXME: This function makes no sense, but we keep it to make sure we
1048 have a way of switching to the debug or regular VM. */
1049 SCM_DEFINE (scm_call_with_vm, "call-with-vm", 1, 0, 1,
1050 (SCM proc, SCM args),
1051 "Apply @var{proc} to @var{args} in a dynamic extent in which\n"
1052 "@var{vm} is the current VM.")
1053 #define FUNC_NAME s_scm_call_with_vm
1054 {
1055 return scm_apply_0 (proc, args);
1056 }
1057 #undef FUNC_NAME
1058
1059 \f
1060 /*
1061 * Initialize
1062 */
1063
1064 SCM
1065 scm_load_compiled_with_vm (SCM file)
1066 {
1067 return scm_call_0 (scm_load_thunk_from_file (file));
1068 }
1069
1070
1071 void
1072 scm_init_vm_builtin_properties (void)
1073 {
1074 /* FIXME: Seems hacky to do this here, but oh well :/ */
1075 scm_sym_apply = scm_from_utf8_symbol ("apply");
1076 scm_sym_values = scm_from_utf8_symbol ("values");
1077 scm_sym_abort_to_prompt = scm_from_utf8_symbol ("abort-to-prompt");
1078 scm_sym_call_with_values = scm_from_utf8_symbol ("call-with-values");
1079 scm_sym_call_with_current_continuation =
1080 scm_from_utf8_symbol ("call-with-current-continuation");
1081
1082 #define INIT_BUILTIN(builtin, BUILTIN, req, opt, rest) \
1083 scm_set_procedure_property_x (vm_builtin_##builtin, scm_sym_name, \
1084 scm_sym_##builtin); \
1085 scm_set_procedure_minimum_arity_x (vm_builtin_##builtin, \
1086 SCM_I_MAKINUM (req), \
1087 SCM_I_MAKINUM (opt), \
1088 scm_from_bool (rest));
1089 FOR_EACH_VM_BUILTIN (INIT_BUILTIN);
1090 #undef INIT_BUILTIN
1091 }
1092
1093 void
1094 scm_bootstrap_vm (void)
1095 {
1096 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1097 "scm_init_vm",
1098 (scm_t_extension_init_func)scm_init_vm, NULL);
1099 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1100 "scm_init_vm_builtins",
1101 (scm_t_extension_init_func)scm_init_vm_builtins,
1102 NULL);
1103
1104 initialize_default_stack_size ();
1105
1106 sym_vm_run = scm_from_latin1_symbol ("vm-run");
1107 sym_vm_error = scm_from_latin1_symbol ("vm-error");
1108 sym_keyword_argument_error = scm_from_latin1_symbol ("keyword-argument-error");
1109 sym_regular = scm_from_latin1_symbol ("regular");
1110 sym_debug = scm_from_latin1_symbol ("debug");
1111
1112 vm_boot_continuation = scm_i_make_program (vm_boot_continuation_code);
1113 SCM_SET_CELL_WORD_0 (vm_boot_continuation,
1114 (SCM_CELL_WORD_0 (vm_boot_continuation)
1115 | SCM_F_PROGRAM_IS_BOOT));
1116
1117 #define DEFINE_BUILTIN(builtin, BUILTIN, req, opt, rest) \
1118 vm_builtin_##builtin = scm_i_make_program (vm_builtin_##builtin##_code);
1119 FOR_EACH_VM_BUILTIN (DEFINE_BUILTIN);
1120 #undef DEFINE_BUILTIN
1121 }
1122
1123 void
1124 scm_init_vm (void)
1125 {
1126 #ifndef SCM_MAGIC_SNARFER
1127 #include "libguile/vm.x"
1128 #endif
1129 }
1130
1131 /*
1132 Local Variables:
1133 c-file-style: "gnu"
1134 End:
1135 */