Fix "VM never extends vp->sp ..." commit
[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;
2a62eda8 1021 new_sp += 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 }
1034 }
1035
2a62eda8
AW
1036 vp->sp_max_since_gc = vp->sp = new_sp;
1037
22d425ec
AW
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. */
1058}
1059
b85cd20f
AW
1060static struct scm_vm *
1061thread_vm (scm_i_thread *t)
55ee3607 1062{
b85cd20f
AW
1063 if (SCM_UNLIKELY (!t->vp))
1064 t->vp = make_vm ();
1065
1066 return t->vp;
55ee3607
AW
1067}
1068
e7f9abab 1069struct scm_vm *
a222cbc9 1070scm_the_vm (void)
271c3d31 1071{
b85cd20f
AW
1072 return thread_vm (SCM_I_CURRENT_THREAD);
1073}
ea9f4f4b 1074
b85cd20f
AW
1075SCM
1076scm_call_n (SCM proc, SCM *argv, size_t nargs)
1077{
1078 scm_i_thread *thread;
1079 struct scm_vm *vp;
bd63e5b2
AW
1080 SCM *base;
1081 ptrdiff_t base_frame_size;
dd1c7dec
AW
1082 /* Cached variables. */
1083 scm_i_jmp_buf registers; /* used for prompts */
bd63e5b2 1084 size_t i;
ea9f4f4b 1085
b85cd20f
AW
1086 thread = SCM_I_CURRENT_THREAD;
1087 vp = thread_vm (thread);
1088
1089 SCM_CHECK_STACK;
bd63e5b2 1090
b914b236
AW
1091 /* Check that we have enough space: 3 words for the boot continuation,
1092 and 3 + nargs for the procedure application. */
1093 base_frame_size = 3 + 3 + nargs;
1094 vm_push_sp (vp, vp->sp + base_frame_size);
bd63e5b2
AW
1095 base = vp->sp + 1 - base_frame_size;
1096
1097 /* Since it's possible to receive the arguments on the stack itself,
1098 shuffle up the arguments first. */
1099 for (i = nargs; i > 0; i--)
1100 base[6 + i - 1] = argv[i - 1];
1101
1102 /* Push the boot continuation, which calls PROC and returns its
1103 result(s). */
1104 base[0] = SCM_PACK (vp->fp); /* dynamic link */
1105 base[1] = SCM_PACK (vp->ip); /* ra */
1106 base[2] = vm_boot_continuation;
1107 vp->fp = &base[2];
1108 vp->ip = (scm_t_uint32 *) vm_boot_continuation_code;
1109
1110 /* The pending call to PROC. */
1111 base[3] = SCM_PACK (vp->fp); /* dynamic link */
1112 base[4] = SCM_PACK (vp->ip); /* ra */
1113 base[5] = proc;
1114 vp->fp = &base[5];
7dba1c2f 1115
dd1c7dec
AW
1116 {
1117 int resume = SCM_I_SETJMP (registers);
1118
1119 if (SCM_UNLIKELY (resume))
1120 /* Non-local return. */
1121 vm_dispatch_abort_hook (vp);
1122
1123 return vm_engines[vp->engine](thread, vp, &registers, resume);
1124 }
271c3d31 1125}
499a4c07 1126
a222cbc9 1127/* Scheme interface */
a98cef7e 1128
17e90c5e
KN
1129#define VM_DEFINE_HOOK(n) \
1130{ \
3d5ee0cd 1131 struct scm_vm *vp; \
e7f9abab 1132 vp = scm_the_vm (); \
8b22ed7a 1133 if (scm_is_false (vp->hooks[n])) \
238e7a11 1134 vp->hooks[n] = scm_make_hook (SCM_I_MAKINUM (1)); \
3d5ee0cd 1135 return vp->hooks[n]; \
17e90c5e
KN
1136}
1137
972275ee
AW
1138SCM_DEFINE (scm_vm_apply_hook, "vm-apply-hook", 0, 0, 0,
1139 (void),
17e90c5e 1140 "")
c45d4d77 1141#define FUNC_NAME s_scm_vm_apply_hook
a98cef7e 1142{
c45d4d77 1143 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK);
a98cef7e
KN
1144}
1145#undef FUNC_NAME
1146
972275ee
AW
1147SCM_DEFINE (scm_vm_push_continuation_hook, "vm-push-continuation-hook", 0, 0, 0,
1148 (void),
17e90c5e 1149 "")
c45d4d77 1150#define FUNC_NAME s_scm_vm_push_continuation_hook
a98cef7e 1151{
c45d4d77 1152 VM_DEFINE_HOOK (SCM_VM_PUSH_CONTINUATION_HOOK);
a98cef7e
KN
1153}
1154#undef FUNC_NAME
1155
972275ee
AW
1156SCM_DEFINE (scm_vm_pop_continuation_hook, "vm-pop-continuation-hook", 0, 0, 0,
1157 (void),
17e90c5e 1158 "")
c45d4d77 1159#define FUNC_NAME s_scm_vm_pop_continuation_hook
a98cef7e 1160{
c45d4d77 1161 VM_DEFINE_HOOK (SCM_VM_POP_CONTINUATION_HOOK);
a98cef7e
KN
1162}
1163#undef FUNC_NAME
1164
972275ee
AW
1165SCM_DEFINE (scm_vm_next_hook, "vm-next-hook", 0, 0, 0,
1166 (void),
17e90c5e 1167 "")
c45d4d77 1168#define FUNC_NAME s_scm_vm_next_hook
a98cef7e 1169{
c45d4d77 1170 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK);
a98cef7e
KN
1171}
1172#undef FUNC_NAME
f3120251 1173
972275ee
AW
1174SCM_DEFINE (scm_vm_abort_continuation_hook, "vm-abort-continuation-hook", 0, 0, 0,
1175 (void),
f3120251
AW
1176 "")
1177#define FUNC_NAME s_scm_vm_abort_continuation_hook
1178{
1179 VM_DEFINE_HOOK (SCM_VM_ABORT_CONTINUATION_HOOK);
1180}
1181#undef FUNC_NAME
1182
972275ee
AW
1183SCM_DEFINE (scm_vm_trace_level, "vm-trace-level", 0, 0, 0,
1184 (void),
17e90c5e 1185 "")
7656f194 1186#define FUNC_NAME s_scm_vm_trace_level
a98cef7e 1187{
e7f9abab 1188 return scm_from_int (scm_the_vm ()->trace_level);
7656f194
AW
1189}
1190#undef FUNC_NAME
1191
972275ee
AW
1192SCM_DEFINE (scm_set_vm_trace_level_x, "set-vm-trace-level!", 1, 0, 0,
1193 (SCM level),
7656f194
AW
1194 "")
1195#define FUNC_NAME s_scm_set_vm_trace_level_x
1196{
e7f9abab 1197 scm_the_vm ()->trace_level = scm_to_int (level);
7656f194 1198 return SCM_UNSPECIFIED;
a98cef7e
KN
1199}
1200#undef FUNC_NAME
1201
1202\f
ea9f4f4b
AW
1203/*
1204 * VM engines
1205 */
1206
1207static int
1208symbol_to_vm_engine (SCM engine, const char *FUNC_NAME)
1209{
1210 if (scm_is_eq (engine, sym_regular))
1211 return SCM_VM_REGULAR_ENGINE;
1212 else if (scm_is_eq (engine, sym_debug))
1213 return SCM_VM_DEBUG_ENGINE;
1214 else
1215 SCM_MISC_ERROR ("Unknown VM engine: ~a", scm_list_1 (engine));
1216}
1217
1218static SCM
1219vm_engine_to_symbol (int engine, const char *FUNC_NAME)
1220{
1221 switch (engine)
1222 {
1223 case SCM_VM_REGULAR_ENGINE:
1224 return sym_regular;
1225 case SCM_VM_DEBUG_ENGINE:
1226 return sym_debug;
1227 default:
1228 /* ? */
1229 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1230 scm_list_1 (scm_from_int (engine)));
1231 }
1232}
1233
972275ee
AW
1234SCM_DEFINE (scm_vm_engine, "vm-engine", 0, 0, 0,
1235 (void),
ea9f4f4b
AW
1236 "")
1237#define FUNC_NAME s_scm_vm_engine
1238{
e7f9abab 1239 return vm_engine_to_symbol (scm_the_vm ()->engine, FUNC_NAME);
ea9f4f4b
AW
1240}
1241#undef FUNC_NAME
1242
1243void
972275ee 1244scm_c_set_vm_engine_x (int engine)
ea9f4f4b
AW
1245#define FUNC_NAME "set-vm-engine!"
1246{
ea9f4f4b
AW
1247 if (engine < 0 || engine >= SCM_VM_NUM_ENGINES)
1248 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1249 scm_list_1 (scm_from_int (engine)));
1250
e7f9abab 1251 scm_the_vm ()->engine = engine;
ea9f4f4b
AW
1252}
1253#undef FUNC_NAME
1254
972275ee
AW
1255SCM_DEFINE (scm_set_vm_engine_x, "set-vm-engine!", 1, 0, 0,
1256 (SCM engine),
ea9f4f4b
AW
1257 "")
1258#define FUNC_NAME s_scm_set_vm_engine_x
1259{
972275ee 1260 scm_c_set_vm_engine_x (symbol_to_vm_engine (engine, FUNC_NAME));
ea9f4f4b
AW
1261 return SCM_UNSPECIFIED;
1262}
1263#undef FUNC_NAME
1264
1265void
1266scm_c_set_default_vm_engine_x (int engine)
1267#define FUNC_NAME "set-default-vm-engine!"
1268{
1269 if (engine < 0 || engine >= SCM_VM_NUM_ENGINES)
1270 SCM_MISC_ERROR ("Unknown VM engine: ~a",
1271 scm_list_1 (scm_from_int (engine)));
1272
1273 vm_default_engine = engine;
1274}
1275#undef FUNC_NAME
1276
1277SCM_DEFINE (scm_set_default_vm_engine_x, "set-default-vm-engine!", 1, 0, 0,
1278 (SCM engine),
1279 "")
1280#define FUNC_NAME s_scm_set_default_vm_engine_x
1281{
1282 scm_c_set_default_vm_engine_x (symbol_to_vm_engine (engine, FUNC_NAME));
1283 return SCM_UNSPECIFIED;
1284}
1285#undef FUNC_NAME
1286
972275ee
AW
1287/* FIXME: This function makes no sense, but we keep it to make sure we
1288 have a way of switching to the debug or regular VM. */
1289SCM_DEFINE (scm_call_with_vm, "call-with-vm", 1, 0, 1,
1290 (SCM proc, SCM args),
ea9f4f4b 1291 "Apply @var{proc} to @var{args} in a dynamic extent in which\n"
972275ee 1292 "@var{vm} is the current VM.")
ea9f4f4b
AW
1293#define FUNC_NAME s_scm_call_with_vm
1294{
972275ee 1295 return scm_apply_0 (proc, args);
ea9f4f4b
AW
1296}
1297#undef FUNC_NAME
1298
1299\f
a98cef7e 1300/*
17e90c5e 1301 * Initialize
a98cef7e
KN
1302 */
1303
55ee3607
AW
1304SCM
1305scm_load_compiled_with_vm (SCM file)
07e56b27 1306{
55ee3607 1307 return scm_call_0 (scm_load_thunk_from_file (file));
07e56b27
AW
1308}
1309
67b699cc 1310
9f309e2c
AW
1311void
1312scm_init_vm_builtin_properties (void)
1313{
1314 /* FIXME: Seems hacky to do this here, but oh well :/ */
1315 scm_sym_apply = scm_from_utf8_symbol ("apply");
1316 scm_sym_values = scm_from_utf8_symbol ("values");
1317 scm_sym_abort_to_prompt = scm_from_utf8_symbol ("abort-to-prompt");
1318 scm_sym_call_with_values = scm_from_utf8_symbol ("call-with-values");
1319 scm_sym_call_with_current_continuation =
1320 scm_from_utf8_symbol ("call-with-current-continuation");
1321
1322#define INIT_BUILTIN(builtin, BUILTIN, req, opt, rest) \
1323 scm_set_procedure_property_x (vm_builtin_##builtin, scm_sym_name, \
1324 scm_sym_##builtin); \
1325 scm_set_procedure_minimum_arity_x (vm_builtin_##builtin, \
1326 SCM_I_MAKINUM (req), \
1327 SCM_I_MAKINUM (opt), \
1328 scm_from_bool (rest));
1329 FOR_EACH_VM_BUILTIN (INIT_BUILTIN);
1330#undef INIT_BUILTIN
1331}
1332
17e90c5e 1333void
07e56b27 1334scm_bootstrap_vm (void)
17e90c5e 1335{
44602b08
AW
1336 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1337 "scm_init_vm",
60ae5ca2 1338 (scm_t_extension_init_func)scm_init_vm, NULL);
486013d6
AW
1339 scm_c_register_extension ("libguile-" SCM_EFFECTIVE_VERSION,
1340 "scm_init_vm_builtins",
1341 (scm_t_extension_init_func)scm_init_vm_builtins,
1342 NULL);
60ae5ca2 1343
7dba1c2f
AW
1344 page_size = getpagesize ();
1345 /* page_size should be a power of two. */
1346 if (page_size & (page_size - 1))
1347 abort ();
1348
aab9d46c
SIT
1349 initialize_default_stack_size ();
1350
4a655e50
AW
1351 sym_vm_run = scm_from_latin1_symbol ("vm-run");
1352 sym_vm_error = scm_from_latin1_symbol ("vm-error");
1353 sym_keyword_argument_error = scm_from_latin1_symbol ("keyword-argument-error");
1354 sym_regular = scm_from_latin1_symbol ("regular");
1355 sym_debug = scm_from_latin1_symbol ("debug");
0404c97d 1356
ef6b7f71
AW
1357 vm_boot_continuation = scm_i_make_program (vm_boot_continuation_code);
1358 SCM_SET_CELL_WORD_0 (vm_boot_continuation,
1359 (SCM_CELL_WORD_0 (vm_boot_continuation)
73c3db66 1360 | SCM_F_PROGRAM_IS_BOOT));
9f309e2c
AW
1361
1362#define DEFINE_BUILTIN(builtin, BUILTIN, req, opt, rest) \
80797145 1363 vm_builtin_##builtin = scm_i_make_program (vm_builtin_##builtin##_code);
9f309e2c
AW
1364 FOR_EACH_VM_BUILTIN (DEFINE_BUILTIN);
1365#undef DEFINE_BUILTIN
07e56b27
AW
1366}
1367
1368void
1369scm_init_vm (void)
1370{
17e90c5e 1371#ifndef SCM_MAGIC_SNARFER
aeeff258 1372#include "libguile/vm.x"
17e90c5e 1373#endif
a98cef7e 1374}
17e90c5e
KN
1375
1376/*
1377 Local Variables:
1378 c-file-style: "gnu"
1379 End:
1380*/