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