Merge remote-tracking branch 'origin/stable-2.0' into stable-2.0
[bpt/guile.git] / libguile / vm.c
CommitLineData
0fc9040f 1/* Copyright (C) 2001, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
a98cef7e 2 *
560b9c25 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
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.
a98cef7e 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
560b9c25
AW
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
a98cef7e 12 *
560b9c25
AW
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
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
560b9c25 17 */
a98cef7e 18
13c47753
AW
19#if HAVE_CONFIG_H
20# include <config.h>
21#endif
22
da8b4747 23#include <stdlib.h>
6d14383e 24#include <alloca.h>
daccfef4 25#include <alignof.h>
17e90c5e 26#include <string.h>
e78d4bf9 27#include <stdint.h>
e3eb628d 28
1c44468d 29#include "libguile/bdw-gc.h"
e3eb628d
LC
30#include <gc/gc_mark.h>
31
560b9c25 32#include "_scm.h"
adaf86ec 33#include "control.h"
ac99cb0c 34#include "frames.h"
17e90c5e 35#include "instructions.h"
8f5cfc81 36#include "objcodes.h"
ac99cb0c 37#include "programs.h"
a98cef7e
KN
38#include "vm.h"
39
97b18a66 40static int vm_default_engine = SCM_VM_REGULAR_ENGINE;
ea9f4f4b
AW
41
42/* Unfortunately we can't snarf these: snarfed things are only loaded up from
43 (system vm vm), which might not be loaded before an error happens. */
44static SCM sym_vm_run;
45static SCM sym_vm_error;
46static SCM sym_keyword_argument_error;
47static SCM sym_regular;
48static SCM sym_debug;
a98cef7e 49
11ea1aba
AW
50/* The VM has a number of internal assertions that shouldn't normally be
51 necessary, but might be if you think you found a bug in the VM. */
52#define VM_ENABLE_ASSERTIONS
53
54/* We can add a mode that ensures that all stack items above the stack pointer
55 are NULL. This is useful for checking the internal consistency of the VM's
56 assumptions and its operators, but isn't necessary for normal operation. It
616167fc 57 will ensure that assertions are enabled. Slows down the VM by about 30%. */
747a1635 58/* NB! If you enable this, search for NULLING in throw.c */
616167fc 59/* #define VM_ENABLE_STACK_NULLING */
11ea1aba 60
53e28ed9
AW
61/* #define VM_ENABLE_PARANOID_ASSERTIONS */
62
11ea1aba
AW
63#if defined (VM_ENABLE_STACK_NULLING) && !defined (VM_ENABLE_ASSERTIONS)
64#define VM_ENABLE_ASSERTIONS
65#endif
66
e3eb628d
LC
67/* When defined, arrange so that the GC doesn't scan the VM stack beyond its
68 current SP. This should help avoid excess data retention. See
69 http://thread.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/3001
70 for a discussion. */
71#define VM_ENABLE_PRECISE_STACK_GC_SCAN
72
f1046e6b
LC
73/* Size in SCM objects of the stack reserve. The reserve is used to run
74 exception handling code in case of a VM stack overflow. */
75#define VM_STACK_RESERVE_SIZE 512
76
e3eb628d 77
a98cef7e 78\f
a98cef7e
KN
79/*
80 * VM Continuation
81 */
82
6f3b0cc2
AW
83void
84scm_i_vm_cont_print (SCM x, SCM port, scm_print_state *pstate)
85{
86 scm_puts ("#<vm-continuation ", port);
87 scm_uintprint (SCM_UNPACK (x), 16, port);
88 scm_puts (">", port);
89}
17e90c5e 90
d8873dfe
AW
91/* In theory, a number of vm instances can be active in the call trace, and we
92 only want to reify the continuations of those in the current continuation
93 root. I don't see a nice way to do this -- ideally it would involve dynwinds,
94 and previous values of the *the-vm* fluid within the current continuation
95 root. But we don't have access to continuation roots in the dynwind stack.
96 So, just punt for now, we just capture the continuation for the current VM.
97
98 While I'm on the topic, ideally we could avoid copying the C stack if the
99 continuation root is inside VM code, and call/cc was invoked within that same
100 call to vm_run; but that's currently not implemented.
101 */
cee1d22c
AW
102SCM
103scm_i_vm_capture_stack (SCM *stack_base, SCM *fp, SCM *sp, scm_t_uint8 *ra,
104 scm_t_uint8 *mvra, scm_t_uint32 flags)
a98cef7e 105{
d8873dfe
AW
106 struct scm_vm_cont *p;
107
108 p = scm_gc_malloc (sizeof (*p), "capture_vm_cont");
109 p->stack_size = sp - stack_base + 1;
d8eeb67c
LC
110 p->stack_base = scm_gc_malloc (p->stack_size * sizeof (SCM),
111 "capture_vm_cont");
d8873dfe
AW
112#if defined(VM_ENABLE_STACK_NULLING) && 0
113 /* Tail continuations leave their frame on the stack for subsequent
114 application, but don't capture the frame -- so there are some elements on
115 the stack then, and this check doesn't work, so disable it for now. */
116 if (sp >= vp->stack_base)
66db076a
AW
117 if (!vp->sp[0] || vp->sp[1])
118 abort ();
11ea1aba
AW
119 memset (p->stack_base, 0, p->stack_size * sizeof (SCM));
120#endif
d8873dfe
AW
121 p->ra = ra;
122 p->mvra = mvra;
123 p->sp = sp;
124 p->fp = fp;
125 memcpy (p->stack_base, stack_base, (sp + 1 - stack_base) * sizeof (SCM));
126 p->reloc = p->stack_base - stack_base;
cee1d22c 127 p->flags = flags;
6f3b0cc2 128 return scm_cell (scm_tc7_vm_cont, (scm_t_bits)p);
a98cef7e
KN
129}
130
131static void
d8873dfe 132vm_return_to_continuation (SCM vm, SCM cont, size_t n, SCM *argv)
a98cef7e 133{
d8873dfe
AW
134 struct scm_vm *vp;
135 struct scm_vm_cont *cp;
136 SCM *argv_copy;
137
138 argv_copy = alloca (n * sizeof(SCM));
139 memcpy (argv_copy, argv, n * sizeof(SCM));
140
141 vp = SCM_VM_DATA (vm);
142 cp = SCM_VM_CONT_DATA (cont);
143
144 if (n == 0 && !cp->mvra)
145 scm_misc_error (NULL, "Too few values returned to continuation",
146 SCM_EOL);
147
148 if (vp->stack_size < cp->stack_size + n + 1)
29366989
AW
149 scm_misc_error ("vm-engine", "not enough space to reinstate continuation",
150 scm_list_2 (vm, cont));
151
11ea1aba
AW
152#ifdef VM_ENABLE_STACK_NULLING
153 {
d8873dfe 154 scm_t_ptrdiff nzero = (vp->sp - cp->sp);
11ea1aba 155 if (nzero > 0)
d8873dfe 156 memset (vp->stack_base + cp->stack_size, 0, nzero * sizeof (SCM));
66db076a
AW
157 /* actually nzero should always be negative, because vm_reset_stack will
158 unwind the stack to some point *below* this continuation */
11ea1aba
AW
159 }
160#endif
d8873dfe
AW
161 vp->sp = cp->sp;
162 vp->fp = cp->fp;
163 memcpy (vp->stack_base, cp->stack_base, cp->stack_size * sizeof (SCM));
bfffd258 164
d8873dfe
AW
165 if (n == 1 || !cp->mvra)
166 {
167 vp->ip = cp->ra;
168 vp->sp++;
169 *vp->sp = argv_copy[0];
170 }
171 else
172 {
173 size_t i;
174 for (i = 0; i < n; i++)
175 {
176 vp->sp++;
177 *vp->sp = argv_copy[i];
178 }
179 vp->sp++;
180 *vp->sp = scm_from_size_t (n);
181 vp->ip = cp->mvra;
182 }
183}
bfffd258 184
bfffd258 185SCM
269479e3 186scm_i_vm_capture_continuation (SCM vm)
bfffd258 187{
d8873dfe 188 struct scm_vm *vp = SCM_VM_DATA (vm);
cee1d22c 189 return scm_i_vm_capture_stack (vp->stack_base, vp->fp, vp->sp, vp->ip, NULL, 0);
a98cef7e
KN
190}
191
b1b942b7 192static void
7656f194 193vm_dispatch_hook (SCM vm, int hook_num)
b1b942b7 194{
7656f194
AW
195 struct scm_vm *vp;
196 SCM hook;
b3567435 197 struct scm_frame c_frame;
8e4c60ff 198 scm_t_cell *frame;
b3567435 199 SCM args[1];
893fb8d0 200 int saved_trace_level;
b1b942b7 201
7656f194
AW
202 vp = SCM_VM_DATA (vm);
203 hook = vp->hooks[hook_num];
b1b942b7 204
7656f194
AW
205 if (SCM_LIKELY (scm_is_false (hook))
206 || scm_is_null (SCM_HOOK_PROCEDURES (hook)))
207 return;
b3567435 208
893fb8d0
AW
209 saved_trace_level = vp->trace_level;
210 vp->trace_level = 0;
b3567435
LC
211
212 /* Allocate a frame object on the stack. This is more efficient than calling
213 `scm_c_make_frame ()' to allocate on the heap, but it forces hooks to not
214 capture frame objects.
215
216 At the same time, procedures such as `frame-procedure' make sense only
217 while the stack frame represented by the frame object is visible, so it
218 seems reasonable to limit the lifetime of frame objects. */
219
220 c_frame.stack_holder = vm;
221 c_frame.fp = vp->fp;
222 c_frame.sp = vp->sp;
223 c_frame.ip = vp->ip;
224 c_frame.offset = 0;
8e4c60ff
LC
225
226 /* Arrange for FRAME to be 8-byte aligned, like any other cell. */
227 frame = alloca (sizeof (*frame) + 8);
228 frame = (scm_t_cell *) ROUND_UP ((scm_t_uintptr) frame, 8UL);
229
230 frame->word_0 = SCM_PACK (scm_tc7_frame);
231 frame->word_1 = PTR2SCM (&c_frame);
232 args[0] = PTR2SCM (frame);
b3567435
LC
233
234 scm_c_run_hookn (hook, args, 1);
235
893fb8d0 236 vp->trace_level = saved_trace_level;
b1b942b7
AW
237}
238
cee1d22c 239static void vm_abort (SCM vm, size_t n, scm_t_int64 cookie) SCM_NORETURN;
4f66bcde 240static void
cee1d22c 241vm_abort (SCM vm, size_t n, scm_t_int64 vm_cookie)
4f66bcde 242{
eaefabee 243 size_t i;
2d026f04
AW
244 ssize_t tail_len;
245 SCM tag, tail, *argv;
eaefabee 246
2d026f04
AW
247 /* FIXME: VM_ENABLE_STACK_NULLING */
248 tail = *(SCM_VM_DATA (vm)->sp--);
249 /* NULLSTACK (1) */
250 tail_len = scm_ilength (tail);
251 if (tail_len < 0)
29366989
AW
252 scm_misc_error ("vm-engine", "tail values to abort should be a list",
253 scm_list_1 (tail));
254
eaefabee 255 tag = SCM_VM_DATA (vm)->sp[-n];
2d026f04 256 argv = alloca ((n + tail_len) * sizeof (SCM));
eaefabee
AW
257 for (i = 0; i < n; i++)
258 argv[i] = SCM_VM_DATA (vm)->sp[-(n-1-i)];
2d026f04
AW
259 for (; i < n + tail_len; i++, tail = scm_cdr (tail))
260 argv[i] = scm_car (tail);
261 /* NULLSTACK (n + 1) */
eaefabee
AW
262 SCM_VM_DATA (vm)->sp -= n + 1;
263
cee1d22c
AW
264 scm_c_abort (vm, tag, n + tail_len, argv, vm_cookie);
265}
266
267static void
07801437 268vm_reinstate_partial_continuation (SCM vm, SCM cont, SCM intwinds,
adbdfd6d 269 size_t n, SCM *argv, scm_t_int64 vm_cookie)
cee1d22c 270{
07801437
AW
271 struct scm_vm *vp;
272 struct scm_vm_cont *cp;
273 SCM *argv_copy, *base;
274 size_t i;
275
276 argv_copy = alloca (n * sizeof(SCM));
277 memcpy (argv_copy, argv, n * sizeof(SCM));
278
279 vp = SCM_VM_DATA (vm);
280 cp = SCM_VM_CONT_DATA (cont);
281 base = SCM_FRAME_UPPER_ADDRESS (vp->fp) + 1;
282
0fc9040f
LC
283#define RELOC(scm_p) \
284 (((SCM *) (scm_p)) + cp->reloc + (base - cp->stack_base))
07801437
AW
285
286 if ((base - vp->stack_base) + cp->stack_size + n + 1 > vp->stack_size)
29366989
AW
287 scm_misc_error ("vm-engine",
288 "not enough space to instate partial continuation",
289 scm_list_2 (vm, cont));
07801437
AW
290
291 memcpy (base, cp->stack_base, cp->stack_size * sizeof (SCM));
292
293 /* now relocate frame pointers */
294 {
295 SCM *fp;
296 for (fp = RELOC (cp->fp);
297 SCM_FRAME_LOWER_ADDRESS (fp) > base;
298 fp = SCM_FRAME_DYNAMIC_LINK (fp))
299 SCM_FRAME_SET_DYNAMIC_LINK (fp, RELOC (SCM_FRAME_DYNAMIC_LINK (fp)));
300 }
301
302 vp->sp = base - 1 + cp->stack_size;
303 vp->fp = RELOC (cp->fp);
304 vp->ip = cp->mvra;
305
07801437
AW
306 /* now push args. ip is in a MV context. */
307 for (i = 0; i < n; i++)
308 {
309 vp->sp++;
310 *vp->sp = argv_copy[i];
311 }
312 vp->sp++;
313 *vp->sp = scm_from_size_t (n);
9a1c6f1f 314
adbdfd6d
AW
315 /* Finally, rewind the dynamic state.
316
317 We have to treat prompts specially, because we could be rewinding the
318 dynamic state from a different thread, or just a different position on the
319 C and/or VM stack -- so we need to reset the jump buffers so that an abort
320 comes back here, with appropriately adjusted sp and fp registers. */
9a1c6f1f
AW
321 {
322 long delta = 0;
323 SCM newwinds = scm_i_dynwinds ();
324 for (; scm_is_pair (intwinds); intwinds = scm_cdr (intwinds), delta--)
adbdfd6d
AW
325 {
326 SCM x = scm_car (intwinds);
327 if (SCM_PROMPT_P (x))
328 /* the jmpbuf will be reset by our caller */
329 x = scm_c_make_prompt (SCM_PROMPT_TAG (x),
330 RELOC (SCM_PROMPT_REGISTERS (x)->fp),
331 RELOC (SCM_PROMPT_REGISTERS (x)->sp),
332 SCM_PROMPT_REGISTERS (x)->ip,
333 SCM_PROMPT_ESCAPE_P (x),
334 vm_cookie,
335 newwinds);
336 newwinds = scm_cons (x, newwinds);
337 }
9a1c6f1f
AW
338 scm_dowinds (newwinds, delta);
339 }
adbdfd6d 340#undef RELOC
4f66bcde
AW
341}
342
343\f
17e90c5e
KN
344/*
345 * VM Internal functions
346 */
347
6f3b0cc2
AW
348void
349scm_i_vm_print (SCM x, SCM port, scm_print_state *pstate)
350{
0a935b2a
LC
351 const struct scm_vm *vm;
352
353 vm = SCM_VM_DATA (x);
354
6f3b0cc2 355 scm_puts ("#<vm ", port);
0a935b2a
LC
356 switch (vm->engine)
357 {
358 case SCM_VM_REGULAR_ENGINE:
359 scm_puts ("regular-engine ", port);
360 break;
361
362 case SCM_VM_DEBUG_ENGINE:
363 scm_puts ("debug-engine ", port);
364 break;
365
366 default:
367 scm_puts ("unknown-engine ", port);
368 }
6f3b0cc2
AW
369 scm_uintprint (SCM_UNPACK (x), 16, port);
370 scm_puts (">", port);
371}
372
53bdfcf0
AW
373\f
374/*
375 * VM Error Handling
376 */
377
378static void vm_error (const char *msg, SCM arg) SCM_NORETURN;
379static void vm_error_bad_instruction (scm_t_uint32 inst) SCM_NORETURN;
380static void vm_error_unbound (SCM proc, SCM sym) SCM_NORETURN;
381static void vm_error_unbound_fluid (SCM proc, SCM fluid) SCM_NORETURN;
382static void vm_error_not_a_variable (const char *func_name, SCM x) SCM_NORETURN;
383static void vm_error_not_a_thunk (const char *func_name, SCM x) SCM_NORETURN;
384static void vm_error_apply_to_non_list (SCM x) SCM_NORETURN;
385static void vm_error_kwargs_length_not_even (SCM proc) SCM_NORETURN;
386static void vm_error_kwargs_invalid_keyword (SCM proc) SCM_NORETURN;
387static void vm_error_kwargs_unrecognized_keyword (SCM proc) SCM_NORETURN;
388static void vm_error_too_many_args (int nargs) SCM_NORETURN;
389static void vm_error_wrong_num_args (SCM proc) SCM_NORETURN;
390static void vm_error_wrong_type_apply (SCM proc) SCM_NORETURN;
391static void vm_error_stack_overflow (struct scm_vm *vp) SCM_NORETURN;
392static void vm_error_stack_underflow (void) SCM_NORETURN;
393static void vm_error_improper_list (SCM x) SCM_NORETURN;
394static void vm_error_not_a_pair (const char *subr, SCM x) SCM_NORETURN;
395static void vm_error_not_a_bytevector (const char *subr, SCM x) SCM_NORETURN;
396static void vm_error_not_a_struct (const char *subr, SCM x) SCM_NORETURN;
397static void vm_error_no_values (void) SCM_NORETURN;
398static void vm_error_not_enough_values (void) SCM_NORETURN;
399static void vm_error_continuation_not_rewindable (SCM cont) SCM_NORETURN;
400static void vm_error_bad_wide_string_length (size_t len) SCM_NORETURN;
401#if VM_CHECK_IP
402static void vm_error_invalid_address (void) SCM_NORETURN;
403#endif
404#if VM_CHECK_OBJECT
405static void vm_error_object (void) SCM_NORETURN;
406#endif
407#if VM_CHECK_FREE_VARIABLES
408static void vm_error_free_variable (void) SCM_NORETURN;
409#endif
410
411static void
412vm_error (const char *msg, SCM arg)
413{
414 scm_throw (sym_vm_error,
415 scm_list_3 (sym_vm_run, scm_from_latin1_string (msg),
416 SCM_UNBNDP (arg) ? SCM_EOL : scm_list_1 (arg)));
417 abort(); /* not reached */
418}
419
420static void
421vm_error_bad_instruction (scm_t_uint32 inst)
422{
423 vm_error ("VM: Bad instruction: ~s", scm_from_uint32 (inst));
424}
425
426static void
427vm_error_unbound (SCM proc, SCM sym)
428{
429 scm_error_scm (scm_misc_error_key, proc,
430 scm_from_latin1_string ("Unbound variable: ~s"),
431 scm_list_1 (sym), SCM_BOOL_F);
432}
433
434static void
435vm_error_unbound_fluid (SCM proc, SCM fluid)
436{
437 scm_error_scm (scm_misc_error_key, proc,
438 scm_from_latin1_string ("Unbound fluid: ~s"),
439 scm_list_1 (fluid), SCM_BOOL_F);
440}
441
442static void
443vm_error_not_a_variable (const char *func_name, SCM x)
444{
445 scm_error (scm_arg_type_key, func_name, "Not a variable: ~S",
446 scm_list_1 (x), scm_list_1 (x));
447}
448
449static void
450vm_error_not_a_thunk (const char *func_name, SCM x)
451{
452 scm_error (scm_arg_type_key, func_name, "Not a thunk: ~S",
453 scm_list_1 (x), scm_list_1 (x));
454}
455
456static void
457vm_error_apply_to_non_list (SCM x)
458{
459 scm_error (scm_arg_type_key, "apply", "Apply to non-list: ~S",
460 scm_list_1 (x), scm_list_1 (x));
461}
462
463static void
464vm_error_kwargs_length_not_even (SCM proc)
465{
466 scm_error_scm (sym_keyword_argument_error, proc,
467 scm_from_latin1_string ("Odd length of keyword argument list"),
468 SCM_EOL, SCM_BOOL_F);
469}
470
471static void
472vm_error_kwargs_invalid_keyword (SCM proc)
473{
474 scm_error_scm (sym_keyword_argument_error, proc,
475 scm_from_latin1_string ("Invalid keyword"),
476 SCM_EOL, SCM_BOOL_F);
477}
478
479static void
480vm_error_kwargs_unrecognized_keyword (SCM proc)
481{
482 scm_error_scm (sym_keyword_argument_error, proc,
483 scm_from_latin1_string ("Unrecognized keyword"),
484 SCM_EOL, SCM_BOOL_F);
485}
486
487static void
488vm_error_too_many_args (int nargs)
489{
490 vm_error ("VM: Too many arguments", scm_from_int (nargs));
491}
492
493static void
494vm_error_wrong_num_args (SCM proc)
495{
496 scm_wrong_num_args (proc);
497}
498
499static void
500vm_error_wrong_type_apply (SCM proc)
501{
502 scm_error (scm_arg_type_key, NULL, "Wrong type to apply: ~S",
503 scm_list_1 (proc), scm_list_1 (proc));
504}
505
506static void
507vm_error_stack_overflow (struct scm_vm *vp)
508{
509 if (vp->stack_limit < vp->stack_base + vp->stack_size)
510 /* There are VM_STACK_RESERVE_SIZE bytes left. Make them available so
511 that `throw' below can run on this VM. */
512 vp->stack_limit = vp->stack_base + vp->stack_size;
513 else
514 /* There is no space left on the stack. FIXME: Do something more
515 sensible here! */
516 abort ();
517 vm_error ("VM: Stack overflow", SCM_UNDEFINED);
518}
519
520static void
521vm_error_stack_underflow (void)
522{
523 vm_error ("VM: Stack underflow", SCM_UNDEFINED);
524}
525
526static void
527vm_error_improper_list (SCM x)
528{
529 vm_error ("Expected a proper list, but got object with tail ~s", x);
530}
531
532static void
533vm_error_not_a_pair (const char *subr, SCM x)
534{
535 scm_wrong_type_arg_msg (subr, 1, x, "pair");
536}
537
538static void
539vm_error_not_a_bytevector (const char *subr, SCM x)
540{
541 scm_wrong_type_arg_msg (subr, 1, x, "bytevector");
542}
543
544static void
545vm_error_not_a_struct (const char *subr, SCM x)
546{
547 scm_wrong_type_arg_msg (subr, 1, x, "struct");
548}
549
550static void
551vm_error_no_values (void)
552{
553 vm_error ("Zero values returned to single-valued continuation",
554 SCM_UNDEFINED);
555}
556
557static void
558vm_error_not_enough_values (void)
559{
560 vm_error ("Too few values returned to continuation", SCM_UNDEFINED);
561}
562
563static void
564vm_error_continuation_not_rewindable (SCM cont)
565{
566 vm_error ("Unrewindable partial continuation", cont);
567}
568
569static void
570vm_error_bad_wide_string_length (size_t len)
571{
572 vm_error ("VM: Bad wide string length: ~S", scm_from_size_t (len));
573}
574
575#ifdef VM_CHECK_IP
576static void
577vm_error_invalid_address (void)
578{
579 vm_error ("VM: Invalid program address", SCM_UNDEFINED);
580}
581#endif
582
583#if VM_CHECK_OBJECT
584static void
585vm_error_object ()
586{
587 vm_error ("VM: Invalid object table access", SCM_UNDEFINED);
588}
589#endif
590
591#if VM_CHECK_FREE_VARIABLES
592static void
593vm_error_free_variable ()
594{
595 vm_error ("VM: Invalid free variable access", SCM_UNDEFINED);
596}
597#endif
598
599\f
28b119ee 600
67b699cc 601static SCM boot_continuation;
2fda0242 602
a98cef7e
KN
603\f
604/*
605 * VM
606 */
607
b7393ea1
AW
608static SCM
609resolve_variable (SCM what, SCM program_module)
610{
9bd48cb1 611 if (SCM_LIKELY (scm_is_symbol (what)))
b7393ea1
AW
612 {
613 if (SCM_LIKELY (scm_module_system_booted_p
614 && scm_is_true (program_module)))
615 /* might longjmp */
616 return scm_module_lookup (program_module, what);
617 else
618 {
619 SCM v = scm_sym2var (what, SCM_BOOL_F, SCM_BOOL_F);
620 if (scm_is_false (v))
621 scm_misc_error (NULL, "unbound variable: ~S", scm_list_1 (what));
622 else
623 return v;
624 }
625 }
626 else
627 {
628 SCM mod;
629 /* compilation of @ or @@
630 `what' is a three-element list: (MODNAME SYM INTERFACE?)
631 INTERFACE? is #t if we compiled @ or #f if we compiled @@
632 */
633 mod = scm_resolve_module (SCM_CAR (what));
634 if (scm_is_true (SCM_CADDR (what)))
635 mod = scm_module_public_interface (mod);
5c8cefe5 636 if (scm_is_false (mod))
b7393ea1
AW
637 scm_misc_error (NULL, "no such module: ~S",
638 scm_list_1 (SCM_CAR (what)));
639 /* might longjmp */
640 return scm_module_lookup (mod, SCM_CADR (what));
641 }
642}
643
51e9ba2f 644#define VM_DEFAULT_STACK_SIZE (64 * 1024)
17e90c5e 645
17e90c5e 646#define VM_NAME vm_regular_engine
6d14383e
AW
647#define FUNC_NAME "vm-regular-engine"
648#define VM_ENGINE SCM_VM_REGULAR_ENGINE
83495480 649#include "vm-engine.c"
17e90c5e 650#undef VM_NAME
6d14383e 651#undef FUNC_NAME
17e90c5e 652#undef VM_ENGINE
17e90c5e
KN
653
654#define VM_NAME vm_debug_engine
6d14383e
AW
655#define FUNC_NAME "vm-debug-engine"
656#define VM_ENGINE SCM_VM_DEBUG_ENGINE
83495480 657#include "vm-engine.c"
17e90c5e 658#undef VM_NAME
6d14383e 659#undef FUNC_NAME
17e90c5e
KN
660#undef VM_ENGINE
661
6d14383e
AW
662static const scm_t_vm_engine vm_engines[] =
663 { vm_regular_engine, vm_debug_engine };
664
e3eb628d
LC
665#ifdef VM_ENABLE_PRECISE_STACK_GC_SCAN
666
667/* The GC "kind" for the VM stack. */
668static int vm_stack_gc_kind;
669
670#endif
671
a98cef7e 672static SCM
17e90c5e
KN
673make_vm (void)
674#define FUNC_NAME "make_vm"
a98cef7e 675{
17e90c5e 676 int i;
7f991c7d 677 struct scm_vm *vp;
747a1635 678
7f991c7d 679 vp = scm_gc_malloc (sizeof (struct scm_vm), "vm");
d8eeb67c 680
3d5ee0cd 681 vp->stack_size = VM_DEFAULT_STACK_SIZE;
e3eb628d
LC
682
683#ifdef VM_ENABLE_PRECISE_STACK_GC_SCAN
4168aa46
TTN
684 vp->stack_base = (SCM *)
685 GC_generic_malloc (vp->stack_size * sizeof (SCM), vm_stack_gc_kind);
e3eb628d
LC
686
687 /* Keep a pointer to VP so that `vm_stack_mark ()' can know what the stack
688 top is. */
689 *vp->stack_base = PTR2SCM (vp);
690 vp->stack_base++;
691 vp->stack_size--;
692#else
d8eeb67c
LC
693 vp->stack_base = scm_gc_malloc (vp->stack_size * sizeof (SCM),
694 "stack-base");
e3eb628d
LC
695#endif
696
2bbe1533
AW
697#ifdef VM_ENABLE_STACK_NULLING
698 memset (vp->stack_base, 0, vp->stack_size * sizeof (SCM));
699#endif
f1046e6b 700 vp->stack_limit = vp->stack_base + vp->stack_size - VM_STACK_RESERVE_SIZE;
3616e9e9
KN
701 vp->ip = NULL;
702 vp->sp = vp->stack_base - 1;
703 vp->fp = NULL;
ea9f4f4b 704 vp->engine = vm_default_engine;
7656f194 705 vp->trace_level = 0;
17e90c5e 706 for (i = 0; i < SCM_VM_NUM_HOOKS; i++)
3d5ee0cd 707 vp->hooks[i] = SCM_BOOL_F;
2d026f04 708 vp->cookie = 0;
6f3b0cc2 709 return scm_cell (scm_tc7_vm, (scm_t_bits)vp);
a98cef7e 710}
17e90c5e 711#undef FUNC_NAME
a98cef7e 712
e3eb628d
LC
713#ifdef VM_ENABLE_PRECISE_STACK_GC_SCAN
714
715/* Mark the VM stack region between its base and its current top. */
716static struct GC_ms_entry *
717vm_stack_mark (GC_word *addr, struct GC_ms_entry *mark_stack_ptr,
718 struct GC_ms_entry *mark_stack_limit, GC_word env)
719{
720 GC_word *word;
721 const struct scm_vm *vm;
722
723 /* The first word of the VM stack should contain a pointer to the
724 corresponding VM. */
725 vm = * ((struct scm_vm **) addr);
726
8071c490 727 if (vm == NULL
f1046e6b 728 || (SCM *) addr != vm->stack_base - 1)
e3eb628d
LC
729 /* ADDR must be a pointer to a free-list element, which we must ignore
730 (see warning in <gc/gc_mark.h>). */
731 return mark_stack_ptr;
732
e3eb628d
LC
733 for (word = (GC_word *) vm->stack_base; word <= (GC_word *) vm->sp; word++)
734 mark_stack_ptr = GC_MARK_AND_PUSH ((* (GC_word **) word),
735 mark_stack_ptr, mark_stack_limit,
736 NULL);
737
738 return mark_stack_ptr;
739}
740
741#endif /* VM_ENABLE_PRECISE_STACK_GC_SCAN */
742
743
6d14383e 744SCM
4abef68f 745scm_c_vm_run (SCM vm, SCM program, SCM *argv, int nargs)
6d14383e 746{
4abef68f 747 struct scm_vm *vp = SCM_VM_DATA (vm);
b95d76fc 748 SCM_CHECK_STACK;
7656f194 749 return vm_engines[vp->engine](vm, program, argv, nargs);
6d14383e
AW
750}
751
a98cef7e
KN
752/* Scheme interface */
753
271c3d31
LC
754SCM_DEFINE (scm_the_vm, "the-vm", 0, 0, 0,
755 (void),
756 "Return the current thread's VM.")
757#define FUNC_NAME s_scm_the_vm
758{
ea9f4f4b
AW
759 scm_i_thread *t = SCM_I_CURRENT_THREAD;
760
761 if (SCM_UNLIKELY (scm_is_false (t->vm)))
762 t->vm = make_vm ();
763
764 return t->vm;
271c3d31 765}
499a4c07
KN
766#undef FUNC_NAME
767
768
a98cef7e
KN
769SCM_DEFINE (scm_vm_p, "vm?", 1, 0, 0,
770 (SCM obj),
17e90c5e 771 "")
a98cef7e
KN
772#define FUNC_NAME s_scm_vm_p
773{
9bd48cb1 774 return scm_from_bool (SCM_VM_P (obj));
a98cef7e
KN
775}
776#undef FUNC_NAME
777
778SCM_DEFINE (scm_make_vm, "make-vm", 0, 0, 0,
17e90c5e
KN
779 (void),
780 "")
781#define FUNC_NAME s_scm_make_vm,
a98cef7e 782{
17e90c5e 783 return make_vm ();
a98cef7e
KN
784}
785#undef FUNC_NAME
786
17e90c5e 787SCM_DEFINE (scm_vm_ip, "vm:ip", 1, 0, 0,
a98cef7e 788 (SCM vm),
17e90c5e
KN
789 "")
790#define FUNC_NAME s_scm_vm_ip
a98cef7e
KN
791{
792 SCM_VALIDATE_VM (1, vm);
3d27ef4b 793 return scm_from_unsigned_integer ((scm_t_bits) SCM_VM_DATA (vm)->ip);
a98cef7e
KN
794}
795#undef FUNC_NAME
796
797SCM_DEFINE (scm_vm_sp, "vm:sp", 1, 0, 0,
798 (SCM vm),
17e90c5e 799 "")
a98cef7e
KN
800#define FUNC_NAME s_scm_vm_sp
801{
802 SCM_VALIDATE_VM (1, vm);
3d27ef4b 803 return scm_from_unsigned_integer ((scm_t_bits) SCM_VM_DATA (vm)->sp);
a98cef7e
KN
804}
805#undef FUNC_NAME
806
807SCM_DEFINE (scm_vm_fp, "vm:fp", 1, 0, 0,
808 (SCM vm),
17e90c5e 809 "")
a98cef7e
KN
810#define FUNC_NAME s_scm_vm_fp
811{
812 SCM_VALIDATE_VM (1, vm);
3d27ef4b 813 return scm_from_unsigned_integer ((scm_t_bits) SCM_VM_DATA (vm)->fp);
a98cef7e
KN
814}
815#undef FUNC_NAME
816
17e90c5e
KN
817#define VM_DEFINE_HOOK(n) \
818{ \
3d5ee0cd 819 struct scm_vm *vp; \
17e90c5e 820 SCM_VALIDATE_VM (1, vm); \
3d5ee0cd 821 vp = SCM_VM_DATA (vm); \
8b22ed7a 822 if (scm_is_false (vp->hooks[n])) \
238e7a11 823 vp->hooks[n] = scm_make_hook (SCM_I_MAKINUM (1)); \
3d5ee0cd 824 return vp->hooks[n]; \
17e90c5e
KN
825}
826
c45d4d77 827SCM_DEFINE (scm_vm_apply_hook, "vm-apply-hook", 1, 0, 0,
17e90c5e
KN
828 (SCM vm),
829 "")
c45d4d77 830#define FUNC_NAME s_scm_vm_apply_hook
a98cef7e 831{
c45d4d77 832 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK);
a98cef7e
KN
833}
834#undef FUNC_NAME
835
c45d4d77 836SCM_DEFINE (scm_vm_push_continuation_hook, "vm-push-continuation-hook", 1, 0, 0,
17e90c5e
KN
837 (SCM vm),
838 "")
c45d4d77 839#define FUNC_NAME s_scm_vm_push_continuation_hook
a98cef7e 840{
c45d4d77 841 VM_DEFINE_HOOK (SCM_VM_PUSH_CONTINUATION_HOOK);
a98cef7e
KN
842}
843#undef FUNC_NAME
844
c45d4d77 845SCM_DEFINE (scm_vm_pop_continuation_hook, "vm-pop-continuation-hook", 1, 0, 0,
a98cef7e 846 (SCM vm),
17e90c5e 847 "")
c45d4d77 848#define FUNC_NAME s_scm_vm_pop_continuation_hook
a98cef7e 849{
c45d4d77 850 VM_DEFINE_HOOK (SCM_VM_POP_CONTINUATION_HOOK);
a98cef7e
KN
851}
852#undef FUNC_NAME
853
c45d4d77 854SCM_DEFINE (scm_vm_next_hook, "vm-next-hook", 1, 0, 0,
a98cef7e 855 (SCM vm),
17e90c5e 856 "")
c45d4d77 857#define FUNC_NAME s_scm_vm_next_hook
a98cef7e 858{
c45d4d77 859 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK);
a98cef7e
KN
860}
861#undef FUNC_NAME
f3120251
AW
862
863SCM_DEFINE (scm_vm_abort_continuation_hook, "vm-abort-continuation-hook", 1, 0, 0,
864 (SCM vm),
865 "")
866#define FUNC_NAME s_scm_vm_abort_continuation_hook
867{
868 VM_DEFINE_HOOK (SCM_VM_ABORT_CONTINUATION_HOOK);
869}
870#undef FUNC_NAME
871
872SCM_DEFINE (scm_vm_restore_continuation_hook, "vm-restore-continuation-hook", 1, 0, 0,
873 (SCM vm),
874 "")
875#define FUNC_NAME s_scm_vm_restore_continuation_hook
876{
877 VM_DEFINE_HOOK (SCM_VM_RESTORE_CONTINUATION_HOOK);
878}
879#undef FUNC_NAME
a98cef7e 880
7656f194 881SCM_DEFINE (scm_vm_trace_level, "vm-trace-level", 1, 0, 0,
17e90c5e
KN
882 (SCM vm),
883 "")
7656f194 884#define FUNC_NAME s_scm_vm_trace_level
a98cef7e 885{
a98cef7e 886 SCM_VALIDATE_VM (1, vm);
7656f194
AW
887 return scm_from_int (SCM_VM_DATA (vm)->trace_level);
888}
889#undef FUNC_NAME
890
891SCM_DEFINE (scm_set_vm_trace_level_x, "set-vm-trace-level!", 2, 0, 0,
892 (SCM vm, SCM level),
893 "")
894#define FUNC_NAME s_scm_set_vm_trace_level_x
895{
896 SCM_VALIDATE_VM (1, vm);
897 SCM_VM_DATA (vm)->trace_level = scm_to_int (level);
898 return SCM_UNSPECIFIED;
a98cef7e
KN
899}
900#undef FUNC_NAME
901
902\f
ea9f4f4b
AW
903/*
904 * VM engines
905 */
906
907static int
908symbol_to_vm_engine (SCM engine, const char *FUNC_NAME)
909{
910 if (scm_is_eq (engine, sym_regular))
911 return SCM_VM_REGULAR_ENGINE;
912 else if (scm_is_eq (engine, sym_debug))
913 return SCM_VM_DEBUG_ENGINE;
914 else
915 SCM_MISC_ERROR ("Unknown VM engine: ~a", scm_list_1 (engine));
916}
917
918static SCM
919vm_engine_to_symbol (int engine, const char *FUNC_NAME)
920{
921 switch (engine)
922 {
923 case SCM_VM_REGULAR_ENGINE:
924 return sym_regular;
925 case SCM_VM_DEBUG_ENGINE:
926 return sym_debug;
927 default:
928 /* ? */
929 SCM_MISC_ERROR ("Unknown VM engine: ~a",
930 scm_list_1 (scm_from_int (engine)));
931 }
932}
933
ea9f4f4b
AW
934SCM_DEFINE (scm_vm_engine, "vm-engine", 1, 0, 0,
935 (SCM vm),
936 "")
937#define FUNC_NAME s_scm_vm_engine
938{
939 SCM_VALIDATE_VM (1, vm);
940 return vm_engine_to_symbol (SCM_VM_DATA (vm)->engine, FUNC_NAME);
941}
942#undef FUNC_NAME
943
944void
945scm_c_set_vm_engine_x (SCM vm, int engine)
946#define FUNC_NAME "set-vm-engine!"
947{
948 SCM_VALIDATE_VM (1, vm);
949
ea9f4f4b
AW
950 if (engine < 0 || engine >= SCM_VM_NUM_ENGINES)
951 SCM_MISC_ERROR ("Unknown VM engine: ~a",
952 scm_list_1 (scm_from_int (engine)));
953
954 SCM_VM_DATA (vm)->engine = engine;
955}
956#undef FUNC_NAME
957
958SCM_DEFINE (scm_set_vm_engine_x, "set-vm-engine!", 2, 0, 0,
959 (SCM vm, SCM engine),
960 "")
961#define FUNC_NAME s_scm_set_vm_engine_x
962{
963 scm_c_set_vm_engine_x (vm, symbol_to_vm_engine (engine, FUNC_NAME));
964 return SCM_UNSPECIFIED;
965}
966#undef FUNC_NAME
967
968void
969scm_c_set_default_vm_engine_x (int engine)
970#define FUNC_NAME "set-default-vm-engine!"
971{
972 if (engine < 0 || engine >= SCM_VM_NUM_ENGINES)
973 SCM_MISC_ERROR ("Unknown VM engine: ~a",
974 scm_list_1 (scm_from_int (engine)));
975
976 vm_default_engine = engine;
977}
978#undef FUNC_NAME
979
980SCM_DEFINE (scm_set_default_vm_engine_x, "set-default-vm-engine!", 1, 0, 0,
981 (SCM engine),
982 "")
983#define FUNC_NAME s_scm_set_default_vm_engine_x
984{
985 scm_c_set_default_vm_engine_x (symbol_to_vm_engine (engine, FUNC_NAME));
986 return SCM_UNSPECIFIED;
987}
988#undef FUNC_NAME
989
990static void reinstate_vm (SCM vm)
991{
992 scm_i_thread *t = SCM_I_CURRENT_THREAD;
993 t->vm = vm;
994}
995
996SCM_DEFINE (scm_call_with_vm, "call-with-vm", 2, 0, 1,
997 (SCM vm, SCM proc, SCM args),
998 "Apply @var{proc} to @var{args} in a dynamic extent in which\n"
999 "@var{vm} is the current VM.\n\n"
1000 "As an implementation restriction, if @var{vm} is not the same\n"
1001 "as the current thread's VM, continuations captured within the\n"
1002 "call to @var{proc} may not be reinstated once control leaves\n"
1003 "@var{proc}.")
1004#define FUNC_NAME s_scm_call_with_vm
1005{
1006 SCM prev_vm, ret;
1007 SCM *argv;
1008 int i, nargs;
1009 scm_t_wind_flags flags;
1010 scm_i_thread *t = SCM_I_CURRENT_THREAD;
1011
1012 SCM_VALIDATE_VM (1, vm);
1013 SCM_VALIDATE_PROC (2, proc);
1014
1015 nargs = scm_ilength (args);
1016 if (SCM_UNLIKELY (nargs < 0))
1017 scm_wrong_type_arg_msg (FUNC_NAME, 3, args, "list");
1018
1019 argv = alloca (nargs * sizeof(SCM));
1020 for (i = 0; i < nargs; i++)
1021 {
1022 argv[i] = SCM_CAR (args);
1023 args = SCM_CDR (args);
1024 }
1025
1026 prev_vm = t->vm;
1027
1028 /* Reentry can happen via invokation of a saved continuation, but
1029 continuations only save the state of the VM that they are in at
1030 capture-time, which might be different from this one. So, in the
1031 case that the VMs are different, set up a non-rewindable frame to
1032 prevent reinstating an incomplete continuation. */
1033 flags = scm_is_eq (prev_vm, vm) ? 0 : SCM_F_WIND_EXPLICITLY;
1034 if (flags)
1035 {
1036 scm_dynwind_begin (0);
1037 scm_dynwind_unwind_handler_with_scm (reinstate_vm, prev_vm, flags);
1038 t->vm = vm;
1039 }
1040
1041 ret = scm_c_vm_run (vm, proc, argv, nargs);
1042
1043 if (flags)
1044 scm_dynwind_end ();
1045
1046 return ret;
1047}
1048#undef FUNC_NAME
1049
1050\f
a98cef7e 1051/*
17e90c5e 1052 * Initialize
a98cef7e
KN
1053 */
1054
07e56b27
AW
1055SCM scm_load_compiled_with_vm (SCM file)
1056{
53e28ed9 1057 SCM program = scm_make_program (scm_load_objcode (file),
20d47c39 1058 SCM_BOOL_F, SCM_BOOL_F);
07e56b27 1059
4abef68f 1060 return scm_c_vm_run (scm_the_vm (), program, NULL, 0);
07e56b27
AW
1061}
1062
67b699cc
AW
1063
1064static SCM
1065make_boot_program (void)
1066{
1067 struct scm_objcode *bp;
1068 size_t bp_size;
1069 SCM u8vec, ret;
1070
1071 const scm_t_uint8 text[] = {
1072 scm_op_make_int8_1,
1073 scm_op_halt
1074 };
1075
1076 bp_size = sizeof (struct scm_objcode) + sizeof (text);
1077 bp = scm_gc_malloc_pointerless (bp_size, "boot-program");
1078 memcpy (SCM_C_OBJCODE_BASE (bp), text, sizeof (text));
1079 bp->len = sizeof(text);
1080 bp->metalen = 0;
1081
1082 u8vec = scm_c_take_gc_bytevector ((scm_t_int8*)bp, bp_size);
1083 ret = scm_make_program (scm_bytecode_to_native_objcode (u8vec),
1084 SCM_BOOL_F, SCM_BOOL_F);
1085 SCM_SET_CELL_WORD_0 (ret, (SCM_CELL_WORD_0 (ret) | SCM_F_PROGRAM_IS_BOOT));
1086
1087 return ret;
1088}
1089
17e90c5e 1090void
07e56b27 1091scm_bootstrap_vm (void)
17e90c5e 1092{
44602b08
AW
1093 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1094 "scm_init_vm",
60ae5ca2
AW
1095 (scm_t_extension_init_func)scm_init_vm, NULL);
1096
4a655e50
AW
1097 sym_vm_run = scm_from_latin1_symbol ("vm-run");
1098 sym_vm_error = scm_from_latin1_symbol ("vm-error");
1099 sym_keyword_argument_error = scm_from_latin1_symbol ("keyword-argument-error");
1100 sym_regular = scm_from_latin1_symbol ("regular");
1101 sym_debug = scm_from_latin1_symbol ("debug");
0404c97d 1102
67b699cc
AW
1103 boot_continuation = make_boot_program ();
1104
e3eb628d
LC
1105#ifdef VM_ENABLE_PRECISE_STACK_GC_SCAN
1106 vm_stack_gc_kind =
1107 GC_new_kind (GC_new_free_list (),
1108 GC_MAKE_PROC (GC_new_proc (vm_stack_mark), 0),
1109 0, 1);
1110
1111#endif
07e56b27
AW
1112}
1113
1114void
1115scm_init_vm (void)
1116{
17e90c5e 1117#ifndef SCM_MAGIC_SNARFER
aeeff258 1118#include "libguile/vm.x"
17e90c5e 1119#endif
a98cef7e 1120}
17e90c5e
KN
1121
1122/*
1123 Local Variables:
1124 c-file-style: "gnu"
1125 End:
1126*/