1 /* Copyright (C) 2001 Free Software Foundation, Inc.
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
47 #include "vm-bootstrap.h"
49 #include "instructions.h"
54 /* I sometimes use this for debugging. */
55 #define vm_puts(OBJ) \
57 scm_display (OBJ, scm_current_error_port ()); \
58 scm_newline (scm_current_error_port ()); \
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
65 /* We can add a mode that ensures that all stack items above the stack pointer
66 are NULL. This is useful for checking the internal consistency of the VM's
67 assumptions and its operators, but isn't necessary for normal operation. It
68 will ensure that assertions are enabled. */
69 #define VM_ENABLE_STACK_NULLING
71 #if defined (VM_ENABLE_STACK_NULLING) && !defined (VM_ENABLE_ASSERTIONS)
72 #define VM_ENABLE_ASSERTIONS
80 scm_t_bits scm_tc16_vm_cont
;
86 scm_t_ptrdiff stack_size
;
92 #define SCM_VM_CONT_P(OBJ) SCM_SMOB_PREDICATE (scm_tc16_vm_cont, OBJ)
93 #define SCM_VM_CONT_DATA(CONT) ((struct scm_vm_cont *) SCM_CELL_WORD_1 (CONT))
96 vm_mark_stack (SCM
*base
, scm_t_ptrdiff size
, SCM
*fp
, scm_t_ptrdiff reloc
)
98 SCM
*sp
, *upper
, *lower
;
101 while (sp
> base
&& fp
)
103 upper
= SCM_FRAME_UPPER_ADDRESS (fp
);
104 lower
= SCM_FRAME_LOWER_ADDRESS (fp
);
106 for (; sp
>= upper
; sp
--)
109 if (scm_in_heap_p (*sp
))
112 fprintf (stderr
, "BADNESS: crap on the stack: %p\n", *sp
);
119 /* update fp from the dynamic link */
120 fp
= (SCM
*)*sp
-- + reloc
;
122 /* mark from the hl down to the lower address */
123 for (; sp
>= lower
; sp
--)
124 if (*sp
&& SCM_NIMP (*sp
))
130 vm_cont_mark (SCM obj
)
132 struct scm_vm_cont
*p
= SCM_VM_CONT_DATA (obj
);
134 vm_mark_stack (p
->stack_base
, p
->stack_size
, p
->stack_base
+ p
->fp
, p
->reloc
);
140 vm_cont_free (SCM obj
)
142 struct scm_vm_cont
*p
= SCM_VM_CONT_DATA (obj
);
144 scm_gc_free (p
->stack_base
, p
->stack_size
* sizeof (SCM
), "stack-base");
145 scm_gc_free (p
, sizeof (struct scm_vm
), "vm");
151 capture_vm_cont (struct scm_vm
*vp
)
153 struct scm_vm_cont
*p
= scm_gc_malloc (sizeof (*p
), "capture_vm_cont");
154 p
->stack_size
= vp
->sp
- vp
->stack_base
+ 1;
155 p
->stack_base
= scm_gc_malloc (p
->stack_size
* sizeof (SCM
),
157 #ifdef VM_ENABLE_STACK_NULLING
158 memset (p
->stack_base
, 0, p
->stack_size
* sizeof (SCM
));
161 p
->sp
= vp
->sp
- vp
->stack_base
;
162 p
->fp
= vp
->fp
- vp
->stack_base
;
163 memcpy (p
->stack_base
, vp
->stack_base
, p
->stack_size
* sizeof (SCM
));
164 p
->reloc
= p
->stack_base
- vp
->stack_base
;
165 SCM_RETURN_NEWSMOB (scm_tc16_vm_cont
, p
);
169 reinstate_vm_cont (struct scm_vm
*vp
, SCM cont
)
171 struct scm_vm_cont
*p
= SCM_VM_CONT_DATA (cont
);
172 if (vp
->stack_size
< p
->stack_size
)
174 /* puts ("FIXME: Need to expand"); */
177 #ifdef VM_ENABLE_STACK_NULLING
179 scm_t_ptrdiff nzero
= (vp
->sp
- vp
->stack_base
) - p
->sp
;
181 memset (vp
->stack_base
+ p
->stack_size
, 0, nzero
);
185 vp
->sp
= vp
->stack_base
+ p
->sp
;
186 vp
->fp
= vp
->stack_base
+ p
->fp
;
187 memcpy (vp
->stack_base
, p
->stack_base
, p
->stack_size
* sizeof (SCM
));
190 /* In theory, a number of vm instances can be active in the call trace, and we
191 only want to reify the continuations of those in the current continuation
192 root. I don't see a nice way to do this -- ideally it would involve dynwinds,
193 and previous values of the *the-vm* fluid within the current continuation
194 root. But we don't have access to continuation roots in the dynwind stack.
195 So, just punt for now -- take the current value of *the-vm*.
197 While I'm on the topic, ideally we could avoid copying the C stack if the
198 continuation root is inside VM code, and call/cc was invoked within that same
199 call to vm_run; but that's currently not implemented.
202 scm_vm_capture_continuations (void)
204 SCM vm
= scm_the_vm ();
205 return scm_acons (vm
, capture_vm_cont (SCM_VM_DATA (vm
)), SCM_EOL
);
209 scm_vm_reinstate_continuations (SCM conts
)
211 for (; conts
!= SCM_EOL
; conts
= SCM_CDR (conts
))
212 reinstate_vm_cont (SCM_VM_DATA (SCM_CAAR (conts
)), SCM_CDAR (conts
));
215 struct vm_unwind_data
224 vm_reset_stack (void *data
)
226 struct vm_unwind_data
*w
= data
;
230 w
->vp
->this_frame
= w
->this_frame
;
231 #ifdef VM_ENABLE_STACK_NULLING
232 memset (w
->vp
->sp
+ 1, 0, w
->vp
->stack_size
- (w
->vp
->sp
+ 1 - w
->vp
->stack_base
));
238 * VM Internal functions
241 static SCM sym_vm_run
;
242 static SCM sym_vm_error
;
243 static SCM sym_debug
;
246 vm_fetch_length (scm_byte_t
*ip
, size_t *lenp
)
248 /* NOTE: format defined in system/vm/conv.scm */
252 else if (*lenp
== 254)
256 *lenp
= (b1
<< 8) + b2
;
264 *lenp
= (b1
<< 24) + (b2
<< 16) + (b3
<< 8) + b4
;
270 vm_heapify_frames_1 (struct scm_vm
*vp
, SCM
*fp
, SCM
*sp
, SCM
**destp
)
273 SCM
*dl
= SCM_FRAME_DYNAMIC_LINK (fp
);
275 SCM
*src
= SCM_FRAME_UPPER_ADDRESS (fp
);
277 SCM
*dest
= SCM_FRAME_LOWER_ADDRESS (fp
);
282 frame
= scm_c_make_heap_frame (fp
);
283 fp
= SCM_HEAP_FRAME_POINTER (frame
);
284 SCM_FRAME_HEAP_LINK (fp
) = SCM_BOOL_T
;
289 SCM link
= SCM_FRAME_HEAP_LINK (dl
);
290 if (!SCM_FALSEP (link
))
291 link
= SCM_FRAME_LOWER_ADDRESS (dl
)[-1]; /* self link */
293 link
= vm_heapify_frames_1 (vp
, dl
, dest
- 1, &dest
);
294 frame
= scm_c_make_heap_frame (fp
);
295 fp
= SCM_HEAP_FRAME_POINTER (frame
);
296 SCM_FRAME_HEAP_LINK (fp
) = link
;
297 SCM_FRAME_SET_DYNAMIC_LINK (fp
, SCM_HEAP_FRAME_POINTER (link
));
300 /* Apparently the intention here is to be able to have a frame on the heap,
301 but data on the stack, so that you can push as much as you want on the
302 stack; but I think that it's currently causing borkage with nonlocal exits
303 and the unwind handler, which reinstates the sp and fp, but it's no longer
304 pointing at a valid stack frame. So disable for now, we'll get back to
307 /* Move stack data */
308 for (; src
<= sp
; src
++, dest
++)
317 vm_heapify_frames (SCM vm
)
319 struct scm_vm
*vp
= SCM_VM_DATA (vm
);
320 if (SCM_FALSEP (SCM_FRAME_HEAP_LINK (vp
->fp
)))
323 vp
->this_frame
= vm_heapify_frames_1 (vp
, vp
->fp
, vp
->sp
, &dest
);
324 vp
->fp
= SCM_HEAP_FRAME_POINTER (vp
->this_frame
);
327 return vp
->this_frame
;
335 #define VM_DEFAULT_STACK_SIZE (16 * 1024)
337 #define VM_REGULAR_ENGINE 0
338 #define VM_DEBUG_ENGINE 1
341 #define VM_NAME vm_regular_engine
342 #define VM_ENGINE VM_REGULAR_ENGINE
343 #include "vm-engine.c"
348 #define VM_NAME vm_debug_engine
349 #define VM_ENGINE VM_DEBUG_ENGINE
350 #include "vm-engine.c"
354 scm_t_bits scm_tc16_vm
;
356 SCM scm_the_vm_fluid
;
360 #define FUNC_NAME "make_vm"
363 struct scm_vm
*vp
= scm_gc_malloc (sizeof (struct scm_vm
), "vm");
365 vp
->stack_size
= VM_DEFAULT_STACK_SIZE
;
366 vp
->stack_base
= scm_gc_malloc (vp
->stack_size
* sizeof (SCM
),
368 vp
->stack_limit
= vp
->stack_base
+ vp
->stack_size
- 3;
370 vp
->sp
= vp
->stack_base
- 1;
374 vp
->options
= SCM_EOL
;
375 vp
->this_frame
= SCM_BOOL_F
;
376 vp
->last_frame
= SCM_BOOL_F
;
378 for (i
= 0; i
< SCM_VM_NUM_HOOKS
; i
++)
379 vp
->hooks
[i
] = SCM_BOOL_F
;
380 SCM_RETURN_NEWSMOB (scm_tc16_vm
, vp
);
388 struct scm_vm
*vp
= SCM_VM_DATA (obj
);
390 #ifdef VM_ENABLE_STACK_NULLING
391 if (vp
->sp
>= vp
->stack_base
)
392 if (!vp
->sp
[0] || vp
->sp
[1])
396 /* mark the stack, precisely */
397 vm_mark_stack (vp
->stack_base
, vp
->sp
+ 1 - vp
->stack_base
, vp
->fp
, 0);
399 /* mark other objects */
400 for (i
= 0; i
< SCM_VM_NUM_HOOKS
; i
++)
401 scm_gc_mark (vp
->hooks
[i
]);
402 scm_gc_mark (vp
->this_frame
);
403 scm_gc_mark (vp
->last_frame
);
410 struct scm_vm
*vp
= SCM_VM_DATA (obj
);
412 scm_gc_free (vp
->stack_base
, vp
->stack_size
* sizeof (SCM
),
414 scm_gc_free (vp
, sizeof (struct scm_vm
), "vm");
420 scm_vm_apply (SCM vm
, SCM program
, SCM args
)
421 #define FUNC_NAME "scm_vm_apply"
423 SCM_VALIDATE_PROGRAM (1, program
);
424 return vm_run (vm
, program
, args
);
428 /* Scheme interface */
430 SCM_DEFINE (scm_vm_version
, "vm-version", 0, 0, 0,
433 #define FUNC_NAME s_scm_vm_version
435 return scm_from_locale_string (PACKAGE_VERSION
);
439 SCM_DEFINE (scm_the_vm
, "the-vm", 0, 0, 0,
442 #define FUNC_NAME s_scm_the_vm
446 if (SCM_NFALSEP ((ret
= scm_fluid_ref (scm_the_vm_fluid
))))
450 scm_fluid_set_x (scm_the_vm_fluid
, ret
);
456 SCM_DEFINE (scm_vm_p
, "vm?", 1, 0, 0,
459 #define FUNC_NAME s_scm_vm_p
461 return SCM_BOOL (SCM_VM_P (obj
));
465 SCM_DEFINE (scm_make_vm
, "make-vm", 0, 0, 0,
468 #define FUNC_NAME s_scm_make_vm,
474 SCM_DEFINE (scm_vm_ip
, "vm:ip", 1, 0, 0,
477 #define FUNC_NAME s_scm_vm_ip
479 SCM_VALIDATE_VM (1, vm
);
480 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->ip
);
484 SCM_DEFINE (scm_vm_sp
, "vm:sp", 1, 0, 0,
487 #define FUNC_NAME s_scm_vm_sp
489 SCM_VALIDATE_VM (1, vm
);
490 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->sp
);
494 SCM_DEFINE (scm_vm_fp
, "vm:fp", 1, 0, 0,
497 #define FUNC_NAME s_scm_vm_fp
499 SCM_VALIDATE_VM (1, vm
);
500 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->fp
);
504 #define VM_DEFINE_HOOK(n) \
507 SCM_VALIDATE_VM (1, vm); \
508 vp = SCM_VM_DATA (vm); \
509 if (SCM_FALSEP (vp->hooks[n])) \
510 vp->hooks[n] = scm_make_hook (SCM_I_MAKINUM (1)); \
511 return vp->hooks[n]; \
514 SCM_DEFINE (scm_vm_boot_hook
, "vm-boot-hook", 1, 0, 0,
517 #define FUNC_NAME s_scm_vm_boot_hook
519 VM_DEFINE_HOOK (SCM_VM_BOOT_HOOK
);
523 SCM_DEFINE (scm_vm_halt_hook
, "vm-halt-hook", 1, 0, 0,
526 #define FUNC_NAME s_scm_vm_halt_hook
528 VM_DEFINE_HOOK (SCM_VM_HALT_HOOK
);
532 SCM_DEFINE (scm_vm_next_hook
, "vm-next-hook", 1, 0, 0,
535 #define FUNC_NAME s_scm_vm_next_hook
537 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK
);
541 SCM_DEFINE (scm_vm_break_hook
, "vm-break-hook", 1, 0, 0,
544 #define FUNC_NAME s_scm_vm_break_hook
546 VM_DEFINE_HOOK (SCM_VM_BREAK_HOOK
);
550 SCM_DEFINE (scm_vm_enter_hook
, "vm-enter-hook", 1, 0, 0,
553 #define FUNC_NAME s_scm_vm_enter_hook
555 VM_DEFINE_HOOK (SCM_VM_ENTER_HOOK
);
559 SCM_DEFINE (scm_vm_apply_hook
, "vm-apply-hook", 1, 0, 0,
562 #define FUNC_NAME s_scm_vm_apply_hook
564 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK
);
568 SCM_DEFINE (scm_vm_exit_hook
, "vm-exit-hook", 1, 0, 0,
571 #define FUNC_NAME s_scm_vm_exit_hook
573 VM_DEFINE_HOOK (SCM_VM_EXIT_HOOK
);
577 SCM_DEFINE (scm_vm_return_hook
, "vm-return-hook", 1, 0, 0,
580 #define FUNC_NAME s_scm_vm_return_hook
582 VM_DEFINE_HOOK (SCM_VM_RETURN_HOOK
);
586 SCM_DEFINE (scm_vm_option
, "vm-option", 2, 0, 0,
589 #define FUNC_NAME s_scm_vm_option
591 SCM_VALIDATE_VM (1, vm
);
592 return scm_assq_ref (SCM_VM_DATA (vm
)->options
, key
);
596 SCM_DEFINE (scm_set_vm_option_x
, "set-vm-option!", 3, 0, 0,
597 (SCM vm
, SCM key
, SCM val
),
599 #define FUNC_NAME s_scm_set_vm_option_x
601 SCM_VALIDATE_VM (1, vm
);
602 SCM_VM_DATA (vm
)->options
603 = scm_assq_set_x (SCM_VM_DATA (vm
)->options
, key
, val
);
604 return SCM_UNSPECIFIED
;
608 SCM_DEFINE (scm_vm_stats
, "vm-stats", 1, 0, 0,
611 #define FUNC_NAME s_scm_vm_stats
615 SCM_VALIDATE_VM (1, vm
);
617 stats
= scm_make_vector (SCM_I_MAKINUM (2), SCM_UNSPECIFIED
);
618 scm_vector_set_x (stats
, SCM_I_MAKINUM (0),
619 scm_from_ulong (SCM_VM_DATA (vm
)->time
));
620 scm_vector_set_x (stats
, SCM_I_MAKINUM (1),
621 scm_from_ulong (SCM_VM_DATA (vm
)->clock
));
627 #define VM_CHECK_RUNNING(vm) \
628 if (!SCM_VM_DATA (vm)->ip) \
629 SCM_MISC_ERROR ("Not running", SCM_LIST1 (vm))
631 SCM_DEFINE (scm_vm_this_frame
, "vm-this-frame", 1, 0, 0,
634 #define FUNC_NAME s_scm_vm_this_frame
636 SCM_VALIDATE_VM (1, vm
);
637 return SCM_VM_DATA (vm
)->this_frame
;
641 SCM_DEFINE (scm_vm_last_frame
, "vm-last-frame", 1, 0, 0,
644 #define FUNC_NAME s_scm_vm_last_frame
646 SCM_VALIDATE_VM (1, vm
);
647 return SCM_VM_DATA (vm
)->last_frame
;
651 SCM_DEFINE (scm_vm_last_ip
, "vm:last-ip", 1, 0, 0,
654 #define FUNC_NAME s_scm_vm_last_ip
656 SCM_VALIDATE_VM (1, vm
);
657 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->last_ip
);
661 SCM_DEFINE (scm_vm_save_stack
, "vm-save-stack", 1, 0, 0,
664 #define FUNC_NAME s_scm_vm_save_stack
668 SCM_VALIDATE_VM (1, vm
);
669 vp
= SCM_VM_DATA (vm
);
673 vp
->last_frame
= vm_heapify_frames_1 (vp
, vp
->fp
, vp
->sp
, &dest
);
674 vp
->last_ip
= vp
->ip
;
678 vp
->last_frame
= SCM_BOOL_F
;
682 return vp
->last_frame
;
686 SCM_DEFINE (scm_vm_fetch_code
, "vm-fetch-code", 1, 0, 0,
689 #define FUNC_NAME s_scm_vm_fetch_code
694 struct scm_instruction
*p
;
696 SCM_VALIDATE_VM (1, vm
);
697 VM_CHECK_RUNNING (vm
);
699 ip
= SCM_VM_DATA (vm
)->ip
;
700 p
= SCM_INSTRUCTION (*ip
);
702 list
= SCM_LIST1 (scm_str2symbol (p
->name
));
703 for (i
= 1; i
<= p
->len
; i
++)
704 list
= scm_cons (SCM_I_MAKINUM (ip
[i
]), list
);
705 return scm_reverse_x (list
, SCM_EOL
);
709 SCM_DEFINE (scm_vm_fetch_stack
, "vm-fetch-stack", 1, 0, 0,
712 #define FUNC_NAME s_scm_vm_fetch_stack
718 SCM_VALIDATE_VM (1, vm
);
719 VM_CHECK_RUNNING (vm
);
721 vp
= SCM_VM_DATA (vm
);
722 for (sp
= vp
->stack_base
; sp
<= vp
->sp
; sp
++)
723 ls
= scm_cons (*sp
, ls
);
733 SCM
scm_load_compiled_with_vm (SCM file
)
735 SCM program
= scm_objcode_to_program (scm_load_objcode (file
));
737 return vm_run (scm_the_vm (), program
, SCM_EOL
);
741 scm_bootstrap_vm (void)
743 static int strappage
= 0;
748 scm_bootstrap_frames ();
749 scm_bootstrap_instructions ();
750 scm_bootstrap_objcodes ();
751 scm_bootstrap_programs ();
753 scm_tc16_vm_cont
= scm_make_smob_type ("vm-cont", 0);
754 scm_set_smob_mark (scm_tc16_vm_cont
, vm_cont_mark
);
755 scm_set_smob_free (scm_tc16_vm_cont
, vm_cont_free
);
757 scm_tc16_vm
= scm_make_smob_type ("vm", 0);
758 scm_set_smob_mark (scm_tc16_vm
, vm_mark
);
759 scm_set_smob_free (scm_tc16_vm
, vm_free
);
760 scm_set_smob_apply (scm_tc16_vm
, scm_vm_apply
, 1, 0, 1);
762 scm_the_vm_fluid
= scm_permanent_object (scm_make_fluid ());
763 scm_fluid_set_x (scm_the_vm_fluid
, make_vm ());
764 scm_c_define ("*the-vm*", scm_the_vm_fluid
);
766 scm_c_define ("load-compiled",
767 scm_c_make_gsubr ("load-compiled/vm", 1, 0, 0,
768 scm_load_compiled_with_vm
));
770 sym_vm_run
= scm_permanent_object (scm_from_locale_symbol ("vm-run"));
771 sym_vm_error
= scm_permanent_object (scm_from_locale_symbol ("vm-error"));
772 sym_debug
= scm_permanent_object (scm_from_locale_symbol ("debug"));
782 #ifndef SCM_MAGIC_SNARFER