Commit | Line | Data |
---|---|---|
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 | ||
62 | static SCM scm_name_property; | |
63 | ||
64 | SCM_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 | ||
73 | SCM_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 | ||
83 | int | |
84 | scm_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 | ||
105 | static void | |
106 | init_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 | 117 | static long scm_instruction_tag; |
a98cef7e | 118 | |
4b482259 | 119 | static 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 | |
131 | static SCM | |
132 | make_instruction (struct scm_instruction *instp) | |
133 | { | |
134 | SCM_RETURN_NEWSMOB (scm_instruction_tag, instp); | |
135 | } | |
136 | ||
137 | static int | |
138 | print_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 | ||
146 | static void | |
147 | init_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 | ||
155 | static struct scm_instruction * | |
4b482259 | 156 | scm_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 | ||
167 | SCM_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 | ||
176 | SCM_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 | ||
185 | SCM_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 | ||
194 | SCM_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 | ||
204 | SCM_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 | ||
220 | SCM_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 | ||
233 | SCM_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 | ||
243 | SCM_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 | ||
253 | SCM_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 | ||
263 | SCM_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 | ||
276 | SCM_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 | ||
297 | static long scm_bytecode_tag; | |
298 | ||
299 | static SCM | |
300 | make_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 | ||
308 | static SCM | |
309 | mark_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 | ||
338 | static int | |
339 | print_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 | ||
347 | static scm_sizet | |
348 | free_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 | ||
361 | static void | |
362 | init_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 | ||
372 | static SCM | |
373 | lookup_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 | ||
384 | SCM_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 | ||
393 | SCM_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 | ||
504 | SCM_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 | ||
571 | static long scm_program_tag; | |
572 | ||
573 | static SCM | |
d608d68d | 574 | make_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 | ||
579 | static SCM | |
580 | mark_program (SCM program) | |
581 | { | |
582 | scm_gc_mark (SCM_PROGRAM_CODE (program)); | |
583 | return SCM_PROGRAM_ENV (program); | |
584 | } | |
585 | ||
26403690 KN |
586 | static SCM scm_vm_apply (SCM vm, SCM program, SCM args); |
587 | static SCM make_vm (int stack_size); | |
588 | ||
589 | static SCM | |
590 | apply_program (SCM program, SCM args) | |
591 | { | |
592 | return scm_vm_apply (make_vm (VM_DEFAULT_STACK_SIZE), program, args); | |
593 | } | |
594 | ||
a98cef7e KN |
595 | static void |
596 | init_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 | ||
606 | SCM_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 | ||
615 | SCM_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 |
625 | SCM_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 | ||
635 | SCM_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 | ||
650 | static long scm_vm_frame_tag; | |
651 | ||
652 | /* This is used for debugging */ | |
653 | struct 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 | ||
667 | static SCM | |
668 | make_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 | ||
690 | static SCM | |
691 | mark_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 | ||
700 | static void | |
701 | init_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 | ||
709 | SCM_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 | ||
718 | SCM_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 | ||
728 | SCM_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 | ||
738 | SCM_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 |
748 | SCM_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 |
758 | SCM_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 | ||
768 | SCM_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 | ||
783 | static long scm_vm_cont_tag; | |
784 | ||
785 | static SCM | |
786 | capture_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 | ||
800 | static void | |
801 | reinstate_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 | ||
815 | static SCM | |
816 | mark_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 | ||
826 | static scm_sizet | |
827 | free_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 | ||
836 | static void | |
837 | init_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 | ||
849 | static long scm_vm_tag; | |
850 | ||
851 | static SCM | |
852 | make_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 | ||
872 | static SCM | |
873 | mark_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 | ||
891 | static void | |
892 | init_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 | ||
901 | SCM_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 | ||
910 | SCM_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 | ||
919 | SCM_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 | ||
928 | SCM_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 | ||
938 | SCM_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 | ||
948 | SCM_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 | ||
958 | SCM_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 | ||
968 | SCM_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 | ||
978 | SCM_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 | ||
1010 | SCM_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 | ||
1027 | SCM_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 | ||
1038 | SCM_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 | ||
1051 | SCM_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 | ||
1061 | SCM_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 | ||
1071 | SCM_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 | ||
1081 | SCM_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 | ||
1091 | SCM_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 | ||
1101 | SCM_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 | ||
1111 | SCM_SYMBOL (sym_debug, "debug"); | |
1112 | ||
1113 | static SCM scm_regular_vm (SCM vm, SCM program); | |
1114 | static 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 | |
1118 | SCM_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 |
1157 | SCM_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 | ||
1227 | static SCM scm_module_vm; | |
1228 | ||
1229 | void | |
1230 | scm_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 | ||
1257 | void | |
1258 | scm_init_vm_vm_module () | |
1259 | { | |
1260 | scm_register_module_xxx ("vm vm", (void *) scm_init_vm); | |
1261 | } |