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. */
48 #include "vm-bootstrap.h"
50 #include "instructions.h"
53 #include "lang.h" /* NULL_OR_NIL_P */
56 /* I sometimes use this for debugging. */
57 #define vm_puts(OBJ) \
59 scm_display (OBJ, scm_current_error_port ()); \
60 scm_newline (scm_current_error_port ()); \
63 /* The VM has a number of internal assertions that shouldn't normally be
64 necessary, but might be if you think you found a bug in the VM. */
65 #define VM_ENABLE_ASSERTIONS
67 /* We can add a mode that ensures that all stack items above the stack pointer
68 are NULL. This is useful for checking the internal consistency of the VM's
69 assumptions and its operators, but isn't necessary for normal operation. It
70 will ensure that assertions are enabled. Slows down the VM by about 30%. */
71 /* NB! If you enable this, search for NULLING in throw.c */
72 /* #define VM_ENABLE_STACK_NULLING */
74 /* #define VM_ENABLE_PARANOID_ASSERTIONS */
76 #if defined (VM_ENABLE_STACK_NULLING) && !defined (VM_ENABLE_ASSERTIONS)
77 #define VM_ENABLE_ASSERTIONS
85 scm_t_bits scm_tc16_vm_cont
;
88 vm_mark_stack (SCM
*base
, scm_t_ptrdiff size
, SCM
*fp
, scm_t_ptrdiff reloc
)
90 SCM
*sp
, *upper
, *lower
;
93 while (sp
> base
&& fp
)
95 upper
= SCM_FRAME_UPPER_ADDRESS (fp
);
96 lower
= SCM_FRAME_LOWER_ADDRESS (fp
);
98 for (; sp
>= upper
; sp
--)
101 if (scm_in_heap_p (*sp
))
104 fprintf (stderr
, "BADNESS: crap on the stack: %p\n", *sp
);
111 /* update fp from the dynamic link */
112 fp
= (SCM
*)*sp
-- + reloc
;
114 /* mark from the el down to the lower address */
115 for (; sp
>= lower
; sp
--)
116 if (*sp
&& SCM_NIMP (*sp
))
122 vm_cont_mark (SCM obj
)
124 struct scm_vm_cont
*p
= SCM_VM_CONT_DATA (obj
);
127 vm_mark_stack (p
->stack_base
, p
->stack_size
, p
->fp
+ p
->reloc
, p
->reloc
);
133 vm_cont_free (SCM obj
)
135 struct scm_vm_cont
*p
= SCM_VM_CONT_DATA (obj
);
137 scm_gc_free (p
->stack_base
, p
->stack_size
* sizeof (SCM
), "stack-base");
138 scm_gc_free (p
, sizeof (struct scm_vm
), "vm");
144 capture_vm_cont (struct scm_vm
*vp
)
146 struct scm_vm_cont
*p
= scm_gc_malloc (sizeof (*p
), "capture_vm_cont");
147 p
->stack_size
= vp
->sp
- vp
->stack_base
+ 1;
148 p
->stack_base
= scm_gc_malloc (p
->stack_size
* sizeof (SCM
),
150 #ifdef VM_ENABLE_STACK_NULLING
151 if (vp
->sp
>= vp
->stack_base
)
152 if (!vp
->sp
[0] || vp
->sp
[1])
154 memset (p
->stack_base
, 0, p
->stack_size
* sizeof (SCM
));
159 memcpy (p
->stack_base
, vp
->stack_base
, p
->stack_size
* sizeof (SCM
));
160 p
->reloc
= p
->stack_base
- vp
->stack_base
;
161 SCM_RETURN_NEWSMOB (scm_tc16_vm_cont
, p
);
165 reinstate_vm_cont (struct scm_vm
*vp
, SCM cont
)
167 struct scm_vm_cont
*p
= SCM_VM_CONT_DATA (cont
);
168 if (vp
->stack_size
< p
->stack_size
)
170 /* puts ("FIXME: Need to expand"); */
173 #ifdef VM_ENABLE_STACK_NULLING
175 scm_t_ptrdiff nzero
= (vp
->sp
- p
->sp
);
177 memset (vp
->stack_base
+ p
->stack_size
, 0, nzero
* sizeof (SCM
));
178 /* actually nzero should always be negative, because vm_reset_stack will
179 unwind the stack to some point *below* this continuation */
185 memcpy (vp
->stack_base
, p
->stack_base
, p
->stack_size
* sizeof (SCM
));
188 /* In theory, a number of vm instances can be active in the call trace, and we
189 only want to reify the continuations of those in the current continuation
190 root. I don't see a nice way to do this -- ideally it would involve dynwinds,
191 and previous values of the *the-vm* fluid within the current continuation
192 root. But we don't have access to continuation roots in the dynwind stack.
193 So, just punt for now -- take the current value of *the-vm*.
195 While I'm on the topic, ideally we could avoid copying the C stack if the
196 continuation root is inside VM code, and call/cc was invoked within that same
197 call to vm_run; but that's currently not implemented.
200 scm_vm_capture_continuations (void)
202 SCM vm
= scm_the_vm ();
203 return scm_acons (vm
, capture_vm_cont (SCM_VM_DATA (vm
)), SCM_EOL
);
207 scm_vm_reinstate_continuations (SCM conts
)
209 for (; conts
!= SCM_EOL
; conts
= SCM_CDR (conts
))
210 reinstate_vm_cont (SCM_VM_DATA (SCM_CAAR (conts
)), SCM_CDAR (conts
));
213 static void enfalsen_frame (void *p
)
215 struct scm_vm
*vp
= p
;
216 vp
->trace_frame
= SCM_BOOL_F
;
220 vm_dispatch_hook (struct scm_vm
*vp
, SCM hook
, SCM hook_args
)
222 if (!SCM_FALSEP (vp
->trace_frame
))
225 scm_dynwind_begin (0);
226 // FIXME, stack holder should be the vm
227 vp
->trace_frame
= scm_c_make_vm_frame (SCM_BOOL_F
, vp
->fp
, vp
->sp
, vp
->ip
, 0);
228 scm_dynwind_unwind_handler (enfalsen_frame
, vp
, SCM_F_WIND_EXPLICITLY
);
230 scm_c_run_hook (hook
, hook_args
);
237 * VM Internal functions
240 static SCM sym_vm_run
;
241 static SCM sym_vm_error
;
242 static SCM sym_debug
;
244 static SCM
make_u8vector (const scm_t_uint8
*bytes
, size_t len
)
246 scm_t_uint8
*new_bytes
= scm_gc_malloc (len
, "make-u8vector");
247 memcpy (new_bytes
, bytes
, len
);
248 return scm_take_u8vector (new_bytes
, len
);
252 really_make_boot_program (long nargs
)
254 scm_byte_t bytes
[] = {0, 0, 0, 0,
257 scm_op_mv_call
, 0, 0, 1, scm_op_make_int8_1
, scm_op_halt
};
259 ((scm_t_uint32
*)bytes
)[1] = 6; /* set len in current endianness, no meta */
260 if (SCM_UNLIKELY (nargs
> 255 || nargs
< 0))
262 bytes
[13] = (scm_byte_t
)nargs
;
263 ret
= scm_make_program (scm_bytecode_to_objcode (make_u8vector (bytes
, sizeof(bytes
))),
264 SCM_BOOL_F
, SCM_EOL
);
265 SCM_SET_SMOB_FLAGS (ret
, SCM_F_PROGRAM_IS_BOOT
);
268 #define NUM_BOOT_PROGS 8
270 vm_make_boot_program (long nargs
)
272 static SCM programs
[NUM_BOOT_PROGS
] = { 0, };
274 if (SCM_UNLIKELY (!programs
[0]))
277 for (i
= 0; i
< NUM_BOOT_PROGS
; i
++)
278 programs
[i
] = scm_permanent_object (really_make_boot_program (i
));
281 if (SCM_LIKELY (nargs
< NUM_BOOT_PROGS
))
282 return programs
[nargs
];
284 return really_make_boot_program (nargs
);
292 #define VM_DEFAULT_STACK_SIZE (16 * 1024)
294 #define VM_NAME vm_regular_engine
295 #define FUNC_NAME "vm-regular-engine"
296 #define VM_ENGINE SCM_VM_REGULAR_ENGINE
297 #include "vm-engine.c"
302 #define VM_NAME vm_debug_engine
303 #define FUNC_NAME "vm-debug-engine"
304 #define VM_ENGINE SCM_VM_DEBUG_ENGINE
305 #include "vm-engine.c"
310 static const scm_t_vm_engine vm_engines
[] =
311 { vm_regular_engine
, vm_debug_engine
};
313 scm_t_bits scm_tc16_vm
;
317 #define FUNC_NAME "make_vm"
322 return SCM_BOOL_F
; /* not booted yet */
324 struct scm_vm
*vp
= scm_gc_malloc (sizeof (struct scm_vm
), "vm");
326 vp
->stack_size
= VM_DEFAULT_STACK_SIZE
;
327 vp
->stack_base
= scm_gc_malloc (vp
->stack_size
* sizeof (SCM
),
329 #ifdef VM_ENABLE_STACK_NULLING
330 memset (vp
->stack_base
, 0, vp
->stack_size
* sizeof (SCM
));
332 vp
->stack_limit
= vp
->stack_base
+ vp
->stack_size
- 3;
334 vp
->sp
= vp
->stack_base
- 1;
336 vp
->engine
= SCM_VM_DEBUG_ENGINE
;
339 vp
->options
= SCM_EOL
;
340 for (i
= 0; i
< SCM_VM_NUM_HOOKS
; i
++)
341 vp
->hooks
[i
] = SCM_BOOL_F
;
342 vp
->trace_frame
= SCM_BOOL_F
;
343 SCM_RETURN_NEWSMOB (scm_tc16_vm
, vp
);
351 struct scm_vm
*vp
= SCM_VM_DATA (obj
);
353 #ifdef VM_ENABLE_STACK_NULLING
354 if (vp
->sp
>= vp
->stack_base
)
355 if (!vp
->sp
[0] || vp
->sp
[1])
359 /* mark the stack, precisely */
360 vm_mark_stack (vp
->stack_base
, vp
->sp
+ 1 - vp
->stack_base
, vp
->fp
, 0);
362 /* mark other objects */
363 for (i
= 0; i
< SCM_VM_NUM_HOOKS
; i
++)
364 scm_gc_mark (vp
->hooks
[i
]);
366 scm_gc_mark (vp
->trace_frame
);
374 struct scm_vm
*vp
= SCM_VM_DATA (obj
);
376 scm_gc_free (vp
->stack_base
, vp
->stack_size
* sizeof (SCM
),
378 scm_gc_free (vp
, sizeof (struct scm_vm
), "vm");
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_EOL
);
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);
649 scm_set_smob_mark (scm_tc16_vm_cont
, vm_cont_mark
);
650 scm_set_smob_free (scm_tc16_vm_cont
, vm_cont_free
);
652 scm_tc16_vm
= scm_make_smob_type ("vm", 0);
653 scm_set_smob_mark (scm_tc16_vm
, vm_mark
);
654 scm_set_smob_free (scm_tc16_vm
, vm_free
);
655 scm_set_smob_apply (scm_tc16_vm
, scm_vm_apply
, 1, 0, 1);
657 scm_c_define ("load-compiled",
658 scm_c_make_gsubr ("load-compiled/vm", 1, 0, 0,
659 scm_load_compiled_with_vm
));
661 sym_vm_run
= scm_permanent_object (scm_from_locale_symbol ("vm-run"));
662 sym_vm_error
= scm_permanent_object (scm_from_locale_symbol ("vm-error"));
663 sym_debug
= scm_permanent_object (scm_from_locale_symbol ("debug"));
673 #ifndef SCM_MAGIC_SNARFER