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