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