*** empty log message ***
[bpt/guile.git] / src / vm.c
... / ...
CommitLineData
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#include <string.h>
43#include "envs.h"
44#include "frames.h"
45#include "instructions.h"
46#include "objcodes.h"
47#include "programs.h"
48#include "vm.h"
49
50/* I sometimes use this for debugging. */
51#define vm_puts(OBJ) \
52{ \
53 scm_display (OBJ, scm_def_errp); \
54 scm_newline (scm_def_errp); \
55}
56
57\f
58/*
59 * VM Continuation
60 */
61
62scm_bits_t scm_tc16_vm_cont;
63
64
65#define SCM_VM_CONT_P(OBJ) SCM_SMOB_PREDICATE (scm_tc16_vm_cont, OBJ)
66#define SCM_VM_CONT_VP(CONT) ((struct scm_vm *) SCM_CELL_WORD_1 (CONT))
67
68static SCM
69capture_vm_cont (struct scm_vm *vp)
70{
71 struct scm_vm *p = scm_must_malloc (sizeof (*p), "capture_vm_cont");
72 p->stack_size = vp->stack_limit - vp->sp;
73 p->stack_base = scm_must_malloc (p->stack_size * sizeof (SCM),
74 "capture_vm_cont");
75 p->stack_limit = p->stack_base + p->stack_size - 2;
76 p->ip = vp->ip;
77 p->sp = (SCM *) (vp->stack_limit - vp->sp);
78 p->fp = (SCM *) (vp->stack_limit - vp->fp);
79 memcpy (p->stack_base, vp->sp + 1, vp->stack_size * sizeof (SCM));
80 SCM_RETURN_NEWSMOB (scm_tc16_vm_cont, p);
81}
82
83static void
84reinstate_vm_cont (struct scm_vm *vp, SCM cont)
85{
86 struct scm_vm *p = SCM_VM_CONT_VP (cont);
87 if (vp->stack_size < p->stack_size)
88 {
89 /* puts ("FIXME: Need to expand"); */
90 abort ();
91 }
92 vp->ip = p->ip;
93 vp->sp = vp->stack_limit - (int) p->sp;
94 vp->fp = vp->stack_limit - (int) p->fp;
95 memcpy (vp->sp + 1, p->stack_base, p->stack_size * sizeof (SCM));
96}
97
98static SCM
99vm_cont_mark (SCM obj)
100{
101 SCM *p;
102 struct scm_vm *vp = SCM_VM_CONT_VP (obj);
103 for (p = vp->stack_base; p <= vp->stack_limit; p++)
104 if (SCM_NIMP (*p))
105 scm_gc_mark (*p);
106 return SCM_BOOL_F;
107}
108
109static scm_sizet
110vm_cont_free (SCM obj)
111{
112 struct scm_vm *p = SCM_VM_CONT_VP (obj);
113 int size = sizeof (struct scm_vm) + p->stack_size * sizeof (SCM);
114 scm_must_free (p->stack_base);
115 scm_must_free (p);
116 return size;
117}
118
119\f
120/*
121 * VM Internal functions
122 */
123
124SCM_SYMBOL (sym_vm_run, "vm-run");
125SCM_SYMBOL (sym_vm_error, "vm-error");
126
127static scm_byte_t *
128vm_fetch_length (scm_byte_t *ip, size_t *lenp)
129{
130 /* NOTE: format defined in system/vm/conv.scm */
131 *lenp = *ip++;
132 if (*lenp < 254)
133 return ip;
134 else if (*lenp == 254)
135 {
136 int b1 = *ip++;
137 int b2 = *ip++;
138 *lenp = (b1 << 8) + b2;
139 }
140 else
141 {
142 int b1 = *ip++;
143 int b2 = *ip++;
144 int b3 = *ip++;
145 int b4 = *ip++;
146 *lenp = (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;
147 }
148 return ip;
149}
150
151static SCM
152vm_heapify_frames_1 (struct scm_vm *vp, SCM *fp, SCM *sp, SCM **destp)
153{
154 SCM frame;
155 SCM *dl = SCM_FRAME_DYNAMIC_LINK (fp);
156 SCM *src = SCM_FRAME_UPPER_ADDRESS (fp);
157 SCM *dest = SCM_FRAME_LOWER_ADDRESS (fp);
158
159 if (!dl)
160 {
161 /* The top frame */
162 frame = scm_c_make_heap_frame (fp);
163 fp = SCM_HEAP_FRAME_POINTER (frame);
164 SCM_FRAME_HEAP_LINK (fp) = SCM_BOOL_T;
165 }
166 else
167 {
168 /* Child frames */
169 SCM link = SCM_FRAME_HEAP_LINK (dl);
170 if (!SCM_FALSEP (link))
171 link = SCM_FRAME_LOWER_ADDRESS (dl)[-1]; /* self link */
172 else
173 link = vm_heapify_frames_1 (vp, dl, dest - 1, &dest);
174 frame = scm_c_make_heap_frame (fp);
175 fp = SCM_HEAP_FRAME_POINTER (frame);
176 SCM_FRAME_HEAP_LINK (fp) = link;
177 SCM_FRAME_DYNAMIC_LINK (fp) = SCM_HEAP_FRAME_POINTER (link);
178 }
179
180 /* Move stack data */
181 for (; src <= sp; src++, dest++)
182 *dest = *src;
183 *destp = dest;
184
185 return frame;
186}
187
188static SCM
189vm_heapify_frames (SCM vm)
190{
191 struct scm_vm *vp = SCM_VM_DATA (vm);
192 if (SCM_FALSEP (SCM_FRAME_HEAP_LINK (vp->fp)))
193 {
194 SCM *dest;
195 vp->this_frame = vm_heapify_frames_1 (vp, vp->fp, vp->sp, &dest);
196 vp->fp = SCM_HEAP_FRAME_POINTER (vp->this_frame);
197 vp->sp = dest - 1;
198 }
199 return vp->this_frame;
200}
201
202\f
203/*
204 * VM
205 */
206
207#define VM_DEFAULT_STACK_SIZE (16 * 1024)
208
209#define VM_REGULAR_ENGINE 0
210#define VM_DEBUG_ENGINE 1
211
212#if 0
213#define VM_NAME vm_regular_engine
214#define VM_ENGINE VM_REGULAR_ENGINE
215#include "vm_engine.c"
216#undef VM_NAME
217#undef VM_ENGINE
218#endif
219
220#define VM_NAME vm_debug_engine
221#define VM_ENGINE VM_DEBUG_ENGINE
222#include "vm_engine.c"
223#undef VM_NAME
224#undef VM_ENGINE
225
226scm_bits_t scm_tc16_vm;
227
228static SCM the_vm;
229
230static SCM
231make_vm (void)
232#define FUNC_NAME "make_vm"
233{
234 int i;
235 struct scm_vm *vp = SCM_MUST_MALLOC (sizeof (struct scm_vm));
236 vp->stack_size = VM_DEFAULT_STACK_SIZE;
237 vp->stack_base = SCM_MUST_MALLOC (vp->stack_size * sizeof (SCM));
238 vp->stack_limit = vp->stack_base + vp->stack_size - 3;
239 vp->ip = NULL;
240 vp->sp = vp->stack_base - 1;
241 vp->fp = NULL;
242 vp->time = 0;
243 vp->clock = 0;
244 vp->options = SCM_EOL;
245 vp->this_frame = SCM_BOOL_F;
246 vp->last_frame = SCM_BOOL_F;
247 for (i = 0; i < SCM_VM_NUM_HOOKS; i++)
248 vp->hooks[i] = SCM_BOOL_F;
249 SCM_RETURN_NEWSMOB (scm_tc16_vm, vp);
250}
251#undef FUNC_NAME
252
253static SCM
254vm_mark (SCM obj)
255{
256 int i;
257 struct scm_vm *vp = SCM_VM_DATA (obj);
258
259 /* mark the stack conservatively */
260 scm_mark_locations ((SCM_STACKITEM *) vp->stack_base,
261 sizeof (SCM) * (vp->sp - vp->stack_base + 1));
262
263 /* mark other objects */
264 for (i = 0; i < SCM_VM_NUM_HOOKS; i++)
265 scm_gc_mark (vp->hooks[i]);
266 scm_gc_mark (vp->this_frame);
267 scm_gc_mark (vp->last_frame);
268 return vp->options;
269}
270
271static scm_sizet
272vm_free (SCM obj)
273{
274 struct scm_vm *vp = SCM_VM_DATA (obj);
275 int size = (sizeof (struct scm_vm) + vp->stack_size * sizeof (SCM));
276 scm_must_free (vp->stack_base);
277 scm_must_free (vp);
278 return size;
279}
280
281SCM_SYMBOL (sym_debug, "debug");
282
283SCM
284scm_vm_apply (SCM vm, SCM program, SCM args)
285#define FUNC_NAME "scm_vm_apply"
286{
287 SCM_VALIDATE_PROGRAM (1, program);
288 return vm_run (vm, program, args);
289}
290#undef FUNC_NAME
291
292/* Scheme interface */
293
294SCM_DEFINE (scm_vm_version, "vm-version", 0, 0, 0,
295 (void),
296 "")
297#define FUNC_NAME s_scm_vm_version
298{
299 return scm_makfrom0str (VERSION);
300}
301#undef FUNC_NAME
302
303SCM_DEFINE (scm_the_vm, "the-vm", 0, 0, 0,
304 (),
305 "")
306#define FUNC_NAME s_scm_the_vm
307{
308 return the_vm;
309}
310#undef FUNC_NAME
311
312
313SCM_DEFINE (scm_vm_p, "vm?", 1, 0, 0,
314 (SCM obj),
315 "")
316#define FUNC_NAME s_scm_vm_p
317{
318 return SCM_BOOL (SCM_VM_P (obj));
319}
320#undef FUNC_NAME
321
322SCM_DEFINE (scm_make_vm, "make-vm", 0, 0, 0,
323 (void),
324 "")
325#define FUNC_NAME s_scm_make_vm,
326{
327 return make_vm ();
328}
329#undef FUNC_NAME
330
331SCM_DEFINE (scm_vm_ip, "vm:ip", 1, 0, 0,
332 (SCM vm),
333 "")
334#define FUNC_NAME s_scm_vm_ip
335{
336 SCM_VALIDATE_VM (1, vm);
337 return scm_ulong2num ((unsigned long) SCM_VM_DATA (vm)->ip);
338}
339#undef FUNC_NAME
340
341SCM_DEFINE (scm_vm_sp, "vm:sp", 1, 0, 0,
342 (SCM vm),
343 "")
344#define FUNC_NAME s_scm_vm_sp
345{
346 SCM_VALIDATE_VM (1, vm);
347 return scm_ulong2num ((unsigned long) SCM_VM_DATA (vm)->sp);
348}
349#undef FUNC_NAME
350
351SCM_DEFINE (scm_vm_fp, "vm:fp", 1, 0, 0,
352 (SCM vm),
353 "")
354#define FUNC_NAME s_scm_vm_fp
355{
356 SCM_VALIDATE_VM (1, vm);
357 return scm_ulong2num ((unsigned long) SCM_VM_DATA (vm)->fp);
358}
359#undef FUNC_NAME
360
361#define VM_DEFINE_HOOK(n) \
362{ \
363 struct scm_vm *vp; \
364 SCM_VALIDATE_VM (1, vm); \
365 vp = SCM_VM_DATA (vm); \
366 if (SCM_FALSEP (vp->hooks[n])) \
367 vp->hooks[n] = scm_make_hook (SCM_MAKINUM (1)); \
368 return vp->hooks[n]; \
369}
370
371SCM_DEFINE (scm_vm_boot_hook, "vm-boot-hook", 1, 0, 0,
372 (SCM vm),
373 "")
374#define FUNC_NAME s_scm_vm_boot_hook
375{
376 VM_DEFINE_HOOK (SCM_VM_BOOT_HOOK);
377}
378#undef FUNC_NAME
379
380SCM_DEFINE (scm_vm_halt_hook, "vm-halt-hook", 1, 0, 0,
381 (SCM vm),
382 "")
383#define FUNC_NAME s_scm_vm_halt_hook
384{
385 VM_DEFINE_HOOK (SCM_VM_HALT_HOOK);
386}
387#undef FUNC_NAME
388
389SCM_DEFINE (scm_vm_next_hook, "vm-next-hook", 1, 0, 0,
390 (SCM vm),
391 "")
392#define FUNC_NAME s_scm_vm_next_hook
393{
394 VM_DEFINE_HOOK (SCM_VM_NEXT_HOOK);
395}
396#undef FUNC_NAME
397
398SCM_DEFINE (scm_vm_enter_hook, "vm-enter-hook", 1, 0, 0,
399 (SCM vm),
400 "")
401#define FUNC_NAME s_scm_vm_enter_hook
402{
403 VM_DEFINE_HOOK (SCM_VM_ENTER_HOOK);
404}
405#undef FUNC_NAME
406
407SCM_DEFINE (scm_vm_apply_hook, "vm-apply-hook", 1, 0, 0,
408 (SCM vm),
409 "")
410#define FUNC_NAME s_scm_vm_apply_hook
411{
412 VM_DEFINE_HOOK (SCM_VM_APPLY_HOOK);
413}
414#undef FUNC_NAME
415
416SCM_DEFINE (scm_vm_exit_hook, "vm-exit-hook", 1, 0, 0,
417 (SCM vm),
418 "")
419#define FUNC_NAME s_scm_vm_exit_hook
420{
421 VM_DEFINE_HOOK (SCM_VM_EXIT_HOOK);
422}
423#undef FUNC_NAME
424
425SCM_DEFINE (scm_vm_return_hook, "vm-return-hook", 1, 0, 0,
426 (SCM vm),
427 "")
428#define FUNC_NAME s_scm_vm_return_hook
429{
430 VM_DEFINE_HOOK (SCM_VM_RETURN_HOOK);
431}
432#undef FUNC_NAME
433
434SCM_DEFINE (scm_vm_option, "vm-option", 2, 0, 0,
435 (SCM vm, SCM key),
436 "")
437#define FUNC_NAME s_scm_vm_option
438{
439 SCM_VALIDATE_VM (1, vm);
440 return scm_assq_ref (SCM_VM_DATA (vm)->options, key);
441}
442#undef FUNC_NAME
443
444SCM_DEFINE (scm_set_vm_option_x, "set-vm-option!", 3, 0, 0,
445 (SCM vm, SCM key, SCM val),
446 "")
447#define FUNC_NAME s_scm_set_vm_option_x
448{
449 SCM_VALIDATE_VM (1, vm);
450 SCM_VM_DATA (vm)->options
451 = scm_assq_set_x (SCM_VM_DATA (vm)->options, key, val);
452 return SCM_UNSPECIFIED;
453}
454#undef FUNC_NAME
455
456SCM_DEFINE (scm_vm_stats, "vm-stats", 1, 0, 0,
457 (SCM vm),
458 "")
459#define FUNC_NAME s_scm_vm_stats
460{
461 SCM stats;
462
463 SCM_VALIDATE_VM (1, vm);
464
465 stats = scm_c_make_vector (2, SCM_MAKINUM (0));
466 SCM_VELTS (stats)[0] = scm_ulong2num (SCM_VM_DATA (vm)->time);
467 SCM_VELTS (stats)[1] = scm_ulong2num (SCM_VM_DATA (vm)->clock);
468
469 return stats;
470}
471#undef FUNC_NAME
472
473#define VM_CHECK_RUNNING(vm) \
474 if (!SCM_VM_DATA (vm)->ip) \
475 SCM_MISC_ERROR ("Not running", SCM_LIST1 (vm))
476
477SCM_DEFINE (scm_vm_this_frame, "vm-this-frame", 1, 0, 0,
478 (SCM vm),
479 "")
480#define FUNC_NAME s_scm_vm_this_frame
481{
482 SCM_VALIDATE_VM (1, vm);
483 return SCM_VM_DATA (vm)->this_frame;
484}
485#undef FUNC_NAME
486
487SCM_DEFINE (scm_vm_last_frame, "vm-last-frame", 1, 0, 0,
488 (SCM vm),
489 "")
490#define FUNC_NAME s_scm_vm_last_frame
491{
492 SCM_VALIDATE_VM (1, vm);
493 return SCM_VM_DATA (vm)->last_frame;
494}
495#undef FUNC_NAME
496
497SCM_DEFINE (scm_vm_fetch_code, "vm-fetch-code", 1, 0, 0,
498 (SCM vm),
499 "")
500#define FUNC_NAME s_scm_vm_fetch_code
501{
502 int i;
503 SCM list;
504 scm_byte_t *ip;
505 struct scm_instruction *p;
506
507 SCM_VALIDATE_VM (1, vm);
508 VM_CHECK_RUNNING (vm);
509
510 ip = SCM_VM_DATA (vm)->ip;
511 p = SCM_INSTRUCTION (*ip);
512
513 list = SCM_LIST1 (scm_str2symbol (p->name));
514 for (i = 1; i <= p->len; i++)
515 list = scm_cons (SCM_MAKINUM (ip[i]), list);
516 return scm_reverse_x (list, SCM_EOL);
517}
518#undef FUNC_NAME
519
520SCM_DEFINE (scm_vm_fetch_stack, "vm-fetch-stack", 1, 0, 0,
521 (SCM vm),
522 "")
523#define FUNC_NAME s_scm_vm_fetch_stack
524{
525 SCM *sp;
526 SCM ls = SCM_EOL;
527 struct scm_vm *vp;
528
529 SCM_VALIDATE_VM (1, vm);
530 VM_CHECK_RUNNING (vm);
531
532 vp = SCM_VM_DATA (vm);
533 for (sp = vp->stack_base; sp <= vp->sp; sp++)
534 ls = scm_cons (*sp, ls);
535 return ls;
536}
537#undef FUNC_NAME
538
539\f
540/*
541 * Initialize
542 */
543
544void
545scm_init_vm (void)
546{
547 scm_init_frames ();
548 scm_init_instructions ();
549 scm_init_objcodes ();
550 scm_init_programs ();
551
552 scm_tc16_vm_cont = scm_make_smob_type ("vm-cont", 0);
553 scm_set_smob_mark (scm_tc16_vm_cont, vm_cont_mark);
554 scm_set_smob_free (scm_tc16_vm_cont, vm_cont_free);
555
556 scm_tc16_vm = scm_make_smob_type ("vm", 0);
557 scm_set_smob_mark (scm_tc16_vm, vm_mark);
558 scm_set_smob_free (scm_tc16_vm, vm_free);
559 scm_set_smob_apply (scm_tc16_vm, scm_vm_apply, 1, 0, 1);
560
561 the_vm = scm_permanent_object (make_vm ());
562
563#ifndef SCM_MAGIC_SNARFER
564#include "vm.x"
565#endif
566}
567
568/*
569 Local Variables:
570 c-file-style: "gnu"
571 End:
572*/