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