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