*** empty log message ***
[bpt/guile.git] / src / vm.c
CommitLineData
a98cef7e
KN
1/* Copyright (C) 2000 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#define SCM_DEBUG_TYPING_STRICTNESS 0
43#include "config.h"
44#include "vm.h"
45
46/* default stack size in the number of SCM */
d608d68d 47#define VM_DEFAULT_STACK_SIZE (16 * 1024) /* = 64KB */
a98cef7e
KN
48#define VM_MAXIMUM_STACK_SIZE (1024 * 1024) /* = 4MB */
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
e6db4668
KN
58/*
59 * Generic object name
60 */
61
62static SCM scm_name_property;
63
64SCM_DEFINE (scm_name, "name", 1, 0, 0,
65 (SCM obj),
66"")
67#define FUNC_NAME s_scm_name
68{
69 return scm_primitive_property_ref (scm_name_property, obj);
70}
71#undef FUNC_NAME
72
73SCM_DEFINE (scm_set_name_x, "set-name!", 2, 0, 0,
74 (SCM obj, SCM name),
75"")
76#define FUNC_NAME s_scm_set_name_x
77{
78 SCM_VALIDATE_SYMBOL (2, name);
79 return scm_primitive_property_set_x (scm_name_property, obj, name);
80}
81#undef FUNC_NAME
82
83int
84scm_smob_print_with_name (SCM smob, SCM port, scm_print_state *pstate)
85{
86 int n = SCM_SMOBNUM (smob);
87 SCM name = scm_name (smob);
88 scm_puts ("#<", port);
89 scm_puts (SCM_SMOBNAME (n) ? SCM_SMOBNAME (n) : "smob", port);
90 scm_putc (' ', port);
91 if (SCM_FALSEP (name))
92 {
93 scm_puts ("0x", port);
94 scm_intprint (SCM_UNPACK (scm_smobs[n].size ? SCM_CDR (smob) : smob),
95 16, port);
96 }
97 else
98 {
99 scm_display (name, port);
100 }
101 scm_putc ('>', port);
102 return 1;
103}
104
105static void
106init_name_property ()
107{
108 scm_name_property
109 = scm_permanent_object (scm_primitive_make_property (SCM_BOOL_F));
110}
111
112\f
a98cef7e
KN
113/*
114 * Instruction
115 */
116
4b482259 117static long scm_instruction_tag;
a98cef7e 118
4b482259 119static struct scm_instruction scm_instruction_table[] = {
77c04abe
KN
120#define VM_INSTRUCTION_TO_TABLE
121#include "vm_expand.h"
122#include "vm_system.i"
123#include "vm_scheme.i"
124#include "vm_number.i"
125#undef VM_INSTRUCTION_TO_TABLE
4b482259
KN
126 {op_last}
127};
a98cef7e 128
4b482259 129#define SCM_INSTRUCTION(OP) &scm_instruction_table[SCM_UNPACK (OP)]
a98cef7e
KN
130
131static SCM
132make_instruction (struct scm_instruction *instp)
133{
134 SCM_RETURN_NEWSMOB (scm_instruction_tag, instp);
135}
136
137static int
138print_instruction (SCM obj, SCM port, scm_print_state *pstate)
139{
140 scm_puts ("#<instruction ", port);
141 scm_puts (SCM_INSTRUCTION_DATA (obj)->name, port);
142 scm_putc ('>', port);
143 return 1;
144}
145
146static void
147init_instruction_type ()
148{
149 scm_instruction_tag = scm_make_smob_type ("instruction", 0);
150 scm_set_smob_print (scm_instruction_tag, print_instruction);
151}
152
153/* C interface */
154
155static struct scm_instruction *
4b482259 156scm_lookup_instruction (const char *name)
a98cef7e
KN
157{
158 struct scm_instruction *p;
4b482259 159 for (p = scm_instruction_table; p->opcode != op_last; p++)
a98cef7e
KN
160 if (strcmp (name, p->name) == 0)
161 return p;
162 return 0;
163}
164
a98cef7e
KN
165/* Scheme interface */
166
167SCM_DEFINE (scm_instruction_p, "instruction?", 1, 0, 0,
168 (SCM obj),
169"")
170#define FUNC_NAME s_scm_instruction_p
171{
172 return SCM_BOOL (SCM_INSTRUCTION_P (obj));
173}
174#undef FUNC_NAME
175
176SCM_DEFINE (scm_system_instruction_p, "system-instruction?", 1, 0, 0,
177 (SCM obj),
178"")
179#define FUNC_NAME s_scm_system_instruction_p
180{
181 return SCM_BOOL (SCM_SYSTEM_INSTRUCTION_P (obj));
182}
183#undef FUNC_NAME
184
185SCM_DEFINE (scm_functional_instruction_p, "functional-instruction?", 1, 0, 0,
186 (SCM obj),
187"")
188#define FUNC_NAME s_scm_functional_instruction_p
189{
190 return SCM_BOOL (SCM_FUNCTIONAL_INSTRUCTION_P (obj));
191}
192#undef FUNC_NAME
193
194SCM_DEFINE (scm_instruction_name_p, "instruction-name?", 1, 0, 0,
195 (SCM name),
196"")
197#define FUNC_NAME s_scm_instruction_name_p
198{
199 SCM_VALIDATE_SYMBOL (1, name);
4b482259 200 return SCM_BOOL (scm_lookup_instruction (SCM_SYMBOL_CHARS (name)));
a98cef7e
KN
201}
202#undef FUNC_NAME
203
204SCM_DEFINE (scm_symbol_to_instruction, "symbol->instruction", 1, 0, 0,
205 (SCM name),
206"")
207#define FUNC_NAME s_scm_symbol_to_instruction
208{
209 struct scm_instruction *p;
210 SCM_VALIDATE_SYMBOL (1, name);
211
4b482259 212 p = scm_lookup_instruction (SCM_SYMBOL_CHARS (name));
a98cef7e
KN
213 if (!p)
214 SCM_MISC_ERROR ("No such instruction: ~S", SCM_LIST1 (name));
215
216 return p->obj;
217}
218#undef FUNC_NAME
219
220SCM_DEFINE (scm_instruction_list, "instruction-list", 0, 0, 0,
221 (),
222"")
223#define FUNC_NAME s_scm_instruction_list
224{
225 SCM list = SCM_EOL;
226 struct scm_instruction *p;
4b482259 227 for (p = scm_instruction_table; p->opcode != op_last; p++)
a98cef7e
KN
228 list = scm_cons (p->obj, list);
229 return scm_reverse_x (list, SCM_EOL);
230}
231#undef FUNC_NAME
232
233SCM_DEFINE (scm_instruction_opcode, "instruction-opcode", 1, 0, 0,
234 (SCM inst),
235"")
236#define FUNC_NAME s_scm_instruction_opcode
237{
238 SCM_VALIDATE_INSTRUCTION (1, inst);
239 return SCM_MAKINUM (SCM_INSTRUCTION_DATA (inst)->opcode);
240}
241#undef FUNC_NAME
242
243SCM_DEFINE (scm_instruction_name, "instruction-name", 1, 0, 0,
244 (SCM inst),
245"")
246#define FUNC_NAME s_scm_instruction_name
247{
248 SCM_VALIDATE_INSTRUCTION (1, inst);
249 return SCM_CAR (scm_intern0 (SCM_INSTRUCTION_DATA (inst)->name));
250}
251#undef FUNC_NAME
252
253SCM_DEFINE (scm_instruction_type, "instruction-type", 1, 0, 0,
254 (SCM inst),
255"")
256#define FUNC_NAME s_scm_instruction_type
257{
258 SCM_VALIDATE_INSTRUCTION (1, inst);
259 return SCM_MAKINUM (SCM_INSTRUCTION_DATA (inst)->type);
260}
261#undef FUNC_NAME
262
263SCM_DEFINE (scm_instruction_scheme_name, "instruction-scheme-name", 1, 0, 0,
264 (SCM inst),
265"")
266#define FUNC_NAME s_scm_instruction_scheme_name
267{
268 SCM_VALIDATE_INSTRUCTION (1, inst);
269 if (SCM_FUNCTIONAL_INSTRUCTION_P (inst))
270 return SCM_CAR (scm_intern0 (SCM_INSTRUCTION_DATA (inst)->sname));
271 else
272 return SCM_BOOL_F;
273}
274#undef FUNC_NAME
275
276SCM_DEFINE (scm_instruction_arity, "instruction-arity", 1, 0, 0,
277 (SCM inst),
278"")
279#define FUNC_NAME s_scm_instruction_arity
280{
281 SCM_VALIDATE_INSTRUCTION (1, inst);
282 if (SCM_FUNCTIONAL_INSTRUCTION_P (inst))
283 {
284 struct scm_instruction *p = SCM_INSTRUCTION_DATA (inst);
285 return SCM_LIST2 (SCM_MAKINUM (p->nargs), SCM_BOOL (p->restp));
286 }
287 else
288 return SCM_BOOL_F;
289}
290#undef FUNC_NAME
291
292\f
293/*
294 * Bytecode
295 */
296
297static long scm_bytecode_tag;
298
299static SCM
300make_bytecode (int size)
301{
302 struct scm_bytecode *p
303 = scm_must_malloc (sizeof (*p) + (size * sizeof (SCM)), "make_bytecode");
304 p->size = size;
305 SCM_RETURN_NEWSMOB (scm_bytecode_tag, p);
306}
307
308static SCM
309mark_bytecode (SCM bytecode)
310{
311 int i;
312 struct scm_instruction *p;
313
314 int size = SCM_BYTECODE_SIZE (bytecode);
315 SCM *base = SCM_BYTECODE_BASE (bytecode);
316
317 for (i = 0; i < size; i++)
318 {
4b482259 319 p = SCM_INSTRUCTION (base[i]);
a98cef7e
KN
320 switch (p->type)
321 {
322 case INST_NONE:
323 break;
324 case INST_SCM:
325 case INST_TOP:
326 case INST_EXT:
327 case INST_CODE:
328 scm_gc_mark (base[++i]);
329 break;
330 case INST_INUM: /* a fixed integer; we don't need to mark it */
331 case INST_ADDR: /* real memory address; we shouldn't mark it! */
332 i++;
333 }
334 }
335 return SCM_BOOL_F;
336}
337
338static int
339print_bytecode (SCM obj, SCM port, scm_print_state *pstate)
340{
341 scm_puts ("#<bytecode 0x", port);
342 scm_intprint ((long) SCM_BYTECODE_BASE (obj), 16, port);
343 scm_putc ('>', port);
344 return 1;
345}
346
347static scm_sizet
348free_bytecode (SCM bytecode)
349{
350 int size = (sizeof (struct scm_bytecode)
351 + (SCM_BYTECODE_SIZE (bytecode) * sizeof (SCM)));
352 if (SCM_BYTECODE_EXTS (bytecode))
353 {
354 size += (SCM_BYTECODE_EXTS (bytecode)[0] + 1) * sizeof (int);
355 scm_must_free (SCM_BYTECODE_EXTS (bytecode));
356 }
357 scm_must_free (SCM_BYTECODE_DATA (bytecode));
358 return size;
359}
360
361static void
362init_bytecode_type ()
363{
364 scm_bytecode_tag = scm_make_smob_type ("bytecode", 0);
365 scm_set_smob_mark (scm_bytecode_tag, mark_bytecode);
366 scm_set_smob_print (scm_bytecode_tag, print_bytecode);
367 scm_set_smob_free (scm_bytecode_tag, free_bytecode);
368}
369
9df03fd0
KN
370/* Internal functions */
371
372static SCM
373lookup_variable (SCM sym)
374{
26403690
KN
375 SCM eclo = scm_standard_eval_closure (scm_selected_module ());
376 SCM var = scm_eval_closure_lookup (eclo, sym, SCM_BOOL_F);
9df03fd0 377 if (SCM_FALSEP (var))
26403690 378 var = scm_eval_closure_lookup (eclo, sym, SCM_BOOL_T);
9df03fd0
KN
379 return var;
380}
381
a98cef7e
KN
382/* Scheme interface */
383
384SCM_DEFINE (scm_bytecode_p, "bytecode?", 1, 0, 0,
385 (SCM obj),
386"")
387#define FUNC_NAME s_scm_bytecode_p
388{
389 return SCM_BOOL (SCM_BYTECODE_P (obj));
390}
391#undef FUNC_NAME
392
393SCM_DEFINE (scm_make_bytecode, "make-bytecode", 1, 0, 0,
394 (SCM code),
395"")
396#define FUNC_NAME s_scm_make_bytecode
397{
398 int i, size, len, offset;
399 SCM header, body, nreqs, restp, nvars, nexts, exts, bytecode;
400 SCM *old, *new, *address;
401
402 /* Type check */
403 SCM_VALIDATE_VECTOR (1, code);
404 SCM_ASSERT_RANGE (1, code, SCM_LENGTH (code) == 2);
405 header = SCM_VELTS (code)[0];
406 body = SCM_VELTS (code)[1];
407 SCM_VALIDATE_VECTOR (1, header);
408 SCM_VALIDATE_VECTOR (2, body);
409 SCM_ASSERT_RANGE (1, header, SCM_LENGTH (header) == 5);
410 nreqs = SCM_VELTS (header)[0];
411 restp = SCM_VELTS (header)[1];
412 nvars = SCM_VELTS (header)[2];
413 nexts = SCM_VELTS (header)[3];
414 exts = SCM_VELTS (header)[4];
415 SCM_VALIDATE_INUM (1, nreqs);
416 SCM_VALIDATE_BOOL (2, restp);
417 SCM_VALIDATE_INUM (3, nvars);
418 SCM_VALIDATE_INUM (4, nexts);
419 SCM_VALIDATE_VECTOR (5, exts);
420
421 /* Create a new bytecode */
422 size = SCM_LENGTH (body);
423 old = SCM_VELTS (body);
424 bytecode = make_bytecode (size);
425 new = SCM_BYTECODE_BASE (bytecode);
426
427 /* Initialize the header */
428 SCM_BYTECODE_NREQS (bytecode) = SCM_INUM (nreqs);
429 SCM_BYTECODE_RESTP (bytecode) = SCM_FALSEP (restp) ? 0 : 1;
430 SCM_BYTECODE_NVARS (bytecode) = SCM_INUM (nvars);
431 SCM_BYTECODE_NEXTS (bytecode) = SCM_INUM (nexts);
432 len = SCM_LENGTH (exts);
433 if (len == 0)
434 {
435 SCM_BYTECODE_EXTS (bytecode) = NULL;
436 }
437 else
438 {
439 SCM_BYTECODE_EXTS (bytecode) =
440 scm_must_malloc ((len + 1) * sizeof (int), FUNC_NAME);
441 SCM_BYTECODE_EXTS (bytecode)[0] = len;
442 for (i = 0; i < len; i++)
443 SCM_BYTECODE_EXTS (bytecode)[i + 1] = SCM_INUM (SCM_VELTS (exts)[i]);
444 }
445
446 /* Initialize the body */
447 for (i = 0; i < size; i++)
448 {
449 struct scm_instruction *p;
450
451 /* Process instruction */
452 if (!SCM_SYMBOLP (old[i])
4b482259 453 || !(p = scm_lookup_instruction (SCM_SYMBOL_CHARS (old[i]))))
a98cef7e 454 SCM_MISC_ERROR ("Invalid instruction: ~S", SCM_LIST1 (old[i]));
4b482259 455 new[i] = SCM_PACK (p->opcode);
a98cef7e
KN
456
457 /* Process arguments */
458 if (p->type == INST_NONE)
459 continue;
460 if (++i >= size)
461 SCM_MISC_ERROR ("Unexpected end of code", SCM_EOL);
462 switch (p->type)
463 {
464 case INST_NONE:
465 /* never come here */
466 case INST_INUM:
467 SCM_VALIDATE_INUM (1, old[i]);
468 /* fall through */
469 case INST_SCM:
470 /* just copy */
471 new[i] = old[i];
472 break;
473 case INST_TOP:
474 /* top-level variable */
475 SCM_VALIDATE_SYMBOL (1, old[i]);
9df03fd0 476 new[i] = lookup_variable (old[i]);
a98cef7e
KN
477 break;
478 case INST_EXT:
479 /* just copy for now */
480 SCM_VALIDATE_CONS (1, old[i]);
481 SCM_VALIDATE_INUM (1, SCM_CAR (old[i]));
482 SCM_VALIDATE_INUM (1, SCM_CDR (old[i]));
483 new[i] = old[i];
484 break;
485 case INST_CODE:
486 /* another bytecode */
487 new[i] = scm_make_bytecode (old[i]);
488 break;
489 case INST_ADDR:
490 /* real address */
491 SCM_VALIDATE_INUM (1, old[i]);
492 /* Without the following intermediate variables, type conversion
493 fails on my machine. Casting doesn't work well, why? */
494 offset = SCM_INUM (old[i]);
495 address = new + offset;
496 new[i] = SCM_VM_MAKE_ADDRESS (address);
497 break;
498 }
499 }
500 return bytecode;
501}
502#undef FUNC_NAME
503
504SCM_DEFINE (scm_bytecode_decode, "bytecode-decode", 1, 0, 0,
505 (SCM bytecode),
506"")
507#define FUNC_NAME s_scm_bytecode_decode
508{
509 int i, size, offset;
510 SCM code, *old, *new;
511
512 SCM_VALIDATE_BYTECODE (1, bytecode);
513
514 size = SCM_BYTECODE_SIZE (bytecode);
515 old = SCM_BYTECODE_BASE (bytecode);
516 code = scm_make_vector (SCM_MAKINUM (size), SCM_BOOL_F);
517 new = SCM_VELTS (code);
518
519 for (i = 0; i < size; i++)
520 {
521 struct scm_instruction *p;
522
523 /* Process instruction */
4b482259 524 p = SCM_INSTRUCTION (old[i]);
a98cef7e
KN
525 if (!p)
526 {
527 broken:
528 SCM_MISC_ERROR ("Broken bytecode", SCM_EOL);
529 }
530 new[i] = scm_instruction_name (p->obj);
531
532 /* Process arguments */
533 if (p->type == INST_NONE)
534 continue;
535 if (++i >= size)
536 goto broken;
537 switch (p->type)
538 {
539 case INST_NONE:
540 /* never come here */
541 case INST_INUM:
542 case INST_SCM:
543 case INST_EXT:
544 /* just copy */
545 new[i] = old[i];
546 break;
547 case INST_TOP:
548 /* top-level variable */
549 new[i] = SCM_CAR (old[i]);
550 break;
551 case INST_CODE:
552 /* another bytecode */
553 new[i] = scm_bytecode_decode (old[i]);
554 break;
555 case INST_ADDR:
556 /* program address */
557 offset = SCM_VM_ADDRESS (old[i]) - old;
558 new[i] = SCM_MAKINUM (offset);
559 break;
560 }
561 }
562 return code;
563}
564#undef FUNC_NAME
565
566\f
567/*
568 * Program
569 */
570
571static long scm_program_tag;
572
573static SCM
d608d68d 574make_program (SCM code, SCM env)
a98cef7e 575{
d608d68d 576 SCM_RETURN_NEWSMOB2 (scm_program_tag, SCM_UNPACK (code), SCM_UNPACK (env));
a98cef7e
KN
577}
578
579static SCM
580mark_program (SCM program)
581{
582 scm_gc_mark (SCM_PROGRAM_CODE (program));
583 return SCM_PROGRAM_ENV (program);
584}
585
26403690
KN
586static SCM scm_vm_apply (SCM vm, SCM program, SCM args);
587static SCM make_vm (int stack_size);
588
589static SCM
590apply_program (SCM program, SCM args)
591{
592 return scm_vm_apply (make_vm (VM_DEFAULT_STACK_SIZE), program, args);
593}
594
a98cef7e
KN
595static void
596init_program_type ()
597{
598 scm_program_tag = scm_make_smob_type ("program", 0);
599 scm_set_smob_mark (scm_program_tag, mark_program);
e6db4668 600 scm_set_smob_print (scm_program_tag, scm_smob_print_with_name);
26403690 601 scm_set_smob_apply (scm_program_tag, apply_program, 0, 0, 1);
a98cef7e
KN
602}
603
604/* Scheme interface */
605
606SCM_DEFINE (scm_program_p, "program?", 1, 0, 0,
607 (SCM obj),
608"")
609#define FUNC_NAME s_scm_program_p
610{
611 return SCM_BOOL (SCM_PROGRAM_P (obj));
612}
613#undef FUNC_NAME
614
615SCM_DEFINE (scm_make_program, "make-program", 2, 0, 0,
616 (SCM bytecode, SCM parent),
617"")
618#define FUNC_NAME s_scm_make_program
619{
620 SCM_VALIDATE_BYTECODE (1, bytecode);
621 return make_program (bytecode, parent);
622}
623#undef FUNC_NAME
624
a98cef7e
KN
625SCM_DEFINE (scm_program_code, "program-code", 1, 0, 0,
626 (SCM program),
627"")
628#define FUNC_NAME s_scm_program_code
629{
630 SCM_VALIDATE_PROGRAM (1, program);
631 return SCM_PROGRAM_CODE (program);
632}
633#undef FUNC_NAME
634
635SCM_DEFINE (scm_program_base, "program-base", 1, 0, 0,
636 (SCM program),
637"")
638#define FUNC_NAME s_scm_program_base
639{
640 SCM_VALIDATE_PROGRAM (1, program);
641 return SCM_VM_MAKE_ADDRESS (SCM_PROGRAM_BASE (program));
642}
643#undef FUNC_NAME
644
a98cef7e
KN
645\f
646/*
647 * VM Frame
648 */
649
650static long scm_vm_frame_tag;
651
652/* This is used for debugging */
653struct scm_vm_frame {
654 int size;
655 SCM program;
656 SCM variables;
657 SCM dynamic_link;
d608d68d 658 SCM external_link;
a98cef7e
KN
659 SCM stack_pointer;
660 SCM return_address;
661};
662
663#define SCM_VM_FRAME_P(OBJ) SCM_SMOB_PREDICATE (scm_vm_frame_tag, OBJ)
664#define SCM_VM_FRAME_DATA(FR) ((struct scm_vm_frame *) SCM_SMOB_DATA (FR))
665#define SCM_VALIDATE_VM_FRAME(POS,OBJ) SCM_MAKE_VALIDATE (POS, OBJ, VM_FRAME_P)
666
667static SCM
668make_vm_frame (SCM *fp)
669{
670 int i;
671 int size = SCM_INUM (SCM_VM_FRAME_SIZE (fp));
672 struct scm_vm_frame *p = scm_must_malloc (sizeof (*p), "make_vm_frame");
673 p->program = SCM_VM_FRAME_PROGRAM (fp);
674 p->dynamic_link = SCM_VM_FRAME_DYNAMIC_LINK (fp);
d608d68d 675 p->external_link = SCM_VM_FRAME_EXTERNAL_LINK (fp);
a98cef7e
KN
676 p->stack_pointer = SCM_VM_FRAME_STACK_POINTER (fp);
677 p->return_address = SCM_VM_FRAME_RETURN_ADDRESS (fp);
678
679 if (!SCM_FALSEP (p->dynamic_link))
680 p->dynamic_link = make_vm_frame (SCM_VM_ADDRESS (p->dynamic_link));
681
682 size += SCM_PROGRAM_NREQS (p->program) + SCM_PROGRAM_RESTP (p->program);
683 p->variables = scm_make_vector (SCM_MAKINUM (size), SCM_BOOL_F);
684 for (i = 0; i < size; i++)
685 SCM_VELTS (p->variables)[i] = SCM_VM_FRAME_VARIABLE (fp, i);
686
687 SCM_RETURN_NEWSMOB (scm_vm_frame_tag, p);
688}
689
690static SCM
691mark_vm_frame (SCM frame)
692{
693 struct scm_vm_frame *p = SCM_VM_FRAME_DATA (frame);
694 scm_gc_mark (p->program);
695 scm_gc_mark (p->dynamic_link);
d608d68d 696 scm_gc_mark (p->external_link);
a98cef7e
KN
697 return p->variables;
698}
699
700static void
701init_vm_frame_type ()
702{
703 scm_vm_frame_tag = scm_make_smob_type ("vm-frame", 0);
704 scm_set_smob_mark (scm_vm_frame_tag, mark_vm_frame);
705}
706
707/* Scheme interface */
708
709SCM_DEFINE (scm_frame_p, "frame?", 1, 0, 0,
710 (SCM obj),
711"")
712#define FUNC_NAME s_scm_frame_p
713{
714 return SCM_BOOL (SCM_VM_FRAME_P (obj));
715}
716#undef FUNC_NAME
717
718SCM_DEFINE (scm_frame_program, "frame-program", 1, 0, 0,
719 (SCM frame),
720"")
721#define FUNC_NAME s_scm_frame_program
722{
723 SCM_VALIDATE_VM_FRAME (1, frame);
724 return SCM_VM_FRAME_DATA (frame)->program;
725}
726#undef FUNC_NAME
727
728SCM_DEFINE (scm_frame_variables, "frame-variables", 1, 0, 0,
729 (SCM frame),
730"")
731#define FUNC_NAME s_scm_frame_variables
732{
733 SCM_VALIDATE_VM_FRAME (1, frame);
734 return SCM_VM_FRAME_DATA (frame)->variables;
735}
736#undef FUNC_NAME
737
738SCM_DEFINE (scm_frame_dynamic_link, "frame-dynamic-link", 1, 0, 0,
739 (SCM frame),
740"")
741#define FUNC_NAME s_scm_frame_dynamic_link
742{
743 SCM_VALIDATE_VM_FRAME (1, frame);
744 return SCM_VM_FRAME_DATA (frame)->dynamic_link;
745}
746#undef FUNC_NAME
747
d608d68d
KN
748SCM_DEFINE (scm_frame_external_link, "frame-external-link", 1, 0, 0,
749 (SCM frame),
750"")
751#define FUNC_NAME s_scm_frame_external_link
752{
753 SCM_VALIDATE_VM_FRAME (1, frame);
754 return SCM_VM_FRAME_DATA (frame)->external_link;
755}
756#undef FUNC_NAME
757
a98cef7e
KN
758SCM_DEFINE (scm_frame_stack_pointer, "frame-stack-pointer", 1, 0, 0,
759 (SCM frame),
760"")
761#define FUNC_NAME s_scm_frame_stack_pointer
762{
763 SCM_VALIDATE_VM_FRAME (1, frame);
764 return SCM_VM_FRAME_DATA (frame)->stack_pointer;
765}
766#undef FUNC_NAME
767
768SCM_DEFINE (scm_frame_return_address, "frame-return-address", 1, 0, 0,
769 (SCM frame),
770"")
771#define FUNC_NAME s_scm_frame_return_address
772{
773 SCM_VALIDATE_VM_FRAME (1, frame);
774 return SCM_VM_FRAME_DATA (frame)->return_address;
775}
776#undef FUNC_NAME
777
778\f
779/*
780 * VM Continuation
781 */
782
783static long scm_vm_cont_tag;
784
785static SCM
786capture_vm_cont (struct scm_vm *vmp)
787{
788 struct scm_vm *p = scm_must_malloc (sizeof (*p), "capture_vm_cont");
789 p->stack_size = vmp->stack_limit - vmp->sp;
790 p->stack_base = scm_must_malloc (p->stack_size * sizeof (SCM),
791 "capture_vm_cont");
792 p->stack_limit = p->stack_base + p->stack_size - 1;
793 p->pc = vmp->pc;
794 p->sp = (SCM *) (vmp->stack_limit - vmp->sp);
795 p->fp = (SCM *) (vmp->stack_limit - vmp->fp);
796 memcpy (p->stack_base, vmp->sp + 1, vmp->stack_size * sizeof (SCM));
797 SCM_RETURN_NEWSMOB (scm_vm_cont_tag, p);
798}
799
800static void
801reinstate_vm_cont (struct scm_vm *vmp, SCM cont)
802{
803 struct scm_vm *p = SCM_VM_CONT_VMP (cont);
804 if (vmp->stack_size < p->stack_size)
805 {
806 puts ("FIXME: Need to expand");
807 abort ();
808 }
809 vmp->pc = p->pc;
810 vmp->sp = vmp->stack_limit - (int) p->sp;
811 vmp->fp = vmp->stack_limit - (int) p->fp;
812 memcpy (vmp->sp + 1, p->stack_base, p->stack_size * sizeof (SCM));
813}
814
815static SCM
816mark_vm_cont (SCM cont)
817{
818 SCM *p;
819 struct scm_vm *vmp = SCM_VM_CONT_VMP (cont);
820 for (p = vmp->stack_base; p <= vmp->stack_limit; p++)
821 if (SCM_NIMP (*p))
822 scm_gc_mark (*p);
823 return SCM_BOOL_F;
824}
825
826static scm_sizet
827free_vm_cont (SCM cont)
828{
829 struct scm_vm *p = SCM_VM_CONT_VMP (cont);
830 int size = sizeof (struct scm_vm) + p->stack_size * sizeof (SCM);
831 scm_must_free (p->stack_base);
832 scm_must_free (p);
833 return size;
834}
835
836static void
837init_vm_cont_type ()
838{
839 scm_vm_cont_tag = scm_make_smob_type ("vm-cont", 0);
840 scm_set_smob_mark (scm_vm_cont_tag, mark_vm_cont);
841 scm_set_smob_free (scm_vm_cont_tag, free_vm_cont);
842}
843
844\f
845/*
846 * VM
847 */
848
849static long scm_vm_tag;
850
851static SCM
852make_vm (int stack_size)
853{
854 struct scm_vm *vmp = scm_must_malloc (sizeof (struct scm_vm), "make_vm");
855 vmp->stack_size = stack_size;
856 vmp->stack_base = scm_must_malloc (stack_size * sizeof (SCM), "make_vm");
857 vmp->stack_limit = vmp->stack_base + vmp->stack_size - 1;
858 vmp->sp = vmp->stack_limit;
859 vmp->ac = SCM_BOOL_F;
860 vmp->pc = NULL;
861 vmp->fp = NULL;
862 vmp->options = SCM_EOL;
863 vmp->boot_hook = scm_make_hook (SCM_MAKINUM (1));
864 vmp->halt_hook = scm_make_hook (SCM_MAKINUM (1));
865 vmp->next_hook = scm_make_hook (SCM_MAKINUM (1));
866 vmp->call_hook = scm_make_hook (SCM_MAKINUM (1));
867 vmp->apply_hook = scm_make_hook (SCM_MAKINUM (1));
868 vmp->return_hook = scm_make_hook (SCM_MAKINUM (1));
869 SCM_RETURN_NEWSMOB (scm_vm_tag, vmp);
870}
871
872static SCM
873mark_vm (SCM vm)
874{
875 SCM *p;
876 struct scm_vm *vmp = SCM_VM_DATA (vm);
877 for (p = vmp->sp + 1; p <= vmp->stack_limit; p++)
878 if (SCM_NIMP (*p))
879 scm_gc_mark (*p);
880
881 scm_gc_mark (vmp->ac);
882 scm_gc_mark (vmp->boot_hook);
883 scm_gc_mark (vmp->halt_hook);
884 scm_gc_mark (vmp->next_hook);
885 scm_gc_mark (vmp->call_hook);
886 scm_gc_mark (vmp->apply_hook);
887 scm_gc_mark (vmp->return_hook);
888 return vmp->options;
889}
890
891static void
892init_vm_type ()
893{
894 scm_vm_tag = scm_make_smob_type ("vm", sizeof (struct scm_vm));
895 scm_set_smob_mark (scm_vm_tag, mark_vm);
e6db4668 896 scm_set_smob_print (scm_vm_tag, scm_smob_print_with_name);
a98cef7e
KN
897}
898
899/* Scheme interface */
900
901SCM_DEFINE (scm_vm_version, "vm-version", 0, 0, 0,
902 (),
903"")
904#define FUNC_NAME s_scm_vm_version
905{
906 return scm_makfrom0str (VERSION);
907}
908#undef FUNC_NAME
909
910SCM_DEFINE (scm_vm_p, "vm?", 1, 0, 0,
911 (SCM obj),
912"")
913#define FUNC_NAME s_scm_vm_p
914{
915 return SCM_BOOL (SCM_VM_P (obj));
916}
917#undef FUNC_NAME
918
919SCM_DEFINE (scm_make_vm, "make-vm", 0, 0, 0,
920 (),
921"")
922#define FUNC_NAME s_scm_make_vm
923{
924 return make_vm (VM_DEFAULT_STACK_SIZE);
925}
926#undef FUNC_NAME
927
928SCM_DEFINE (scm_vm_ac, "vm:ac", 1, 0, 0,
929 (SCM vm),
930"")
931#define FUNC_NAME s_scm_vm_ac
932{
933 SCM_VALIDATE_VM (1, vm);
934 return SCM_VM_DATA (vm)->ac;
935}
936#undef FUNC_NAME
937
938SCM_DEFINE (scm_vm_pc, "vm:pc", 1, 0, 0,
939 (SCM vm),
940"")
941#define FUNC_NAME s_scm_vm_pc
942{
943 SCM_VALIDATE_VM (1, vm);
944 return SCM_VM_MAKE_ADDRESS (SCM_VM_DATA (vm)->pc);
945}
946#undef FUNC_NAME
947
948SCM_DEFINE (scm_vm_sp, "vm:sp", 1, 0, 0,
949 (SCM vm),
950"")
951#define FUNC_NAME s_scm_vm_sp
952{
953 SCM_VALIDATE_VM (1, vm);
954 return SCM_VM_MAKE_ADDRESS (SCM_VM_DATA (vm)->sp);
955}
956#undef FUNC_NAME
957
958SCM_DEFINE (scm_vm_fp, "vm:fp", 1, 0, 0,
959 (SCM vm),
960"")
961#define FUNC_NAME s_scm_vm_fp
962{
963 SCM_VALIDATE_VM (1, vm);
964 return SCM_VM_MAKE_ADDRESS (SCM_VM_DATA (vm)->fp);
965}
966#undef FUNC_NAME
967
968SCM_DEFINE (scm_vm_current_frame, "vm-current-frame", 1, 0, 0,
969 (SCM vm),
970"")
971#define FUNC_NAME s_scm_vm_current_frame
972{
973 SCM_VALIDATE_VM (1, vm);
974 return make_vm_frame (SCM_VM_DATA (vm)->fp);
975}
976#undef FUNC_NAME
977
978SCM_DEFINE (scm_vm_fetch_code, "vm-fetch-code", 2, 0, 0,
979 (SCM vm, SCM addr),
980"")
981#define FUNC_NAME s_scm_vm_fetch_code
982{
983 SCM *p, list;
984 struct scm_instruction *inst;
985
986 SCM_VALIDATE_VM (1, vm);
987 SCM_VALIDATE_INUM (2, addr);
988
989 p = SCM_VM_ADDRESS (addr);
990
4b482259 991 inst = SCM_INSTRUCTION (*p);
a98cef7e
KN
992 if (!inst)
993 SCM_MISC_ERROR ("Broken bytecode", SCM_LIST1 (addr));
994
995 list = SCM_LIST1 (scm_instruction_name (inst->obj));
996 if (inst->type != INST_NONE)
997 {
998 if (inst->type == INST_ADDR)
999 {
1000 p = SCM_CODE_TO_ADDR (p[1]);
1001 SCM_SETCDR (list, SCM_LIST1 (SCM_VM_MAKE_ADDRESS (p)));
1002 }
1003 else
1004 SCM_SETCDR (list, SCM_LIST1 (p[1]));
1005 }
1006 return list;
1007}
1008#undef FUNC_NAME
1009
1010SCM_DEFINE (scm_vm_stack_to_list, "vm-stack->list", 1, 0, 0,
1011 (SCM vm),
1012"")
1013#define FUNC_NAME s_scm_vm_stack_to_list
1014{
1015 struct scm_vm *vmp;
1016 SCM *p, list = SCM_EOL;
1017
1018 SCM_VALIDATE_VM (1, vm);
1019
1020 vmp = SCM_VM_DATA (vm);
1021 for (p = vmp->sp + 1; p <= vmp->stack_limit; p++)
1022 list = scm_cons (*p, list);
1023 return list;
1024}
1025#undef FUNC_NAME
1026
1027SCM_DEFINE (scm_vm_option, "vm-option", 2, 0, 0,
1028 (SCM vm, SCM key),
1029"")
1030#define FUNC_NAME s_scm_vm_option
1031{
1032 SCM_VALIDATE_VM (1, vm);
1033 SCM_VALIDATE_SYMBOL (2, key);
1034 return scm_assq_ref (SCM_VM_DATA (vm)->options, key);
1035}
1036#undef FUNC_NAME
1037
1038SCM_DEFINE (scm_vm_set_option_x, "vm-set-option!", 3, 0, 0,
1039 (SCM vm, SCM key, SCM val),
1040"")
1041#define FUNC_NAME s_scm_vm_set_option_x
1042{
1043 SCM_VALIDATE_VM (1, vm);
1044 SCM_VALIDATE_SYMBOL (2, key);
1045 SCM_VM_DATA (vm)->options
1046 = scm_assq_set_x (SCM_VM_DATA (vm)->options, key, val);
1047 return SCM_UNSPECIFIED;
1048}
1049#undef FUNC_NAME
1050
1051SCM_DEFINE (scm_vm_boot_hook, "vm-boot-hook", 1, 0, 0,
1052 (SCM vm),
1053"")
1054#define FUNC_NAME s_scm_vm_boot_hook
1055{
1056 SCM_VALIDATE_VM (1, vm);
1057 return SCM_VM_DATA (vm)->boot_hook;
1058}
1059#undef FUNC_NAME
1060
1061SCM_DEFINE (scm_vm_halt_hook, "vm-halt-hook", 1, 0, 0,
1062 (SCM vm),
1063"")
1064#define FUNC_NAME s_scm_vm_halt_hook
1065{
1066 SCM_VALIDATE_VM (1, vm);
1067 return SCM_VM_DATA (vm)->halt_hook;
1068}
1069#undef FUNC_NAME
1070
1071SCM_DEFINE (scm_vm_next_hook, "vm-next-hook", 1, 0, 0,
1072 (SCM vm),
1073"")
1074#define FUNC_NAME s_scm_vm_next_hook
1075{
1076 SCM_VALIDATE_VM (1, vm);
1077 return SCM_VM_DATA (vm)->next_hook;
1078}
1079#undef FUNC_NAME
1080
1081SCM_DEFINE (scm_vm_call_hook, "vm-call-hook", 1, 0, 0,
1082 (SCM vm),
1083"")
1084#define FUNC_NAME s_scm_vm_call_hook
1085{
1086 SCM_VALIDATE_VM (1, vm);
1087 return SCM_VM_DATA (vm)->call_hook;
1088}
1089#undef FUNC_NAME
1090
1091SCM_DEFINE (scm_vm_apply_hook, "vm-apply-hook", 1, 0, 0,
1092 (SCM vm),
1093"")
1094#define FUNC_NAME s_scm_vm_apply_hook
1095{
1096 SCM_VALIDATE_VM (1, vm);
1097 return SCM_VM_DATA (vm)->apply_hook;
1098}
1099#undef FUNC_NAME
1100
1101SCM_DEFINE (scm_vm_return_hook, "vm-return-hook", 1, 0, 0,
1102 (SCM vm),
1103"")
1104#define FUNC_NAME s_scm_vm_return_hook
1105{
1106 SCM_VALIDATE_VM (1, vm);
1107 return SCM_VM_DATA (vm)->return_hook;
1108}
1109#undef FUNC_NAME
1110
1111SCM_SYMBOL (sym_debug, "debug");
1112
1113static SCM scm_regular_vm (SCM vm, SCM program);
1114static SCM scm_debug_vm (SCM vm, SCM program);
1115
4b482259 1116#define VM_CODE(name) SCM_PACK (scm_lookup_instruction (name)->opcode)
a98cef7e
KN
1117
1118SCM_DEFINE (scm_vm_run, "vm-run", 2, 0, 0,
1119 (SCM vm, SCM program),
1120"")
1121#define FUNC_NAME s_scm_vm_run
1122{
1123 SCM bootcode;
1124 static SCM template[5];
1125
1126 SCM_VALIDATE_VM (1, vm);
1127 SCM_VALIDATE_PROGRAM (2, program);
1128
1129 if (SCM_EQ_P (template[0], SCM_PACK (0)))
1130 {
1131 template[0] = VM_CODE ("%loadc");
26403690 1132 template[1] = SCM_BOOL_F; /* overwritten */
a98cef7e
KN
1133 template[2] = VM_CODE ("%call");
1134 template[3] = SCM_MAKINUM (0);
1135 template[4] = VM_CODE ("%halt");
1136 }
1137
1138 /* Create a boot program */
1139 bootcode = make_bytecode (5);
1140 memcpy (SCM_BYTECODE_BASE (bootcode), template, sizeof (SCM) * 5);
1141 SCM_BYTECODE_BASE (bootcode)[1] = program;
1142 SCM_BYTECODE_SIZE (bootcode) = 5;
1143 SCM_BYTECODE_EXTS (bootcode) = NULL;
1144 SCM_BYTECODE_NREQS (bootcode) = 0;
1145 SCM_BYTECODE_RESTP (bootcode) = 0;
1146 SCM_BYTECODE_NVARS (bootcode) = 0;
1147 SCM_BYTECODE_NEXTS (bootcode) = 0;
1148 program = SCM_MAKE_PROGRAM (bootcode, SCM_BOOL_F);
1149
1150 if (SCM_FALSEP (scm_vm_option (vm, sym_debug)))
1151 return scm_regular_vm (vm, program);
1152 else
1153 return scm_debug_vm (vm, program);
1154}
1155#undef FUNC_NAME
1156
26403690
KN
1157SCM_DEFINE (scm_vm_apply, "vm-apply", 3, 0, 0,
1158 (SCM vm, SCM program, SCM args),
1159"")
1160#define FUNC_NAME s_scm_vm_apply
1161{
1162 int len;
1163 SCM bootcode;
1164 static SCM template[7];
1165
1166 SCM_VALIDATE_VM (1, vm);
1167 SCM_VALIDATE_PROGRAM (2, program);
1168 SCM_VALIDATE_LIST_COPYLEN (3, args, len);
1169
1170 if (SCM_EQ_P (template[0], SCM_PACK (0)))
1171 {
1172 template[0] = VM_CODE ("%push-list");
1173 template[1] = SCM_EOL; /* overwritten */
1174 template[2] = VM_CODE ("%loadc");
1175 template[3] = SCM_BOOL_F; /* overwritten */
1176 template[4] = VM_CODE ("%call");
1177 template[5] = SCM_MAKINUM (0); /* overwritten */
1178 template[6] = VM_CODE ("%halt");
1179 }
1180
1181 /* Create a boot program */
1182 bootcode = make_bytecode (7);
1183 memcpy (SCM_BYTECODE_BASE (bootcode), template, sizeof (SCM) * 7);
1184 SCM_BYTECODE_BASE (bootcode)[1] = args;
1185 SCM_BYTECODE_BASE (bootcode)[3] = program;
1186 SCM_BYTECODE_BASE (bootcode)[5] = SCM_MAKINUM (len);
1187 SCM_BYTECODE_SIZE (bootcode) = 7;
1188 SCM_BYTECODE_EXTS (bootcode) = NULL;
1189 SCM_BYTECODE_NREQS (bootcode) = 0;
1190 SCM_BYTECODE_RESTP (bootcode) = 0;
1191 SCM_BYTECODE_NVARS (bootcode) = 0;
1192 SCM_BYTECODE_NEXTS (bootcode) = 0;
1193 program = SCM_MAKE_PROGRAM (bootcode, SCM_BOOL_F);
1194
1195 if (SCM_FALSEP (scm_vm_option (vm, sym_debug)))
1196 return scm_regular_vm (vm, program);
1197 else
1198 return scm_debug_vm (vm, program);
1199}
1200#undef FUNC_NAME
1201
a98cef7e
KN
1202\f
1203/*
1204 * The VM engines
1205 */
1206
1207/* We don't want to snarf the engines */
1208#ifndef SCM_MAGIC_SNARFER
1209
1210/* the regular engine */
1211#define VM_ENGINE SCM_VM_REGULAR_ENGINE
1212#include "vm_engine.c"
1213#undef VM_ENGINE
1214
1215/* the debug engine */
1216#define VM_ENGINE SCM_VM_DEBUG_ENGINE
1217#include "vm_engine.c"
1218#undef VM_ENGINE
1219
1220#endif /* not SCM_MAGIC_SNARFER */
1221
1222\f
1223/*
1224 * Initialize
1225 */
1226
1227static SCM scm_module_vm;
1228
1229void
1230scm_init_vm ()
1231{
1232 SCM old_module;
1233
1234 /* Initialize the module */
1235 scm_module_vm = scm_make_module (scm_read_0str ("(vm vm)"));
1236 old_module = scm_select_module (scm_module_vm);
e6db4668 1237 init_name_property ();
a98cef7e
KN
1238 init_instruction_type ();
1239 init_bytecode_type ();
1240 init_program_type ();
1241 init_vm_frame_type ();
1242 init_vm_cont_type ();
1243 init_vm_type ();
a98cef7e 1244#include "vm.x"
a98cef7e
KN
1245 scm_select_module (old_module);
1246
a98cef7e 1247 {
a98cef7e 1248 struct scm_instruction *p;
4b482259 1249 for (p = scm_instruction_table; p->opcode != op_last; p++)
a98cef7e 1250 {
4b482259 1251 p->obj = scm_permanent_object (make_instruction (p));
a98cef7e 1252 if (p->restp) p->type = INST_INUM;
a98cef7e
KN
1253 }
1254 }
1255}
1256
1257void
1258scm_init_vm_vm_module ()
1259{
1260 scm_register_module_xxx ("vm vm", (void *) scm_init_vm);
1261}