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 if (vp
->sp
>= vp
->stack_base
)
159 if (!vp
->sp
[0] || vp
->sp
[1])
161 memset (p
->stack_base
, 0, p
->stack_size
* sizeof (SCM
));
164 p
->sp
= vp
->sp
- vp
->stack_base
;
165 p
->fp
= vp
->fp
- vp
->stack_base
;
166 memcpy (p
->stack_base
, vp
->stack_base
, p
->stack_size
* sizeof (SCM
));
167 p
->reloc
= p
->stack_base
- vp
->stack_base
;
168 SCM_RETURN_NEWSMOB (scm_tc16_vm_cont
, p
);
172 reinstate_vm_cont (struct scm_vm
*vp
, SCM cont
)
174 struct scm_vm_cont
*p
= SCM_VM_CONT_DATA (cont
);
175 if (vp
->stack_size
< p
->stack_size
)
177 /* puts ("FIXME: Need to expand"); */
180 #ifdef VM_ENABLE_STACK_NULLING
182 scm_t_ptrdiff nzero
= (vp
->sp
- vp
->stack_base
) - p
->sp
;
184 memset (vp
->stack_base
+ p
->stack_size
, 0, nzero
* sizeof (SCM
));
185 /* actually nzero should always be negative, because vm_reset_stack will
186 unwind the stack to some point *below* this continuation */
190 vp
->sp
= vp
->stack_base
+ p
->sp
;
191 vp
->fp
= vp
->stack_base
+ p
->fp
;
192 memcpy (vp
->stack_base
, p
->stack_base
, p
->stack_size
* sizeof (SCM
));
195 /* In theory, a number of vm instances can be active in the call trace, and we
196 only want to reify the continuations of those in the current continuation
197 root. I don't see a nice way to do this -- ideally it would involve dynwinds,
198 and previous values of the *the-vm* fluid within the current continuation
199 root. But we don't have access to continuation roots in the dynwind stack.
200 So, just punt for now -- take the current value of *the-vm*.
202 While I'm on the topic, ideally we could avoid copying the C stack if the
203 continuation root is inside VM code, and call/cc was invoked within that same
204 call to vm_run; but that's currently not implemented.
207 scm_vm_capture_continuations (void)
209 SCM vm
= scm_the_vm ();
210 return scm_acons (vm
, capture_vm_cont (SCM_VM_DATA (vm
)), SCM_EOL
);
214 scm_vm_reinstate_continuations (SCM conts
)
216 for (; conts
!= SCM_EOL
; conts
= SCM_CDR (conts
))
217 reinstate_vm_cont (SCM_VM_DATA (SCM_CAAR (conts
)), SCM_CDAR (conts
));
220 struct vm_unwind_data
229 vm_reset_stack (void *data
)
231 struct vm_unwind_data
*w
= data
;
232 struct scm_vm
*vp
= w
->vp
;
236 vp
->this_frame
= w
->this_frame
;
237 #ifdef VM_ENABLE_STACK_NULLING
238 memset (vp
->sp
+ 1, 0, (vp
->stack_size
- (vp
->sp
+ 1 - vp
->stack_base
)) * sizeof(SCM
));
244 * VM Internal functions
247 static SCM sym_vm_run
;
248 static SCM sym_vm_error
;
249 static SCM sym_debug
;
252 vm_fetch_length (scm_byte_t
*ip
, size_t *lenp
)
254 /* NOTE: format defined in system/vm/conv.scm */
258 else if (*lenp
== 254)
262 *lenp
= (b1
<< 8) + b2
;
270 *lenp
= (b1
<< 24) + (b2
<< 16) + (b3
<< 8) + b4
;
276 vm_heapify_frames_1 (struct scm_vm
*vp
, SCM
*fp
, SCM
*sp
, SCM
**destp
)
279 SCM
*dl
= SCM_FRAME_DYNAMIC_LINK (fp
);
281 SCM
*src
= SCM_FRAME_UPPER_ADDRESS (fp
);
283 SCM
*dest
= SCM_FRAME_LOWER_ADDRESS (fp
);
288 frame
= scm_c_make_heap_frame (fp
);
289 fp
= SCM_HEAP_FRAME_POINTER (frame
);
290 SCM_FRAME_HEAP_LINK (fp
) = SCM_BOOL_T
;
295 SCM link
= SCM_FRAME_HEAP_LINK (dl
);
296 if (!SCM_FALSEP (link
))
297 link
= SCM_FRAME_LOWER_ADDRESS (dl
)[-1]; /* self link */
299 link
= vm_heapify_frames_1 (vp
, dl
, dest
- 1, &dest
);
300 frame
= scm_c_make_heap_frame (fp
);
301 fp
= SCM_HEAP_FRAME_POINTER (frame
);
302 /* FIXME: I don't think we should be storing heap links on the stack. */
303 SCM_FRAME_HEAP_LINK (fp
) = link
;
304 SCM_FRAME_SET_DYNAMIC_LINK (fp
, SCM_HEAP_FRAME_POINTER (link
));
307 /* Apparently the intention here is to be able to have a frame on the heap,
308 but data on the stack, so that you can push as much as you want on the
309 stack; but I think that it's currently causing borkage with nonlocal exits
310 and the unwind handler, which reinstates the sp and fp, but it's no longer
311 pointing at a valid stack frame. So disable for now, we'll get back to
314 /* Move stack data */
315 for (; src
<= sp
; src
++, dest
++)
324 vm_heapify_frames (SCM vm
)
326 struct scm_vm
*vp
= SCM_VM_DATA (vm
);
327 if (SCM_FALSEP (SCM_FRAME_HEAP_LINK (vp
->fp
)))
330 vp
->this_frame
= vm_heapify_frames_1 (vp
, vp
->fp
, vp
->sp
, &dest
);
331 vp
->fp
= SCM_HEAP_FRAME_POINTER (vp
->this_frame
);
334 return vp
->this_frame
;
342 #define VM_DEFAULT_STACK_SIZE (16 * 1024)
344 #define VM_REGULAR_ENGINE 0
345 #define VM_DEBUG_ENGINE 1
348 #define VM_NAME vm_regular_engine
349 #define VM_ENGINE VM_REGULAR_ENGINE
350 #include "vm-engine.c"
355 #define VM_NAME vm_debug_engine
356 #define VM_ENGINE VM_DEBUG_ENGINE
357 #include "vm-engine.c"
361 scm_t_bits scm_tc16_vm
;
363 SCM scm_the_vm_fluid
;
367 #define FUNC_NAME "make_vm"
370 struct scm_vm
*vp
= scm_gc_malloc (sizeof (struct scm_vm
), "vm");
372 vp
->stack_size
= VM_DEFAULT_STACK_SIZE
;
373 vp
->stack_base
= scm_gc_malloc (vp
->stack_size
* sizeof (SCM
),
375 vp
->stack_limit
= vp
->stack_base
+ vp
->stack_size
- 3;
377 vp
->sp
= vp
->stack_base
- 1;
381 vp
->options
= SCM_EOL
;
382 vp
->this_frame
= SCM_BOOL_F
;
383 vp
->last_frame
= SCM_BOOL_F
;
385 for (i
= 0; i
< SCM_VM_NUM_HOOKS
; i
++)
386 vp
->hooks
[i
] = SCM_BOOL_F
;
387 SCM_RETURN_NEWSMOB (scm_tc16_vm
, vp
);
395 struct scm_vm
*vp
= SCM_VM_DATA (obj
);
397 #ifdef VM_ENABLE_STACK_NULLING
398 if (vp
->sp
>= vp
->stack_base
)
399 if (!vp
->sp
[0] || vp
->sp
[1])
403 /* mark the stack, precisely */
404 vm_mark_stack (vp
->stack_base
, vp
->sp
+ 1 - vp
->stack_base
, vp
->fp
, 0);
406 /* mark other objects */
407 for (i
= 0; i
< SCM_VM_NUM_HOOKS
; i
++)
408 scm_gc_mark (vp
->hooks
[i
]);
409 scm_gc_mark (vp
->this_frame
);
410 scm_gc_mark (vp
->last_frame
);
417 struct scm_vm
*vp
= SCM_VM_DATA (obj
);
419 scm_gc_free (vp
->stack_base
, vp
->stack_size
* sizeof (SCM
),
421 scm_gc_free (vp
, sizeof (struct scm_vm
), "vm");
427 scm_vm_apply (SCM vm
, SCM program
, SCM args
)
428 #define FUNC_NAME "scm_vm_apply"
430 SCM_VALIDATE_PROGRAM (1, program
);
431 return vm_run (vm
, program
, args
);
435 /* Scheme interface */
437 SCM_DEFINE (scm_vm_version
, "vm-version", 0, 0, 0,
440 #define FUNC_NAME s_scm_vm_version
442 return scm_from_locale_string (PACKAGE_VERSION
);
446 SCM_DEFINE (scm_the_vm
, "the-vm", 0, 0, 0,
449 #define FUNC_NAME s_scm_the_vm
453 if (SCM_NFALSEP ((ret
= scm_fluid_ref (scm_the_vm_fluid
))))
457 scm_fluid_set_x (scm_the_vm_fluid
, ret
);
463 SCM_DEFINE (scm_vm_p
, "vm?", 1, 0, 0,
466 #define FUNC_NAME s_scm_vm_p
468 return SCM_BOOL (SCM_VM_P (obj
));
472 SCM_DEFINE (scm_make_vm
, "make-vm", 0, 0, 0,
475 #define FUNC_NAME s_scm_make_vm,
481 SCM_DEFINE (scm_vm_ip
, "vm:ip", 1, 0, 0,
484 #define FUNC_NAME s_scm_vm_ip
486 SCM_VALIDATE_VM (1, vm
);
487 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->ip
);
491 SCM_DEFINE (scm_vm_sp
, "vm:sp", 1, 0, 0,
494 #define FUNC_NAME s_scm_vm_sp
496 SCM_VALIDATE_VM (1, vm
);
497 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->sp
);
501 SCM_DEFINE (scm_vm_fp
, "vm:fp", 1, 0, 0,
504 #define FUNC_NAME s_scm_vm_fp
506 SCM_VALIDATE_VM (1, vm
);
507 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->fp
);
511 #define VM_DEFINE_HOOK(n) \
514 SCM_VALIDATE_VM (1, vm); \
515 vp = SCM_VM_DATA (vm); \
516 if (SCM_FALSEP (vp->hooks[n])) \
517 vp->hooks[n] = scm_make_hook (SCM_I_MAKINUM (1)); \
518 return vp->hooks[n]; \
521 SCM_DEFINE (scm_vm_boot_hook
, "vm-boot-hook", 1, 0, 0,
524 #define FUNC_NAME s_scm_vm_boot_hook
526 VM_DEFINE_HOOK (SCM_VM_BOOT_HOOK
);
530 SCM_DEFINE (scm_vm_halt_hook
, "vm-halt-hook", 1, 0, 0,
533 #define FUNC_NAME s_scm_vm_halt_hook
535 VM_DEFINE_HOOK (SCM_VM_HALT_HOOK
);
539 SCM_DEFINE (scm_vm_next_hook
, "vm-next-hook", 1, 0, 0,
542 #define FUNC_NAME s_scm_vm_next_hook
544 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK
);
548 SCM_DEFINE (scm_vm_break_hook
, "vm-break-hook", 1, 0, 0,
551 #define FUNC_NAME s_scm_vm_break_hook
553 VM_DEFINE_HOOK (SCM_VM_BREAK_HOOK
);
557 SCM_DEFINE (scm_vm_enter_hook
, "vm-enter-hook", 1, 0, 0,
560 #define FUNC_NAME s_scm_vm_enter_hook
562 VM_DEFINE_HOOK (SCM_VM_ENTER_HOOK
);
566 SCM_DEFINE (scm_vm_apply_hook
, "vm-apply-hook", 1, 0, 0,
569 #define FUNC_NAME s_scm_vm_apply_hook
571 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK
);
575 SCM_DEFINE (scm_vm_exit_hook
, "vm-exit-hook", 1, 0, 0,
578 #define FUNC_NAME s_scm_vm_exit_hook
580 VM_DEFINE_HOOK (SCM_VM_EXIT_HOOK
);
584 SCM_DEFINE (scm_vm_return_hook
, "vm-return-hook", 1, 0, 0,
587 #define FUNC_NAME s_scm_vm_return_hook
589 VM_DEFINE_HOOK (SCM_VM_RETURN_HOOK
);
593 SCM_DEFINE (scm_vm_option
, "vm-option", 2, 0, 0,
596 #define FUNC_NAME s_scm_vm_option
598 SCM_VALIDATE_VM (1, vm
);
599 return scm_assq_ref (SCM_VM_DATA (vm
)->options
, key
);
603 SCM_DEFINE (scm_set_vm_option_x
, "set-vm-option!", 3, 0, 0,
604 (SCM vm
, SCM key
, SCM val
),
606 #define FUNC_NAME s_scm_set_vm_option_x
608 SCM_VALIDATE_VM (1, vm
);
609 SCM_VM_DATA (vm
)->options
610 = scm_assq_set_x (SCM_VM_DATA (vm
)->options
, key
, val
);
611 return SCM_UNSPECIFIED
;
615 SCM_DEFINE (scm_vm_stats
, "vm-stats", 1, 0, 0,
618 #define FUNC_NAME s_scm_vm_stats
622 SCM_VALIDATE_VM (1, vm
);
624 stats
= scm_make_vector (SCM_I_MAKINUM (2), SCM_UNSPECIFIED
);
625 scm_vector_set_x (stats
, SCM_I_MAKINUM (0),
626 scm_from_ulong (SCM_VM_DATA (vm
)->time
));
627 scm_vector_set_x (stats
, SCM_I_MAKINUM (1),
628 scm_from_ulong (SCM_VM_DATA (vm
)->clock
));
634 #define VM_CHECK_RUNNING(vm) \
635 if (!SCM_VM_DATA (vm)->ip) \
636 SCM_MISC_ERROR ("Not running", SCM_LIST1 (vm))
638 SCM_DEFINE (scm_vm_this_frame
, "vm-this-frame", 1, 0, 0,
641 #define FUNC_NAME s_scm_vm_this_frame
643 SCM_VALIDATE_VM (1, vm
);
644 return SCM_VM_DATA (vm
)->this_frame
;
648 SCM_DEFINE (scm_vm_last_frame
, "vm-last-frame", 1, 0, 0,
651 #define FUNC_NAME s_scm_vm_last_frame
653 SCM_VALIDATE_VM (1, vm
);
654 return SCM_VM_DATA (vm
)->last_frame
;
658 SCM_DEFINE (scm_vm_last_ip
, "vm:last-ip", 1, 0, 0,
661 #define FUNC_NAME s_scm_vm_last_ip
663 SCM_VALIDATE_VM (1, vm
);
664 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->last_ip
);
668 SCM_DEFINE (scm_vm_save_stack
, "vm-save-stack", 1, 0, 0,
671 #define FUNC_NAME s_scm_vm_save_stack
675 SCM_VALIDATE_VM (1, vm
);
676 vp
= SCM_VM_DATA (vm
);
680 #ifdef VM_ENABLE_STACK_NULLING
681 if (vp
->sp
>= vp
->stack_base
)
682 if (!vp
->sp
[0] || vp
->sp
[1])
685 vp
->last_frame
= vm_heapify_frames_1 (vp
, vp
->fp
, vp
->sp
, &dest
);
686 vp
->last_ip
= vp
->ip
;
690 vp
->last_frame
= SCM_BOOL_F
;
694 return vp
->last_frame
;
698 SCM_DEFINE (scm_vm_fetch_code
, "vm-fetch-code", 1, 0, 0,
701 #define FUNC_NAME s_scm_vm_fetch_code
706 struct scm_instruction
*p
;
708 SCM_VALIDATE_VM (1, vm
);
709 VM_CHECK_RUNNING (vm
);
711 ip
= SCM_VM_DATA (vm
)->ip
;
712 p
= SCM_INSTRUCTION (*ip
);
714 list
= SCM_LIST1 (scm_str2symbol (p
->name
));
715 for (i
= 1; i
<= p
->len
; i
++)
716 list
= scm_cons (SCM_I_MAKINUM (ip
[i
]), list
);
717 return scm_reverse_x (list
, SCM_EOL
);
721 SCM_DEFINE (scm_vm_fetch_stack
, "vm-fetch-stack", 1, 0, 0,
724 #define FUNC_NAME s_scm_vm_fetch_stack
730 SCM_VALIDATE_VM (1, vm
);
731 VM_CHECK_RUNNING (vm
);
733 vp
= SCM_VM_DATA (vm
);
734 for (sp
= vp
->stack_base
; sp
<= vp
->sp
; sp
++)
735 ls
= scm_cons (*sp
, ls
);
745 SCM
scm_load_compiled_with_vm (SCM file
)
747 SCM program
= scm_objcode_to_program (scm_load_objcode (file
));
749 return vm_run (scm_the_vm (), program
, SCM_EOL
);
753 scm_bootstrap_vm (void)
755 static int strappage
= 0;
760 scm_bootstrap_frames ();
761 scm_bootstrap_instructions ();
762 scm_bootstrap_objcodes ();
763 scm_bootstrap_programs ();
765 scm_tc16_vm_cont
= scm_make_smob_type ("vm-cont", 0);
766 scm_set_smob_mark (scm_tc16_vm_cont
, vm_cont_mark
);
767 scm_set_smob_free (scm_tc16_vm_cont
, vm_cont_free
);
769 scm_tc16_vm
= scm_make_smob_type ("vm", 0);
770 scm_set_smob_mark (scm_tc16_vm
, vm_mark
);
771 scm_set_smob_free (scm_tc16_vm
, vm_free
);
772 scm_set_smob_apply (scm_tc16_vm
, scm_vm_apply
, 1, 0, 1);
774 scm_the_vm_fluid
= scm_permanent_object (scm_make_fluid ());
775 scm_fluid_set_x (scm_the_vm_fluid
, make_vm ());
776 scm_c_define ("*the-vm*", scm_the_vm_fluid
);
778 scm_c_define ("load-compiled",
779 scm_c_make_gsubr ("load-compiled/vm", 1, 0, 0,
780 scm_load_compiled_with_vm
));
782 sym_vm_run
= scm_permanent_object (scm_from_locale_symbol ("vm-run"));
783 sym_vm_error
= scm_permanent_object (scm_from_locale_symbol ("vm-error"));
784 sym_debug
= scm_permanent_object (scm_from_locale_symbol ("debug"));
794 #ifndef SCM_MAGIC_SNARFER