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