Add VM and compiler support for calls to known procedures
[bpt/guile.git] / libguile / vm.c
CommitLineData
02c624fc 1/* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013, 2014 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
22d425ec
AW
19/* For mremap(2) on GNU/Linux systems. */
20#define _GNU_SOURCE
21
13c47753
AW
22#if HAVE_CONFIG_H
23# include <config.h>
24#endif
25
da8b4747 26#include <stdlib.h>
6d14383e 27#include <alloca.h>
daccfef4 28#include <alignof.h>
17e90c5e 29#include <string.h>
e78d4bf9 30#include <stdint.h>
7dba1c2f 31#include <unistd.h>
e3eb628d 32
5f18bc84
AW
33#ifdef HAVE_SYS_MMAN_H
34#include <sys/mman.h>
35#endif
36
1c44468d 37#include "libguile/bdw-gc.h"
e3eb628d
LC
38#include <gc/gc_mark.h>
39
560b9c25 40#include "_scm.h"
adaf86ec 41#include "control.h"
ac99cb0c 42#include "frames.h"
aef1fcf9 43#include "gc-inline.h"
17e90c5e 44#include "instructions.h"
4cbc95f1 45#include "loader.h"
ac99cb0c 46#include "programs.h"
87fc4596 47#include "simpos.h"
a98cef7e 48#include "vm.h"
486013d6 49#include "vm-builtins.h"
a98cef7e 50
97b18a66 51static int vm_default_engine = SCM_VM_REGULAR_ENGINE;
ea9f4f4b
AW
52
53/* Unfortunately we can't snarf these: snarfed things are only loaded up from
54 (system vm vm), which might not be loaded before an error happens. */
55static SCM sym_vm_run;
56static SCM sym_vm_error;
57static SCM sym_keyword_argument_error;
58static SCM sym_regular;
59static SCM sym_debug;
a98cef7e 60
11ea1aba
AW
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
64
53e28ed9
AW
65/* #define VM_ENABLE_PARANOID_ASSERTIONS */
66
e3eb628d 67
a98cef7e 68\f
a98cef7e
KN
69/*
70 * VM Continuation
71 */
72
6f3b0cc2
AW
73void
74scm_i_vm_cont_print (SCM x, SCM port, scm_print_state *pstate)
75{
0607ebbf 76 scm_puts_unlocked ("#<vm-continuation ", port);
6f3b0cc2 77 scm_uintprint (SCM_UNPACK (x), 16, port);
0607ebbf 78 scm_puts_unlocked (">", port);
6f3b0cc2 79}
17e90c5e 80
d8873dfe
AW
81/* In theory, a number of vm instances can be active in the call trace, and we
82 only want to reify the continuations of those in the current continuation
83 root. I don't see a nice way to do this -- ideally it would involve dynwinds,
84 and previous values of the *the-vm* fluid within the current continuation
85 root. But we don't have access to continuation roots in the dynwind stack.
86 So, just punt for now, we just capture the continuation for the current VM.
87
88 While I'm on the topic, ideally we could avoid copying the C stack if the
89 continuation root is inside VM code, and call/cc was invoked within that same
90 call to vm_run; but that's currently not implemented.
91 */
cee1d22c 92SCM
9121d9f1 93scm_i_vm_capture_stack (SCM *stack_base, SCM *fp, SCM *sp, scm_t_uint32 *ra,
840ec334 94 scm_t_dynstack *dynstack, scm_t_uint32 flags)
a98cef7e 95{
d8873dfe
AW
96 struct scm_vm_cont *p;
97
98 p = scm_gc_malloc (sizeof (*p), "capture_vm_cont");
99 p->stack_size = sp - stack_base + 1;
d8eeb67c
LC
100 p->stack_base = scm_gc_malloc (p->stack_size * sizeof (SCM),
101 "capture_vm_cont");
d8873dfe 102 p->ra = ra;
d8873dfe
AW
103 p->sp = sp;
104 p->fp = fp;
105 memcpy (p->stack_base, stack_base, (sp + 1 - stack_base) * sizeof (SCM));
106 p->reloc = p->stack_base - stack_base;
9ede013f 107 p->dynstack = dynstack;
cee1d22c 108 p->flags = flags;
6f3b0cc2 109 return scm_cell (scm_tc7_vm_cont, (scm_t_bits)p);
a98cef7e
KN
110}
111
112static void
796e54a7 113vm_return_to_continuation (struct scm_vm *vp, SCM cont, size_t n, SCM *argv)
a98cef7e 114{
d8873dfe
AW
115 struct scm_vm_cont *cp;
116 SCM *argv_copy;
117
118 argv_copy = alloca (n * sizeof(SCM));
119 memcpy (argv_copy, argv, n * sizeof(SCM));
120
d8873dfe
AW
121 cp = SCM_VM_CONT_DATA (cont);
122
f8085163 123 if (vp->stack_size < cp->stack_size + n + 3)
29366989 124 scm_misc_error ("vm-engine", "not enough space to reinstate continuation",
796e54a7 125 scm_list_1 (cont));
29366989 126
d8873dfe
AW
127 vp->sp = cp->sp;
128 vp->fp = cp->fp;
129 memcpy (vp->stack_base, cp->stack_base, cp->stack_size * sizeof (SCM));
bfffd258 130
03f16599
AW
131 {
132 size_t i;
133
134 /* Push on an empty frame, as the continuation expects. */
f8085163 135 for (i = 0; i < 3; i++)
03f16599
AW
136 {
137 vp->sp++;
138 *vp->sp = SCM_BOOL_F;
139 }
140
141 /* Push the return values. */
142 for (i = 0; i < n; i++)
143 {
144 vp->sp++;
145 *vp->sp = argv_copy[i];
146 }
7dba1c2f
AW
147 if (vp->sp > vp->sp_max_since_gc)
148 vp->sp_max_since_gc = vp->sp;
840ec334 149 vp->ip = cp->ra;
03f16599 150 }
d8873dfe 151}
bfffd258 152
b85cd20f 153static struct scm_vm * thread_vm (scm_i_thread *t);
bfffd258 154SCM
9ede013f 155scm_i_capture_current_stack (void)
bfffd258 156{
9ede013f 157 scm_i_thread *thread;
9ede013f
AW
158 struct scm_vm *vp;
159
160 thread = SCM_I_CURRENT_THREAD;
b85cd20f 161 vp = thread_vm (thread);
9ede013f 162
840ec334 163 return scm_i_vm_capture_stack (vp->stack_base, vp->fp, vp->sp, vp->ip,
9ede013f
AW
164 scm_dynstack_capture_all (&thread->dynstack),
165 0);
a98cef7e
KN
166}
167
59f85eed
AW
168static void vm_dispatch_apply_hook (struct scm_vm *vp) SCM_NOINLINE;
169static void vm_dispatch_push_continuation_hook (struct scm_vm *vp) SCM_NOINLINE;
170static void vm_dispatch_pop_continuation_hook (struct scm_vm *vp, SCM *old_fp) SCM_NOINLINE;
171static void vm_dispatch_next_hook (struct scm_vm *vp) SCM_NOINLINE;
172static void vm_dispatch_abort_hook (struct scm_vm *vp) SCM_NOINLINE;
c850a0ff 173
b1b942b7 174static void
59f85eed 175vm_dispatch_hook (struct scm_vm *vp, int hook_num, SCM *argv, int n)
b1b942b7 176{
7656f194 177 SCM hook;
b3567435 178 struct scm_frame c_frame;
8e4c60ff 179 scm_t_cell *frame;
893fb8d0 180 int saved_trace_level;
b1b942b7 181
7656f194 182 hook = vp->hooks[hook_num];
b1b942b7 183
7656f194
AW
184 if (SCM_LIKELY (scm_is_false (hook))
185 || scm_is_null (SCM_HOOK_PROCEDURES (hook)))
186 return;
b3567435 187
893fb8d0
AW
188 saved_trace_level = vp->trace_level;
189 vp->trace_level = 0;
b3567435
LC
190
191 /* Allocate a frame object on the stack. This is more efficient than calling
192 `scm_c_make_frame ()' to allocate on the heap, but it forces hooks to not
193 capture frame objects.
194
195 At the same time, procedures such as `frame-procedure' make sense only
196 while the stack frame represented by the frame object is visible, so it
197 seems reasonable to limit the lifetime of frame objects. */
198
5515edc5 199 c_frame.stack_holder = vp;
89b235af
AW
200 c_frame.fp_offset = vp->fp - vp->stack_base;
201 c_frame.sp_offset = vp->sp - vp->stack_base;
b3567435 202 c_frame.ip = vp->ip;
8e4c60ff
LC
203
204 /* Arrange for FRAME to be 8-byte aligned, like any other cell. */
205 frame = alloca (sizeof (*frame) + 8);
206 frame = (scm_t_cell *) ROUND_UP ((scm_t_uintptr) frame, 8UL);
207
050a40db 208 frame->word_0 = SCM_PACK (scm_tc7_frame | (SCM_VM_FRAME_KIND_VM << 8));
21041372 209 frame->word_1 = SCM_PACK_POINTER (&c_frame);
b3567435 210
c850a0ff
AW
211 if (n == 0)
212 {
213 SCM args[1];
214
215 args[0] = SCM_PACK_POINTER (frame);
216 scm_c_run_hookn (hook, args, 1);
217 }
218 else if (n == 1)
219 {
220 SCM args[2];
221
222 args[0] = SCM_PACK_POINTER (frame);
223 args[1] = argv[0];
224 scm_c_run_hookn (hook, args, 2);
225 }
226 else
227 {
228 SCM args = SCM_EOL;
229
230 while (n--)
231 args = scm_cons (argv[n], args);
232 scm_c_run_hook (hook, scm_cons (SCM_PACK_POINTER (frame), args));
233 }
b3567435 234
893fb8d0 235 vp->trace_level = saved_trace_level;
b1b942b7
AW
236}
237
ea0cd17d 238static void
59f85eed 239vm_dispatch_apply_hook (struct scm_vm *vp)
ea0cd17d 240{
59f85eed 241 return vm_dispatch_hook (vp, SCM_VM_APPLY_HOOK, NULL, 0);
ea0cd17d 242}
59f85eed 243static void vm_dispatch_push_continuation_hook (struct scm_vm *vp)
ea0cd17d 244{
59f85eed 245 return vm_dispatch_hook (vp, SCM_VM_PUSH_CONTINUATION_HOOK, NULL, 0);
ea0cd17d 246}
59f85eed 247static void vm_dispatch_pop_continuation_hook (struct scm_vm *vp, SCM *old_fp)
ea0cd17d 248{
59f85eed 249 return vm_dispatch_hook (vp, SCM_VM_POP_CONTINUATION_HOOK,
ea0cd17d
AW
250 &SCM_FRAME_LOCAL (old_fp, 1),
251 SCM_FRAME_NUM_LOCALS (old_fp, vp->sp) - 1);
252}
59f85eed 253static void vm_dispatch_next_hook (struct scm_vm *vp)
ea0cd17d 254{
59f85eed 255 return vm_dispatch_hook (vp, SCM_VM_NEXT_HOOK, NULL, 0);
ea0cd17d 256}
59f85eed 257static void vm_dispatch_abort_hook (struct scm_vm *vp)
ea0cd17d 258{
59f85eed 259 return vm_dispatch_hook (vp, SCM_VM_ABORT_CONTINUATION_HOOK,
ea0cd17d
AW
260 &SCM_FRAME_LOCAL (vp->fp, 1),
261 SCM_FRAME_NUM_LOCALS (vp->fp, vp->sp) - 1);
262}
ea0cd17d 263
4f66bcde 264static void
b44f5451
AW
265vm_abort (struct scm_vm *vp, SCM tag,
266 size_t nstack, SCM *stack_args, SCM tail, SCM *sp,
99511cd0 267 scm_i_jmp_buf *current_registers) SCM_NORETURN;
9d381ba4
AW
268
269static void
b44f5451
AW
270vm_abort (struct scm_vm *vp, SCM tag,
271 size_t nstack, SCM *stack_args, SCM tail, SCM *sp,
99511cd0 272 scm_i_jmp_buf *current_registers)
4f66bcde 273{
eaefabee 274 size_t i;
2d026f04 275 ssize_t tail_len;
99511cd0 276 SCM *argv;
eaefabee 277
2d026f04
AW
278 tail_len = scm_ilength (tail);
279 if (tail_len < 0)
29366989
AW
280 scm_misc_error ("vm-engine", "tail values to abort should be a list",
281 scm_list_1 (tail));
282
99511cd0
AW
283 argv = alloca ((nstack + tail_len) * sizeof (SCM));
284 for (i = 0; i < nstack; i++)
285 argv[i] = stack_args[i];
286 for (; i < nstack + tail_len; i++, tail = scm_cdr (tail))
2d026f04 287 argv[i] = scm_car (tail);
eaefabee 288
99511cd0 289 /* FIXME: NULLSTACK (SCM_VM_DATA (vp)->sp - sp) */
b44f5451 290 vp->sp = sp;
99511cd0 291
b44f5451 292 scm_c_abort (vp, tag, nstack + tail_len, argv, current_registers);
cee1d22c
AW
293}
294
7dba1c2f
AW
295static void vm_expand_stack (struct scm_vm *vp) SCM_NOINLINE;
296
9d381ba4 297static void
44ece399
AW
298vm_reinstate_partial_continuation (struct scm_vm *vp, SCM cont,
299 size_t n, SCM *argv,
9d381ba4
AW
300 scm_t_dynstack *dynstack,
301 scm_i_jmp_buf *registers)
cee1d22c 302{
07801437
AW
303 struct scm_vm_cont *cp;
304 SCM *argv_copy, *base;
9ede013f 305 scm_t_ptrdiff reloc;
07801437
AW
306 size_t i;
307
308 argv_copy = alloca (n * sizeof(SCM));
309 memcpy (argv_copy, argv, n * sizeof(SCM));
310
07801437 311 cp = SCM_VM_CONT_DATA (cont);
7dba1c2f
AW
312
313 while (1)
314 {
315 scm_t_ptrdiff saved_stack_height = vp->sp - vp->stack_base;
316
317 base = SCM_FRAME_LOCALS_ADDRESS (vp->fp);
318 reloc = cp->reloc + (base - cp->stack_base);
319
320 vp->sp = base + cp->stack_size + n + 1;
321 if (vp->sp < vp->stack_limit)
322 break;
323
324 vm_expand_stack (vp);
325 vp->sp = vp->stack_base + saved_stack_height;
326 }
07801437 327
0fc9040f 328#define RELOC(scm_p) \
9ede013f 329 (((SCM *) (scm_p)) + reloc)
07801437 330
07801437
AW
331 memcpy (base, cp->stack_base, cp->stack_size * sizeof (SCM));
332
333 /* now relocate frame pointers */
334 {
335 SCM *fp;
336 for (fp = RELOC (cp->fp);
337 SCM_FRAME_LOWER_ADDRESS (fp) > base;
338 fp = SCM_FRAME_DYNAMIC_LINK (fp))
339 SCM_FRAME_SET_DYNAMIC_LINK (fp, RELOC (SCM_FRAME_DYNAMIC_LINK (fp)));
340 }
341
342 vp->sp = base - 1 + cp->stack_size;
343 vp->fp = RELOC (cp->fp);
840ec334 344 vp->ip = cp->ra;
07801437 345
840ec334 346 /* Push the arguments. */
07801437
AW
347 for (i = 0; i < n; i++)
348 {
349 vp->sp++;
350 *vp->sp = argv_copy[i];
351 }
9a1c6f1f 352
7dba1c2f
AW
353 if (vp->sp > vp->sp_max_since_gc)
354 vp->sp_max_since_gc = vp->sp;
355
9d381ba4
AW
356 /* The prompt captured a slice of the dynamic stack. Here we wind
357 those entries onto the current thread's stack. We also have to
358 relocate any prompts that we see along the way. */
359 {
360 scm_t_bits *walk;
361
362 for (walk = SCM_DYNSTACK_FIRST (cp->dynstack);
363 SCM_DYNSTACK_TAG (walk);
364 walk = SCM_DYNSTACK_NEXT (walk))
365 {
366 scm_t_bits tag = SCM_DYNSTACK_TAG (walk);
367
368 if (SCM_DYNSTACK_TAG_TYPE (tag) == SCM_DYNSTACK_TYPE_PROMPT)
369 scm_dynstack_wind_prompt (dynstack, walk, reloc, registers);
370 else
371 scm_dynstack_wind_1 (dynstack, walk);
372 }
373 }
adbdfd6d 374#undef RELOC
4f66bcde
AW
375}
376
377\f
53bdfcf0
AW
378/*
379 * VM Error Handling
380 */
381
382static void vm_error (const char *msg, SCM arg) SCM_NORETURN;
4d497b62
AW
383static void vm_error_bad_instruction (scm_t_uint32 inst) SCM_NORETURN SCM_NOINLINE;
384static void vm_error_unbound (SCM proc, SCM sym) SCM_NORETURN SCM_NOINLINE;
385static void vm_error_unbound_fluid (SCM proc, SCM fluid) SCM_NORETURN SCM_NOINLINE;
386static void vm_error_not_a_variable (const char *func_name, SCM x) SCM_NORETURN SCM_NOINLINE;
387static void vm_error_apply_to_non_list (SCM x) SCM_NORETURN SCM_NOINLINE;
388static void vm_error_kwargs_length_not_even (SCM proc) SCM_NORETURN SCM_NOINLINE;
28d5d253
MW
389static void vm_error_kwargs_invalid_keyword (SCM proc, SCM obj) SCM_NORETURN SCM_NOINLINE;
390static void vm_error_kwargs_unrecognized_keyword (SCM proc, SCM kw) SCM_NORETURN SCM_NOINLINE;
4d497b62
AW
391static void vm_error_too_many_args (int nargs) SCM_NORETURN SCM_NOINLINE;
392static void vm_error_wrong_num_args (SCM proc) SCM_NORETURN SCM_NOINLINE;
393static void vm_error_wrong_type_apply (SCM proc) SCM_NORETURN SCM_NOINLINE;
4d497b62
AW
394static void vm_error_stack_underflow (void) SCM_NORETURN SCM_NOINLINE;
395static void vm_error_improper_list (SCM x) SCM_NORETURN SCM_NOINLINE;
396static void vm_error_not_a_pair (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
397static void vm_error_not_a_bytevector (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
398static void vm_error_not_a_struct (const char *subr, SCM x) SCM_NORETURN SCM_NOINLINE;
399static void vm_error_no_values (void) SCM_NORETURN SCM_NOINLINE;
400static void vm_error_not_enough_values (void) SCM_NORETURN SCM_NOINLINE;
82f4bac4 401static void vm_error_wrong_number_of_values (scm_t_uint32 expected) SCM_NORETURN SCM_NOINLINE;
4d497b62
AW
402static void vm_error_continuation_not_rewindable (SCM cont) SCM_NORETURN SCM_NOINLINE;
403static void vm_error_bad_wide_string_length (size_t len) SCM_NORETURN SCM_NOINLINE;
53bdfcf0
AW
404
405static void
406vm_error (const char *msg, SCM arg)
407{
408 scm_throw (sym_vm_error,
409 scm_list_3 (sym_vm_run, scm_from_latin1_string (msg),
410 SCM_UNBNDP (arg) ? SCM_EOL : scm_list_1 (arg)));
411 abort(); /* not reached */
412}
413
414static void
415vm_error_bad_instruction (scm_t_uint32 inst)
416{
417 vm_error ("VM: Bad instruction: ~s", scm_from_uint32 (inst));
418}
419
420static void
421vm_error_unbound (SCM proc, SCM sym)
422{
423 scm_error_scm (scm_misc_error_key, proc,
424 scm_from_latin1_string ("Unbound variable: ~s"),
425 scm_list_1 (sym), SCM_BOOL_F);
426}
427
428static void
429vm_error_unbound_fluid (SCM proc, SCM fluid)
430{
431 scm_error_scm (scm_misc_error_key, proc,
432 scm_from_latin1_string ("Unbound fluid: ~s"),
433 scm_list_1 (fluid), SCM_BOOL_F);
434}
435
436static void
437vm_error_not_a_variable (const char *func_name, SCM x)
438{
439 scm_error (scm_arg_type_key, func_name, "Not a variable: ~S",
440 scm_list_1 (x), scm_list_1 (x));
441}
442
53bdfcf0
AW
443static void
444vm_error_apply_to_non_list (SCM x)
445{
446 scm_error (scm_arg_type_key, "apply", "Apply to non-list: ~S",
447 scm_list_1 (x), scm_list_1 (x));
448}
449
450static void
451vm_error_kwargs_length_not_even (SCM proc)
452{
453 scm_error_scm (sym_keyword_argument_error, proc,
454 scm_from_latin1_string ("Odd length of keyword argument list"),
455 SCM_EOL, SCM_BOOL_F);
456}
457
458static void
4af0d97e 459vm_error_kwargs_invalid_keyword (SCM proc, SCM obj)
53bdfcf0
AW
460{
461 scm_error_scm (sym_keyword_argument_error, proc,
462 scm_from_latin1_string ("Invalid keyword"),
4af0d97e 463 SCM_EOL, scm_list_1 (obj));
53bdfcf0
AW
464}
465
466static void
4af0d97e 467vm_error_kwargs_unrecognized_keyword (SCM proc, SCM kw)
53bdfcf0
AW
468{
469 scm_error_scm (sym_keyword_argument_error, proc,
470 scm_from_latin1_string ("Unrecognized keyword"),
4af0d97e 471 SCM_EOL, scm_list_1 (kw));
53bdfcf0
AW
472}
473
474static void
475vm_error_too_many_args (int nargs)
476{
477 vm_error ("VM: Too many arguments", scm_from_int (nargs));
478}
479
480static void
481vm_error_wrong_num_args (SCM proc)
482{
483 scm_wrong_num_args (proc);
484}
485
486static void
487vm_error_wrong_type_apply (SCM proc)
488{
489 scm_error (scm_arg_type_key, NULL, "Wrong type to apply: ~S",
490 scm_list_1 (proc), scm_list_1 (proc));
491}
492
53bdfcf0
AW
493static void
494vm_error_stack_underflow (void)
495{
496 vm_error ("VM: Stack underflow", SCM_UNDEFINED);
497}
498
499static void
500vm_error_improper_list (SCM x)
501{
502 vm_error ("Expected a proper list, but got object with tail ~s", x);
503}
504
505static void
506vm_error_not_a_pair (const char *subr, SCM x)
507{
508 scm_wrong_type_arg_msg (subr, 1, x, "pair");
509}
510
511static void
512vm_error_not_a_bytevector (const char *subr, SCM x)
513{
514 scm_wrong_type_arg_msg (subr, 1, x, "bytevector");
515}
516
517static void
518vm_error_not_a_struct (const char *subr, SCM x)
519{
520 scm_wrong_type_arg_msg (subr, 1, x, "struct");
521}
522
523static void
524vm_error_no_values (void)
525{
526 vm_error ("Zero values returned to single-valued continuation",
527 SCM_UNDEFINED);
528}
529
530static void
531vm_error_not_enough_values (void)
532{
533 vm_error ("Too few values returned to continuation", SCM_UNDEFINED);
534}
535
82f4bac4
AW
536static void
537vm_error_wrong_number_of_values (scm_t_uint32 expected)
538{
539 vm_error ("Wrong number of values returned to continuation (expected ~a)",
540 scm_from_uint32 (expected));
541}
542
53bdfcf0
AW
543static void
544vm_error_continuation_not_rewindable (SCM cont)
545{
546 vm_error ("Unrewindable partial continuation", cont);
547}
548
549static void
550vm_error_bad_wide_string_length (size_t len)
551{
552 vm_error ("VM: Bad wide string length: ~S", scm_from_size_t (len));
553}
554
53bdfcf0
AW
555
556\f
28b119ee 557
ef6b7f71 558static SCM vm_boot_continuation;
486013d6
AW
559static SCM vm_builtin_apply;
560static SCM vm_builtin_values;
561static SCM vm_builtin_abort_to_prompt;
562static SCM vm_builtin_call_with_values;
563static SCM vm_builtin_call_with_current_continuation;
510ca126 564
ef6b7f71 565static const scm_t_uint32 vm_boot_continuation_code[] = {
095100bb 566 SCM_PACK_OP_24 (halt, 0)
510ca126
AW
567};
568
486013d6 569static const scm_t_uint32 vm_builtin_apply_code[] = {
095100bb
AW
570 SCM_PACK_OP_24 (assert_nargs_ge, 3),
571 SCM_PACK_OP_24 (tail_apply, 0), /* proc in r1, args from r2 */
510ca126
AW
572};
573
486013d6 574static const scm_t_uint32 vm_builtin_values_code[] = {
095100bb 575 SCM_PACK_OP_24 (return_values, 0) /* vals from r1 */
510ca126
AW
576};
577
486013d6 578static const scm_t_uint32 vm_builtin_abort_to_prompt_code[] = {
095100bb
AW
579 SCM_PACK_OP_24 (assert_nargs_ge, 2),
580 SCM_PACK_OP_24 (abort, 0), /* tag in r1, vals from r2 */
486013d6 581 /* FIXME: Partial continuation should capture caller regs. */
095100bb 582 SCM_PACK_OP_24 (return_values, 0) /* vals from r1 */
486013d6
AW
583};
584
585static const scm_t_uint32 vm_builtin_call_with_values_code[] = {
095100bb
AW
586 SCM_PACK_OP_24 (assert_nargs_ee, 3),
587 SCM_PACK_OP_24 (alloc_frame, 7),
588 SCM_PACK_OP_12_12 (mov, 6, 1),
589 SCM_PACK_OP_24 (call, 6), SCM_PACK_OP_ARG_8_24 (0, 1),
590 SCM_PACK_OP_12_12 (mov, 0, 2),
591 SCM_PACK_OP_24 (tail_call_shuffle, 7)
486013d6
AW
592};
593
594static const scm_t_uint32 vm_builtin_call_with_current_continuation_code[] = {
095100bb
AW
595 SCM_PACK_OP_24 (assert_nargs_ee, 2),
596 SCM_PACK_OP_24 (call_cc, 0)
486013d6
AW
597};
598
599
600static SCM
601scm_vm_builtin_ref (unsigned idx)
602{
603 switch (idx)
604 {
9f309e2c 605#define INDEX_TO_NAME(builtin, BUILTIN, req, opt, rest) \
486013d6
AW
606 case SCM_VM_BUILTIN_##BUILTIN: return vm_builtin_##builtin;
607 FOR_EACH_VM_BUILTIN(INDEX_TO_NAME)
608#undef INDEX_TO_NAME
609 default: abort();
610 }
611}
612
9f309e2c 613SCM scm_sym_apply;
486013d6
AW
614static SCM scm_sym_values;
615static SCM scm_sym_abort_to_prompt;
616static SCM scm_sym_call_with_values;
617static SCM scm_sym_call_with_current_continuation;
618
619SCM
620scm_vm_builtin_name_to_index (SCM name)
621#define FUNC_NAME "builtin-name->index"
622{
623 SCM_VALIDATE_SYMBOL (1, name);
624
9f309e2c 625#define NAME_TO_INDEX(builtin, BUILTIN, req, opt, rest) \
486013d6
AW
626 if (scm_is_eq (name, scm_sym_##builtin)) \
627 return scm_from_uint (SCM_VM_BUILTIN_##BUILTIN);
628 FOR_EACH_VM_BUILTIN(NAME_TO_INDEX)
629#undef NAME_TO_INDEX
630
631 return SCM_BOOL_F;
632}
633#undef FUNC_NAME
634
635SCM
636scm_vm_builtin_index_to_name (SCM index)
637#define FUNC_NAME "builtin-index->name"
638{
639 unsigned idx;
640
641 SCM_VALIDATE_UINT_COPY (1, index, idx);
642
643 switch (idx)
644 {
9f309e2c 645#define INDEX_TO_NAME(builtin, BUILTIN, req, opt, rest) \
486013d6
AW
646 case SCM_VM_BUILTIN_##BUILTIN: return scm_sym_##builtin;
647 FOR_EACH_VM_BUILTIN(INDEX_TO_NAME)
648#undef INDEX_TO_NAME
649 default: return SCM_BOOL_F;
650 }
651}
652#undef FUNC_NAME
653
654static void
655scm_init_vm_builtins (void)
656{
486013d6
AW
657 scm_c_define_gsubr ("builtin-name->index", 1, 0, 0,
658 scm_vm_builtin_name_to_index);
659 scm_c_define_gsubr ("builtin-index->name", 1, 0, 0,
660 scm_vm_builtin_index_to_name);
661}
662
663SCM
664scm_i_call_with_current_continuation (SCM proc)
665{
666 return scm_call_1 (vm_builtin_call_with_current_continuation, proc);
667}
510ca126 668
a98cef7e
KN
669\f
670/*
671 * VM
672 */
673
22d425ec
AW
674/* Hard stack limit is 512M words: 2 gigabytes on 32-bit machines, 4 on
675 64-bit machines. */
676static const size_t hard_max_stack_size = 512 * 1024 * 1024;
677
678/* Initial stack size: 4 or 8 kB. */
679static const size_t initial_stack_size = 1024;
680
681/* Default soft stack limit is 1M words (4 or 8 megabytes). */
682static size_t default_max_stack_size = 1024 * 1024;
aab9d46c
SIT
683
684static void
685initialize_default_stack_size (void)
686{
22d425ec
AW
687 int size = scm_getenv_int ("GUILE_STACK_SIZE", (int) default_max_stack_size);
688 if (size >= initial_stack_size && (size_t) size < ((size_t) -1) / sizeof(SCM))
689 default_max_stack_size = size;
aab9d46c 690}
17e90c5e 691
f42cfbf0
AW
692#define VM_NAME vm_regular_engine
693#define VM_USE_HOOKS 0
6d14383e 694#define FUNC_NAME "vm-regular-engine"
83495480 695#include "vm-engine.c"
6d14383e 696#undef FUNC_NAME
f42cfbf0
AW
697#undef VM_USE_HOOKS
698#undef VM_NAME
17e90c5e 699
f42cfbf0
AW
700#define VM_NAME vm_debug_engine
701#define VM_USE_HOOKS 1
6d14383e 702#define FUNC_NAME "vm-debug-engine"
83495480 703#include "vm-engine.c"
6d14383e 704#undef FUNC_NAME
f42cfbf0
AW
705#undef VM_USE_HOOKS
706#undef VM_NAME
17e90c5e 707
dd1c7dec
AW
708typedef SCM (*scm_t_vm_engine) (scm_i_thread *current_thread, struct scm_vm *vp,
709 scm_i_jmp_buf *registers, int resume);
73c3db66 710
f42cfbf0
AW
711static const scm_t_vm_engine vm_engines[SCM_VM_NUM_ENGINES] =
712 { vm_regular_engine, vm_debug_engine };
73c3db66 713
5f18bc84
AW
714static SCM*
715allocate_stack (size_t size)
716#define FUNC_NAME "make_vm"
717{
718 void *ret;
e3eb628d 719
5f18bc84
AW
720 if (size >= ((size_t) -1) / sizeof (SCM))
721 abort ();
722
723 size *= sizeof (SCM);
e3eb628d 724
5f18bc84
AW
725#if HAVE_SYS_MMAN_H
726 ret = mmap (NULL, size, PROT_READ | PROT_WRITE,
727 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
728 if (ret == MAP_FAILED)
729 SCM_SYSERROR;
730#else
731 ret = malloc (size);
732 if (!ret)
733 SCM_SYSERROR;
e3eb628d
LC
734#endif
735
5f18bc84
AW
736 return (SCM *) ret;
737}
738#undef FUNC_NAME
739
740static void
741free_stack (SCM *stack, size_t size)
742{
743 size *= sizeof (SCM);
744
745#if HAVE_SYS_MMAN_H
746 munmap (stack, size);
747#else
748 free (stack);
749#endif
750}
751
22d425ec
AW
752static SCM*
753expand_stack (SCM *old_stack, size_t old_size, size_t new_size)
754#define FUNC_NAME "expand_stack"
755{
756#if defined MREMAP_MAYMOVE
757 void *new_stack;
758
759 if (new_size >= ((size_t) -1) / sizeof (SCM))
760 abort ();
761
762 old_size *= sizeof (SCM);
763 new_size *= sizeof (SCM);
764
765 new_stack = mremap (old_stack, old_size, new_size, MREMAP_MAYMOVE);
766 if (new_stack == MAP_FAILED)
767 SCM_SYSERROR;
768
769 return (SCM *) new_stack;
770#else
771 SCM *new_stack;
772
773 new_stack = allocate_stack (new_size);
774 memcpy (new_stack, old_stack, old_size * sizeof (SCM));
775 free_stack (old_stack, old_size);
776
777 return new_stack;
778#endif
779}
780#undef FUNC_NAME
781
3506b152 782static struct scm_vm *
17e90c5e
KN
783make_vm (void)
784#define FUNC_NAME "make_vm"
a98cef7e 785{
17e90c5e 786 int i;
7f991c7d 787 struct scm_vm *vp;
747a1635 788
7f991c7d 789 vp = scm_gc_malloc (sizeof (struct scm_vm), "vm");
d8eeb67c 790
22d425ec 791 vp->stack_size = initial_stack_size;
5f18bc84 792 vp->stack_base = allocate_stack (vp->stack_size);
22d425ec
AW
793 vp->stack_limit = vp->stack_base + vp->stack_size;
794 vp->max_stack_size = default_max_stack_size;
3616e9e9
KN
795 vp->ip = NULL;
796 vp->sp = vp->stack_base - 1;
797 vp->fp = NULL;
ea9f4f4b 798 vp->engine = vm_default_engine;
7656f194 799 vp->trace_level = 0;
17e90c5e 800 for (i = 0; i < SCM_VM_NUM_HOOKS; i++)
3d5ee0cd 801 vp->hooks[i] = SCM_BOOL_F;
3506b152
AW
802
803 return vp;
a98cef7e 804}
17e90c5e 805#undef FUNC_NAME
a98cef7e 806
7dba1c2f
AW
807static size_t page_size;
808
809static void
810return_unused_stack_to_os (struct scm_vm *vp)
811{
812#if HAVE_SYS_MMAN_H
813 scm_t_uintptr start = (scm_t_uintptr) vp->sp;
814 scm_t_uintptr end = (scm_t_uintptr) vp->sp_max_since_gc;
815
816 start = ((start - 1U) | (page_size - 1U)) + 1U; /* round up */
817 end = ((end - 1U) | (page_size - 1U)) + 1U; /* round up */
818
819 /* Return these pages to the OS. The next time they are paged in,
820 they will be zeroed. */
821 if (start < end)
822 madvise ((void *) start, end - start, MADV_DONTNEED);
823
824 vp->sp_max_since_gc = vp->sp;
825#endif
826}
827
40719006
AW
828#define DEAD_SLOT_MAP_CACHE_SIZE 32U
829struct dead_slot_map_cache_entry
830{
831 scm_t_uint32 *ip;
832 const scm_t_uint8 *map;
833};
834
835struct dead_slot_map_cache
836{
837 struct dead_slot_map_cache_entry entries[DEAD_SLOT_MAP_CACHE_SIZE];
838};
839
840static const scm_t_uint8 *
841find_dead_slot_map (scm_t_uint32 *ip, struct dead_slot_map_cache *cache)
842{
843 /* The lower two bits should be zero. FIXME: Use a better hash
844 function; we don't expose scm_raw_hashq currently. */
845 size_t slot = (((scm_t_uintptr) ip) >> 2) % DEAD_SLOT_MAP_CACHE_SIZE;
846 const scm_t_uint8 *map;
847
848 if (cache->entries[slot].ip == ip)
849 map = cache->entries[slot].map;
850 else
851 {
852 map = scm_find_dead_slot_map_unlocked (ip);
853 cache->entries[slot].ip = ip;
854 cache->entries[slot].map = map;
855 }
856
857 return map;
858}
859
e3eb628d 860/* Mark the VM stack region between its base and its current top. */
5f18bc84
AW
861struct GC_ms_entry *
862scm_i_vm_mark_stack (struct scm_vm *vp, struct GC_ms_entry *mark_stack_ptr,
863 struct GC_ms_entry *mark_stack_limit)
e3eb628d 864{
1cdf9b78 865 SCM *sp, *fp;
02c624fc
AW
866 /* The first frame will be marked conservatively (without a dead
867 slot map). This is because GC can happen at any point within the
868 hottest activation, due to multiple threads or per-instruction
869 hooks, and providing dead slot maps for all points in a program
870 would take a prohibitive amount of space. */
871 const scm_t_uint8 *dead_slots = NULL;
7161ec11
AW
872 scm_t_uintptr upper = (scm_t_uintptr) GC_greatest_plausible_heap_addr;
873 scm_t_uintptr lower = (scm_t_uintptr) GC_least_plausible_heap_addr;
40719006
AW
874 struct dead_slot_map_cache cache;
875
876 memset (&cache, 0, sizeof (cache));
e3eb628d 877
1cdf9b78
AW
878 for (fp = vp->fp, sp = vp->sp; fp; fp = SCM_FRAME_DYNAMIC_LINK (fp))
879 {
880 for (; sp >= &SCM_FRAME_LOCAL (fp, 0); sp--)
881 {
882 SCM elt = *sp;
7161ec11
AW
883 if (SCM_NIMP (elt)
884 && SCM_UNPACK (elt) >= lower && SCM_UNPACK (elt) <= upper)
02c624fc
AW
885 {
886 if (dead_slots)
887 {
888 size_t slot = sp - &SCM_FRAME_LOCAL (fp, 0);
889 if (dead_slots[slot / 8U] & (1U << (slot % 8U)))
890 {
891 /* This value may become dead as a result of GC,
892 so we can't just leave it on the stack. */
893 *sp = SCM_UNBOUND;
894 continue;
895 }
896 }
897
7161ec11 898 mark_stack_ptr = GC_mark_and_push ((void *) elt,
02c624fc
AW
899 mark_stack_ptr,
900 mark_stack_limit,
901 NULL);
902 }
1cdf9b78
AW
903 }
904 sp = SCM_FRAME_PREVIOUS_SP (fp);
02c624fc
AW
905 /* Inner frames may have a dead slots map for precise marking.
906 Note that there may be other reasons to not have a dead slots
907 map, e.g. if all of the frame's slots below the callee frame
908 are live. */
40719006 909 dead_slots = find_dead_slot_map (SCM_FRAME_RETURN_ADDRESS (fp), &cache);
1cdf9b78 910 }
e3eb628d 911
7dba1c2f
AW
912 return_unused_stack_to_os (vp);
913
e3eb628d
LC
914 return mark_stack_ptr;
915}
916
5f18bc84
AW
917/* Free the VM stack, as this thread is exiting. */
918void
919scm_i_vm_free_stack (struct scm_vm *vp)
920{
921 free_stack (vp->stack_base, vp->stack_size);
922 vp->stack_base = vp->stack_limit = NULL;
923 vp->stack_size = 0;
924}
e3eb628d 925
22d425ec
AW
926static void
927vm_expand_stack (struct scm_vm *vp)
928{
929 scm_t_ptrdiff stack_size = vp->sp + 1 - vp->stack_base;
930
931 if (stack_size > hard_max_stack_size)
932 {
933 /* We have expanded the soft limit to the point that we reached a
934 hard limit. There is nothing sensible to do. */
935 fprintf (stderr, "Hard stack size limit (%zu words) reached; aborting.\n",
936 hard_max_stack_size);
937 abort ();
938 }
939
940 if (stack_size > vp->stack_size)
941 {
942 SCM *old_stack;
943 size_t new_size;
944 scm_t_ptrdiff reloc;
945
946 new_size = vp->stack_size;
947 while (new_size < stack_size)
948 new_size *= 2;
949 old_stack = vp->stack_base;
950 vp->stack_base = expand_stack (old_stack, vp->stack_size, new_size);
951 vp->stack_size = new_size;
952 vp->stack_limit = vp->stack_base + new_size;
953 reloc = vp->stack_base - old_stack;
954
955 if (reloc)
956 {
957 SCM *fp;
958 vp->fp += reloc;
959 vp->sp += reloc;
7dba1c2f 960 vp->sp_max_since_gc += reloc;
22d425ec
AW
961 fp = vp->fp;
962 while (fp)
963 {
964 SCM *next_fp = SCM_FRAME_DYNAMIC_LINK (fp);
965 if (next_fp)
966 {
967 next_fp += reloc;
968 SCM_FRAME_SET_DYNAMIC_LINK (fp, next_fp);
969 }
970 fp = next_fp;
971 }
972 }
973 }
974
975 if (stack_size >= vp->max_stack_size)
976 {
977 /* Expand the soft limit by 256K entries to give us space to
978 handle the error. */
979 vp->max_stack_size += 256 * 1024;
980
981 /* If it's still not big enough... it's quite improbable, but go
982 ahead and set to the full available stack size. */
983 if (vp->max_stack_size < stack_size)
984 vp->max_stack_size = vp->stack_size;
985
986 /* But don't exceed the hard maximum. */
987 if (vp->max_stack_size > hard_max_stack_size)
988 vp->max_stack_size = hard_max_stack_size;
989
990 /* Finally, reset the limit, to catch further overflows. */
991 vp->stack_limit = vp->stack_base + vp->max_stack_size;
992
993 vm_error ("VM: Stack overflow", SCM_UNDEFINED);
994 }
995
996 /* Otherwise continue, with the new enlarged stack. */
997}
998
b85cd20f
AW
999static struct scm_vm *
1000thread_vm (scm_i_thread *t)
55ee3607 1001{
b85cd20f
AW
1002 if (SCM_UNLIKELY (!t->vp))
1003 t->vp = make_vm ();
1004
1005 return t->vp;
55ee3607
AW
1006}
1007
e7f9abab 1008struct scm_vm *
a222cbc9 1009scm_the_vm (void)
271c3d31 1010{
b85cd20f
AW
1011 return thread_vm (SCM_I_CURRENT_THREAD);
1012}
ea9f4f4b 1013
b85cd20f
AW
1014SCM
1015scm_call_n (SCM proc, SCM *argv, size_t nargs)
1016{
1017 scm_i_thread *thread;
1018 struct scm_vm *vp;
bd63e5b2
AW
1019 SCM *base;
1020 ptrdiff_t base_frame_size;
dd1c7dec
AW
1021 /* Cached variables. */
1022 scm_i_jmp_buf registers; /* used for prompts */
bd63e5b2 1023 size_t i;
ea9f4f4b 1024
b85cd20f
AW
1025 thread = SCM_I_CURRENT_THREAD;
1026 vp = thread_vm (thread);
1027
1028 SCM_CHECK_STACK;
bd63e5b2
AW
1029
1030 /* Check that we have enough space: 3 words for the boot
1031 continuation, 3 + nargs for the procedure application, and 3 for
1032 setting up a new frame. */
1033 base_frame_size = 3 + 3 + nargs + 3;
1034 vp->sp += base_frame_size;
1035 if (vp->sp >= vp->stack_limit)
22d425ec 1036 vm_expand_stack (vp);
bd63e5b2
AW
1037 base = vp->sp + 1 - base_frame_size;
1038
1039 /* Since it's possible to receive the arguments on the stack itself,
1040 shuffle up the arguments first. */
1041 for (i = nargs; i > 0; i--)
1042 base[6 + i - 1] = argv[i - 1];
1043
1044 /* Push the boot continuation, which calls PROC and returns its
1045 result(s). */
1046 base[0] = SCM_PACK (vp->fp); /* dynamic link */
1047 base[1] = SCM_PACK (vp->ip); /* ra */
1048 base[2] = vm_boot_continuation;
1049 vp->fp = &base[2];
1050 vp->ip = (scm_t_uint32 *) vm_boot_continuation_code;
1051
1052 /* The pending call to PROC. */
1053 base[3] = SCM_PACK (vp->fp); /* dynamic link */
1054 base[4] = SCM_PACK (vp->ip); /* ra */
1055 base[5] = proc;
1056 vp->fp = &base[5];
1057 vp->sp = &SCM_FRAME_LOCAL (vp->fp, nargs);
1058
7dba1c2f
AW
1059 if (vp->sp > vp->sp_max_since_gc)
1060 vp->sp_max_since_gc = vp->sp;
1061
dd1c7dec
AW
1062 {
1063 int resume = SCM_I_SETJMP (registers);
1064
1065 if (SCM_UNLIKELY (resume))
1066 /* Non-local return. */
1067 vm_dispatch_abort_hook (vp);
1068
1069 return vm_engines[vp->engine](thread, vp, &registers, resume);
1070 }
271c3d31 1071}
499a4c07 1072
a222cbc9 1073/* Scheme interface */
a98cef7e 1074
17e90c5e
KN
1075#define VM_DEFINE_HOOK(n) \
1076{ \
3d5ee0cd 1077 struct scm_vm *vp; \
e7f9abab 1078 vp = scm_the_vm (); \
8b22ed7a 1079 if (scm_is_false (vp->hooks[n])) \
238e7a11 1080 vp->hooks[n] = scm_make_hook (SCM_I_MAKINUM (1)); \
3d5ee0cd 1081 return vp->hooks[n]; \
17e90c5e
KN
1082}
1083
972275ee
AW
1084SCM_DEFINE (scm_vm_apply_hook, "vm-apply-hook", 0, 0, 0,
1085 (void),
17e90c5e 1086 "")
c45d4d77 1087#define FUNC_NAME s_scm_vm_apply_hook
a98cef7e 1088{
c45d4d77 1089 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK);
a98cef7e
KN
1090}
1091#undef FUNC_NAME
1092
972275ee
AW
1093SCM_DEFINE (scm_vm_push_continuation_hook, "vm-push-continuation-hook", 0, 0, 0,
1094 (void),
17e90c5e 1095 "")
c45d4d77 1096#define FUNC_NAME s_scm_vm_push_continuation_hook
a98cef7e 1097{
c45d4d77 1098 VM_DEFINE_HOOK (SCM_VM_PUSH_CONTINUATION_HOOK);
a98cef7e
KN
1099}
1100#undef FUNC_NAME
1101
972275ee
AW
1102SCM_DEFINE (scm_vm_pop_continuation_hook, "vm-pop-continuation-hook", 0, 0, 0,
1103 (void),
17e90c5e 1104 "")
c45d4d77 1105#define FUNC_NAME s_scm_vm_pop_continuation_hook
a98cef7e 1106{
c45d4d77 1107 VM_DEFINE_HOOK (SCM_VM_POP_CONTINUATION_HOOK);
a98cef7e
KN
1108}
1109#undef FUNC_NAME
1110
972275ee
AW
1111SCM_DEFINE (scm_vm_next_hook, "vm-next-hook", 0, 0, 0,
1112 (void),
17e90c5e 1113 "")
c45d4d77 1114#define FUNC_NAME s_scm_vm_next_hook
a98cef7e 1115{
c45d4d77 1116 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK);
a98cef7e
KN
1117}
1118#undef FUNC_NAME
f3120251 1119
972275ee
AW
1120SCM_DEFINE (scm_vm_abort_continuation_hook, "vm-abort-continuation-hook", 0, 0, 0,
1121 (void),
f3120251
AW
1122 "")
1123#define FUNC_NAME s_scm_vm_abort_continuation_hook
1124{
1125 VM_DEFINE_HOOK (SCM_VM_ABORT_CONTINUATION_HOOK);
1126}
1127#undef FUNC_NAME
1128
972275ee
AW
1129SCM_DEFINE (scm_vm_trace_level, "vm-trace-level", 0, 0, 0,
1130 (void),
17e90c5e 1131 "")
7656f194 1132#define FUNC_NAME s_scm_vm_trace_level
a98cef7e 1133{
e7f9abab 1134 return scm_from_int (scm_the_vm ()->trace_level);
7656f194
AW
1135}
1136#undef FUNC_NAME
1137
972275ee
AW
1138SCM_DEFINE (scm_set_vm_trace_level_x, "set-vm-trace-level!", 1, 0, 0,
1139 (SCM level),
7656f194
AW
1140 "")
1141#define FUNC_NAME s_scm_set_vm_trace_level_x
1142{
e7f9abab 1143 scm_the_vm ()->trace_level = scm_to_int (level);
7656f194 1144 return SCM_UNSPECIFIED;
a98cef7e
KN
1145}
1146#undef FUNC_NAME
1147
1148\f
ea9f4f4b
AW
1149/*
1150 * VM engines
1151 */
1152
1153static int
1154symbol_to_vm_engine (SCM engine, const char *FUNC_NAME)
1155{
1156 if (scm_is_eq (engine, sym_regular))
1157 return SCM_VM_REGULAR_ENGINE;
1158 else if (scm_is_eq (engine, sym_debug))
1159 return SCM_VM_DEBUG_ENGINE;
1160 else
1161 SCM_MISC_ERROR ("Unknown VM engine: ~a", scm_list_1 (engine));
1162}
1163
1164static SCM
1165vm_engine_to_symbol (int engine, const char *FUNC_NAME)
1166{
1167 switch (engine)
1168 {
1169 case SCM_VM_REGULAR_ENGINE:
1170 return sym_regular;
1171 case SCM_VM_DEBUG_ENGINE:
1172 return sym_debug;
1173 default:
1174 /* ? */
1175 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1176 scm_list_1 (scm_from_int (engine)));
1177 }
1178}
1179
972275ee
AW
1180SCM_DEFINE (scm_vm_engine, "vm-engine", 0, 0, 0,
1181 (void),
ea9f4f4b
AW
1182 "")
1183#define FUNC_NAME s_scm_vm_engine
1184{
e7f9abab 1185 return vm_engine_to_symbol (scm_the_vm ()->engine, FUNC_NAME);
ea9f4f4b
AW
1186}
1187#undef FUNC_NAME
1188
1189void
972275ee 1190scm_c_set_vm_engine_x (int engine)
ea9f4f4b
AW
1191#define FUNC_NAME "set-vm-engine!"
1192{
ea9f4f4b
AW
1193 if (engine < 0 || engine >= SCM_VM_NUM_ENGINES)
1194 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1195 scm_list_1 (scm_from_int (engine)));
1196
e7f9abab 1197 scm_the_vm ()->engine = engine;
ea9f4f4b
AW
1198}
1199#undef FUNC_NAME
1200
972275ee
AW
1201SCM_DEFINE (scm_set_vm_engine_x, "set-vm-engine!", 1, 0, 0,
1202 (SCM engine),
ea9f4f4b
AW
1203 "")
1204#define FUNC_NAME s_scm_set_vm_engine_x
1205{
972275ee 1206 scm_c_set_vm_engine_x (symbol_to_vm_engine (engine, FUNC_NAME));
ea9f4f4b
AW
1207 return SCM_UNSPECIFIED;
1208}
1209#undef FUNC_NAME
1210
1211void
1212scm_c_set_default_vm_engine_x (int engine)
1213#define FUNC_NAME "set-default-vm-engine!"
1214{
1215 if (engine < 0 || engine >= SCM_VM_NUM_ENGINES)
1216 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1217 scm_list_1 (scm_from_int (engine)));
1218
1219 vm_default_engine = engine;
1220}
1221#undef FUNC_NAME
1222
1223SCM_DEFINE (scm_set_default_vm_engine_x, "set-default-vm-engine!", 1, 0, 0,
1224 (SCM engine),
1225 "")
1226#define FUNC_NAME s_scm_set_default_vm_engine_x
1227{
1228 scm_c_set_default_vm_engine_x (symbol_to_vm_engine (engine, FUNC_NAME));
1229 return SCM_UNSPECIFIED;
1230}
1231#undef FUNC_NAME
1232
972275ee
AW
1233/* FIXME: This function makes no sense, but we keep it to make sure we
1234 have a way of switching to the debug or regular VM. */
1235SCM_DEFINE (scm_call_with_vm, "call-with-vm", 1, 0, 1,
1236 (SCM proc, SCM args),
ea9f4f4b 1237 "Apply @var{proc} to @var{args} in a dynamic extent in which\n"
972275ee 1238 "@var{vm} is the current VM.")
ea9f4f4b
AW
1239#define FUNC_NAME s_scm_call_with_vm
1240{
972275ee 1241 return scm_apply_0 (proc, args);
ea9f4f4b
AW
1242}
1243#undef FUNC_NAME
1244
1245\f
a98cef7e 1246/*
17e90c5e 1247 * Initialize
a98cef7e
KN
1248 */
1249
55ee3607
AW
1250SCM
1251scm_load_compiled_with_vm (SCM file)
07e56b27 1252{
55ee3607 1253 return scm_call_0 (scm_load_thunk_from_file (file));
07e56b27
AW
1254}
1255
67b699cc 1256
9f309e2c
AW
1257void
1258scm_init_vm_builtin_properties (void)
1259{
1260 /* FIXME: Seems hacky to do this here, but oh well :/ */
1261 scm_sym_apply = scm_from_utf8_symbol ("apply");
1262 scm_sym_values = scm_from_utf8_symbol ("values");
1263 scm_sym_abort_to_prompt = scm_from_utf8_symbol ("abort-to-prompt");
1264 scm_sym_call_with_values = scm_from_utf8_symbol ("call-with-values");
1265 scm_sym_call_with_current_continuation =
1266 scm_from_utf8_symbol ("call-with-current-continuation");
1267
1268#define INIT_BUILTIN(builtin, BUILTIN, req, opt, rest) \
1269 scm_set_procedure_property_x (vm_builtin_##builtin, scm_sym_name, \
1270 scm_sym_##builtin); \
1271 scm_set_procedure_minimum_arity_x (vm_builtin_##builtin, \
1272 SCM_I_MAKINUM (req), \
1273 SCM_I_MAKINUM (opt), \
1274 scm_from_bool (rest));
1275 FOR_EACH_VM_BUILTIN (INIT_BUILTIN);
1276#undef INIT_BUILTIN
1277}
1278
17e90c5e 1279void
07e56b27 1280scm_bootstrap_vm (void)
17e90c5e 1281{
44602b08
AW
1282 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1283 "scm_init_vm",
60ae5ca2 1284 (scm_t_extension_init_func)scm_init_vm, NULL);
486013d6
AW
1285 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1286 "scm_init_vm_builtins",
1287 (scm_t_extension_init_func)scm_init_vm_builtins,
1288 NULL);
60ae5ca2 1289
7dba1c2f
AW
1290 page_size = getpagesize ();
1291 /* page_size should be a power of two. */
1292 if (page_size & (page_size - 1))
1293 abort ();
1294
aab9d46c
SIT
1295 initialize_default_stack_size ();
1296
4a655e50
AW
1297 sym_vm_run = scm_from_latin1_symbol ("vm-run");
1298 sym_vm_error = scm_from_latin1_symbol ("vm-error");
1299 sym_keyword_argument_error = scm_from_latin1_symbol ("keyword-argument-error");
1300 sym_regular = scm_from_latin1_symbol ("regular");
1301 sym_debug = scm_from_latin1_symbol ("debug");
0404c97d 1302
ef6b7f71
AW
1303 vm_boot_continuation = scm_i_make_program (vm_boot_continuation_code);
1304 SCM_SET_CELL_WORD_0 (vm_boot_continuation,
1305 (SCM_CELL_WORD_0 (vm_boot_continuation)
73c3db66 1306 | SCM_F_PROGRAM_IS_BOOT));
9f309e2c
AW
1307
1308#define DEFINE_BUILTIN(builtin, BUILTIN, req, opt, rest) \
80797145 1309 vm_builtin_##builtin = scm_i_make_program (vm_builtin_##builtin##_code);
9f309e2c
AW
1310 FOR_EACH_VM_BUILTIN (DEFINE_BUILTIN);
1311#undef DEFINE_BUILTIN
07e56b27
AW
1312}
1313
1314void
1315scm_init_vm (void)
1316{
17e90c5e 1317#ifndef SCM_MAGIC_SNARFER
aeeff258 1318#include "libguile/vm.x"
17e90c5e 1319#endif
a98cef7e 1320}
17e90c5e
KN
1321
1322/*
1323 Local Variables:
1324 c-file-style: "gnu"
1325 End:
1326*/