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 ()); \
66 scm_t_bits scm_tc16_vm_cont
;
72 scm_t_ptrdiff stack_size
;
77 #define SCM_VM_CONT_P(OBJ) SCM_SMOB_PREDICATE (scm_tc16_vm_cont, OBJ)
78 #define SCM_VM_CONT_DATA(CONT) ((struct scm_vm_cont *) SCM_CELL_WORD_1 (CONT))
81 vm_cont_mark (SCM obj
)
83 scm_t_ptrdiff i
, size
;
86 stack
= SCM_VM_CONT_DATA (obj
)->stack_base
;
87 size
= SCM_VM_CONT_DATA (obj
)->stack_size
;
89 /* we could be smarter about this. */
90 for (i
= 0; i
< size
; i
++)
91 if (SCM_NIMP (stack
[i
]))
92 scm_gc_mark (stack
[i
]);
98 vm_cont_free (SCM obj
)
100 struct scm_vm_cont
*p
= SCM_VM_CONT_DATA (obj
);
102 scm_gc_free (p
->stack_base
, p
->stack_size
* sizeof (SCM
), "stack-base");
103 scm_gc_free (p
, sizeof (struct scm_vm
), "vm");
109 capture_vm_cont (struct scm_vm
*vp
)
111 struct scm_vm_cont
*p
= scm_gc_malloc (sizeof (*p
), "capture_vm_cont");
112 p
->stack_size
= vp
->sp
- vp
->stack_base
+ 1;
113 p
->stack_base
= scm_gc_malloc (p
->stack_size
* sizeof (SCM
),
116 p
->sp
= vp
->sp
- vp
->stack_base
;
117 p
->fp
= vp
->fp
- vp
->stack_base
;
118 memcpy (p
->stack_base
, vp
->stack_base
, p
->stack_size
* sizeof (SCM
));
119 SCM_RETURN_NEWSMOB (scm_tc16_vm_cont
, p
);
123 reinstate_vm_cont (struct scm_vm
*vp
, SCM cont
)
125 struct scm_vm_cont
*p
= SCM_VM_CONT_DATA (cont
);
126 if (vp
->stack_size
< p
->stack_size
)
128 /* puts ("FIXME: Need to expand"); */
132 vp
->sp
= vp
->stack_base
+ p
->sp
;
133 vp
->fp
= vp
->stack_base
+ p
->fp
;
134 memcpy (vp
->stack_base
, p
->stack_base
, p
->stack_size
* sizeof (SCM
));
137 /* In theory, a number of vm instances can be active in the call trace, and we
138 only want to reify the continuations of those in the current continuation
139 root. I don't see a nice way to do this -- ideally it would involve dynwinds,
140 and previous values of the *the-vm* fluid within the current continuation
141 root. But we don't have access to continuation roots in the dynwind stack.
142 So, just punt for now -- take the current value of *the-vm*.
144 While I'm on the topic, ideally we could avoid copying the C stack if the
145 continuation root is inside VM code, and call/cc was invoked within that same
146 call to vm_run; but that's currently not implemented.
149 scm_vm_capture_continuations (void)
151 SCM vm
= scm_the_vm ();
152 return scm_acons (vm
, capture_vm_cont (SCM_VM_DATA (vm
)), SCM_EOL
);
156 scm_vm_reinstate_continuations (SCM conts
)
158 for (; conts
!= SCM_EOL
; conts
= SCM_CDR (conts
))
159 reinstate_vm_cont (SCM_VM_DATA (SCM_CAAR (conts
)), SCM_CDAR (conts
));
162 struct vm_unwind_data
171 vm_reset_stack (void *data
)
173 struct vm_unwind_data
*w
= data
;
177 w
->vp
->this_frame
= w
->this_frame
;
182 * VM Internal functions
185 static SCM sym_vm_run
;
186 static SCM sym_vm_error
;
187 static SCM sym_debug
;
190 vm_fetch_length (scm_byte_t
*ip
, size_t *lenp
)
192 /* NOTE: format defined in system/vm/conv.scm */
196 else if (*lenp
== 254)
200 *lenp
= (b1
<< 8) + b2
;
208 *lenp
= (b1
<< 24) + (b2
<< 16) + (b3
<< 8) + b4
;
214 vm_heapify_frames_1 (struct scm_vm
*vp
, SCM
*fp
, SCM
*sp
, SCM
**destp
)
217 SCM
*dl
= SCM_FRAME_DYNAMIC_LINK (fp
);
219 SCM
*src
= SCM_FRAME_UPPER_ADDRESS (fp
);
221 SCM
*dest
= SCM_FRAME_LOWER_ADDRESS (fp
);
226 frame
= scm_c_make_heap_frame (fp
);
227 fp
= SCM_HEAP_FRAME_POINTER (frame
);
228 SCM_FRAME_HEAP_LINK (fp
) = SCM_BOOL_T
;
233 SCM link
= SCM_FRAME_HEAP_LINK (dl
);
234 if (!SCM_FALSEP (link
))
235 link
= SCM_FRAME_LOWER_ADDRESS (dl
)[-1]; /* self link */
237 link
= vm_heapify_frames_1 (vp
, dl
, dest
- 1, &dest
);
238 frame
= scm_c_make_heap_frame (fp
);
239 fp
= SCM_HEAP_FRAME_POINTER (frame
);
240 SCM_FRAME_HEAP_LINK (fp
) = link
;
241 SCM_FRAME_SET_DYNAMIC_LINK (fp
, SCM_HEAP_FRAME_POINTER (link
));
244 /* Apparently the intention here is to be able to have a frame on the heap,
245 but data on the stack, so that you can push as much as you want on the
246 stack; but I think that it's currently causing borkage with nonlocal exits
247 and the unwind handler, which reinstates the sp and fp, but it's no longer
248 pointing at a valid stack frame. So disable for now, we'll get back to
251 /* Move stack data */
252 for (; src
<= sp
; src
++, dest
++)
261 vm_heapify_frames (SCM vm
)
263 struct scm_vm
*vp
= SCM_VM_DATA (vm
);
264 if (SCM_FALSEP (SCM_FRAME_HEAP_LINK (vp
->fp
)))
267 vp
->this_frame
= vm_heapify_frames_1 (vp
, vp
->fp
, vp
->sp
, &dest
);
268 vp
->fp
= SCM_HEAP_FRAME_POINTER (vp
->this_frame
);
271 return vp
->this_frame
;
279 #define VM_DEFAULT_STACK_SIZE (16 * 1024)
281 #define VM_REGULAR_ENGINE 0
282 #define VM_DEBUG_ENGINE 1
285 #define VM_NAME vm_regular_engine
286 #define VM_ENGINE VM_REGULAR_ENGINE
287 #include "vm-engine.c"
292 #define VM_NAME vm_debug_engine
293 #define VM_ENGINE VM_DEBUG_ENGINE
294 #include "vm-engine.c"
298 scm_t_bits scm_tc16_vm
;
300 SCM scm_the_vm_fluid
;
304 #define FUNC_NAME "make_vm"
307 struct scm_vm
*vp
= scm_gc_malloc (sizeof (struct scm_vm
), "vm");
309 vp
->stack_size
= VM_DEFAULT_STACK_SIZE
;
310 vp
->stack_base
= scm_gc_malloc (vp
->stack_size
* sizeof (SCM
),
312 vp
->stack_limit
= vp
->stack_base
+ vp
->stack_size
- 3;
314 vp
->sp
= vp
->stack_base
- 1;
318 vp
->options
= SCM_EOL
;
319 vp
->this_frame
= SCM_BOOL_F
;
320 vp
->last_frame
= SCM_BOOL_F
;
322 for (i
= 0; i
< SCM_VM_NUM_HOOKS
; i
++)
323 vp
->hooks
[i
] = SCM_BOOL_F
;
324 SCM_RETURN_NEWSMOB (scm_tc16_vm
, vp
);
332 struct scm_vm
*vp
= SCM_VM_DATA (obj
);
334 /* mark the stack conservatively */
335 scm_mark_locations ((SCM_STACKITEM
*) vp
->stack_base
,
336 sizeof (SCM
) * (vp
->sp
- vp
->stack_base
+ 1));
338 /* mark other objects */
339 for (i
= 0; i
< SCM_VM_NUM_HOOKS
; i
++)
340 scm_gc_mark (vp
->hooks
[i
]);
341 scm_gc_mark (vp
->this_frame
);
342 scm_gc_mark (vp
->last_frame
);
349 struct scm_vm
*vp
= SCM_VM_DATA (obj
);
351 scm_gc_free (vp
->stack_base
, vp
->stack_size
* sizeof (SCM
),
353 scm_gc_free (vp
, sizeof (struct scm_vm
), "vm");
359 scm_vm_apply (SCM vm
, SCM program
, SCM args
)
360 #define FUNC_NAME "scm_vm_apply"
362 SCM_VALIDATE_PROGRAM (1, program
);
363 return vm_run (vm
, program
, args
);
367 /* Scheme interface */
369 SCM_DEFINE (scm_vm_version
, "vm-version", 0, 0, 0,
372 #define FUNC_NAME s_scm_vm_version
374 return scm_from_locale_string (PACKAGE_VERSION
);
378 SCM_DEFINE (scm_the_vm
, "the-vm", 0, 0, 0,
381 #define FUNC_NAME s_scm_the_vm
385 if (SCM_NFALSEP ((ret
= scm_fluid_ref (scm_the_vm_fluid
))))
389 scm_fluid_set_x (scm_the_vm_fluid
, ret
);
395 SCM_DEFINE (scm_vm_p
, "vm?", 1, 0, 0,
398 #define FUNC_NAME s_scm_vm_p
400 return SCM_BOOL (SCM_VM_P (obj
));
404 SCM_DEFINE (scm_make_vm
, "make-vm", 0, 0, 0,
407 #define FUNC_NAME s_scm_make_vm,
413 SCM_DEFINE (scm_vm_ip
, "vm:ip", 1, 0, 0,
416 #define FUNC_NAME s_scm_vm_ip
418 SCM_VALIDATE_VM (1, vm
);
419 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->ip
);
423 SCM_DEFINE (scm_vm_sp
, "vm:sp", 1, 0, 0,
426 #define FUNC_NAME s_scm_vm_sp
428 SCM_VALIDATE_VM (1, vm
);
429 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->sp
);
433 SCM_DEFINE (scm_vm_fp
, "vm:fp", 1, 0, 0,
436 #define FUNC_NAME s_scm_vm_fp
438 SCM_VALIDATE_VM (1, vm
);
439 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->fp
);
443 #define VM_DEFINE_HOOK(n) \
446 SCM_VALIDATE_VM (1, vm); \
447 vp = SCM_VM_DATA (vm); \
448 if (SCM_FALSEP (vp->hooks[n])) \
449 vp->hooks[n] = scm_make_hook (SCM_I_MAKINUM (1)); \
450 return vp->hooks[n]; \
453 SCM_DEFINE (scm_vm_boot_hook
, "vm-boot-hook", 1, 0, 0,
456 #define FUNC_NAME s_scm_vm_boot_hook
458 VM_DEFINE_HOOK (SCM_VM_BOOT_HOOK
);
462 SCM_DEFINE (scm_vm_halt_hook
, "vm-halt-hook", 1, 0, 0,
465 #define FUNC_NAME s_scm_vm_halt_hook
467 VM_DEFINE_HOOK (SCM_VM_HALT_HOOK
);
471 SCM_DEFINE (scm_vm_next_hook
, "vm-next-hook", 1, 0, 0,
474 #define FUNC_NAME s_scm_vm_next_hook
476 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK
);
480 SCM_DEFINE (scm_vm_break_hook
, "vm-break-hook", 1, 0, 0,
483 #define FUNC_NAME s_scm_vm_break_hook
485 VM_DEFINE_HOOK (SCM_VM_BREAK_HOOK
);
489 SCM_DEFINE (scm_vm_enter_hook
, "vm-enter-hook", 1, 0, 0,
492 #define FUNC_NAME s_scm_vm_enter_hook
494 VM_DEFINE_HOOK (SCM_VM_ENTER_HOOK
);
498 SCM_DEFINE (scm_vm_apply_hook
, "vm-apply-hook", 1, 0, 0,
501 #define FUNC_NAME s_scm_vm_apply_hook
503 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK
);
507 SCM_DEFINE (scm_vm_exit_hook
, "vm-exit-hook", 1, 0, 0,
510 #define FUNC_NAME s_scm_vm_exit_hook
512 VM_DEFINE_HOOK (SCM_VM_EXIT_HOOK
);
516 SCM_DEFINE (scm_vm_return_hook
, "vm-return-hook", 1, 0, 0,
519 #define FUNC_NAME s_scm_vm_return_hook
521 VM_DEFINE_HOOK (SCM_VM_RETURN_HOOK
);
525 SCM_DEFINE (scm_vm_option
, "vm-option", 2, 0, 0,
528 #define FUNC_NAME s_scm_vm_option
530 SCM_VALIDATE_VM (1, vm
);
531 return scm_assq_ref (SCM_VM_DATA (vm
)->options
, key
);
535 SCM_DEFINE (scm_set_vm_option_x
, "set-vm-option!", 3, 0, 0,
536 (SCM vm
, SCM key
, SCM val
),
538 #define FUNC_NAME s_scm_set_vm_option_x
540 SCM_VALIDATE_VM (1, vm
);
541 SCM_VM_DATA (vm
)->options
542 = scm_assq_set_x (SCM_VM_DATA (vm
)->options
, key
, val
);
543 return SCM_UNSPECIFIED
;
547 SCM_DEFINE (scm_vm_stats
, "vm-stats", 1, 0, 0,
550 #define FUNC_NAME s_scm_vm_stats
554 SCM_VALIDATE_VM (1, vm
);
556 stats
= scm_make_vector (SCM_I_MAKINUM (2), SCM_UNSPECIFIED
);
557 scm_vector_set_x (stats
, SCM_I_MAKINUM (0),
558 scm_from_ulong (SCM_VM_DATA (vm
)->time
));
559 scm_vector_set_x (stats
, SCM_I_MAKINUM (1),
560 scm_from_ulong (SCM_VM_DATA (vm
)->clock
));
566 #define VM_CHECK_RUNNING(vm) \
567 if (!SCM_VM_DATA (vm)->ip) \
568 SCM_MISC_ERROR ("Not running", SCM_LIST1 (vm))
570 SCM_DEFINE (scm_vm_this_frame
, "vm-this-frame", 1, 0, 0,
573 #define FUNC_NAME s_scm_vm_this_frame
575 SCM_VALIDATE_VM (1, vm
);
576 return SCM_VM_DATA (vm
)->this_frame
;
580 SCM_DEFINE (scm_vm_last_frame
, "vm-last-frame", 1, 0, 0,
583 #define FUNC_NAME s_scm_vm_last_frame
585 SCM_VALIDATE_VM (1, vm
);
586 return SCM_VM_DATA (vm
)->last_frame
;
590 SCM_DEFINE (scm_vm_last_ip
, "vm:last-ip", 1, 0, 0,
593 #define FUNC_NAME s_scm_vm_last_ip
595 SCM_VALIDATE_VM (1, vm
);
596 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm
)->last_ip
);
600 SCM_DEFINE (scm_vm_save_stack
, "vm-save-stack", 1, 0, 0,
603 #define FUNC_NAME s_scm_vm_save_stack
607 SCM_VALIDATE_VM (1, vm
);
608 vp
= SCM_VM_DATA (vm
);
612 vp
->last_frame
= vm_heapify_frames_1 (vp
, vp
->fp
, vp
->sp
, &dest
);
613 vp
->last_ip
= vp
->ip
;
617 vp
->last_frame
= SCM_BOOL_F
;
621 return vp
->last_frame
;
625 SCM_DEFINE (scm_vm_fetch_code
, "vm-fetch-code", 1, 0, 0,
628 #define FUNC_NAME s_scm_vm_fetch_code
633 struct scm_instruction
*p
;
635 SCM_VALIDATE_VM (1, vm
);
636 VM_CHECK_RUNNING (vm
);
638 ip
= SCM_VM_DATA (vm
)->ip
;
639 p
= SCM_INSTRUCTION (*ip
);
641 list
= SCM_LIST1 (scm_str2symbol (p
->name
));
642 for (i
= 1; i
<= p
->len
; i
++)
643 list
= scm_cons (SCM_I_MAKINUM (ip
[i
]), list
);
644 return scm_reverse_x (list
, SCM_EOL
);
648 SCM_DEFINE (scm_vm_fetch_stack
, "vm-fetch-stack", 1, 0, 0,
651 #define FUNC_NAME s_scm_vm_fetch_stack
657 SCM_VALIDATE_VM (1, vm
);
658 VM_CHECK_RUNNING (vm
);
660 vp
= SCM_VM_DATA (vm
);
661 for (sp
= vp
->stack_base
; sp
<= vp
->sp
; sp
++)
662 ls
= scm_cons (*sp
, ls
);
672 SCM
scm_load_compiled_with_vm (SCM file
)
674 SCM program
= scm_objcode_to_program (scm_load_objcode (file
));
676 return vm_run (scm_the_vm (), program
, SCM_EOL
);
680 scm_bootstrap_vm (void)
682 static int strappage
= 0;
687 scm_bootstrap_frames ();
688 scm_bootstrap_instructions ();
689 scm_bootstrap_objcodes ();
690 scm_bootstrap_programs ();
692 scm_tc16_vm_cont
= scm_make_smob_type ("vm-cont", 0);
693 scm_set_smob_mark (scm_tc16_vm_cont
, vm_cont_mark
);
694 scm_set_smob_free (scm_tc16_vm_cont
, vm_cont_free
);
696 scm_tc16_vm
= scm_make_smob_type ("vm", 0);
697 scm_set_smob_mark (scm_tc16_vm
, vm_mark
);
698 scm_set_smob_free (scm_tc16_vm
, vm_free
);
699 scm_set_smob_apply (scm_tc16_vm
, scm_vm_apply
, 1, 0, 1);
701 scm_the_vm_fluid
= scm_permanent_object (scm_make_fluid ());
702 scm_fluid_set_x (scm_the_vm_fluid
, make_vm ());
703 scm_c_define ("*the-vm*", scm_the_vm_fluid
);
705 scm_c_define ("load-compiled",
706 scm_c_make_gsubr ("load-compiled/vm", 1, 0, 0,
707 scm_load_compiled_with_vm
));
709 sym_vm_run
= scm_permanent_object (scm_from_locale_symbol ("vm-run"));
710 sym_vm_error
= scm_permanent_object (scm_from_locale_symbol ("vm-error"));
711 sym_debug
= scm_permanent_object (scm_from_locale_symbol ("debug"));
721 #ifndef SCM_MAGIC_SNARFER