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