Relax assumptions made in the precise VM stack marking procedure.
[bpt/guile.git] / libguile / vm.c
1 /* Copyright (C) 2001, 2009 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 <string.h>
26 #include <assert.h>
27
28 #include "libguile/boehm-gc.h"
29 #include <gc/gc_mark.h>
30
31 #include "_scm.h"
32 #include "vm-bootstrap.h"
33 #include "frames.h"
34 #include "instructions.h"
35 #include "objcodes.h"
36 #include "programs.h"
37 #include "lang.h" /* NULL_OR_NIL_P */
38 #include "vm.h"
39
40 /* I sometimes use this for debugging. */
41 #define vm_puts(OBJ) \
42 { \
43 scm_display (OBJ, scm_current_error_port ()); \
44 scm_newline (scm_current_error_port ()); \
45 }
46
47 /* The VM has a number of internal assertions that shouldn't normally be
48 necessary, but might be if you think you found a bug in the VM. */
49 #define VM_ENABLE_ASSERTIONS
50
51 /* We can add a mode that ensures that all stack items above the stack pointer
52 are NULL. This is useful for checking the internal consistency of the VM's
53 assumptions and its operators, but isn't necessary for normal operation. It
54 will ensure that assertions are enabled. Slows down the VM by about 30%. */
55 /* NB! If you enable this, search for NULLING in throw.c */
56 /* #define VM_ENABLE_STACK_NULLING */
57
58 /* #define VM_ENABLE_PARANOID_ASSERTIONS */
59
60 #if defined (VM_ENABLE_STACK_NULLING) && !defined (VM_ENABLE_ASSERTIONS)
61 #define VM_ENABLE_ASSERTIONS
62 #endif
63
64 /* When defined, arrange so that the GC doesn't scan the VM stack beyond its
65 current SP. This should help avoid excess data retention. See
66 http://thread.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/3001
67 for a discussion. */
68 #define VM_ENABLE_PRECISE_STACK_GC_SCAN
69
70
71 \f
72 /*
73 * VM Continuation
74 */
75
76 scm_t_bits scm_tc16_vm_cont;
77
78 static SCM
79 capture_vm_cont (struct scm_vm *vp)
80 {
81 struct scm_vm_cont *p = scm_gc_malloc (sizeof (*p), "capture_vm_cont");
82 p->stack_size = vp->sp - vp->stack_base + 1;
83 p->stack_base = scm_gc_malloc (p->stack_size * sizeof (SCM),
84 "capture_vm_cont");
85 #ifdef VM_ENABLE_STACK_NULLING
86 if (vp->sp >= vp->stack_base)
87 if (!vp->sp[0] || vp->sp[1])
88 abort ();
89 memset (p->stack_base, 0, p->stack_size * sizeof (SCM));
90 #endif
91 p->ip = vp->ip;
92 p->sp = vp->sp;
93 p->fp = vp->fp;
94 memcpy (p->stack_base, vp->stack_base, p->stack_size * sizeof (SCM));
95 p->reloc = p->stack_base - vp->stack_base;
96 SCM_RETURN_NEWSMOB (scm_tc16_vm_cont, p);
97 }
98
99 static void
100 reinstate_vm_cont (struct scm_vm *vp, SCM cont)
101 {
102 struct scm_vm_cont *p = SCM_VM_CONT_DATA (cont);
103 if (vp->stack_size < p->stack_size)
104 {
105 /* puts ("FIXME: Need to expand"); */
106 abort ();
107 }
108 #ifdef VM_ENABLE_STACK_NULLING
109 {
110 scm_t_ptrdiff nzero = (vp->sp - p->sp);
111 if (nzero > 0)
112 memset (vp->stack_base + p->stack_size, 0, nzero * sizeof (SCM));
113 /* actually nzero should always be negative, because vm_reset_stack will
114 unwind the stack to some point *below* this continuation */
115 }
116 #endif
117 vp->ip = p->ip;
118 vp->sp = p->sp;
119 vp->fp = p->fp;
120 memcpy (vp->stack_base, p->stack_base, p->stack_size * sizeof (SCM));
121 }
122
123 /* In theory, a number of vm instances can be active in the call trace, and we
124 only want to reify the continuations of those in the current continuation
125 root. I don't see a nice way to do this -- ideally it would involve dynwinds,
126 and previous values of the *the-vm* fluid within the current continuation
127 root. But we don't have access to continuation roots in the dynwind stack.
128 So, just punt for now -- take the current value of *the-vm*.
129
130 While I'm on the topic, ideally we could avoid copying the C stack if the
131 continuation root is inside VM code, and call/cc was invoked within that same
132 call to vm_run; but that's currently not implemented.
133 */
134 SCM
135 scm_vm_capture_continuations (void)
136 {
137 SCM vm = scm_the_vm ();
138 return scm_acons (vm, capture_vm_cont (SCM_VM_DATA (vm)), SCM_EOL);
139 }
140
141 void
142 scm_vm_reinstate_continuations (SCM conts)
143 {
144 for (; conts != SCM_EOL; conts = SCM_CDR (conts))
145 reinstate_vm_cont (SCM_VM_DATA (SCM_CAAR (conts)), SCM_CDAR (conts));
146 }
147
148 static void enfalsen_frame (void *p)
149 {
150 struct scm_vm *vp = p;
151 vp->trace_frame = SCM_BOOL_F;
152 }
153
154 static void
155 vm_dispatch_hook (struct scm_vm *vp, SCM hook, SCM hook_args)
156 {
157 if (!SCM_FALSEP (vp->trace_frame))
158 return;
159
160 scm_dynwind_begin (0);
161 // FIXME, stack holder should be the vm
162 vp->trace_frame = scm_c_make_vm_frame (SCM_BOOL_F, vp->fp, vp->sp, vp->ip, 0);
163 scm_dynwind_unwind_handler (enfalsen_frame, vp, SCM_F_WIND_EXPLICITLY);
164
165 scm_c_run_hook (hook, hook_args);
166
167 scm_dynwind_end ();
168 }
169
170 \f
171 /*
172 * VM Internal functions
173 */
174
175 static SCM sym_vm_run;
176 static SCM sym_vm_error;
177 static SCM sym_debug;
178
179 static SCM
180 really_make_boot_program (long nargs)
181 {
182 SCM u8vec;
183 /* Make sure "bytes" is 64-bit aligned. */
184 scm_t_uint8 text[] = { scm_op_mv_call, 0, 0, 1,
185 scm_op_make_int8_1, scm_op_nop, scm_op_nop, scm_op_nop,
186 scm_op_halt };
187 struct scm_objcode *bp;
188 SCM ret;
189
190 if (SCM_UNLIKELY (nargs > 255 || nargs < 0))
191 abort ();
192 text[1] = (scm_t_uint8)nargs;
193
194 bp = scm_gc_malloc (sizeof (struct scm_objcode) + sizeof (text),
195 "make-u8vector");
196 memcpy (bp->base, text, sizeof (text));
197 bp->nargs = 0;
198 bp->nrest = 0;
199 bp->nlocs = 0;
200 bp->len = sizeof(text);
201 bp->metalen = 0;
202 bp->unused = 0;
203
204 u8vec = scm_take_u8vector ((scm_t_uint8*)bp,
205 sizeof (struct scm_objcode) + sizeof (text));
206 ret = scm_make_program (scm_bytecode_to_objcode (u8vec),
207 SCM_BOOL_F, SCM_BOOL_F);
208 SCM_SET_SMOB_FLAGS (ret, SCM_F_PROGRAM_IS_BOOT);
209
210 return ret;
211 }
212 #define NUM_BOOT_PROGS 8
213 static SCM
214 vm_make_boot_program (long nargs)
215 {
216 static SCM programs[NUM_BOOT_PROGS] = { 0, };
217
218 if (SCM_UNLIKELY (!programs[0]))
219 {
220 int i;
221 for (i = 0; i < NUM_BOOT_PROGS; i++)
222 programs[i] = scm_permanent_object (really_make_boot_program (i));
223 }
224
225 if (SCM_LIKELY (nargs < NUM_BOOT_PROGS))
226 return programs[nargs];
227 else
228 return really_make_boot_program (nargs);
229 }
230
231 \f
232 /*
233 * VM
234 */
235
236 static SCM
237 resolve_variable (SCM what, SCM program_module)
238 {
239 if (SCM_LIKELY (SCM_SYMBOLP (what)))
240 {
241 if (SCM_LIKELY (scm_module_system_booted_p
242 && scm_is_true (program_module)))
243 /* might longjmp */
244 return scm_module_lookup (program_module, what);
245 else
246 {
247 SCM v = scm_sym2var (what, SCM_BOOL_F, SCM_BOOL_F);
248 if (scm_is_false (v))
249 scm_misc_error (NULL, "unbound variable: ~S", scm_list_1 (what));
250 else
251 return v;
252 }
253 }
254 else
255 {
256 SCM mod;
257 /* compilation of @ or @@
258 `what' is a three-element list: (MODNAME SYM INTERFACE?)
259 INTERFACE? is #t if we compiled @ or #f if we compiled @@
260 */
261 mod = scm_resolve_module (SCM_CAR (what));
262 if (scm_is_true (SCM_CADDR (what)))
263 mod = scm_module_public_interface (mod);
264 if (SCM_FALSEP (mod))
265 scm_misc_error (NULL, "no such module: ~S",
266 scm_list_1 (SCM_CAR (what)));
267 /* might longjmp */
268 return scm_module_lookup (mod, SCM_CADR (what));
269 }
270 }
271
272
273 #define VM_DEFAULT_STACK_SIZE (64 * 1024)
274
275 #define VM_NAME vm_regular_engine
276 #define FUNC_NAME "vm-regular-engine"
277 #define VM_ENGINE SCM_VM_REGULAR_ENGINE
278 #include "vm-engine.c"
279 #undef VM_NAME
280 #undef FUNC_NAME
281 #undef VM_ENGINE
282
283 #define VM_NAME vm_debug_engine
284 #define FUNC_NAME "vm-debug-engine"
285 #define VM_ENGINE SCM_VM_DEBUG_ENGINE
286 #include "vm-engine.c"
287 #undef VM_NAME
288 #undef FUNC_NAME
289 #undef VM_ENGINE
290
291 static const scm_t_vm_engine vm_engines[] =
292 { vm_regular_engine, vm_debug_engine };
293
294 scm_t_bits scm_tc16_vm;
295
296 #ifdef VM_ENABLE_PRECISE_STACK_GC_SCAN
297
298 /* The GC "kind" for the VM stack. */
299 static int vm_stack_gc_kind;
300
301 #endif
302
303 static SCM
304 make_vm (void)
305 #define FUNC_NAME "make_vm"
306 {
307 int i;
308
309 if (!scm_tc16_vm)
310 return SCM_BOOL_F; /* not booted yet */
311
312 struct scm_vm *vp = scm_gc_malloc (sizeof (struct scm_vm), "vm");
313
314 vp->stack_size = VM_DEFAULT_STACK_SIZE;
315
316 #ifdef VM_ENABLE_PRECISE_STACK_GC_SCAN
317 vp->stack_base = GC_generic_malloc (vp->stack_size * sizeof (SCM),
318 vm_stack_gc_kind);
319
320 /* Keep a pointer to VP so that `vm_stack_mark ()' can know what the stack
321 top is. */
322 *vp->stack_base = PTR2SCM (vp);
323 vp->stack_base++;
324 vp->stack_size--;
325 #else
326 vp->stack_base = scm_gc_malloc (vp->stack_size * sizeof (SCM),
327 "stack-base");
328 #endif
329
330 #ifdef VM_ENABLE_STACK_NULLING
331 memset (vp->stack_base, 0, vp->stack_size * sizeof (SCM));
332 #endif
333 vp->stack_limit = vp->stack_base + vp->stack_size;
334 vp->ip = NULL;
335 vp->sp = vp->stack_base - 1;
336 vp->fp = NULL;
337 vp->engine = SCM_VM_DEBUG_ENGINE;
338 vp->time = 0;
339 vp->clock = 0;
340 vp->options = SCM_EOL;
341 for (i = 0; i < SCM_VM_NUM_HOOKS; i++)
342 vp->hooks[i] = SCM_BOOL_F;
343 vp->trace_frame = SCM_BOOL_F;
344 SCM_RETURN_NEWSMOB (scm_tc16_vm, vp);
345 }
346 #undef FUNC_NAME
347
348 #ifdef VM_ENABLE_PRECISE_STACK_GC_SCAN
349
350 /* Mark the VM stack region between its base and its current top. */
351 static struct GC_ms_entry *
352 vm_stack_mark (GC_word *addr, struct GC_ms_entry *mark_stack_ptr,
353 struct GC_ms_entry *mark_stack_limit, GC_word env)
354 {
355 GC_word *word;
356 const struct scm_vm *vm;
357
358 /* The first word of the VM stack should contain a pointer to the
359 corresponding VM. */
360 vm = * ((struct scm_vm **) addr);
361
362 if ((SCM *) addr != vm->stack_base - 1
363 || vm->stack_limit - vm->stack_base != vm->stack_size)
364 /* ADDR must be a pointer to a free-list element, which we must ignore
365 (see warning in <gc/gc_mark.h>). */
366 return mark_stack_ptr;
367
368 for (word = (GC_word *) vm->stack_base; word <= (GC_word *) vm->sp; word++)
369 mark_stack_ptr = GC_MARK_AND_PUSH ((* (GC_word **) word),
370 mark_stack_ptr, mark_stack_limit,
371 NULL);
372
373 return mark_stack_ptr;
374 }
375
376 #endif /* VM_ENABLE_PRECISE_STACK_GC_SCAN */
377
378
379 SCM
380 scm_c_vm_run (SCM vm, SCM program, SCM *argv, int nargs)
381 {
382 struct scm_vm *vp = SCM_VM_DATA (vm);
383 return vm_engines[vp->engine](vp, program, argv, nargs);
384 }
385
386 SCM
387 scm_vm_apply (SCM vm, SCM program, SCM args)
388 #define FUNC_NAME "scm_vm_apply"
389 {
390 SCM *argv;
391 int i, nargs;
392
393 SCM_VALIDATE_VM (1, vm);
394 SCM_VALIDATE_PROGRAM (2, program);
395
396 nargs = scm_ilength (args);
397 if (SCM_UNLIKELY (nargs < 0))
398 scm_wrong_type_arg_msg (FUNC_NAME, 3, args, "list");
399
400 argv = alloca(nargs * sizeof(SCM));
401 for (i = 0; i < nargs; i++)
402 {
403 argv[i] = SCM_CAR (args);
404 args = SCM_CDR (args);
405 }
406
407 return scm_c_vm_run (vm, program, argv, nargs);
408 }
409 #undef FUNC_NAME
410
411 /* Scheme interface */
412
413 SCM_DEFINE (scm_vm_version, "vm-version", 0, 0, 0,
414 (void),
415 "")
416 #define FUNC_NAME s_scm_vm_version
417 {
418 return scm_from_locale_string (PACKAGE_VERSION);
419 }
420 #undef FUNC_NAME
421
422 SCM_DEFINE (scm_the_vm, "the-vm", 0, 0, 0,
423 (void),
424 "")
425 #define FUNC_NAME s_scm_the_vm
426 {
427 scm_i_thread *t = SCM_I_CURRENT_THREAD;
428
429 if (SCM_UNLIKELY (SCM_FALSEP ((t->vm))))
430 t->vm = make_vm ();
431
432 return t->vm;
433 }
434 #undef FUNC_NAME
435
436
437 SCM_DEFINE (scm_vm_p, "vm?", 1, 0, 0,
438 (SCM obj),
439 "")
440 #define FUNC_NAME s_scm_vm_p
441 {
442 return SCM_BOOL (SCM_VM_P (obj));
443 }
444 #undef FUNC_NAME
445
446 SCM_DEFINE (scm_make_vm, "make-vm", 0, 0, 0,
447 (void),
448 "")
449 #define FUNC_NAME s_scm_make_vm,
450 {
451 return make_vm ();
452 }
453 #undef FUNC_NAME
454
455 SCM_DEFINE (scm_vm_ip, "vm:ip", 1, 0, 0,
456 (SCM vm),
457 "")
458 #define FUNC_NAME s_scm_vm_ip
459 {
460 SCM_VALIDATE_VM (1, vm);
461 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm)->ip);
462 }
463 #undef FUNC_NAME
464
465 SCM_DEFINE (scm_vm_sp, "vm:sp", 1, 0, 0,
466 (SCM vm),
467 "")
468 #define FUNC_NAME s_scm_vm_sp
469 {
470 SCM_VALIDATE_VM (1, vm);
471 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm)->sp);
472 }
473 #undef FUNC_NAME
474
475 SCM_DEFINE (scm_vm_fp, "vm:fp", 1, 0, 0,
476 (SCM vm),
477 "")
478 #define FUNC_NAME s_scm_vm_fp
479 {
480 SCM_VALIDATE_VM (1, vm);
481 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm)->fp);
482 }
483 #undef FUNC_NAME
484
485 #define VM_DEFINE_HOOK(n) \
486 { \
487 struct scm_vm *vp; \
488 SCM_VALIDATE_VM (1, vm); \
489 vp = SCM_VM_DATA (vm); \
490 if (SCM_FALSEP (vp->hooks[n])) \
491 vp->hooks[n] = scm_make_hook (SCM_I_MAKINUM (1)); \
492 return vp->hooks[n]; \
493 }
494
495 SCM_DEFINE (scm_vm_boot_hook, "vm-boot-hook", 1, 0, 0,
496 (SCM vm),
497 "")
498 #define FUNC_NAME s_scm_vm_boot_hook
499 {
500 VM_DEFINE_HOOK (SCM_VM_BOOT_HOOK);
501 }
502 #undef FUNC_NAME
503
504 SCM_DEFINE (scm_vm_halt_hook, "vm-halt-hook", 1, 0, 0,
505 (SCM vm),
506 "")
507 #define FUNC_NAME s_scm_vm_halt_hook
508 {
509 VM_DEFINE_HOOK (SCM_VM_HALT_HOOK);
510 }
511 #undef FUNC_NAME
512
513 SCM_DEFINE (scm_vm_next_hook, "vm-next-hook", 1, 0, 0,
514 (SCM vm),
515 "")
516 #define FUNC_NAME s_scm_vm_next_hook
517 {
518 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK);
519 }
520 #undef FUNC_NAME
521
522 SCM_DEFINE (scm_vm_break_hook, "vm-break-hook", 1, 0, 0,
523 (SCM vm),
524 "")
525 #define FUNC_NAME s_scm_vm_break_hook
526 {
527 VM_DEFINE_HOOK (SCM_VM_BREAK_HOOK);
528 }
529 #undef FUNC_NAME
530
531 SCM_DEFINE (scm_vm_enter_hook, "vm-enter-hook", 1, 0, 0,
532 (SCM vm),
533 "")
534 #define FUNC_NAME s_scm_vm_enter_hook
535 {
536 VM_DEFINE_HOOK (SCM_VM_ENTER_HOOK);
537 }
538 #undef FUNC_NAME
539
540 SCM_DEFINE (scm_vm_apply_hook, "vm-apply-hook", 1, 0, 0,
541 (SCM vm),
542 "")
543 #define FUNC_NAME s_scm_vm_apply_hook
544 {
545 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK);
546 }
547 #undef FUNC_NAME
548
549 SCM_DEFINE (scm_vm_exit_hook, "vm-exit-hook", 1, 0, 0,
550 (SCM vm),
551 "")
552 #define FUNC_NAME s_scm_vm_exit_hook
553 {
554 VM_DEFINE_HOOK (SCM_VM_EXIT_HOOK);
555 }
556 #undef FUNC_NAME
557
558 SCM_DEFINE (scm_vm_return_hook, "vm-return-hook", 1, 0, 0,
559 (SCM vm),
560 "")
561 #define FUNC_NAME s_scm_vm_return_hook
562 {
563 VM_DEFINE_HOOK (SCM_VM_RETURN_HOOK);
564 }
565 #undef FUNC_NAME
566
567 SCM_DEFINE (scm_vm_option, "vm-option", 2, 0, 0,
568 (SCM vm, SCM key),
569 "")
570 #define FUNC_NAME s_scm_vm_option
571 {
572 SCM_VALIDATE_VM (1, vm);
573 return scm_assq_ref (SCM_VM_DATA (vm)->options, key);
574 }
575 #undef FUNC_NAME
576
577 SCM_DEFINE (scm_set_vm_option_x, "set-vm-option!", 3, 0, 0,
578 (SCM vm, SCM key, SCM val),
579 "")
580 #define FUNC_NAME s_scm_set_vm_option_x
581 {
582 SCM_VALIDATE_VM (1, vm);
583 SCM_VM_DATA (vm)->options
584 = scm_assq_set_x (SCM_VM_DATA (vm)->options, key, val);
585 return SCM_UNSPECIFIED;
586 }
587 #undef FUNC_NAME
588
589 SCM_DEFINE (scm_vm_stats, "vm-stats", 1, 0, 0,
590 (SCM vm),
591 "")
592 #define FUNC_NAME s_scm_vm_stats
593 {
594 SCM stats;
595
596 SCM_VALIDATE_VM (1, vm);
597
598 stats = scm_make_vector (SCM_I_MAKINUM (2), SCM_UNSPECIFIED);
599 scm_vector_set_x (stats, SCM_I_MAKINUM (0),
600 scm_from_ulong (SCM_VM_DATA (vm)->time));
601 scm_vector_set_x (stats, SCM_I_MAKINUM (1),
602 scm_from_ulong (SCM_VM_DATA (vm)->clock));
603
604 return stats;
605 }
606 #undef FUNC_NAME
607
608 SCM_DEFINE (scm_vm_trace_frame, "vm-trace-frame", 1, 0, 0,
609 (SCM vm),
610 "")
611 #define FUNC_NAME s_scm_vm_trace_frame
612 {
613 SCM_VALIDATE_VM (1, vm);
614 return SCM_VM_DATA (vm)->trace_frame;
615 }
616 #undef FUNC_NAME
617
618 \f
619 /*
620 * Initialize
621 */
622
623 SCM scm_load_compiled_with_vm (SCM file)
624 {
625 SCM program = scm_make_program (scm_load_objcode (file),
626 SCM_BOOL_F, SCM_BOOL_F);
627
628 return scm_c_vm_run (scm_the_vm (), program, NULL, 0);
629 }
630
631 void
632 scm_bootstrap_vm (void)
633 {
634 static int strappage = 0;
635
636 if (strappage)
637 return;
638
639 scm_bootstrap_frames ();
640 scm_bootstrap_instructions ();
641 scm_bootstrap_objcodes ();
642 scm_bootstrap_programs ();
643
644 scm_tc16_vm_cont = scm_make_smob_type ("vm-cont", 0);
645
646 scm_tc16_vm = scm_make_smob_type ("vm", 0);
647 scm_set_smob_apply (scm_tc16_vm, scm_vm_apply, 1, 0, 1);
648
649 scm_c_define ("load-compiled",
650 scm_c_make_gsubr ("load-compiled/vm", 1, 0, 0,
651 scm_load_compiled_with_vm));
652
653 sym_vm_run = scm_permanent_object (scm_from_locale_symbol ("vm-run"));
654 sym_vm_error = scm_permanent_object (scm_from_locale_symbol ("vm-error"));
655 sym_debug = scm_permanent_object (scm_from_locale_symbol ("debug"));
656
657 scm_c_register_extension ("libguile", "scm_init_vm",
658 (scm_t_extension_init_func)scm_init_vm, NULL);
659
660 strappage = 1;
661
662 #ifdef VM_ENABLE_PRECISE_STACK_GC_SCAN
663 vm_stack_gc_kind =
664 GC_new_kind (GC_new_free_list (),
665 GC_MAKE_PROC (GC_new_proc (vm_stack_mark), 0),
666 0, 1);
667
668 #endif
669 }
670
671 void
672 scm_init_vm (void)
673 {
674 scm_bootstrap_vm ();
675
676 #ifndef SCM_MAGIC_SNARFER
677 #include "libguile/vm.x"
678 #endif
679 }
680
681 /*
682 Local Variables:
683 c-file-style: "gnu"
684 End:
685 */