Default stack size is one page.
[bpt/guile.git] / libguile / vm.c
1 /* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013, 2014 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 /* For mremap(2) on GNU/Linux systems. */
20 #define _GNU_SOURCE
21
22 #if HAVE_CONFIG_H
23 # include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <alloca.h>
28 #include <alignof.h>
29 #include <string.h>
30 #include <stdint.h>
31 #include <unistd.h>
32
33 #ifdef HAVE_SYS_MMAN_H
34 #include <sys/mman.h>
35 #endif
36
37 #include "libguile/bdw-gc.h"
38 #include <gc/gc_mark.h>
39
40 #include "_scm.h"
41 #include "control.h"
42 #include "frames.h"
43 #include "gc-inline.h"
44 #include "instructions.h"
45 #include "loader.h"
46 #include "programs.h"
47 #include "simpos.h"
48 #include "vm.h"
49 #include "vm-builtins.h"
50
51 static int vm_default_engine = SCM_VM_REGULAR_ENGINE;
52
53 /* Unfortunately we can't snarf these: snarfed things are only loaded up from
54 (system vm vm), which might not be loaded before an error happens. */
55 static SCM sym_vm_run;
56 static SCM sym_vm_error;
57 static SCM sym_keyword_argument_error;
58 static SCM sym_regular;
59 static SCM sym_debug;
60
61 /* The VM has a number of internal assertions that shouldn't normally be
62 necessary, but might be if you think you found a bug in the VM. */
63 #define VM_ENABLE_ASSERTIONS
64
65 /* #define VM_ENABLE_PARANOID_ASSERTIONS */
66
67 static void vm_expand_stack (struct scm_vm *vp) SCM_NOINLINE;
68
69 /* RESTORE is for the case where we know we have done a PUSH of equal or
70 greater stack size in the past. Otherwise PUSH is the thing, which
71 may expand the stack. */
72 enum vm_increase_sp_kind { VM_SP_PUSH, VM_SP_RESTORE };
73
74 static inline void
75 vm_increase_sp (struct scm_vm *vp, SCM *new_sp, enum vm_increase_sp_kind kind)
76 {
77 vp->sp = new_sp;
78 if (new_sp > vp->sp_max_since_gc)
79 {
80 vp->sp_max_since_gc = new_sp;
81 if (kind == VM_SP_PUSH && new_sp >= vp->stack_limit)
82 vm_expand_stack (vp);
83 }
84 }
85
86 static inline void
87 vm_push_sp (struct scm_vm *vp, SCM *new_sp)
88 {
89 vm_increase_sp (vp, new_sp, VM_SP_PUSH);
90 }
91
92 static inline void
93 vm_restore_sp (struct scm_vm *vp, SCM *new_sp)
94 {
95 vm_increase_sp (vp, new_sp, VM_SP_RESTORE);
96 }
97
98 \f
99 /*
100 * VM Continuation
101 */
102
103 void
104 scm_i_vm_cont_print (SCM x, SCM port, scm_print_state *pstate)
105 {
106 scm_puts_unlocked ("#<vm-continuation ", port);
107 scm_uintprint (SCM_UNPACK (x), 16, port);
108 scm_puts_unlocked (">", port);
109 }
110
111 /* In theory, a number of vm instances can be active in the call trace, and we
112 only want to reify the continuations of those in the current continuation
113 root. I don't see a nice way to do this -- ideally it would involve dynwinds,
114 and previous values of the *the-vm* fluid within the current continuation
115 root. But we don't have access to continuation roots in the dynwind stack.
116 So, just punt for now, we just capture the continuation for the current VM.
117
118 While I'm on the topic, ideally we could avoid copying the C stack if the
119 continuation root is inside VM code, and call/cc was invoked within that same
120 call to vm_run; but that's currently not implemented.
121 */
122 SCM
123 scm_i_vm_capture_stack (SCM *stack_base, SCM *fp, SCM *sp, scm_t_uint32 *ra,
124 scm_t_dynstack *dynstack, scm_t_uint32 flags)
125 {
126 struct scm_vm_cont *p;
127
128 p = scm_gc_malloc (sizeof (*p), "capture_vm_cont");
129 p->stack_size = sp - stack_base + 1;
130 p->stack_base = scm_gc_malloc (p->stack_size * sizeof (SCM),
131 "capture_vm_cont");
132 p->ra = ra;
133 p->sp = sp;
134 p->fp = fp;
135 memcpy (p->stack_base, stack_base, (sp + 1 - stack_base) * sizeof (SCM));
136 p->reloc = p->stack_base - stack_base;
137 p->dynstack = dynstack;
138 p->flags = flags;
139 return scm_cell (scm_tc7_vm_cont, (scm_t_bits)p);
140 }
141
142 static void
143 vm_return_to_continuation (struct scm_vm *vp, SCM cont, size_t n, SCM *argv)
144 {
145 struct scm_vm_cont *cp;
146 SCM *argv_copy;
147 scm_t_ptrdiff reloc;
148
149 argv_copy = alloca (n * sizeof(SCM));
150 memcpy (argv_copy, argv, n * sizeof(SCM));
151
152 cp = SCM_VM_CONT_DATA (cont);
153
154 /* FIXME: Need to prevent GC while futzing with the stack; otherwise,
155 another thread causing GC may initiate a mark of a stack in an
156 inconsistent state. */
157
158 /* We know that there is enough space for the continuation, because we
159 captured it in the past. However there may have been an expansion
160 since the capture, so we may have to re-link the frame
161 pointers. */
162 reloc = (vp->stack_base - (cp->stack_base - cp->reloc));
163 vp->fp = cp->fp + reloc;
164 memcpy (vp->stack_base, cp->stack_base, cp->stack_size * sizeof (SCM));
165 vm_restore_sp (vp, cp->sp + reloc);
166
167 if (reloc)
168 {
169 SCM *fp = vp->fp;
170 while (fp)
171 {
172 SCM *next_fp = SCM_FRAME_DYNAMIC_LINK (fp);
173 if (next_fp)
174 {
175 next_fp += reloc;
176 SCM_FRAME_SET_DYNAMIC_LINK (fp, next_fp);
177 }
178 fp = next_fp;
179 }
180 }
181
182 /* Now we have the continuation properly copied over. We just need to
183 copy the arguments. It is not guaranteed that there is actually
184 space for the arguments, though, so we have to bump the SP first. */
185 vm_push_sp (vp, vp->sp + 3 + n);
186
187 /* Now copy on an empty frame and the return values, as the
188 continuation expects. */
189 {
190 SCM *base = vp->sp + 1 - 3 - n;
191 size_t i;
192
193 for (i = 0; i < 3; i++)
194 base[i] = SCM_BOOL_F;
195
196 for (i = 0; i < n; i++)
197 base[i + 3] = argv_copy[i];
198 }
199
200 vp->ip = cp->ra;
201 }
202
203 static struct scm_vm * thread_vm (scm_i_thread *t);
204 SCM
205 scm_i_capture_current_stack (void)
206 {
207 scm_i_thread *thread;
208 struct scm_vm *vp;
209
210 thread = SCM_I_CURRENT_THREAD;
211 vp = thread_vm (thread);
212
213 return scm_i_vm_capture_stack (vp->stack_base, vp->fp, vp->sp, vp->ip,
214 scm_dynstack_capture_all (&thread->dynstack),
215 0);
216 }
217
218 static void vm_dispatch_apply_hook (struct scm_vm *vp) SCM_NOINLINE;
219 static void vm_dispatch_push_continuation_hook (struct scm_vm *vp) SCM_NOINLINE;
220 static void vm_dispatch_pop_continuation_hook (struct scm_vm *vp, SCM *old_fp) SCM_NOINLINE;
221 static void vm_dispatch_next_hook (struct scm_vm *vp) SCM_NOINLINE;
222 static void vm_dispatch_abort_hook (struct scm_vm *vp) SCM_NOINLINE;
223
224 static void
225 vm_dispatch_hook (struct scm_vm *vp, int hook_num, SCM *argv, int n)
226 {
227 SCM hook;
228 struct scm_frame c_frame;
229 scm_t_cell *frame;
230 int saved_trace_level;
231
232 hook = vp->hooks[hook_num];
233
234 if (SCM_LIKELY (scm_is_false (hook))
235 || scm_is_null (SCM_HOOK_PROCEDURES (hook)))
236 return;
237
238 saved_trace_level = vp->trace_level;
239 vp->trace_level = 0;
240
241 /* Allocate a frame object on the stack. This is more efficient than calling
242 `scm_c_make_frame ()' to allocate on the heap, but it forces hooks to not
243 capture frame objects.
244
245 At the same time, procedures such as `frame-procedure' make sense only
246 while the stack frame represented by the frame object is visible, so it
247 seems reasonable to limit the lifetime of frame objects. */
248
249 c_frame.stack_holder = vp;
250 c_frame.fp_offset = vp->fp - vp->stack_base;
251 c_frame.sp_offset = vp->sp - vp->stack_base;
252 c_frame.ip = vp->ip;
253
254 /* Arrange for FRAME to be 8-byte aligned, like any other cell. */
255 frame = alloca (sizeof (*frame) + 8);
256 frame = (scm_t_cell *) ROUND_UP ((scm_t_uintptr) frame, 8UL);
257
258 frame->word_0 = SCM_PACK (scm_tc7_frame | (SCM_VM_FRAME_KIND_VM << 8));
259 frame->word_1 = SCM_PACK_POINTER (&c_frame);
260
261 if (n == 0)
262 {
263 SCM args[1];
264
265 args[0] = SCM_PACK_POINTER (frame);
266 scm_c_run_hookn (hook, args, 1);
267 }
268 else if (n == 1)
269 {
270 SCM args[2];
271
272 args[0] = SCM_PACK_POINTER (frame);
273 args[1] = argv[0];
274 scm_c_run_hookn (hook, args, 2);
275 }
276 else
277 {
278 SCM args = SCM_EOL;
279
280 while (n--)
281 args = scm_cons (argv[n], args);
282 scm_c_run_hook (hook, scm_cons (SCM_PACK_POINTER (frame), args));
283 }
284
285 vp->trace_level = saved_trace_level;
286 }
287
288 static void
289 vm_dispatch_apply_hook (struct scm_vm *vp)
290 {
291 return vm_dispatch_hook (vp, SCM_VM_APPLY_HOOK, NULL, 0);
292 }
293 static void vm_dispatch_push_continuation_hook (struct scm_vm *vp)
294 {
295 return vm_dispatch_hook (vp, SCM_VM_PUSH_CONTINUATION_HOOK, NULL, 0);
296 }
297 static void vm_dispatch_pop_continuation_hook (struct scm_vm *vp, SCM *old_fp)
298 {
299 return vm_dispatch_hook (vp, SCM_VM_POP_CONTINUATION_HOOK,
300 &SCM_FRAME_LOCAL (old_fp, 1),
301 SCM_FRAME_NUM_LOCALS (old_fp, vp->sp) - 1);
302 }
303 static void vm_dispatch_next_hook (struct scm_vm *vp)
304 {
305 return vm_dispatch_hook (vp, SCM_VM_NEXT_HOOK, NULL, 0);
306 }
307 static void vm_dispatch_abort_hook (struct scm_vm *vp)
308 {
309 return vm_dispatch_hook (vp, SCM_VM_ABORT_CONTINUATION_HOOK,
310 &SCM_FRAME_LOCAL (vp->fp, 1),
311 SCM_FRAME_NUM_LOCALS (vp->fp, vp->sp) - 1);
312 }
313
314 static void
315 vm_abort (struct scm_vm *vp, SCM tag,
316 size_t nstack, SCM *stack_args, SCM tail, SCM *sp,
317 scm_i_jmp_buf *current_registers) SCM_NORETURN;
318
319 static void
320 vm_abort (struct scm_vm *vp, SCM tag,
321 size_t nstack, SCM *stack_args, SCM tail, SCM *sp,
322 scm_i_jmp_buf *current_registers)
323 {
324 size_t i;
325 ssize_t tail_len;
326 SCM *argv;
327
328 tail_len = scm_ilength (tail);
329 if (tail_len < 0)
330 scm_misc_error ("vm-engine", "tail values to abort should be a list",
331 scm_list_1 (tail));
332
333 argv = alloca ((nstack + tail_len) * sizeof (SCM));
334 for (i = 0; i < nstack; i++)
335 argv[i] = stack_args[i];
336 for (; i < nstack + tail_len; i++, tail = scm_cdr (tail))
337 argv[i] = scm_car (tail);
338
339 /* FIXME: NULLSTACK (SCM_VM_DATA (vp)->sp - sp) */
340 vp->sp = sp;
341
342 scm_c_abort (vp, tag, nstack + tail_len, argv, current_registers);
343 }
344
345 static void
346 vm_reinstate_partial_continuation (struct scm_vm *vp, SCM cont,
347 size_t n, SCM *argv,
348 scm_t_dynstack *dynstack,
349 scm_i_jmp_buf *registers)
350 {
351 struct scm_vm_cont *cp;
352 SCM *argv_copy, *base;
353 scm_t_ptrdiff reloc;
354 size_t i;
355
356 argv_copy = alloca (n * sizeof(SCM));
357 memcpy (argv_copy, argv, n * sizeof(SCM));
358
359 cp = SCM_VM_CONT_DATA (cont);
360
361 vm_push_sp (vp, SCM_FRAME_LOCALS_ADDRESS (vp->fp) + cp->stack_size + n - 1);
362
363 base = SCM_FRAME_LOCALS_ADDRESS (vp->fp);
364 reloc = cp->reloc + (base - cp->stack_base);
365
366 memcpy (base, cp->stack_base, cp->stack_size * sizeof (SCM));
367
368 vp->fp = cp->fp + reloc;
369 vp->ip = cp->ra;
370
371 /* now relocate frame pointers */
372 {
373 SCM *fp;
374 for (fp = vp->fp;
375 SCM_FRAME_LOWER_ADDRESS (fp) > base;
376 fp = SCM_FRAME_DYNAMIC_LINK (fp))
377 SCM_FRAME_SET_DYNAMIC_LINK (fp, SCM_FRAME_DYNAMIC_LINK (fp) + reloc);
378 }
379
380 /* Push the arguments. */
381 for (i = 0; i < n; i++)
382 vp->sp[i + 1 - n] = argv_copy[i];
383
384 /* The prompt captured a slice of the dynamic stack. Here we wind
385 those entries onto the current thread's stack. We also have to
386 relocate any prompts that we see along the way. */
387 {
388 scm_t_bits *walk;
389
390 for (walk = SCM_DYNSTACK_FIRST (cp->dynstack);
391 SCM_DYNSTACK_TAG (walk);
392 walk = SCM_DYNSTACK_NEXT (walk))
393 {
394 scm_t_bits tag = SCM_DYNSTACK_TAG (walk);
395
396 if (SCM_DYNSTACK_TAG_TYPE (tag) == SCM_DYNSTACK_TYPE_PROMPT)
397 scm_dynstack_wind_prompt (dynstack, walk, reloc, registers);
398 else
399 scm_dynstack_wind_1 (dynstack, walk);
400 }
401 }
402 }
403
404 \f
405 /*
406 * VM Error Handling
407 */
408
409 static void vm_error (const char *msg, SCM arg) SCM_NORETURN;
410 static void vm_error_bad_instruction (scm_t_uint32 inst) SCM_NORETURN SCM_NOINLINE;
411 static void vm_error_unbound (SCM proc, SCM sym) SCM_NORETURN SCM_NOINLINE;
412 static void vm_error_unbound_fluid (SCM proc, SCM fluid) SCM_NORETURN SCM_NOINLINE;
413 static void vm_error_not_a_variable (const char *func_name, SCM x) SCM_NORETURN SCM_NOINLINE;
414 static void vm_error_apply_to_non_list (SCM x) SCM_NORETURN SCM_NOINLINE;
415 static void vm_error_kwargs_length_not_even (SCM proc) SCM_NORETURN SCM_NOINLINE;
416 static void vm_error_kwargs_invalid_keyword (SCM proc, SCM obj) SCM_NORETURN SCM_NOINLINE;
417 static void vm_error_kwargs_unrecognized_keyword (SCM proc, SCM kw) SCM_NORETURN SCM_NOINLINE;
418 static void vm_error_too_many_args (int nargs) SCM_NORETURN SCM_NOINLINE;
419 static void vm_error_wrong_num_args (SCM proc) SCM_NORETURN SCM_NOINLINE;
420 static void vm_error_wrong_type_apply (SCM proc) SCM_NORETURN SCM_NOINLINE;
421 static void vm_error_stack_underflow (void) SCM_NORETURN SCM_NOINLINE;
422 static void vm_error_improper_list (SCM x) SCM_NORETURN SCM_NOINLINE;
423 static void vm_error_not_a_pair (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
424 static void vm_error_not_a_bytevector (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
425 static void vm_error_not_a_struct (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
426 static void vm_error_not_a_vector (const char *subr, SCM v) SCM_NORETURN SCM_NOINLINE;
427 static void vm_error_out_of_range (const char *subr, SCM k) SCM_NORETURN SCM_NOINLINE;
428 static void vm_error_no_values (void) SCM_NORETURN SCM_NOINLINE;
429 static void vm_error_not_enough_values (void) SCM_NORETURN SCM_NOINLINE;
430 static void vm_error_wrong_number_of_values (scm_t_uint32 expected) SCM_NORETURN SCM_NOINLINE;
431 static void vm_error_continuation_not_rewindable (SCM cont) SCM_NORETURN SCM_NOINLINE;
432 static void vm_error_bad_wide_string_length (size_t len) SCM_NORETURN SCM_NOINLINE;
433
434 static void
435 vm_error (const char *msg, SCM arg)
436 {
437 scm_throw (sym_vm_error,
438 scm_list_3 (sym_vm_run, scm_from_latin1_string (msg),
439 SCM_UNBNDP (arg) ? SCM_EOL : scm_list_1 (arg)));
440 abort(); /* not reached */
441 }
442
443 static void
444 vm_error_bad_instruction (scm_t_uint32 inst)
445 {
446 vm_error ("VM: Bad instruction: ~s", scm_from_uint32 (inst));
447 }
448
449 static void
450 vm_error_unbound (SCM proc, SCM sym)
451 {
452 scm_error_scm (scm_misc_error_key, proc,
453 scm_from_latin1_string ("Unbound variable: ~s"),
454 scm_list_1 (sym), SCM_BOOL_F);
455 }
456
457 static void
458 vm_error_unbound_fluid (SCM proc, SCM fluid)
459 {
460 scm_error_scm (scm_misc_error_key, proc,
461 scm_from_latin1_string ("Unbound fluid: ~s"),
462 scm_list_1 (fluid), SCM_BOOL_F);
463 }
464
465 static void
466 vm_error_not_a_variable (const char *func_name, SCM x)
467 {
468 scm_error (scm_arg_type_key, func_name, "Not a variable: ~S",
469 scm_list_1 (x), scm_list_1 (x));
470 }
471
472 static void
473 vm_error_apply_to_non_list (SCM x)
474 {
475 scm_error (scm_arg_type_key, "apply", "Apply to non-list: ~S",
476 scm_list_1 (x), scm_list_1 (x));
477 }
478
479 static void
480 vm_error_kwargs_length_not_even (SCM proc)
481 {
482 scm_error_scm (sym_keyword_argument_error, proc,
483 scm_from_latin1_string ("Odd length of keyword argument list"),
484 SCM_EOL, SCM_BOOL_F);
485 }
486
487 static void
488 vm_error_kwargs_invalid_keyword (SCM proc, SCM obj)
489 {
490 scm_error_scm (sym_keyword_argument_error, proc,
491 scm_from_latin1_string ("Invalid keyword"),
492 SCM_EOL, scm_list_1 (obj));
493 }
494
495 static void
496 vm_error_kwargs_unrecognized_keyword (SCM proc, SCM kw)
497 {
498 scm_error_scm (sym_keyword_argument_error, proc,
499 scm_from_latin1_string ("Unrecognized keyword"),
500 SCM_EOL, scm_list_1 (kw));
501 }
502
503 static void
504 vm_error_too_many_args (int nargs)
505 {
506 vm_error ("VM: Too many arguments", scm_from_int (nargs));
507 }
508
509 static void
510 vm_error_wrong_num_args (SCM proc)
511 {
512 scm_wrong_num_args (proc);
513 }
514
515 static void
516 vm_error_wrong_type_apply (SCM proc)
517 {
518 scm_error (scm_arg_type_key, NULL, "Wrong type to apply: ~S",
519 scm_list_1 (proc), scm_list_1 (proc));
520 }
521
522 static void
523 vm_error_stack_underflow (void)
524 {
525 vm_error ("VM: Stack underflow", SCM_UNDEFINED);
526 }
527
528 static void
529 vm_error_improper_list (SCM x)
530 {
531 vm_error ("Expected a proper list, but got object with tail ~s", x);
532 }
533
534 static void
535 vm_error_not_a_pair (const char *subr, SCM x)
536 {
537 scm_wrong_type_arg_msg (subr, 1, x, "pair");
538 }
539
540 static void
541 vm_error_not_a_bytevector (const char *subr, SCM x)
542 {
543 scm_wrong_type_arg_msg (subr, 1, x, "bytevector");
544 }
545
546 static void
547 vm_error_not_a_struct (const char *subr, SCM x)
548 {
549 scm_wrong_type_arg_msg (subr, 1, x, "struct");
550 }
551
552 static void
553 vm_error_not_a_vector (const char *subr, SCM x)
554 {
555 scm_wrong_type_arg_msg (subr, 1, x, "vector");
556 }
557
558 static void
559 vm_error_out_of_range (const char *subr, SCM k)
560 {
561 scm_to_size_t (k);
562 scm_out_of_range (subr, k);
563 }
564
565 static void
566 vm_error_no_values (void)
567 {
568 vm_error ("Zero values returned to single-valued continuation",
569 SCM_UNDEFINED);
570 }
571
572 static void
573 vm_error_not_enough_values (void)
574 {
575 vm_error ("Too few values returned to continuation", SCM_UNDEFINED);
576 }
577
578 static void
579 vm_error_wrong_number_of_values (scm_t_uint32 expected)
580 {
581 vm_error ("Wrong number of values returned to continuation (expected ~a)",
582 scm_from_uint32 (expected));
583 }
584
585 static void
586 vm_error_continuation_not_rewindable (SCM cont)
587 {
588 vm_error ("Unrewindable partial continuation", cont);
589 }
590
591 static void
592 vm_error_bad_wide_string_length (size_t len)
593 {
594 vm_error ("VM: Bad wide string length: ~S", scm_from_size_t (len));
595 }
596
597
598 \f
599
600 static SCM vm_boot_continuation;
601 static SCM vm_builtin_apply;
602 static SCM vm_builtin_values;
603 static SCM vm_builtin_abort_to_prompt;
604 static SCM vm_builtin_call_with_values;
605 static SCM vm_builtin_call_with_current_continuation;
606
607 static const scm_t_uint32 vm_boot_continuation_code[] = {
608 SCM_PACK_OP_24 (halt, 0)
609 };
610
611 static const scm_t_uint32 vm_builtin_apply_code[] = {
612 SCM_PACK_OP_24 (assert_nargs_ge, 3),
613 SCM_PACK_OP_24 (tail_apply, 0), /* proc in r1, args from r2 */
614 };
615
616 static const scm_t_uint32 vm_builtin_values_code[] = {
617 SCM_PACK_OP_24 (return_values, 0) /* vals from r1 */
618 };
619
620 static const scm_t_uint32 vm_builtin_abort_to_prompt_code[] = {
621 SCM_PACK_OP_24 (assert_nargs_ge, 2),
622 SCM_PACK_OP_24 (abort, 0), /* tag in r1, vals from r2 */
623 /* FIXME: Partial continuation should capture caller regs. */
624 SCM_PACK_OP_24 (return_values, 0) /* vals from r1 */
625 };
626
627 static const scm_t_uint32 vm_builtin_call_with_values_code[] = {
628 SCM_PACK_OP_24 (assert_nargs_ee, 3),
629 SCM_PACK_OP_24 (alloc_frame, 7),
630 SCM_PACK_OP_12_12 (mov, 6, 1),
631 SCM_PACK_OP_24 (call, 6), SCM_PACK_OP_ARG_8_24 (0, 1),
632 SCM_PACK_OP_12_12 (mov, 0, 2),
633 SCM_PACK_OP_24 (tail_call_shuffle, 7)
634 };
635
636 static const scm_t_uint32 vm_builtin_call_with_current_continuation_code[] = {
637 SCM_PACK_OP_24 (assert_nargs_ee, 2),
638 SCM_PACK_OP_24 (call_cc, 0)
639 };
640
641
642 static SCM
643 scm_vm_builtin_ref (unsigned idx)
644 {
645 switch (idx)
646 {
647 #define INDEX_TO_NAME(builtin, BUILTIN, req, opt, rest) \
648 case SCM_VM_BUILTIN_##BUILTIN: return vm_builtin_##builtin;
649 FOR_EACH_VM_BUILTIN(INDEX_TO_NAME)
650 #undef INDEX_TO_NAME
651 default: abort();
652 }
653 }
654
655 SCM scm_sym_apply;
656 static SCM scm_sym_values;
657 static SCM scm_sym_abort_to_prompt;
658 static SCM scm_sym_call_with_values;
659 static SCM scm_sym_call_with_current_continuation;
660
661 SCM
662 scm_vm_builtin_name_to_index (SCM name)
663 #define FUNC_NAME "builtin-name->index"
664 {
665 SCM_VALIDATE_SYMBOL (1, name);
666
667 #define NAME_TO_INDEX(builtin, BUILTIN, req, opt, rest) \
668 if (scm_is_eq (name, scm_sym_##builtin)) \
669 return scm_from_uint (SCM_VM_BUILTIN_##BUILTIN);
670 FOR_EACH_VM_BUILTIN(NAME_TO_INDEX)
671 #undef NAME_TO_INDEX
672
673 return SCM_BOOL_F;
674 }
675 #undef FUNC_NAME
676
677 SCM
678 scm_vm_builtin_index_to_name (SCM index)
679 #define FUNC_NAME "builtin-index->name"
680 {
681 unsigned idx;
682
683 SCM_VALIDATE_UINT_COPY (1, index, idx);
684
685 switch (idx)
686 {
687 #define INDEX_TO_NAME(builtin, BUILTIN, req, opt, rest) \
688 case SCM_VM_BUILTIN_##BUILTIN: return scm_sym_##builtin;
689 FOR_EACH_VM_BUILTIN(INDEX_TO_NAME)
690 #undef INDEX_TO_NAME
691 default: return SCM_BOOL_F;
692 }
693 }
694 #undef FUNC_NAME
695
696 static void
697 scm_init_vm_builtins (void)
698 {
699 scm_c_define_gsubr ("builtin-name->index", 1, 0, 0,
700 scm_vm_builtin_name_to_index);
701 scm_c_define_gsubr ("builtin-index->name", 1, 0, 0,
702 scm_vm_builtin_index_to_name);
703 }
704
705 SCM
706 scm_i_call_with_current_continuation (SCM proc)
707 {
708 return scm_call_1 (vm_builtin_call_with_current_continuation, proc);
709 }
710
711 \f
712 /*
713 * VM
714 */
715
716 /* The page size. */
717 static size_t page_size;
718
719 /* Hard stack limit is 512M words: 2 gigabytes on 32-bit machines, 4 on
720 64-bit machines. */
721 static const size_t hard_max_stack_size = 512 * 1024 * 1024;
722
723 /* Initial stack size. Defaults to one page. */
724 static size_t initial_stack_size;
725
726 /* Default soft stack limit is 1M words (4 or 8 megabytes). */
727 static size_t default_max_stack_size = 1024 * 1024;
728
729 static void
730 initialize_default_stack_size (void)
731 {
732 initial_stack_size = page_size / sizeof (SCM);
733
734 {
735 int size;
736 size = scm_getenv_int ("GUILE_STACK_SIZE", (int) default_max_stack_size);
737 if (size >= initial_stack_size
738 && (size_t) size < ((size_t) -1) / sizeof(SCM))
739 default_max_stack_size = size;
740 }
741 }
742
743 #define VM_NAME vm_regular_engine
744 #define VM_USE_HOOKS 0
745 #define FUNC_NAME "vm-regular-engine"
746 #include "vm-engine.c"
747 #undef FUNC_NAME
748 #undef VM_USE_HOOKS
749 #undef VM_NAME
750
751 #define VM_NAME vm_debug_engine
752 #define VM_USE_HOOKS 1
753 #define FUNC_NAME "vm-debug-engine"
754 #include "vm-engine.c"
755 #undef FUNC_NAME
756 #undef VM_USE_HOOKS
757 #undef VM_NAME
758
759 typedef SCM (*scm_t_vm_engine) (scm_i_thread *current_thread, struct scm_vm *vp,
760 scm_i_jmp_buf *registers, int resume);
761
762 static const scm_t_vm_engine vm_engines[SCM_VM_NUM_ENGINES] =
763 { vm_regular_engine, vm_debug_engine };
764
765 static SCM*
766 allocate_stack (size_t size)
767 #define FUNC_NAME "make_vm"
768 {
769 void *ret;
770
771 if (size >= ((size_t) -1) / sizeof (SCM))
772 abort ();
773
774 size *= sizeof (SCM);
775
776 #if HAVE_SYS_MMAN_H
777 ret = mmap (NULL, size, PROT_READ | PROT_WRITE,
778 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
779 if (ret == MAP_FAILED)
780 ret = NULL;
781 #else
782 ret = malloc (size);
783 #endif
784
785 if (!ret)
786 {
787 perror ("allocate_stack failed");
788 return NULL;
789 }
790
791 return (SCM *) ret;
792 }
793 #undef FUNC_NAME
794
795 static void
796 free_stack (SCM *stack, size_t size)
797 {
798 size *= sizeof (SCM);
799
800 #if HAVE_SYS_MMAN_H
801 munmap (stack, size);
802 #else
803 free (stack);
804 #endif
805 }
806
807 static SCM*
808 expand_stack (SCM *old_stack, size_t old_size, size_t new_size)
809 #define FUNC_NAME "expand_stack"
810 {
811 #if defined MREMAP_MAYMOVE
812 void *new_stack;
813
814 if (new_size >= ((size_t) -1) / sizeof (SCM))
815 abort ();
816
817 old_size *= sizeof (SCM);
818 new_size *= sizeof (SCM);
819
820 new_stack = mremap (old_stack, old_size, new_size, MREMAP_MAYMOVE);
821 if (new_stack == MAP_FAILED)
822 return NULL;
823
824 return (SCM *) new_stack;
825 #else
826 SCM *new_stack;
827
828 new_stack = allocate_stack (new_size);
829 if (!new_stack)
830 return NULL;
831
832 memcpy (new_stack, old_stack, old_size * sizeof (SCM));
833 free_stack (old_stack, old_size);
834
835 return new_stack;
836 #endif
837 }
838 #undef FUNC_NAME
839
840 static struct scm_vm *
841 make_vm (void)
842 #define FUNC_NAME "make_vm"
843 {
844 int i;
845 struct scm_vm *vp;
846
847 vp = scm_gc_malloc (sizeof (struct scm_vm), "vm");
848
849 vp->stack_size = initial_stack_size;
850 vp->stack_base = allocate_stack (vp->stack_size);
851 if (!vp->stack_base)
852 /* As in expand_stack, we don't have any way to throw an exception
853 if we can't allocate one measely page -- there's no stack to
854 handle it. For now, abort. */
855 abort ();
856 vp->stack_limit = vp->stack_base + vp->stack_size;
857 vp->max_stack_size = default_max_stack_size;
858 vp->ip = NULL;
859 vp->sp = vp->stack_base - 1;
860 vp->fp = NULL;
861 vp->engine = vm_default_engine;
862 vp->trace_level = 0;
863 for (i = 0; i < SCM_VM_NUM_HOOKS; i++)
864 vp->hooks[i] = SCM_BOOL_F;
865
866 return vp;
867 }
868 #undef FUNC_NAME
869
870 static void
871 return_unused_stack_to_os (struct scm_vm *vp)
872 {
873 #if HAVE_SYS_MMAN_H
874 scm_t_uintptr start = (scm_t_uintptr) (vp->sp + 1);
875 scm_t_uintptr end = (scm_t_uintptr) vp->stack_limit;
876 /* The second condition is needed to protect against wrap-around. */
877 if (vp->sp_max_since_gc < vp->stack_limit && vp->sp < vp->sp_max_since_gc)
878 end = (scm_t_uintptr) (vp->sp_max_since_gc + 1);
879
880 start = ((start - 1U) | (page_size - 1U)) + 1U; /* round up */
881 end = ((end - 1U) | (page_size - 1U)) + 1U; /* round up */
882
883 /* Return these pages to the OS. The next time they are paged in,
884 they will be zeroed. */
885 if (start < end)
886 {
887 int ret = 0;
888
889 do
890 ret = madvise ((void *) start, end - start, MADV_DONTNEED);
891 while (ret && errno == -EAGAIN);
892
893 if (ret)
894 perror ("madvise failed");
895 }
896
897 vp->sp_max_since_gc = vp->sp;
898 #endif
899 }
900
901 #define DEAD_SLOT_MAP_CACHE_SIZE 32U
902 struct dead_slot_map_cache_entry
903 {
904 scm_t_uint32 *ip;
905 const scm_t_uint8 *map;
906 };
907
908 struct dead_slot_map_cache
909 {
910 struct dead_slot_map_cache_entry entries[DEAD_SLOT_MAP_CACHE_SIZE];
911 };
912
913 static const scm_t_uint8 *
914 find_dead_slot_map (scm_t_uint32 *ip, struct dead_slot_map_cache *cache)
915 {
916 /* The lower two bits should be zero. FIXME: Use a better hash
917 function; we don't expose scm_raw_hashq currently. */
918 size_t slot = (((scm_t_uintptr) ip) >> 2) % DEAD_SLOT_MAP_CACHE_SIZE;
919 const scm_t_uint8 *map;
920
921 if (cache->entries[slot].ip == ip)
922 map = cache->entries[slot].map;
923 else
924 {
925 map = scm_find_dead_slot_map_unlocked (ip);
926 cache->entries[slot].ip = ip;
927 cache->entries[slot].map = map;
928 }
929
930 return map;
931 }
932
933 /* Mark the VM stack region between its base and its current top. */
934 struct GC_ms_entry *
935 scm_i_vm_mark_stack (struct scm_vm *vp, struct GC_ms_entry *mark_stack_ptr,
936 struct GC_ms_entry *mark_stack_limit)
937 {
938 SCM *sp, *fp;
939 /* The first frame will be marked conservatively (without a dead
940 slot map). This is because GC can happen at any point within the
941 hottest activation, due to multiple threads or per-instruction
942 hooks, and providing dead slot maps for all points in a program
943 would take a prohibitive amount of space. */
944 const scm_t_uint8 *dead_slots = NULL;
945 scm_t_uintptr upper = (scm_t_uintptr) GC_greatest_plausible_heap_addr;
946 scm_t_uintptr lower = (scm_t_uintptr) GC_least_plausible_heap_addr;
947 struct dead_slot_map_cache cache;
948
949 memset (&cache, 0, sizeof (cache));
950
951 for (fp = vp->fp, sp = vp->sp; fp; fp = SCM_FRAME_DYNAMIC_LINK (fp))
952 {
953 for (; sp >= &SCM_FRAME_LOCAL (fp, 0); sp--)
954 {
955 SCM elt = *sp;
956 if (SCM_NIMP (elt)
957 && SCM_UNPACK (elt) >= lower && SCM_UNPACK (elt) <= upper)
958 {
959 if (dead_slots)
960 {
961 size_t slot = sp - &SCM_FRAME_LOCAL (fp, 0);
962 if (dead_slots[slot / 8U] & (1U << (slot % 8U)))
963 {
964 /* This value may become dead as a result of GC,
965 so we can't just leave it on the stack. */
966 *sp = SCM_UNBOUND;
967 continue;
968 }
969 }
970
971 mark_stack_ptr = GC_mark_and_push ((void *) elt,
972 mark_stack_ptr,
973 mark_stack_limit,
974 NULL);
975 }
976 }
977 sp = SCM_FRAME_PREVIOUS_SP (fp);
978 /* Inner frames may have a dead slots map for precise marking.
979 Note that there may be other reasons to not have a dead slots
980 map, e.g. if all of the frame's slots below the callee frame
981 are live. */
982 dead_slots = find_dead_slot_map (SCM_FRAME_RETURN_ADDRESS (fp), &cache);
983 }
984
985 return_unused_stack_to_os (vp);
986
987 return mark_stack_ptr;
988 }
989
990 /* Free the VM stack, as this thread is exiting. */
991 void
992 scm_i_vm_free_stack (struct scm_vm *vp)
993 {
994 free_stack (vp->stack_base, vp->stack_size);
995 vp->stack_base = vp->stack_limit = NULL;
996 vp->stack_size = 0;
997 }
998
999 static void
1000 vm_expand_stack (struct scm_vm *vp)
1001 {
1002 scm_t_ptrdiff stack_size = vp->sp + 1 - vp->stack_base;
1003
1004 if (stack_size > hard_max_stack_size)
1005 {
1006 /* We have expanded the soft limit to the point that we reached a
1007 hard limit. There is nothing sensible to do. */
1008 fprintf (stderr, "Hard stack size limit (%zu words) reached; aborting.\n",
1009 hard_max_stack_size);
1010 abort ();
1011 }
1012
1013 /* FIXME: Prevent GC while we expand the stack, to ensure that a
1014 stack marker can trace the stack. */
1015 if (stack_size > vp->stack_size)
1016 {
1017 SCM *old_stack, *new_stack;
1018 size_t new_size;
1019 scm_t_ptrdiff reloc;
1020
1021 new_size = vp->stack_size;
1022 while (new_size < stack_size)
1023 new_size *= 2;
1024 old_stack = vp->stack_base;
1025 new_stack = expand_stack (vp->stack_base, vp->stack_size, new_size);
1026 if (!new_stack)
1027 /* It would be nice to throw an exception here, but that is
1028 extraordinarily hard. Exceptionally hard, you might say!
1029 "throw" is implemented in Scheme, and there may be arbitrary
1030 pre-unwind handlers that push on more frames. We will
1031 endeavor to do so in the future, but for now we just
1032 abort. */
1033 abort ();
1034
1035 vp->stack_base = new_stack;
1036 vp->stack_size = new_size;
1037 vp->stack_limit = vp->stack_base + new_size;
1038 reloc = vp->stack_base - old_stack;
1039
1040 if (reloc)
1041 {
1042 SCM *fp;
1043 if (vp->fp)
1044 vp->fp += reloc;
1045 vp->sp += reloc;
1046 vp->sp_max_since_gc += reloc;
1047 fp = vp->fp;
1048 while (fp)
1049 {
1050 SCM *next_fp = SCM_FRAME_DYNAMIC_LINK (fp);
1051 if (next_fp)
1052 {
1053 next_fp += reloc;
1054 SCM_FRAME_SET_DYNAMIC_LINK (fp, next_fp);
1055 }
1056 fp = next_fp;
1057 }
1058 }
1059 }
1060
1061 if (stack_size >= vp->max_stack_size)
1062 {
1063 /* Expand the soft limit by 256K entries to give us space to
1064 handle the error. */
1065 vp->max_stack_size += 256 * 1024;
1066
1067 /* If it's still not big enough... it's quite improbable, but go
1068 ahead and set to the full available stack size. */
1069 if (vp->max_stack_size < stack_size)
1070 vp->max_stack_size = vp->stack_size;
1071
1072 /* But don't exceed the hard maximum. */
1073 if (vp->max_stack_size > hard_max_stack_size)
1074 vp->max_stack_size = hard_max_stack_size;
1075
1076 /* Finally, reset the limit, to catch further overflows. */
1077 vp->stack_limit = vp->stack_base + vp->max_stack_size;
1078
1079 vm_error ("VM: Stack overflow", SCM_UNDEFINED);
1080 }
1081
1082 /* Otherwise continue, with the new enlarged stack. */
1083 }
1084
1085 static struct scm_vm *
1086 thread_vm (scm_i_thread *t)
1087 {
1088 if (SCM_UNLIKELY (!t->vp))
1089 t->vp = make_vm ();
1090
1091 return t->vp;
1092 }
1093
1094 struct scm_vm *
1095 scm_the_vm (void)
1096 {
1097 return thread_vm (SCM_I_CURRENT_THREAD);
1098 }
1099
1100 SCM
1101 scm_call_n (SCM proc, SCM *argv, size_t nargs)
1102 {
1103 scm_i_thread *thread;
1104 struct scm_vm *vp;
1105 SCM *base;
1106 ptrdiff_t base_frame_size;
1107 /* Cached variables. */
1108 scm_i_jmp_buf registers; /* used for prompts */
1109 size_t i;
1110
1111 thread = SCM_I_CURRENT_THREAD;
1112 vp = thread_vm (thread);
1113
1114 SCM_CHECK_STACK;
1115
1116 /* Check that we have enough space: 3 words for the boot continuation,
1117 and 3 + nargs for the procedure application. */
1118 base_frame_size = 3 + 3 + nargs;
1119 vm_push_sp (vp, vp->sp + base_frame_size);
1120 base = vp->sp + 1 - base_frame_size;
1121
1122 /* Since it's possible to receive the arguments on the stack itself,
1123 shuffle up the arguments first. */
1124 for (i = nargs; i > 0; i--)
1125 base[6 + i - 1] = argv[i - 1];
1126
1127 /* Push the boot continuation, which calls PROC and returns its
1128 result(s). */
1129 base[0] = SCM_PACK (vp->fp); /* dynamic link */
1130 base[1] = SCM_PACK (vp->ip); /* ra */
1131 base[2] = vm_boot_continuation;
1132 vp->fp = &base[2];
1133 vp->ip = (scm_t_uint32 *) vm_boot_continuation_code;
1134
1135 /* The pending call to PROC. */
1136 base[3] = SCM_PACK (vp->fp); /* dynamic link */
1137 base[4] = SCM_PACK (vp->ip); /* ra */
1138 base[5] = proc;
1139 vp->fp = &base[5];
1140
1141 {
1142 int resume = SCM_I_SETJMP (registers);
1143
1144 if (SCM_UNLIKELY (resume))
1145 /* Non-local return. */
1146 vm_dispatch_abort_hook (vp);
1147
1148 return vm_engines[vp->engine](thread, vp, &registers, resume);
1149 }
1150 }
1151
1152 /* Scheme interface */
1153
1154 #define VM_DEFINE_HOOK(n) \
1155 { \
1156 struct scm_vm *vp; \
1157 vp = scm_the_vm (); \
1158 if (scm_is_false (vp->hooks[n])) \
1159 vp->hooks[n] = scm_make_hook (SCM_I_MAKINUM (1)); \
1160 return vp->hooks[n]; \
1161 }
1162
1163 SCM_DEFINE (scm_vm_apply_hook, "vm-apply-hook", 0, 0, 0,
1164 (void),
1165 "")
1166 #define FUNC_NAME s_scm_vm_apply_hook
1167 {
1168 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK);
1169 }
1170 #undef FUNC_NAME
1171
1172 SCM_DEFINE (scm_vm_push_continuation_hook, "vm-push-continuation-hook", 0, 0, 0,
1173 (void),
1174 "")
1175 #define FUNC_NAME s_scm_vm_push_continuation_hook
1176 {
1177 VM_DEFINE_HOOK (SCM_VM_PUSH_CONTINUATION_HOOK);
1178 }
1179 #undef FUNC_NAME
1180
1181 SCM_DEFINE (scm_vm_pop_continuation_hook, "vm-pop-continuation-hook", 0, 0, 0,
1182 (void),
1183 "")
1184 #define FUNC_NAME s_scm_vm_pop_continuation_hook
1185 {
1186 VM_DEFINE_HOOK (SCM_VM_POP_CONTINUATION_HOOK);
1187 }
1188 #undef FUNC_NAME
1189
1190 SCM_DEFINE (scm_vm_next_hook, "vm-next-hook", 0, 0, 0,
1191 (void),
1192 "")
1193 #define FUNC_NAME s_scm_vm_next_hook
1194 {
1195 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK);
1196 }
1197 #undef FUNC_NAME
1198
1199 SCM_DEFINE (scm_vm_abort_continuation_hook, "vm-abort-continuation-hook", 0, 0, 0,
1200 (void),
1201 "")
1202 #define FUNC_NAME s_scm_vm_abort_continuation_hook
1203 {
1204 VM_DEFINE_HOOK (SCM_VM_ABORT_CONTINUATION_HOOK);
1205 }
1206 #undef FUNC_NAME
1207
1208 SCM_DEFINE (scm_vm_trace_level, "vm-trace-level", 0, 0, 0,
1209 (void),
1210 "")
1211 #define FUNC_NAME s_scm_vm_trace_level
1212 {
1213 return scm_from_int (scm_the_vm ()->trace_level);
1214 }
1215 #undef FUNC_NAME
1216
1217 SCM_DEFINE (scm_set_vm_trace_level_x, "set-vm-trace-level!", 1, 0, 0,
1218 (SCM level),
1219 "")
1220 #define FUNC_NAME s_scm_set_vm_trace_level_x
1221 {
1222 scm_the_vm ()->trace_level = scm_to_int (level);
1223 return SCM_UNSPECIFIED;
1224 }
1225 #undef FUNC_NAME
1226
1227 \f
1228 /*
1229 * VM engines
1230 */
1231
1232 static int
1233 symbol_to_vm_engine (SCM engine, const char *FUNC_NAME)
1234 {
1235 if (scm_is_eq (engine, sym_regular))
1236 return SCM_VM_REGULAR_ENGINE;
1237 else if (scm_is_eq (engine, sym_debug))
1238 return SCM_VM_DEBUG_ENGINE;
1239 else
1240 SCM_MISC_ERROR ("Unknown VM engine: ~a", scm_list_1 (engine));
1241 }
1242
1243 static SCM
1244 vm_engine_to_symbol (int engine, const char *FUNC_NAME)
1245 {
1246 switch (engine)
1247 {
1248 case SCM_VM_REGULAR_ENGINE:
1249 return sym_regular;
1250 case SCM_VM_DEBUG_ENGINE:
1251 return sym_debug;
1252 default:
1253 /* ? */
1254 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1255 scm_list_1 (scm_from_int (engine)));
1256 }
1257 }
1258
1259 SCM_DEFINE (scm_vm_engine, "vm-engine", 0, 0, 0,
1260 (void),
1261 "")
1262 #define FUNC_NAME s_scm_vm_engine
1263 {
1264 return vm_engine_to_symbol (scm_the_vm ()->engine, FUNC_NAME);
1265 }
1266 #undef FUNC_NAME
1267
1268 void
1269 scm_c_set_vm_engine_x (int engine)
1270 #define FUNC_NAME "set-vm-engine!"
1271 {
1272 if (engine < 0 || engine >= SCM_VM_NUM_ENGINES)
1273 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1274 scm_list_1 (scm_from_int (engine)));
1275
1276 scm_the_vm ()->engine = engine;
1277 }
1278 #undef FUNC_NAME
1279
1280 SCM_DEFINE (scm_set_vm_engine_x, "set-vm-engine!", 1, 0, 0,
1281 (SCM engine),
1282 "")
1283 #define FUNC_NAME s_scm_set_vm_engine_x
1284 {
1285 scm_c_set_vm_engine_x (symbol_to_vm_engine (engine, FUNC_NAME));
1286 return SCM_UNSPECIFIED;
1287 }
1288 #undef FUNC_NAME
1289
1290 void
1291 scm_c_set_default_vm_engine_x (int engine)
1292 #define FUNC_NAME "set-default-vm-engine!"
1293 {
1294 if (engine < 0 || engine >= SCM_VM_NUM_ENGINES)
1295 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1296 scm_list_1 (scm_from_int (engine)));
1297
1298 vm_default_engine = engine;
1299 }
1300 #undef FUNC_NAME
1301
1302 SCM_DEFINE (scm_set_default_vm_engine_x, "set-default-vm-engine!", 1, 0, 0,
1303 (SCM engine),
1304 "")
1305 #define FUNC_NAME s_scm_set_default_vm_engine_x
1306 {
1307 scm_c_set_default_vm_engine_x (symbol_to_vm_engine (engine, FUNC_NAME));
1308 return SCM_UNSPECIFIED;
1309 }
1310 #undef FUNC_NAME
1311
1312 /* FIXME: This function makes no sense, but we keep it to make sure we
1313 have a way of switching to the debug or regular VM. */
1314 SCM_DEFINE (scm_call_with_vm, "call-with-vm", 1, 0, 1,
1315 (SCM proc, SCM args),
1316 "Apply @var{proc} to @var{args} in a dynamic extent in which\n"
1317 "@var{vm} is the current VM.")
1318 #define FUNC_NAME s_scm_call_with_vm
1319 {
1320 return scm_apply_0 (proc, args);
1321 }
1322 #undef FUNC_NAME
1323
1324 \f
1325 /*
1326 * Initialize
1327 */
1328
1329 SCM
1330 scm_load_compiled_with_vm (SCM file)
1331 {
1332 return scm_call_0 (scm_load_thunk_from_file (file));
1333 }
1334
1335
1336 void
1337 scm_init_vm_builtin_properties (void)
1338 {
1339 /* FIXME: Seems hacky to do this here, but oh well :/ */
1340 scm_sym_apply = scm_from_utf8_symbol ("apply");
1341 scm_sym_values = scm_from_utf8_symbol ("values");
1342 scm_sym_abort_to_prompt = scm_from_utf8_symbol ("abort-to-prompt");
1343 scm_sym_call_with_values = scm_from_utf8_symbol ("call-with-values");
1344 scm_sym_call_with_current_continuation =
1345 scm_from_utf8_symbol ("call-with-current-continuation");
1346
1347 #define INIT_BUILTIN(builtin, BUILTIN, req, opt, rest) \
1348 scm_set_procedure_property_x (vm_builtin_##builtin, scm_sym_name, \
1349 scm_sym_##builtin); \
1350 scm_set_procedure_minimum_arity_x (vm_builtin_##builtin, \
1351 SCM_I_MAKINUM (req), \
1352 SCM_I_MAKINUM (opt), \
1353 scm_from_bool (rest));
1354 FOR_EACH_VM_BUILTIN (INIT_BUILTIN);
1355 #undef INIT_BUILTIN
1356 }
1357
1358 void
1359 scm_bootstrap_vm (void)
1360 {
1361 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1362 "scm_init_vm",
1363 (scm_t_extension_init_func)scm_init_vm, NULL);
1364 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1365 "scm_init_vm_builtins",
1366 (scm_t_extension_init_func)scm_init_vm_builtins,
1367 NULL);
1368
1369 page_size = getpagesize ();
1370 /* page_size should be a power of two. */
1371 if (page_size & (page_size - 1))
1372 abort ();
1373
1374 initialize_default_stack_size ();
1375
1376 sym_vm_run = scm_from_latin1_symbol ("vm-run");
1377 sym_vm_error = scm_from_latin1_symbol ("vm-error");
1378 sym_keyword_argument_error = scm_from_latin1_symbol ("keyword-argument-error");
1379 sym_regular = scm_from_latin1_symbol ("regular");
1380 sym_debug = scm_from_latin1_symbol ("debug");
1381
1382 vm_boot_continuation = scm_i_make_program (vm_boot_continuation_code);
1383 SCM_SET_CELL_WORD_0 (vm_boot_continuation,
1384 (SCM_CELL_WORD_0 (vm_boot_continuation)
1385 | SCM_F_PROGRAM_IS_BOOT));
1386
1387 #define DEFINE_BUILTIN(builtin, BUILTIN, req, opt, rest) \
1388 vm_builtin_##builtin = scm_i_make_program (vm_builtin_##builtin##_code);
1389 FOR_EACH_VM_BUILTIN (DEFINE_BUILTIN);
1390 #undef DEFINE_BUILTIN
1391 }
1392
1393 void
1394 scm_init_vm (void)
1395 {
1396 #ifndef SCM_MAGIC_SNARFER
1397 #include "libguile/vm.x"
1398 #endif
1399 }
1400
1401 /*
1402 Local Variables:
1403 c-file-style: "gnu"
1404 End:
1405 */