Merge commit '5cfeff11cc58148c58a85a879fd7a3e7cfbbe8e2'
[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_no_values (void) SCM_NORETURN SCM_NOINLINE;
427 static void vm_error_not_enough_values (void) SCM_NORETURN SCM_NOINLINE;
428 static void vm_error_wrong_number_of_values (scm_t_uint32 expected) SCM_NORETURN SCM_NOINLINE;
429 static void vm_error_continuation_not_rewindable (SCM cont) SCM_NORETURN SCM_NOINLINE;
430 static void vm_error_bad_wide_string_length (size_t len) SCM_NORETURN SCM_NOINLINE;
431
432 static void
433 vm_error (const char *msg, SCM arg)
434 {
435 scm_throw (sym_vm_error,
436 scm_list_3 (sym_vm_run, scm_from_latin1_string (msg),
437 SCM_UNBNDP (arg) ? SCM_EOL : scm_list_1 (arg)));
438 abort(); /* not reached */
439 }
440
441 static void
442 vm_error_bad_instruction (scm_t_uint32 inst)
443 {
444 vm_error ("VM: Bad instruction: ~s", scm_from_uint32 (inst));
445 }
446
447 static void
448 vm_error_unbound (SCM proc, SCM sym)
449 {
450 scm_error_scm (scm_misc_error_key, proc,
451 scm_from_latin1_string ("Unbound variable: ~s"),
452 scm_list_1 (sym), SCM_BOOL_F);
453 }
454
455 static void
456 vm_error_unbound_fluid (SCM proc, SCM fluid)
457 {
458 scm_error_scm (scm_misc_error_key, proc,
459 scm_from_latin1_string ("Unbound fluid: ~s"),
460 scm_list_1 (fluid), SCM_BOOL_F);
461 }
462
463 static void
464 vm_error_not_a_variable (const char *func_name, SCM x)
465 {
466 scm_error (scm_arg_type_key, func_name, "Not a variable: ~S",
467 scm_list_1 (x), scm_list_1 (x));
468 }
469
470 static void
471 vm_error_apply_to_non_list (SCM x)
472 {
473 scm_error (scm_arg_type_key, "apply", "Apply to non-list: ~S",
474 scm_list_1 (x), scm_list_1 (x));
475 }
476
477 static void
478 vm_error_kwargs_length_not_even (SCM proc)
479 {
480 scm_error_scm (sym_keyword_argument_error, proc,
481 scm_from_latin1_string ("Odd length of keyword argument list"),
482 SCM_EOL, SCM_BOOL_F);
483 }
484
485 static void
486 vm_error_kwargs_invalid_keyword (SCM proc, SCM obj)
487 {
488 scm_error_scm (sym_keyword_argument_error, proc,
489 scm_from_latin1_string ("Invalid keyword"),
490 SCM_EOL, scm_list_1 (obj));
491 }
492
493 static void
494 vm_error_kwargs_unrecognized_keyword (SCM proc, SCM kw)
495 {
496 scm_error_scm (sym_keyword_argument_error, proc,
497 scm_from_latin1_string ("Unrecognized keyword"),
498 SCM_EOL, scm_list_1 (kw));
499 }
500
501 static void
502 vm_error_too_many_args (int nargs)
503 {
504 vm_error ("VM: Too many arguments", scm_from_int (nargs));
505 }
506
507 static void
508 vm_error_wrong_num_args (SCM proc)
509 {
510 scm_wrong_num_args (proc);
511 }
512
513 static void
514 vm_error_wrong_type_apply (SCM proc)
515 {
516 scm_error (scm_arg_type_key, NULL, "Wrong type to apply: ~S",
517 scm_list_1 (proc), scm_list_1 (proc));
518 }
519
520 static void
521 vm_error_stack_underflow (void)
522 {
523 vm_error ("VM: Stack underflow", SCM_UNDEFINED);
524 }
525
526 static void
527 vm_error_improper_list (SCM x)
528 {
529 vm_error ("Expected a proper list, but got object with tail ~s", x);
530 }
531
532 static void
533 vm_error_not_a_pair (const char *subr, SCM x)
534 {
535 scm_wrong_type_arg_msg (subr, 1, x, "pair");
536 }
537
538 static void
539 vm_error_not_a_bytevector (const char *subr, SCM x)
540 {
541 scm_wrong_type_arg_msg (subr, 1, x, "bytevector");
542 }
543
544 static void
545 vm_error_not_a_struct (const char *subr, SCM x)
546 {
547 scm_wrong_type_arg_msg (subr, 1, x, "struct");
548 }
549
550 static void
551 vm_error_no_values (void)
552 {
553 vm_error ("Zero values returned to single-valued continuation",
554 SCM_UNDEFINED);
555 }
556
557 static void
558 vm_error_not_enough_values (void)
559 {
560 vm_error ("Too few values returned to continuation", SCM_UNDEFINED);
561 }
562
563 static void
564 vm_error_wrong_number_of_values (scm_t_uint32 expected)
565 {
566 vm_error ("Wrong number of values returned to continuation (expected ~a)",
567 scm_from_uint32 (expected));
568 }
569
570 static void
571 vm_error_continuation_not_rewindable (SCM cont)
572 {
573 vm_error ("Unrewindable partial continuation", cont);
574 }
575
576 static void
577 vm_error_bad_wide_string_length (size_t len)
578 {
579 vm_error ("VM: Bad wide string length: ~S", scm_from_size_t (len));
580 }
581
582
583 \f
584
585 static SCM vm_boot_continuation;
586 static SCM vm_builtin_apply;
587 static SCM vm_builtin_values;
588 static SCM vm_builtin_abort_to_prompt;
589 static SCM vm_builtin_call_with_values;
590 static SCM vm_builtin_call_with_current_continuation;
591
592 static const scm_t_uint32 vm_boot_continuation_code[] = {
593 SCM_PACK_OP_24 (halt, 0)
594 };
595
596 static const scm_t_uint32 vm_builtin_apply_code[] = {
597 SCM_PACK_OP_24 (assert_nargs_ge, 3),
598 SCM_PACK_OP_24 (tail_apply, 0), /* proc in r1, args from r2 */
599 };
600
601 static const scm_t_uint32 vm_builtin_values_code[] = {
602 SCM_PACK_OP_24 (return_values, 0) /* vals from r1 */
603 };
604
605 static const scm_t_uint32 vm_builtin_abort_to_prompt_code[] = {
606 SCM_PACK_OP_24 (assert_nargs_ge, 2),
607 SCM_PACK_OP_24 (abort, 0), /* tag in r1, vals from r2 */
608 /* FIXME: Partial continuation should capture caller regs. */
609 SCM_PACK_OP_24 (return_values, 0) /* vals from r1 */
610 };
611
612 static const scm_t_uint32 vm_builtin_call_with_values_code[] = {
613 SCM_PACK_OP_24 (assert_nargs_ee, 3),
614 SCM_PACK_OP_24 (alloc_frame, 7),
615 SCM_PACK_OP_12_12 (mov, 6, 1),
616 SCM_PACK_OP_24 (call, 6), SCM_PACK_OP_ARG_8_24 (0, 1),
617 SCM_PACK_OP_12_12 (mov, 0, 2),
618 SCM_PACK_OP_24 (tail_call_shuffle, 7)
619 };
620
621 static const scm_t_uint32 vm_builtin_call_with_current_continuation_code[] = {
622 SCM_PACK_OP_24 (assert_nargs_ee, 2),
623 SCM_PACK_OP_24 (call_cc, 0)
624 };
625
626
627 static SCM
628 scm_vm_builtin_ref (unsigned idx)
629 {
630 switch (idx)
631 {
632 #define INDEX_TO_NAME(builtin, BUILTIN, req, opt, rest) \
633 case SCM_VM_BUILTIN_##BUILTIN: return vm_builtin_##builtin;
634 FOR_EACH_VM_BUILTIN(INDEX_TO_NAME)
635 #undef INDEX_TO_NAME
636 default: abort();
637 }
638 }
639
640 SCM scm_sym_apply;
641 static SCM scm_sym_values;
642 static SCM scm_sym_abort_to_prompt;
643 static SCM scm_sym_call_with_values;
644 static SCM scm_sym_call_with_current_continuation;
645
646 SCM
647 scm_vm_builtin_name_to_index (SCM name)
648 #define FUNC_NAME "builtin-name->index"
649 {
650 SCM_VALIDATE_SYMBOL (1, name);
651
652 #define NAME_TO_INDEX(builtin, BUILTIN, req, opt, rest) \
653 if (scm_is_eq (name, scm_sym_##builtin)) \
654 return scm_from_uint (SCM_VM_BUILTIN_##BUILTIN);
655 FOR_EACH_VM_BUILTIN(NAME_TO_INDEX)
656 #undef NAME_TO_INDEX
657
658 return SCM_BOOL_F;
659 }
660 #undef FUNC_NAME
661
662 SCM
663 scm_vm_builtin_index_to_name (SCM index)
664 #define FUNC_NAME "builtin-index->name"
665 {
666 unsigned idx;
667
668 SCM_VALIDATE_UINT_COPY (1, index, idx);
669
670 switch (idx)
671 {
672 #define INDEX_TO_NAME(builtin, BUILTIN, req, opt, rest) \
673 case SCM_VM_BUILTIN_##BUILTIN: return scm_sym_##builtin;
674 FOR_EACH_VM_BUILTIN(INDEX_TO_NAME)
675 #undef INDEX_TO_NAME
676 default: return SCM_BOOL_F;
677 }
678 }
679 #undef FUNC_NAME
680
681 static void
682 scm_init_vm_builtins (void)
683 {
684 scm_c_define_gsubr ("builtin-name->index", 1, 0, 0,
685 scm_vm_builtin_name_to_index);
686 scm_c_define_gsubr ("builtin-index->name", 1, 0, 0,
687 scm_vm_builtin_index_to_name);
688 }
689
690 SCM
691 scm_i_call_with_current_continuation (SCM proc)
692 {
693 return scm_call_1 (vm_builtin_call_with_current_continuation, proc);
694 }
695
696 \f
697 /*
698 * VM
699 */
700
701 /* Hard stack limit is 512M words: 2 gigabytes on 32-bit machines, 4 on
702 64-bit machines. */
703 static const size_t hard_max_stack_size = 512 * 1024 * 1024;
704
705 /* Initial stack size: 4 or 8 kB. */
706 static const size_t initial_stack_size = 1024;
707
708 /* Default soft stack limit is 1M words (4 or 8 megabytes). */
709 static size_t default_max_stack_size = 1024 * 1024;
710
711 static void
712 initialize_default_stack_size (void)
713 {
714 int size = scm_getenv_int ("GUILE_STACK_SIZE", (int) default_max_stack_size);
715 if (size >= initial_stack_size && (size_t) size < ((size_t) -1) / sizeof(SCM))
716 default_max_stack_size = size;
717 }
718
719 #define VM_NAME vm_regular_engine
720 #define VM_USE_HOOKS 0
721 #define FUNC_NAME "vm-regular-engine"
722 #include "vm-engine.c"
723 #undef FUNC_NAME
724 #undef VM_USE_HOOKS
725 #undef VM_NAME
726
727 #define VM_NAME vm_debug_engine
728 #define VM_USE_HOOKS 1
729 #define FUNC_NAME "vm-debug-engine"
730 #include "vm-engine.c"
731 #undef FUNC_NAME
732 #undef VM_USE_HOOKS
733 #undef VM_NAME
734
735 typedef SCM (*scm_t_vm_engine) (scm_i_thread *current_thread, struct scm_vm *vp,
736 scm_i_jmp_buf *registers, int resume);
737
738 static const scm_t_vm_engine vm_engines[SCM_VM_NUM_ENGINES] =
739 { vm_regular_engine, vm_debug_engine };
740
741 static SCM*
742 allocate_stack (size_t size)
743 #define FUNC_NAME "make_vm"
744 {
745 void *ret;
746
747 if (size >= ((size_t) -1) / sizeof (SCM))
748 abort ();
749
750 size *= sizeof (SCM);
751
752 #if HAVE_SYS_MMAN_H
753 ret = mmap (NULL, size, PROT_READ | PROT_WRITE,
754 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
755 if (ret == MAP_FAILED)
756 SCM_SYSERROR;
757 #else
758 ret = malloc (size);
759 if (!ret)
760 SCM_SYSERROR;
761 #endif
762
763 return (SCM *) ret;
764 }
765 #undef FUNC_NAME
766
767 static void
768 free_stack (SCM *stack, size_t size)
769 {
770 size *= sizeof (SCM);
771
772 #if HAVE_SYS_MMAN_H
773 munmap (stack, size);
774 #else
775 free (stack);
776 #endif
777 }
778
779 static SCM*
780 expand_stack (SCM *old_stack, size_t old_size, size_t new_size)
781 #define FUNC_NAME "expand_stack"
782 {
783 #if defined MREMAP_MAYMOVE
784 void *new_stack;
785
786 if (new_size >= ((size_t) -1) / sizeof (SCM))
787 abort ();
788
789 old_size *= sizeof (SCM);
790 new_size *= sizeof (SCM);
791
792 new_stack = mremap (old_stack, old_size, new_size, MREMAP_MAYMOVE);
793 if (new_stack == MAP_FAILED)
794 SCM_SYSERROR;
795
796 return (SCM *) new_stack;
797 #else
798 SCM *new_stack;
799
800 new_stack = allocate_stack (new_size);
801 memcpy (new_stack, old_stack, old_size * sizeof (SCM));
802 free_stack (old_stack, old_size);
803
804 return new_stack;
805 #endif
806 }
807 #undef FUNC_NAME
808
809 static struct scm_vm *
810 make_vm (void)
811 #define FUNC_NAME "make_vm"
812 {
813 int i;
814 struct scm_vm *vp;
815
816 vp = scm_gc_malloc (sizeof (struct scm_vm), "vm");
817
818 vp->stack_size = initial_stack_size;
819 vp->stack_base = allocate_stack (vp->stack_size);
820 vp->stack_limit = vp->stack_base + vp->stack_size;
821 vp->max_stack_size = default_max_stack_size;
822 vp->ip = NULL;
823 vp->sp = vp->stack_base - 1;
824 vp->fp = NULL;
825 vp->engine = vm_default_engine;
826 vp->trace_level = 0;
827 for (i = 0; i < SCM_VM_NUM_HOOKS; i++)
828 vp->hooks[i] = SCM_BOOL_F;
829
830 return vp;
831 }
832 #undef FUNC_NAME
833
834 static size_t page_size;
835
836 static void
837 return_unused_stack_to_os (struct scm_vm *vp)
838 {
839 #if HAVE_SYS_MMAN_H
840 scm_t_uintptr start = (scm_t_uintptr) (vp->sp + 1);
841 scm_t_uintptr end = (scm_t_uintptr) vp->stack_limit;
842 /* The second condition is needed to protect against wrap-around. */
843 if (vp->sp_max_since_gc < vp->stack_limit && vp->sp < vp->sp_max_since_gc)
844 end = (scm_t_uintptr) (vp->sp_max_since_gc + 1);
845
846 start = ((start - 1U) | (page_size - 1U)) + 1U; /* round up */
847 end = ((end - 1U) | (page_size - 1U)) + 1U; /* round up */
848
849 /* Return these pages to the OS. The next time they are paged in,
850 they will be zeroed. */
851 if (start < end)
852 madvise ((void *) start, end - start, MADV_DONTNEED);
853
854 vp->sp_max_since_gc = vp->sp;
855 #endif
856 }
857
858 #define DEAD_SLOT_MAP_CACHE_SIZE 32U
859 struct dead_slot_map_cache_entry
860 {
861 scm_t_uint32 *ip;
862 const scm_t_uint8 *map;
863 };
864
865 struct dead_slot_map_cache
866 {
867 struct dead_slot_map_cache_entry entries[DEAD_SLOT_MAP_CACHE_SIZE];
868 };
869
870 static const scm_t_uint8 *
871 find_dead_slot_map (scm_t_uint32 *ip, struct dead_slot_map_cache *cache)
872 {
873 /* The lower two bits should be zero. FIXME: Use a better hash
874 function; we don't expose scm_raw_hashq currently. */
875 size_t slot = (((scm_t_uintptr) ip) >> 2) % DEAD_SLOT_MAP_CACHE_SIZE;
876 const scm_t_uint8 *map;
877
878 if (cache->entries[slot].ip == ip)
879 map = cache->entries[slot].map;
880 else
881 {
882 map = scm_find_dead_slot_map_unlocked (ip);
883 cache->entries[slot].ip = ip;
884 cache->entries[slot].map = map;
885 }
886
887 return map;
888 }
889
890 /* Mark the VM stack region between its base and its current top. */
891 struct GC_ms_entry *
892 scm_i_vm_mark_stack (struct scm_vm *vp, struct GC_ms_entry *mark_stack_ptr,
893 struct GC_ms_entry *mark_stack_limit)
894 {
895 SCM *sp, *fp;
896 /* The first frame will be marked conservatively (without a dead
897 slot map). This is because GC can happen at any point within the
898 hottest activation, due to multiple threads or per-instruction
899 hooks, and providing dead slot maps for all points in a program
900 would take a prohibitive amount of space. */
901 const scm_t_uint8 *dead_slots = NULL;
902 scm_t_uintptr upper = (scm_t_uintptr) GC_greatest_plausible_heap_addr;
903 scm_t_uintptr lower = (scm_t_uintptr) GC_least_plausible_heap_addr;
904 struct dead_slot_map_cache cache;
905
906 memset (&cache, 0, sizeof (cache));
907
908 for (fp = vp->fp, sp = vp->sp; fp; fp = SCM_FRAME_DYNAMIC_LINK (fp))
909 {
910 for (; sp >= &SCM_FRAME_LOCAL (fp, 0); sp--)
911 {
912 SCM elt = *sp;
913 if (SCM_NIMP (elt)
914 && SCM_UNPACK (elt) >= lower && SCM_UNPACK (elt) <= upper)
915 {
916 if (dead_slots)
917 {
918 size_t slot = sp - &SCM_FRAME_LOCAL (fp, 0);
919 if (dead_slots[slot / 8U] & (1U << (slot % 8U)))
920 {
921 /* This value may become dead as a result of GC,
922 so we can't just leave it on the stack. */
923 *sp = SCM_UNBOUND;
924 continue;
925 }
926 }
927
928 mark_stack_ptr = GC_mark_and_push ((void *) elt,
929 mark_stack_ptr,
930 mark_stack_limit,
931 NULL);
932 }
933 }
934 sp = SCM_FRAME_PREVIOUS_SP (fp);
935 /* Inner frames may have a dead slots map for precise marking.
936 Note that there may be other reasons to not have a dead slots
937 map, e.g. if all of the frame's slots below the callee frame
938 are live. */
939 dead_slots = find_dead_slot_map (SCM_FRAME_RETURN_ADDRESS (fp), &cache);
940 }
941
942 return_unused_stack_to_os (vp);
943
944 return mark_stack_ptr;
945 }
946
947 /* Free the VM stack, as this thread is exiting. */
948 void
949 scm_i_vm_free_stack (struct scm_vm *vp)
950 {
951 free_stack (vp->stack_base, vp->stack_size);
952 vp->stack_base = vp->stack_limit = NULL;
953 vp->stack_size = 0;
954 }
955
956 static void
957 vm_expand_stack (struct scm_vm *vp)
958 {
959 scm_t_ptrdiff stack_size = vp->sp + 1 - vp->stack_base;
960
961 if (stack_size > hard_max_stack_size)
962 {
963 /* We have expanded the soft limit to the point that we reached a
964 hard limit. There is nothing sensible to do. */
965 fprintf (stderr, "Hard stack size limit (%zu words) reached; aborting.\n",
966 hard_max_stack_size);
967 abort ();
968 }
969
970 /* FIXME: Prevent GC while we expand the stack, to ensure that a
971 stack marker can trace the stack. */
972 if (stack_size > vp->stack_size)
973 {
974 SCM *old_stack;
975 size_t new_size;
976 scm_t_ptrdiff reloc;
977
978 new_size = vp->stack_size;
979 while (new_size < stack_size)
980 new_size *= 2;
981 old_stack = vp->stack_base;
982 vp->stack_base = expand_stack (old_stack, vp->stack_size, new_size);
983 vp->stack_size = new_size;
984 vp->stack_limit = vp->stack_base + new_size;
985 reloc = vp->stack_base - old_stack;
986
987 if (reloc)
988 {
989 SCM *fp;
990 if (vp->fp)
991 vp->fp += reloc;
992 vp->sp += reloc;
993 vp->sp_max_since_gc += reloc;
994 fp = vp->fp;
995 while (fp)
996 {
997 SCM *next_fp = SCM_FRAME_DYNAMIC_LINK (fp);
998 if (next_fp)
999 {
1000 next_fp += reloc;
1001 SCM_FRAME_SET_DYNAMIC_LINK (fp, next_fp);
1002 }
1003 fp = next_fp;
1004 }
1005 }
1006 }
1007
1008 if (stack_size >= vp->max_stack_size)
1009 {
1010 /* Expand the soft limit by 256K entries to give us space to
1011 handle the error. */
1012 vp->max_stack_size += 256 * 1024;
1013
1014 /* If it's still not big enough... it's quite improbable, but go
1015 ahead and set to the full available stack size. */
1016 if (vp->max_stack_size < stack_size)
1017 vp->max_stack_size = vp->stack_size;
1018
1019 /* But don't exceed the hard maximum. */
1020 if (vp->max_stack_size > hard_max_stack_size)
1021 vp->max_stack_size = hard_max_stack_size;
1022
1023 /* Finally, reset the limit, to catch further overflows. */
1024 vp->stack_limit = vp->stack_base + vp->max_stack_size;
1025
1026 vm_error ("VM: Stack overflow", SCM_UNDEFINED);
1027 }
1028
1029 /* Otherwise continue, with the new enlarged stack. */
1030 }
1031
1032 static struct scm_vm *
1033 thread_vm (scm_i_thread *t)
1034 {
1035 if (SCM_UNLIKELY (!t->vp))
1036 t->vp = make_vm ();
1037
1038 return t->vp;
1039 }
1040
1041 struct scm_vm *
1042 scm_the_vm (void)
1043 {
1044 return thread_vm (SCM_I_CURRENT_THREAD);
1045 }
1046
1047 SCM
1048 scm_call_n (SCM proc, SCM *argv, size_t nargs)
1049 {
1050 scm_i_thread *thread;
1051 struct scm_vm *vp;
1052 SCM *base;
1053 ptrdiff_t base_frame_size;
1054 /* Cached variables. */
1055 scm_i_jmp_buf registers; /* used for prompts */
1056 size_t i;
1057
1058 thread = SCM_I_CURRENT_THREAD;
1059 vp = thread_vm (thread);
1060
1061 SCM_CHECK_STACK;
1062
1063 /* Check that we have enough space: 3 words for the boot continuation,
1064 and 3 + nargs for the procedure application. */
1065 base_frame_size = 3 + 3 + nargs;
1066 vm_push_sp (vp, vp->sp + base_frame_size);
1067 base = vp->sp + 1 - base_frame_size;
1068
1069 /* Since it's possible to receive the arguments on the stack itself,
1070 shuffle up the arguments first. */
1071 for (i = nargs; i > 0; i--)
1072 base[6 + i - 1] = argv[i - 1];
1073
1074 /* Push the boot continuation, which calls PROC and returns its
1075 result(s). */
1076 base[0] = SCM_PACK (vp->fp); /* dynamic link */
1077 base[1] = SCM_PACK (vp->ip); /* ra */
1078 base[2] = vm_boot_continuation;
1079 vp->fp = &base[2];
1080 vp->ip = (scm_t_uint32 *) vm_boot_continuation_code;
1081
1082 /* The pending call to PROC. */
1083 base[3] = SCM_PACK (vp->fp); /* dynamic link */
1084 base[4] = SCM_PACK (vp->ip); /* ra */
1085 base[5] = proc;
1086 vp->fp = &base[5];
1087
1088 {
1089 int resume = SCM_I_SETJMP (registers);
1090
1091 if (SCM_UNLIKELY (resume))
1092 /* Non-local return. */
1093 vm_dispatch_abort_hook (vp);
1094
1095 return vm_engines[vp->engine](thread, vp, &registers, resume);
1096 }
1097 }
1098
1099 /* Scheme interface */
1100
1101 #define VM_DEFINE_HOOK(n) \
1102 { \
1103 struct scm_vm *vp; \
1104 vp = scm_the_vm (); \
1105 if (scm_is_false (vp->hooks[n])) \
1106 vp->hooks[n] = scm_make_hook (SCM_I_MAKINUM (1)); \
1107 return vp->hooks[n]; \
1108 }
1109
1110 SCM_DEFINE (scm_vm_apply_hook, "vm-apply-hook", 0, 0, 0,
1111 (void),
1112 "")
1113 #define FUNC_NAME s_scm_vm_apply_hook
1114 {
1115 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK);
1116 }
1117 #undef FUNC_NAME
1118
1119 SCM_DEFINE (scm_vm_push_continuation_hook, "vm-push-continuation-hook", 0, 0, 0,
1120 (void),
1121 "")
1122 #define FUNC_NAME s_scm_vm_push_continuation_hook
1123 {
1124 VM_DEFINE_HOOK (SCM_VM_PUSH_CONTINUATION_HOOK);
1125 }
1126 #undef FUNC_NAME
1127
1128 SCM_DEFINE (scm_vm_pop_continuation_hook, "vm-pop-continuation-hook", 0, 0, 0,
1129 (void),
1130 "")
1131 #define FUNC_NAME s_scm_vm_pop_continuation_hook
1132 {
1133 VM_DEFINE_HOOK (SCM_VM_POP_CONTINUATION_HOOK);
1134 }
1135 #undef FUNC_NAME
1136
1137 SCM_DEFINE (scm_vm_next_hook, "vm-next-hook", 0, 0, 0,
1138 (void),
1139 "")
1140 #define FUNC_NAME s_scm_vm_next_hook
1141 {
1142 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK);
1143 }
1144 #undef FUNC_NAME
1145
1146 SCM_DEFINE (scm_vm_abort_continuation_hook, "vm-abort-continuation-hook", 0, 0, 0,
1147 (void),
1148 "")
1149 #define FUNC_NAME s_scm_vm_abort_continuation_hook
1150 {
1151 VM_DEFINE_HOOK (SCM_VM_ABORT_CONTINUATION_HOOK);
1152 }
1153 #undef FUNC_NAME
1154
1155 SCM_DEFINE (scm_vm_trace_level, "vm-trace-level", 0, 0, 0,
1156 (void),
1157 "")
1158 #define FUNC_NAME s_scm_vm_trace_level
1159 {
1160 return scm_from_int (scm_the_vm ()->trace_level);
1161 }
1162 #undef FUNC_NAME
1163
1164 SCM_DEFINE (scm_set_vm_trace_level_x, "set-vm-trace-level!", 1, 0, 0,
1165 (SCM level),
1166 "")
1167 #define FUNC_NAME s_scm_set_vm_trace_level_x
1168 {
1169 scm_the_vm ()->trace_level = scm_to_int (level);
1170 return SCM_UNSPECIFIED;
1171 }
1172 #undef FUNC_NAME
1173
1174 \f
1175 /*
1176 * VM engines
1177 */
1178
1179 static int
1180 symbol_to_vm_engine (SCM engine, const char *FUNC_NAME)
1181 {
1182 if (scm_is_eq (engine, sym_regular))
1183 return SCM_VM_REGULAR_ENGINE;
1184 else if (scm_is_eq (engine, sym_debug))
1185 return SCM_VM_DEBUG_ENGINE;
1186 else
1187 SCM_MISC_ERROR ("Unknown VM engine: ~a", scm_list_1 (engine));
1188 }
1189
1190 static SCM
1191 vm_engine_to_symbol (int engine, const char *FUNC_NAME)
1192 {
1193 switch (engine)
1194 {
1195 case SCM_VM_REGULAR_ENGINE:
1196 return sym_regular;
1197 case SCM_VM_DEBUG_ENGINE:
1198 return sym_debug;
1199 default:
1200 /* ? */
1201 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1202 scm_list_1 (scm_from_int (engine)));
1203 }
1204 }
1205
1206 SCM_DEFINE (scm_vm_engine, "vm-engine", 0, 0, 0,
1207 (void),
1208 "")
1209 #define FUNC_NAME s_scm_vm_engine
1210 {
1211 return vm_engine_to_symbol (scm_the_vm ()->engine, FUNC_NAME);
1212 }
1213 #undef FUNC_NAME
1214
1215 void
1216 scm_c_set_vm_engine_x (int engine)
1217 #define FUNC_NAME "set-vm-engine!"
1218 {
1219 if (engine < 0 || engine >= SCM_VM_NUM_ENGINES)
1220 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1221 scm_list_1 (scm_from_int (engine)));
1222
1223 scm_the_vm ()->engine = engine;
1224 }
1225 #undef FUNC_NAME
1226
1227 SCM_DEFINE (scm_set_vm_engine_x, "set-vm-engine!", 1, 0, 0,
1228 (SCM engine),
1229 "")
1230 #define FUNC_NAME s_scm_set_vm_engine_x
1231 {
1232 scm_c_set_vm_engine_x (symbol_to_vm_engine (engine, FUNC_NAME));
1233 return SCM_UNSPECIFIED;
1234 }
1235 #undef FUNC_NAME
1236
1237 void
1238 scm_c_set_default_vm_engine_x (int engine)
1239 #define FUNC_NAME "set-default-vm-engine!"
1240 {
1241 if (engine < 0 || engine >= SCM_VM_NUM_ENGINES)
1242 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1243 scm_list_1 (scm_from_int (engine)));
1244
1245 vm_default_engine = engine;
1246 }
1247 #undef FUNC_NAME
1248
1249 SCM_DEFINE (scm_set_default_vm_engine_x, "set-default-vm-engine!", 1, 0, 0,
1250 (SCM engine),
1251 "")
1252 #define FUNC_NAME s_scm_set_default_vm_engine_x
1253 {
1254 scm_c_set_default_vm_engine_x (symbol_to_vm_engine (engine, FUNC_NAME));
1255 return SCM_UNSPECIFIED;
1256 }
1257 #undef FUNC_NAME
1258
1259 /* FIXME: This function makes no sense, but we keep it to make sure we
1260 have a way of switching to the debug or regular VM. */
1261 SCM_DEFINE (scm_call_with_vm, "call-with-vm", 1, 0, 1,
1262 (SCM proc, SCM args),
1263 "Apply @var{proc} to @var{args} in a dynamic extent in which\n"
1264 "@var{vm} is the current VM.")
1265 #define FUNC_NAME s_scm_call_with_vm
1266 {
1267 return scm_apply_0 (proc, args);
1268 }
1269 #undef FUNC_NAME
1270
1271 \f
1272 /*
1273 * Initialize
1274 */
1275
1276 SCM
1277 scm_load_compiled_with_vm (SCM file)
1278 {
1279 return scm_call_0 (scm_load_thunk_from_file (file));
1280 }
1281
1282
1283 void
1284 scm_init_vm_builtin_properties (void)
1285 {
1286 /* FIXME: Seems hacky to do this here, but oh well :/ */
1287 scm_sym_apply = scm_from_utf8_symbol ("apply");
1288 scm_sym_values = scm_from_utf8_symbol ("values");
1289 scm_sym_abort_to_prompt = scm_from_utf8_symbol ("abort-to-prompt");
1290 scm_sym_call_with_values = scm_from_utf8_symbol ("call-with-values");
1291 scm_sym_call_with_current_continuation =
1292 scm_from_utf8_symbol ("call-with-current-continuation");
1293
1294 #define INIT_BUILTIN(builtin, BUILTIN, req, opt, rest) \
1295 scm_set_procedure_property_x (vm_builtin_##builtin, scm_sym_name, \
1296 scm_sym_##builtin); \
1297 scm_set_procedure_minimum_arity_x (vm_builtin_##builtin, \
1298 SCM_I_MAKINUM (req), \
1299 SCM_I_MAKINUM (opt), \
1300 scm_from_bool (rest));
1301 FOR_EACH_VM_BUILTIN (INIT_BUILTIN);
1302 #undef INIT_BUILTIN
1303 }
1304
1305 void
1306 scm_bootstrap_vm (void)
1307 {
1308 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1309 "scm_init_vm",
1310 (scm_t_extension_init_func)scm_init_vm, NULL);
1311 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1312 "scm_init_vm_builtins",
1313 (scm_t_extension_init_func)scm_init_vm_builtins,
1314 NULL);
1315
1316 page_size = getpagesize ();
1317 /* page_size should be a power of two. */
1318 if (page_size & (page_size - 1))
1319 abort ();
1320
1321 initialize_default_stack_size ();
1322
1323 sym_vm_run = scm_from_latin1_symbol ("vm-run");
1324 sym_vm_error = scm_from_latin1_symbol ("vm-error");
1325 sym_keyword_argument_error = scm_from_latin1_symbol ("keyword-argument-error");
1326 sym_regular = scm_from_latin1_symbol ("regular");
1327 sym_debug = scm_from_latin1_symbol ("debug");
1328
1329 vm_boot_continuation = scm_i_make_program (vm_boot_continuation_code);
1330 SCM_SET_CELL_WORD_0 (vm_boot_continuation,
1331 (SCM_CELL_WORD_0 (vm_boot_continuation)
1332 | SCM_F_PROGRAM_IS_BOOT));
1333
1334 #define DEFINE_BUILTIN(builtin, BUILTIN, req, opt, rest) \
1335 vm_builtin_##builtin = scm_i_make_program (vm_builtin_##builtin##_code);
1336 FOR_EACH_VM_BUILTIN (DEFINE_BUILTIN);
1337 #undef DEFINE_BUILTIN
1338 }
1339
1340 void
1341 scm_init_vm (void)
1342 {
1343 #ifndef SCM_MAGIC_SNARFER
1344 #include "libguile/vm.x"
1345 #endif
1346 }
1347
1348 /*
1349 Local Variables:
1350 c-file-style: "gnu"
1351 End:
1352 */