1 /* Copyright (C) 2001, 2009 Free Software Foundation, Inc.
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.
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.
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
28 #include "libguile/boehm-gc.h"
29 #include <gc/gc_mark.h>
32 #include "vm-bootstrap.h"
34 #include "instructions.h"
37 #include "lang.h" /* NULL_OR_NIL_P */
40 /* I sometimes use this for debugging. */
41 #define vm_puts(OBJ) \
43 scm_display (OBJ, scm_current_error_port ()); \
44 scm_newline (scm_current_error_port ()); \
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
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 */
58 /* #define VM_ENABLE_PARANOID_ASSERTIONS */
60 #if defined (VM_ENABLE_STACK_NULLING) && !defined (VM_ENABLE_ASSERTIONS)
61 #define VM_ENABLE_ASSERTIONS
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
68 #define VM_ENABLE_PRECISE_STACK_GC_SCAN
76 scm_t_bits scm_tc16_vm_cont
;
79 capture_vm_cont (struct scm_vm
*vp
)
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
),
85 #ifdef VM_ENABLE_STACK_NULLING
86 if (vp
->sp
>= vp
->stack_base
)
87 if (!vp
->sp
[0] || vp
->sp
[1])
89 memset (p
->stack_base
, 0, p
->stack_size
* sizeof (SCM
));
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
);
100 reinstate_vm_cont (struct scm_vm
*vp
, SCM cont
)
102 struct scm_vm_cont
*p
= SCM_VM_CONT_DATA (cont
);
103 if (vp
->stack_size
< p
->stack_size
)
105 /* puts ("FIXME: Need to expand"); */
108 #ifdef VM_ENABLE_STACK_NULLING
110 scm_t_ptrdiff nzero
= (vp
->sp
- p
->sp
);
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 */
120 memcpy (vp
->stack_base
, p
->stack_base
, p
->stack_size
* sizeof (SCM
));
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*.
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.
135 scm_vm_capture_continuations (void)
137 SCM vm
= scm_the_vm ();
138 return scm_acons (vm
, capture_vm_cont (SCM_VM_DATA (vm
)), SCM_EOL
);
142 scm_vm_reinstate_continuations (SCM conts
)
144 for (; conts
!= SCM_EOL
; conts
= SCM_CDR (conts
))
145 reinstate_vm_cont (SCM_VM_DATA (SCM_CAAR (conts
)), SCM_CDAR (conts
));
148 static void enfalsen_frame (void *p
)
150 struct scm_vm
*vp
= p
;
151 vp
->trace_frame
= SCM_BOOL_F
;
155 vm_dispatch_hook (struct scm_vm
*vp
, SCM hook
, SCM hook_args
)
157 if (!SCM_FALSEP (vp
->trace_frame
))
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
);
165 scm_c_run_hook (hook
, hook_args
);
172 * VM Internal functions
175 static SCM sym_vm_run
;
176 static SCM sym_vm_error
;
177 static SCM sym_debug
;
180 really_make_boot_program (long nargs
)
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
,
187 struct scm_objcode
*bp
;
190 if (SCM_UNLIKELY (nargs
> 255 || nargs
< 0))
192 text
[1] = (scm_t_uint8
)nargs
;
194 bp
= scm_gc_malloc (sizeof (struct scm_objcode
) + sizeof (text
),
196 memcpy (bp
->base
, text
, sizeof (text
));
200 bp
->len
= sizeof(text
);
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
);
212 #define NUM_BOOT_PROGS 8
214 vm_make_boot_program (long nargs
)
216 static SCM programs
[NUM_BOOT_PROGS
] = { 0, };
218 if (SCM_UNLIKELY (!programs
[0]))
221 for (i
= 0; i
< NUM_BOOT_PROGS
; i
++)
222 programs
[i
] = scm_permanent_object (really_make_boot_program (i
));
225 if (SCM_LIKELY (nargs
< NUM_BOOT_PROGS
))
226 return programs
[nargs
];
228 return really_make_boot_program (nargs
);
237 resolve_variable (SCM what
, SCM program_module
)
239 if (SCM_LIKELY (SCM_SYMBOLP (what
)))
241 if (SCM_LIKELY (scm_module_system_booted_p
242 && scm_is_true (program_module
)))
244 return scm_module_lookup (program_module
, what
);
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
));
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 @@
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
)));
268 return scm_module_lookup (mod
, SCM_CADR (what
));
273 #define VM_DEFAULT_STACK_SIZE (64 * 1024)
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"
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"
291 static const scm_t_vm_engine vm_engines
[] =
292 { vm_regular_engine
, vm_debug_engine
};
294 scm_t_bits scm_tc16_vm
;
296 #ifdef VM_ENABLE_PRECISE_STACK_GC_SCAN
298 /* The GC "kind" for the VM stack. */
299 static int vm_stack_gc_kind
;
305 #define FUNC_NAME "make_vm"
310 return SCM_BOOL_F
; /* not booted yet */
312 struct scm_vm
*vp
= scm_gc_malloc (sizeof (struct scm_vm
), "vm");
314 vp
->stack_size
= VM_DEFAULT_STACK_SIZE
;
316 #ifdef VM_ENABLE_PRECISE_STACK_GC_SCAN
317 vp
->stack_base
= GC_generic_malloc (vp
->stack_size
* sizeof (SCM
),
320 /* Keep a pointer to VP so that `vm_stack_mark ()' can know what the stack
322 *vp
->stack_base
= PTR2SCM (vp
);
326 vp
->stack_base
= scm_gc_malloc (vp
->stack_size
* sizeof (SCM
),
330 #ifdef VM_ENABLE_STACK_NULLING
331 memset (vp
->stack_base
, 0, vp
->stack_size
* sizeof (SCM
));
333 vp
->stack_limit
= vp
->stack_base
+ vp
->stack_size
;
335 vp
->sp
= vp
->stack_base
- 1;
337 vp
->engine
= SCM_VM_DEBUG_ENGINE
;
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
);
348 #ifdef VM_ENABLE_PRECISE_STACK_GC_SCAN
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
)
356 const struct scm_vm
*vm
;
358 /* The first word of the VM stack should contain a pointer to the
360 vm
= * ((struct scm_vm
**) addr
);
362 if (vm
->stack_base
== NULL
)
363 /* ADDR must be a pointer to a free-list element, which we must ignore
364 (see warning in <gc/gc_mark.h>). */
365 return mark_stack_ptr
;
368 assert ((SCM
*) addr
== vm
->stack_base
- 1);
369 assert (vm
->sp
>= (SCM
*) addr
);
370 assert (vm
->stack_limit
- vm
->stack_base
== vm
->stack_size
);
372 for (word
= (GC_word
*) vm
->stack_base
; word
<= (GC_word
*) vm
->sp
; word
++)
373 mark_stack_ptr
= GC_MARK_AND_PUSH ((* (GC_word
**) word
),
374 mark_stack_ptr
, mark_stack_limit
,
377 return mark_stack_ptr
;
380 #endif /* VM_ENABLE_PRECISE_STACK_GC_SCAN */
384 scm_c_vm_run (SCM vm
, SCM program
, SCM
*argv
, int nargs
)
386 struct scm_vm
*vp
= SCM_VM_DATA (vm
);
387 return vm_engines
[vp
->engine
](vp
, program
, argv
, nargs
);
391 scm_vm_apply (SCM vm
, SCM program
, SCM args
)
392 #define FUNC_NAME "scm_vm_apply"
397 SCM_VALIDATE_VM (1, vm
);
398 SCM_VALIDATE_PROGRAM (2, program
);
400 nargs
= scm_ilength (args
);
401 if (SCM_UNLIKELY (nargs
< 0))
402 scm_wrong_type_arg_msg (FUNC_NAME
, 3, args
, "list");
404 argv
= alloca(nargs
* sizeof(SCM
));
405 for (i
= 0; i
< nargs
; i
++)
407 argv
[i
] = SCM_CAR (args
);
408 args
= SCM_CDR (args
);
411 return scm_c_vm_run (vm
, program
, argv
, nargs
);
415 /* Scheme interface */
417 SCM_DEFINE (scm_vm_version
, "vm-version", 0, 0, 0,
420 #define FUNC_NAME s_scm_vm_version
422 return scm_from_locale_string (PACKAGE_VERSION
);
426 SCM_DEFINE (scm_the_vm
, "the-vm", 0, 0, 0,
429 #define FUNC_NAME s_scm_the_vm
431 scm_i_thread
*t
= SCM_I_CURRENT_THREAD
;
433 if (SCM_UNLIKELY (SCM_FALSEP ((t
->vm
))))
441 SCM_DEFINE (scm_vm_p
, "vm?", 1, 0, 0,
444 #define FUNC_NAME s_scm_vm_p
446 return SCM_BOOL (SCM_VM_P (obj
));
450 SCM_DEFINE (scm_make_vm
, "make-vm", 0, 0, 0,
453 #define FUNC_NAME s_scm_make_vm,
459 SCM_DEFINE (scm_vm_ip
, "vm:ip", 1, 0, 0,
462 #define FUNC_NAME s_scm_vm_ip
464 SCM_VALIDATE_VM (1, vm
);
465 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->ip
);
469 SCM_DEFINE (scm_vm_sp
, "vm:sp", 1, 0, 0,
472 #define FUNC_NAME s_scm_vm_sp
474 SCM_VALIDATE_VM (1, vm
);
475 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->sp
);
479 SCM_DEFINE (scm_vm_fp
, "vm:fp", 1, 0, 0,
482 #define FUNC_NAME s_scm_vm_fp
484 SCM_VALIDATE_VM (1, vm
);
485 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->fp
);
489 #define VM_DEFINE_HOOK(n) \
492 SCM_VALIDATE_VM (1, vm); \
493 vp = SCM_VM_DATA (vm); \
494 if (SCM_FALSEP (vp->hooks[n])) \
495 vp->hooks[n] = scm_make_hook (SCM_I_MAKINUM (1)); \
496 return vp->hooks[n]; \
499 SCM_DEFINE (scm_vm_boot_hook
, "vm-boot-hook", 1, 0, 0,
502 #define FUNC_NAME s_scm_vm_boot_hook
504 VM_DEFINE_HOOK (SCM_VM_BOOT_HOOK
);
508 SCM_DEFINE (scm_vm_halt_hook
, "vm-halt-hook", 1, 0, 0,
511 #define FUNC_NAME s_scm_vm_halt_hook
513 VM_DEFINE_HOOK (SCM_VM_HALT_HOOK
);
517 SCM_DEFINE (scm_vm_next_hook
, "vm-next-hook", 1, 0, 0,
520 #define FUNC_NAME s_scm_vm_next_hook
522 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK
);
526 SCM_DEFINE (scm_vm_break_hook
, "vm-break-hook", 1, 0, 0,
529 #define FUNC_NAME s_scm_vm_break_hook
531 VM_DEFINE_HOOK (SCM_VM_BREAK_HOOK
);
535 SCM_DEFINE (scm_vm_enter_hook
, "vm-enter-hook", 1, 0, 0,
538 #define FUNC_NAME s_scm_vm_enter_hook
540 VM_DEFINE_HOOK (SCM_VM_ENTER_HOOK
);
544 SCM_DEFINE (scm_vm_apply_hook
, "vm-apply-hook", 1, 0, 0,
547 #define FUNC_NAME s_scm_vm_apply_hook
549 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK
);
553 SCM_DEFINE (scm_vm_exit_hook
, "vm-exit-hook", 1, 0, 0,
556 #define FUNC_NAME s_scm_vm_exit_hook
558 VM_DEFINE_HOOK (SCM_VM_EXIT_HOOK
);
562 SCM_DEFINE (scm_vm_return_hook
, "vm-return-hook", 1, 0, 0,
565 #define FUNC_NAME s_scm_vm_return_hook
567 VM_DEFINE_HOOK (SCM_VM_RETURN_HOOK
);
571 SCM_DEFINE (scm_vm_option
, "vm-option", 2, 0, 0,
574 #define FUNC_NAME s_scm_vm_option
576 SCM_VALIDATE_VM (1, vm
);
577 return scm_assq_ref (SCM_VM_DATA (vm
)->options
, key
);
581 SCM_DEFINE (scm_set_vm_option_x
, "set-vm-option!", 3, 0, 0,
582 (SCM vm
, SCM key
, SCM val
),
584 #define FUNC_NAME s_scm_set_vm_option_x
586 SCM_VALIDATE_VM (1, vm
);
587 SCM_VM_DATA (vm
)->options
588 = scm_assq_set_x (SCM_VM_DATA (vm
)->options
, key
, val
);
589 return SCM_UNSPECIFIED
;
593 SCM_DEFINE (scm_vm_stats
, "vm-stats", 1, 0, 0,
596 #define FUNC_NAME s_scm_vm_stats
600 SCM_VALIDATE_VM (1, vm
);
602 stats
= scm_make_vector (SCM_I_MAKINUM (2), SCM_UNSPECIFIED
);
603 scm_vector_set_x (stats
, SCM_I_MAKINUM (0),
604 scm_from_ulong (SCM_VM_DATA (vm
)->time
));
605 scm_vector_set_x (stats
, SCM_I_MAKINUM (1),
606 scm_from_ulong (SCM_VM_DATA (vm
)->clock
));
612 SCM_DEFINE (scm_vm_trace_frame
, "vm-trace-frame", 1, 0, 0,
615 #define FUNC_NAME s_scm_vm_trace_frame
617 SCM_VALIDATE_VM (1, vm
);
618 return SCM_VM_DATA (vm
)->trace_frame
;
627 SCM
scm_load_compiled_with_vm (SCM file
)
629 SCM program
= scm_make_program (scm_load_objcode (file
),
630 SCM_BOOL_F
, SCM_BOOL_F
);
632 return scm_c_vm_run (scm_the_vm (), program
, NULL
, 0);
636 scm_bootstrap_vm (void)
638 static int strappage
= 0;
643 scm_bootstrap_frames ();
644 scm_bootstrap_instructions ();
645 scm_bootstrap_objcodes ();
646 scm_bootstrap_programs ();
648 scm_tc16_vm_cont
= scm_make_smob_type ("vm-cont", 0);
650 scm_tc16_vm
= scm_make_smob_type ("vm", 0);
651 scm_set_smob_apply (scm_tc16_vm
, scm_vm_apply
, 1, 0, 1);
653 scm_c_define ("load-compiled",
654 scm_c_make_gsubr ("load-compiled/vm", 1, 0, 0,
655 scm_load_compiled_with_vm
));
657 sym_vm_run
= scm_permanent_object (scm_from_locale_symbol ("vm-run"));
658 sym_vm_error
= scm_permanent_object (scm_from_locale_symbol ("vm-error"));
659 sym_debug
= scm_permanent_object (scm_from_locale_symbol ("debug"));
661 scm_c_register_extension ("libguile", "scm_init_vm",
662 (scm_t_extension_init_func
)scm_init_vm
, NULL
);
666 #ifdef VM_ENABLE_PRECISE_STACK_GC_SCAN
668 GC_new_kind (GC_new_free_list (),
669 GC_MAKE_PROC (GC_new_proc (vm_stack_mark
), 0),
680 #ifndef SCM_MAGIC_SNARFER
681 #include "libguile/vm.x"