merge guile-vm into libguile itself
[bpt/guile.git] / libguile / vm.c
1 /* Copyright (C) 2001 Free Software Foundation, Inc.
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41
42 #if HAVE_CONFIG_H
43 # include <config.h>
44 #endif
45
46 #include <string.h>
47 #include "vm-bootstrap.h"
48 #include "frames.h"
49 #include "instructions.h"
50 #include "objcodes.h"
51 #include "programs.h"
52 #include "vm.h"
53
54 /* I sometimes use this for debugging. */
55 #define vm_puts(OBJ) \
56 { \
57 scm_display (OBJ, scm_current_error_port ()); \
58 scm_newline (scm_current_error_port ()); \
59 }
60
61 \f
62 /*
63 * VM Continuation
64 */
65
66 scm_t_bits scm_tc16_vm_cont;
67
68
69 #define SCM_VM_CONT_P(OBJ) SCM_SMOB_PREDICATE (scm_tc16_vm_cont, OBJ)
70 #define SCM_VM_CONT_VP(CONT) ((struct scm_vm *) SCM_CELL_WORD_1 (CONT))
71
72 static SCM
73 capture_vm_cont (struct scm_vm *vp)
74 {
75 struct scm_vm *p = scm_gc_malloc (sizeof (*p), "capture_vm_cont");
76 p->stack_size = vp->stack_limit - vp->sp;
77 p->stack_base = scm_gc_malloc (p->stack_size * sizeof (SCM),
78 "capture_vm_cont");
79 p->stack_limit = p->stack_base + p->stack_size - 2;
80 p->ip = vp->ip;
81 p->sp = (SCM *) (vp->stack_limit - vp->sp);
82 p->fp = (SCM *) (vp->stack_limit - vp->fp);
83 memcpy (p->stack_base, vp->sp + 1, vp->stack_size * sizeof (SCM));
84 SCM_RETURN_NEWSMOB (scm_tc16_vm_cont, p);
85 }
86
87 static void
88 reinstate_vm_cont (struct scm_vm *vp, SCM cont)
89 {
90 struct scm_vm *p = SCM_VM_CONT_VP (cont);
91 if (vp->stack_size < p->stack_size)
92 {
93 /* puts ("FIXME: Need to expand"); */
94 abort ();
95 }
96 vp->ip = p->ip;
97 vp->sp = vp->stack_limit - (int) p->sp;
98 vp->fp = vp->stack_limit - (int) p->fp;
99 memcpy (vp->sp + 1, p->stack_base, p->stack_size * sizeof (SCM));
100 }
101
102 struct vm_unwind_data
103 {
104 struct scm_vm *vp;
105 SCM *sp;
106 SCM *fp;
107 SCM this_frame;
108 };
109
110 static void
111 vm_reset_stack (void *data)
112 {
113 struct vm_unwind_data *w = data;
114
115 w->vp->sp = w->sp;
116 w->vp->fp = w->fp;
117 w->vp->this_frame = w->this_frame;
118 }
119
120 static SCM
121 vm_cont_mark (SCM obj)
122 {
123 SCM *p;
124 struct scm_vm *vp = SCM_VM_CONT_VP (obj);
125 for (p = vp->stack_base; p <= vp->stack_limit; p++)
126 if (SCM_NIMP (*p))
127 scm_gc_mark (*p);
128 return SCM_BOOL_F;
129 }
130
131 static scm_sizet
132 vm_cont_free (SCM obj)
133 {
134 struct scm_vm *p = SCM_VM_CONT_VP (obj);
135
136 scm_gc_free (p->stack_base, p->stack_size * sizeof (SCM), "stack-base");
137 scm_gc_free (p, sizeof (struct scm_vm), "vm");
138
139 return 0;
140 }
141
142 \f
143 /*
144 * VM Internal functions
145 */
146
147 SCM_SYMBOL (sym_vm_run, "vm-run");
148 SCM_SYMBOL (sym_vm_error, "vm-error");
149
150 static scm_byte_t *
151 vm_fetch_length (scm_byte_t *ip, size_t *lenp)
152 {
153 /* NOTE: format defined in system/vm/conv.scm */
154 *lenp = *ip++;
155 if (*lenp < 254)
156 return ip;
157 else if (*lenp == 254)
158 {
159 int b1 = *ip++;
160 int b2 = *ip++;
161 *lenp = (b1 << 8) + b2;
162 }
163 else
164 {
165 int b1 = *ip++;
166 int b2 = *ip++;
167 int b3 = *ip++;
168 int b4 = *ip++;
169 *lenp = (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
170 }
171 return ip;
172 }
173
174 static SCM
175 vm_heapify_frames_1 (struct scm_vm *vp, SCM *fp, SCM *sp, SCM **destp)
176 {
177 SCM frame;
178 SCM *dl = SCM_FRAME_DYNAMIC_LINK (fp);
179 #if 0
180 SCM *src = SCM_FRAME_UPPER_ADDRESS (fp);
181 #endif
182 SCM *dest = SCM_FRAME_LOWER_ADDRESS (fp);
183
184 if (!dl)
185 {
186 /* The top frame */
187 frame = scm_c_make_heap_frame (fp);
188 fp = SCM_HEAP_FRAME_POINTER (frame);
189 SCM_FRAME_HEAP_LINK (fp) = SCM_BOOL_T;
190 }
191 else
192 {
193 /* Child frames */
194 SCM link = SCM_FRAME_HEAP_LINK (dl);
195 if (!SCM_FALSEP (link))
196 link = SCM_FRAME_LOWER_ADDRESS (dl)[-1]; /* self link */
197 else
198 link = vm_heapify_frames_1 (vp, dl, dest - 1, &dest);
199 frame = scm_c_make_heap_frame (fp);
200 fp = SCM_HEAP_FRAME_POINTER (frame);
201 SCM_FRAME_HEAP_LINK (fp) = link;
202 SCM_FRAME_SET_DYNAMIC_LINK (fp, SCM_HEAP_FRAME_POINTER (link));
203 }
204
205 /* Apparently the intention here is to be able to have a frame on the heap,
206 but data on the stack, so that you can push as much as you want on the
207 stack; but I think that it's currently causing borkage with nonlocal exits
208 and the unwind handler, which reinstates the sp and fp, but it's no longer
209 pointing at a valid stack frame. So disable for now, we'll get back to
210 this later. */
211 #if 0
212 /* Move stack data */
213 for (; src <= sp; src++, dest++)
214 *dest = *src;
215 *destp = dest;
216 #endif
217
218 return frame;
219 }
220
221 static SCM
222 vm_heapify_frames (SCM vm)
223 {
224 struct scm_vm *vp = SCM_VM_DATA (vm);
225 if (SCM_FALSEP (SCM_FRAME_HEAP_LINK (vp->fp)))
226 {
227 SCM *dest;
228 vp->this_frame = vm_heapify_frames_1 (vp, vp->fp, vp->sp, &dest);
229 vp->fp = SCM_HEAP_FRAME_POINTER (vp->this_frame);
230 vp->sp = dest - 1;
231 }
232 return vp->this_frame;
233 }
234
235 \f
236 /*
237 * VM
238 */
239
240 #define VM_DEFAULT_STACK_SIZE (16 * 1024)
241
242 #define VM_REGULAR_ENGINE 0
243 #define VM_DEBUG_ENGINE 1
244
245 #if 0
246 #define VM_NAME vm_regular_engine
247 #define VM_ENGINE VM_REGULAR_ENGINE
248 #include "vm-engine.c"
249 #undef VM_NAME
250 #undef VM_ENGINE
251 #endif
252
253 #define VM_NAME vm_debug_engine
254 #define VM_ENGINE VM_DEBUG_ENGINE
255 #include "vm-engine.c"
256 #undef VM_NAME
257 #undef VM_ENGINE
258
259 scm_t_bits scm_tc16_vm;
260
261 static SCM the_vm;
262
263 static SCM
264 make_vm (void)
265 #define FUNC_NAME "make_vm"
266 {
267 int i;
268 struct scm_vm *vp = scm_gc_malloc (sizeof (struct scm_vm), "vm");
269
270 vp->stack_size = VM_DEFAULT_STACK_SIZE;
271 vp->stack_base = scm_gc_malloc (vp->stack_size * sizeof (SCM),
272 "stack-base");
273 vp->stack_limit = vp->stack_base + vp->stack_size - 3;
274 vp->ip = NULL;
275 vp->sp = vp->stack_base - 1;
276 vp->fp = NULL;
277 vp->time = 0;
278 vp->clock = 0;
279 vp->options = SCM_EOL;
280 vp->this_frame = SCM_BOOL_F;
281 vp->last_frame = SCM_BOOL_F;
282 vp->last_ip = NULL;
283 for (i = 0; i < SCM_VM_NUM_HOOKS; i++)
284 vp->hooks[i] = SCM_BOOL_F;
285 SCM_RETURN_NEWSMOB (scm_tc16_vm, vp);
286 }
287 #undef FUNC_NAME
288
289 static SCM
290 vm_mark (SCM obj)
291 {
292 int i;
293 struct scm_vm *vp = SCM_VM_DATA (obj);
294
295 /* mark the stack conservatively */
296 scm_mark_locations ((SCM_STACKITEM *) vp->stack_base,
297 sizeof (SCM) * (vp->sp - vp->stack_base + 1));
298
299 /* mark other objects */
300 for (i = 0; i < SCM_VM_NUM_HOOKS; i++)
301 scm_gc_mark (vp->hooks[i]);
302 scm_gc_mark (vp->this_frame);
303 scm_gc_mark (vp->last_frame);
304 return vp->options;
305 }
306
307 static scm_sizet
308 vm_free (SCM obj)
309 {
310 struct scm_vm *vp = SCM_VM_DATA (obj);
311
312 scm_gc_free (vp->stack_base, vp->stack_size * sizeof (SCM),
313 "stack-base");
314 scm_gc_free (vp, sizeof (struct scm_vm), "vm");
315
316 return 0;
317 }
318
319 SCM_SYMBOL (sym_debug, "debug");
320
321 SCM
322 scm_vm_apply (SCM vm, SCM program, SCM args)
323 #define FUNC_NAME "scm_vm_apply"
324 {
325 SCM_VALIDATE_PROGRAM (1, program);
326 return vm_run (vm, program, args);
327 }
328 #undef FUNC_NAME
329
330 /* Scheme interface */
331
332 SCM_DEFINE (scm_vm_version, "vm-version", 0, 0, 0,
333 (void),
334 "")
335 #define FUNC_NAME s_scm_vm_version
336 {
337 return scm_from_locale_string (PACKAGE_VERSION);
338 }
339 #undef FUNC_NAME
340
341 SCM_DEFINE (scm_the_vm, "the-vm", 0, 0, 0,
342 (void),
343 "")
344 #define FUNC_NAME s_scm_the_vm
345 {
346 return the_vm;
347 }
348 #undef FUNC_NAME
349
350
351 SCM_DEFINE (scm_vm_p, "vm?", 1, 0, 0,
352 (SCM obj),
353 "")
354 #define FUNC_NAME s_scm_vm_p
355 {
356 return SCM_BOOL (SCM_VM_P (obj));
357 }
358 #undef FUNC_NAME
359
360 SCM_DEFINE (scm_make_vm, "make-vm", 0, 0, 0,
361 (void),
362 "")
363 #define FUNC_NAME s_scm_make_vm,
364 {
365 return make_vm ();
366 }
367 #undef FUNC_NAME
368
369 SCM_DEFINE (scm_vm_ip, "vm:ip", 1, 0, 0,
370 (SCM vm),
371 "")
372 #define FUNC_NAME s_scm_vm_ip
373 {
374 SCM_VALIDATE_VM (1, vm);
375 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm)->ip);
376 }
377 #undef FUNC_NAME
378
379 SCM_DEFINE (scm_vm_sp, "vm:sp", 1, 0, 0,
380 (SCM vm),
381 "")
382 #define FUNC_NAME s_scm_vm_sp
383 {
384 SCM_VALIDATE_VM (1, vm);
385 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm)->sp);
386 }
387 #undef FUNC_NAME
388
389 SCM_DEFINE (scm_vm_fp, "vm:fp", 1, 0, 0,
390 (SCM vm),
391 "")
392 #define FUNC_NAME s_scm_vm_fp
393 {
394 SCM_VALIDATE_VM (1, vm);
395 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm)->fp);
396 }
397 #undef FUNC_NAME
398
399 #define VM_DEFINE_HOOK(n) \
400 { \
401 struct scm_vm *vp; \
402 SCM_VALIDATE_VM (1, vm); \
403 vp = SCM_VM_DATA (vm); \
404 if (SCM_FALSEP (vp->hooks[n])) \
405 vp->hooks[n] = scm_make_hook (SCM_I_MAKINUM (1)); \
406 return vp->hooks[n]; \
407 }
408
409 SCM_DEFINE (scm_vm_boot_hook, "vm-boot-hook", 1, 0, 0,
410 (SCM vm),
411 "")
412 #define FUNC_NAME s_scm_vm_boot_hook
413 {
414 VM_DEFINE_HOOK (SCM_VM_BOOT_HOOK);
415 }
416 #undef FUNC_NAME
417
418 SCM_DEFINE (scm_vm_halt_hook, "vm-halt-hook", 1, 0, 0,
419 (SCM vm),
420 "")
421 #define FUNC_NAME s_scm_vm_halt_hook
422 {
423 VM_DEFINE_HOOK (SCM_VM_HALT_HOOK);
424 }
425 #undef FUNC_NAME
426
427 SCM_DEFINE (scm_vm_next_hook, "vm-next-hook", 1, 0, 0,
428 (SCM vm),
429 "")
430 #define FUNC_NAME s_scm_vm_next_hook
431 {
432 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK);
433 }
434 #undef FUNC_NAME
435
436 SCM_DEFINE (scm_vm_break_hook, "vm-break-hook", 1, 0, 0,
437 (SCM vm),
438 "")
439 #define FUNC_NAME s_scm_vm_break_hook
440 {
441 VM_DEFINE_HOOK (SCM_VM_BREAK_HOOK);
442 }
443 #undef FUNC_NAME
444
445 SCM_DEFINE (scm_vm_enter_hook, "vm-enter-hook", 1, 0, 0,
446 (SCM vm),
447 "")
448 #define FUNC_NAME s_scm_vm_enter_hook
449 {
450 VM_DEFINE_HOOK (SCM_VM_ENTER_HOOK);
451 }
452 #undef FUNC_NAME
453
454 SCM_DEFINE (scm_vm_apply_hook, "vm-apply-hook", 1, 0, 0,
455 (SCM vm),
456 "")
457 #define FUNC_NAME s_scm_vm_apply_hook
458 {
459 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK);
460 }
461 #undef FUNC_NAME
462
463 SCM_DEFINE (scm_vm_exit_hook, "vm-exit-hook", 1, 0, 0,
464 (SCM vm),
465 "")
466 #define FUNC_NAME s_scm_vm_exit_hook
467 {
468 VM_DEFINE_HOOK (SCM_VM_EXIT_HOOK);
469 }
470 #undef FUNC_NAME
471
472 SCM_DEFINE (scm_vm_return_hook, "vm-return-hook", 1, 0, 0,
473 (SCM vm),
474 "")
475 #define FUNC_NAME s_scm_vm_return_hook
476 {
477 VM_DEFINE_HOOK (SCM_VM_RETURN_HOOK);
478 }
479 #undef FUNC_NAME
480
481 SCM_DEFINE (scm_vm_option, "vm-option", 2, 0, 0,
482 (SCM vm, SCM key),
483 "")
484 #define FUNC_NAME s_scm_vm_option
485 {
486 SCM_VALIDATE_VM (1, vm);
487 return scm_assq_ref (SCM_VM_DATA (vm)->options, key);
488 }
489 #undef FUNC_NAME
490
491 SCM_DEFINE (scm_set_vm_option_x, "set-vm-option!", 3, 0, 0,
492 (SCM vm, SCM key, SCM val),
493 "")
494 #define FUNC_NAME s_scm_set_vm_option_x
495 {
496 SCM_VALIDATE_VM (1, vm);
497 SCM_VM_DATA (vm)->options
498 = scm_assq_set_x (SCM_VM_DATA (vm)->options, key, val);
499 return SCM_UNSPECIFIED;
500 }
501 #undef FUNC_NAME
502
503 SCM_DEFINE (scm_vm_stats, "vm-stats", 1, 0, 0,
504 (SCM vm),
505 "")
506 #define FUNC_NAME s_scm_vm_stats
507 {
508 SCM stats;
509
510 SCM_VALIDATE_VM (1, vm);
511
512 stats = scm_make_vector (SCM_I_MAKINUM (2), SCM_UNSPECIFIED);
513 scm_vector_set_x (stats, SCM_I_MAKINUM (0),
514 scm_from_ulong (SCM_VM_DATA (vm)->time));
515 scm_vector_set_x (stats, SCM_I_MAKINUM (1),
516 scm_from_ulong (SCM_VM_DATA (vm)->clock));
517
518 return stats;
519 }
520 #undef FUNC_NAME
521
522 #define VM_CHECK_RUNNING(vm) \
523 if (!SCM_VM_DATA (vm)->ip) \
524 SCM_MISC_ERROR ("Not running", SCM_LIST1 (vm))
525
526 SCM_DEFINE (scm_vm_this_frame, "vm-this-frame", 1, 0, 0,
527 (SCM vm),
528 "")
529 #define FUNC_NAME s_scm_vm_this_frame
530 {
531 SCM_VALIDATE_VM (1, vm);
532 return SCM_VM_DATA (vm)->this_frame;
533 }
534 #undef FUNC_NAME
535
536 SCM_DEFINE (scm_vm_last_frame, "vm-last-frame", 1, 0, 0,
537 (SCM vm),
538 "")
539 #define FUNC_NAME s_scm_vm_last_frame
540 {
541 SCM_VALIDATE_VM (1, vm);
542 return SCM_VM_DATA (vm)->last_frame;
543 }
544 #undef FUNC_NAME
545
546 SCM_DEFINE (scm_vm_last_ip, "vm:last-ip", 1, 0, 0,
547 (SCM vm),
548 "")
549 #define FUNC_NAME s_scm_vm_last_ip
550 {
551 SCM_VALIDATE_VM (1, vm);
552 return scm_from_ulong ((unsigned long) SCM_VM_DATA (vm)->last_ip);
553 }
554 #undef FUNC_NAME
555
556 SCM_DEFINE (scm_vm_save_stack, "vm-save-stack", 1, 0, 0,
557 (SCM vm),
558 "")
559 #define FUNC_NAME s_scm_vm_save_stack
560 {
561 struct scm_vm *vp;
562 SCM *dest;
563 SCM_VALIDATE_VM (1, vm);
564 vp = SCM_VM_DATA (vm);
565
566 if (vp->fp)
567 {
568 vp->last_frame = vm_heapify_frames_1 (vp, vp->fp, vp->sp, &dest);
569 vp->last_ip = vp->ip;
570 }
571 else
572 {
573 vp->last_frame = SCM_BOOL_F;
574 }
575
576
577 return vp->last_frame;
578 }
579 #undef FUNC_NAME
580
581 SCM_DEFINE (scm_vm_fetch_code, "vm-fetch-code", 1, 0, 0,
582 (SCM vm),
583 "")
584 #define FUNC_NAME s_scm_vm_fetch_code
585 {
586 int i;
587 SCM list;
588 scm_byte_t *ip;
589 struct scm_instruction *p;
590
591 SCM_VALIDATE_VM (1, vm);
592 VM_CHECK_RUNNING (vm);
593
594 ip = SCM_VM_DATA (vm)->ip;
595 p = SCM_INSTRUCTION (*ip);
596
597 list = SCM_LIST1 (scm_str2symbol (p->name));
598 for (i = 1; i <= p->len; i++)
599 list = scm_cons (SCM_I_MAKINUM (ip[i]), list);
600 return scm_reverse_x (list, SCM_EOL);
601 }
602 #undef FUNC_NAME
603
604 SCM_DEFINE (scm_vm_fetch_stack, "vm-fetch-stack", 1, 0, 0,
605 (SCM vm),
606 "")
607 #define FUNC_NAME s_scm_vm_fetch_stack
608 {
609 SCM *sp;
610 SCM ls = SCM_EOL;
611 struct scm_vm *vp;
612
613 SCM_VALIDATE_VM (1, vm);
614 VM_CHECK_RUNNING (vm);
615
616 vp = SCM_VM_DATA (vm);
617 for (sp = vp->stack_base; sp <= vp->sp; sp++)
618 ls = scm_cons (*sp, ls);
619 return ls;
620 }
621 #undef FUNC_NAME
622
623 \f
624 /*
625 * Initialize
626 */
627
628 SCM scm_load_compiled_with_vm (SCM file)
629 {
630 SCM program = scm_objcode_to_program (scm_load_objcode (file));
631
632 return vm_run (the_vm, program, SCM_EOL);
633 }
634
635 void
636 scm_bootstrap_vm (void)
637 {
638 static int strappage = 0;
639
640 if (strappage)
641 return;
642
643 scm_bootstrap_frames ();
644 scm_bootstrap_instructions ();
645 scm_bootstrap_objcodes ();
646 scm_bootstrap_programs ();
647
648 scm_tc16_vm_cont = scm_make_smob_type ("vm-cont", 0);
649 scm_set_smob_mark (scm_tc16_vm_cont, vm_cont_mark);
650 scm_set_smob_free (scm_tc16_vm_cont, vm_cont_free);
651
652 scm_tc16_vm = scm_make_smob_type ("vm", 0);
653 scm_set_smob_mark (scm_tc16_vm, vm_mark);
654 scm_set_smob_free (scm_tc16_vm, vm_free);
655 scm_set_smob_apply (scm_tc16_vm, scm_vm_apply, 1, 0, 1);
656
657 the_vm = scm_permanent_object (make_vm ());
658
659 scm_c_define ("load-compiled",
660 scm_c_make_gsubr ("load-compiled/vm", 1, 0, 0,
661 scm_load_compiled_with_vm));
662
663 strappage = 1;
664 }
665
666 void
667 scm_init_vm (void)
668 {
669 scm_bootstrap_vm ();
670
671 #ifndef SCM_MAGIC_SNARFER
672 #include "vm.x"
673 #endif
674 }
675
676 /*
677 Local Variables:
678 c-file-style: "gnu"
679 End:
680 */