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