generics now dispatch as applicable structs
[bpt/guile.git] / libguile / vm-i-system.c
1 /* Copyright (C) 2001,2008,2009 Free Software Foundation, Inc.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
17 */
18
19
20 /* This file is included in vm_engine.c */
21
22 \f
23 /*
24 * Basic operations
25 */
26
27 VM_DEFINE_INSTRUCTION (0, nop, "nop", 0, 0, 0)
28 {
29 NEXT;
30 }
31
32 VM_DEFINE_INSTRUCTION (1, halt, "halt", 0, 0, 0)
33 {
34 vp->time += scm_c_get_internal_run_time () - start_time;
35 HALT_HOOK ();
36 nvalues = SCM_I_INUM (*sp--);
37 NULLSTACK (1);
38 if (nvalues == 1)
39 POP (finish_args);
40 else
41 {
42 POP_LIST (nvalues);
43 POP (finish_args);
44 SYNC_REGISTER ();
45 finish_args = scm_values (finish_args);
46 }
47
48 {
49 #ifdef VM_ENABLE_STACK_NULLING
50 SCM *old_sp = sp;
51 #endif
52
53 /* Restore registers */
54 sp = SCM_FRAME_LOWER_ADDRESS (fp) - 1;
55 /* Setting the ip here doesn't actually affect control flow, as the calling
56 code will restore its own registers, but it does help when walking the
57 stack */
58 ip = SCM_FRAME_RETURN_ADDRESS (fp);
59 fp = SCM_FRAME_DYNAMIC_LINK (fp);
60 NULLSTACK (old_sp - sp);
61 }
62
63 goto vm_done;
64 }
65
66 VM_DEFINE_INSTRUCTION (2, break, "break", 0, 0, 0)
67 {
68 BREAK_HOOK ();
69 NEXT;
70 }
71
72 VM_DEFINE_INSTRUCTION (3, drop, "drop", 0, 1, 0)
73 {
74 DROP ();
75 NEXT;
76 }
77
78 VM_DEFINE_INSTRUCTION (4, dup, "dup", 0, 0, 1)
79 {
80 SCM x = *sp;
81 PUSH (x);
82 NEXT;
83 }
84
85 \f
86 /*
87 * Object creation
88 */
89
90 VM_DEFINE_INSTRUCTION (5, void, "void", 0, 0, 1)
91 {
92 PUSH (SCM_UNSPECIFIED);
93 NEXT;
94 }
95
96 VM_DEFINE_INSTRUCTION (6, make_true, "make-true", 0, 0, 1)
97 {
98 PUSH (SCM_BOOL_T);
99 NEXT;
100 }
101
102 VM_DEFINE_INSTRUCTION (7, make_false, "make-false", 0, 0, 1)
103 {
104 PUSH (SCM_BOOL_F);
105 NEXT;
106 }
107
108 VM_DEFINE_INSTRUCTION (8, make_eol, "make-eol", 0, 0, 1)
109 {
110 PUSH (SCM_EOL);
111 NEXT;
112 }
113
114 VM_DEFINE_INSTRUCTION (9, make_int8, "make-int8", 1, 0, 1)
115 {
116 PUSH (SCM_I_MAKINUM ((signed char) FETCH ()));
117 NEXT;
118 }
119
120 VM_DEFINE_INSTRUCTION (10, make_int8_0, "make-int8:0", 0, 0, 1)
121 {
122 PUSH (SCM_INUM0);
123 NEXT;
124 }
125
126 VM_DEFINE_INSTRUCTION (11, make_int8_1, "make-int8:1", 0, 0, 1)
127 {
128 PUSH (SCM_I_MAKINUM (1));
129 NEXT;
130 }
131
132 VM_DEFINE_INSTRUCTION (12, make_int16, "make-int16", 2, 0, 1)
133 {
134 int h = FETCH ();
135 int l = FETCH ();
136 PUSH (SCM_I_MAKINUM ((signed short) (h << 8) + l));
137 NEXT;
138 }
139
140 VM_DEFINE_INSTRUCTION (13, make_int64, "make-int64", 8, 0, 1)
141 {
142 scm_t_uint64 v = 0;
143 v += FETCH ();
144 v <<= 8; v += FETCH ();
145 v <<= 8; v += FETCH ();
146 v <<= 8; v += FETCH ();
147 v <<= 8; v += FETCH ();
148 v <<= 8; v += FETCH ();
149 v <<= 8; v += FETCH ();
150 v <<= 8; v += FETCH ();
151 PUSH (scm_from_int64 ((scm_t_int64) v));
152 NEXT;
153 }
154
155 VM_DEFINE_INSTRUCTION (14, make_uint64, "make-uint64", 8, 0, 1)
156 {
157 scm_t_uint64 v = 0;
158 v += FETCH ();
159 v <<= 8; v += FETCH ();
160 v <<= 8; v += FETCH ();
161 v <<= 8; v += FETCH ();
162 v <<= 8; v += FETCH ();
163 v <<= 8; v += FETCH ();
164 v <<= 8; v += FETCH ();
165 v <<= 8; v += FETCH ();
166 PUSH (scm_from_uint64 (v));
167 NEXT;
168 }
169
170 VM_DEFINE_INSTRUCTION (15, make_char8, "make-char8", 1, 0, 1)
171 {
172 scm_t_uint8 v = 0;
173 v = FETCH ();
174
175 PUSH (SCM_MAKE_CHAR (v));
176 /* Don't simplify this to PUSH (SCM_MAKE_CHAR (FETCH ())). The
177 contents of SCM_MAKE_CHAR may be evaluated more than once,
178 resulting in a double fetch. */
179 NEXT;
180 }
181
182 VM_DEFINE_INSTRUCTION (16, make_char32, "make-char32", 4, 0, 1)
183 {
184 scm_t_wchar v = 0;
185 v += FETCH ();
186 v <<= 8; v += FETCH ();
187 v <<= 8; v += FETCH ();
188 v <<= 8; v += FETCH ();
189 PUSH (SCM_MAKE_CHAR (v));
190 NEXT;
191 }
192
193
194
195 VM_DEFINE_INSTRUCTION (17, list, "list", 2, -1, 1)
196 {
197 unsigned h = FETCH ();
198 unsigned l = FETCH ();
199 unsigned len = ((h << 8) + l);
200 POP_LIST (len);
201 NEXT;
202 }
203
204 VM_DEFINE_INSTRUCTION (18, vector, "vector", 2, -1, 1)
205 {
206 unsigned h = FETCH ();
207 unsigned l = FETCH ();
208 unsigned len = ((h << 8) + l);
209 SCM vect;
210
211 SYNC_REGISTER ();
212 sp++; sp -= len;
213 CHECK_UNDERFLOW ();
214 vect = scm_make_vector (scm_from_uint (len), SCM_BOOL_F);
215 memcpy (SCM_I_VECTOR_WELTS(vect), sp, sizeof(SCM) * len);
216 NULLSTACK (len);
217 *sp = vect;
218
219 NEXT;
220 }
221
222 \f
223 /*
224 * Variable access
225 */
226
227 #define OBJECT_REF(i) objects[i]
228 #define OBJECT_SET(i,o) objects[i] = o
229
230 #define LOCAL_REF(i) SCM_FRAME_VARIABLE (fp, i)
231 #define LOCAL_SET(i,o) SCM_FRAME_VARIABLE (fp, i) = o
232
233 /* For the variable operations, we _must_ obviously avoid function calls to
234 `scm_variable_ref ()', `scm_variable_bound_p ()' and friends which do
235 nothing more than the corresponding macros. */
236 #define VARIABLE_REF(v) SCM_VARIABLE_REF (v)
237 #define VARIABLE_SET(v,o) SCM_VARIABLE_SET (v, o)
238 #define VARIABLE_BOUNDP(v) (VARIABLE_REF (v) != SCM_UNDEFINED)
239
240 #define FREE_VARIABLE_REF(i) free_vars[i]
241
242 /* ref */
243
244 VM_DEFINE_INSTRUCTION (19, object_ref, "object-ref", 1, 0, 1)
245 {
246 register unsigned objnum = FETCH ();
247 CHECK_OBJECT (objnum);
248 PUSH (OBJECT_REF (objnum));
249 NEXT;
250 }
251
252 /* FIXME: necessary? elt 255 of the vector could be a vector... */
253 VM_DEFINE_INSTRUCTION (20, long_object_ref, "long-object-ref", 2, 0, 1)
254 {
255 unsigned int objnum = FETCH ();
256 objnum <<= 8;
257 objnum += FETCH ();
258 CHECK_OBJECT (objnum);
259 PUSH (OBJECT_REF (objnum));
260 NEXT;
261 }
262
263 VM_DEFINE_INSTRUCTION (21, local_ref, "local-ref", 1, 0, 1)
264 {
265 PUSH (LOCAL_REF (FETCH ()));
266 ASSERT_BOUND (*sp);
267 NEXT;
268 }
269
270 VM_DEFINE_INSTRUCTION (22, long_local_ref, "long-local-ref", 2, 0, 1)
271 {
272 unsigned int i = FETCH ();
273 i <<= 8;
274 i += FETCH ();
275 PUSH (LOCAL_REF (i));
276 ASSERT_BOUND (*sp);
277 NEXT;
278 }
279
280 VM_DEFINE_INSTRUCTION (23, local_bound, "local-bound?", 1, 0, 1)
281 {
282 if (LOCAL_REF (FETCH ()) == SCM_UNDEFINED)
283 PUSH (SCM_BOOL_F);
284 else
285 PUSH (SCM_BOOL_T);
286 NEXT;
287 }
288
289 VM_DEFINE_INSTRUCTION (24, long_local_bound, "long-local-bound?", 2, 0, 1)
290 {
291 unsigned int i = FETCH ();
292 i <<= 8;
293 i += FETCH ();
294 if (LOCAL_REF (i) == SCM_UNDEFINED)
295 PUSH (SCM_BOOL_F);
296 else
297 PUSH (SCM_BOOL_T);
298 NEXT;
299 }
300
301 VM_DEFINE_INSTRUCTION (25, variable_ref, "variable-ref", 0, 0, 1)
302 {
303 SCM x = *sp;
304
305 if (!VARIABLE_BOUNDP (x))
306 {
307 finish_args = scm_list_1 (x);
308 /* Was: finish_args = SCM_LIST1 (SCM_CAR (x)); */
309 goto vm_error_unbound;
310 }
311 else
312 {
313 SCM o = VARIABLE_REF (x);
314 *sp = o;
315 }
316
317 NEXT;
318 }
319
320 VM_DEFINE_INSTRUCTION (26, variable_bound, "variable-bound?", 0, 0, 1)
321 {
322 if (VARIABLE_BOUNDP (*sp))
323 *sp = SCM_BOOL_T;
324 else
325 *sp = SCM_BOOL_F;
326 NEXT;
327 }
328
329 VM_DEFINE_INSTRUCTION (27, toplevel_ref, "toplevel-ref", 1, 0, 1)
330 {
331 unsigned objnum = FETCH ();
332 SCM what;
333 CHECK_OBJECT (objnum);
334 what = OBJECT_REF (objnum);
335
336 if (!SCM_VARIABLEP (what))
337 {
338 SYNC_REGISTER ();
339 what = resolve_variable (what, scm_program_module (program));
340 if (!VARIABLE_BOUNDP (what))
341 {
342 finish_args = scm_list_1 (what);
343 goto vm_error_unbound;
344 }
345 OBJECT_SET (objnum, what);
346 }
347
348 PUSH (VARIABLE_REF (what));
349 NEXT;
350 }
351
352 VM_DEFINE_INSTRUCTION (28, long_toplevel_ref, "long-toplevel-ref", 2, 0, 1)
353 {
354 SCM what;
355 unsigned int objnum = FETCH ();
356 objnum <<= 8;
357 objnum += FETCH ();
358 CHECK_OBJECT (objnum);
359 what = OBJECT_REF (objnum);
360
361 if (!SCM_VARIABLEP (what))
362 {
363 SYNC_REGISTER ();
364 what = resolve_variable (what, scm_program_module (program));
365 if (!VARIABLE_BOUNDP (what))
366 {
367 finish_args = scm_list_1 (what);
368 goto vm_error_unbound;
369 }
370 OBJECT_SET (objnum, what);
371 }
372
373 PUSH (VARIABLE_REF (what));
374 NEXT;
375 }
376
377 /* set */
378
379 VM_DEFINE_INSTRUCTION (29, local_set, "local-set", 1, 1, 0)
380 {
381 LOCAL_SET (FETCH (), *sp);
382 DROP ();
383 NEXT;
384 }
385
386 VM_DEFINE_INSTRUCTION (30, long_local_set, "long-local-set", 2, 1, 0)
387 {
388 unsigned int i = FETCH ();
389 i <<= 8;
390 i += FETCH ();
391 LOCAL_SET (i, *sp);
392 DROP ();
393 NEXT;
394 }
395
396 VM_DEFINE_INSTRUCTION (31, variable_set, "variable-set", 0, 1, 0)
397 {
398 VARIABLE_SET (sp[0], sp[-1]);
399 DROPN (2);
400 NEXT;
401 }
402
403 VM_DEFINE_INSTRUCTION (32, toplevel_set, "toplevel-set", 1, 1, 0)
404 {
405 unsigned objnum = FETCH ();
406 SCM what;
407 CHECK_OBJECT (objnum);
408 what = OBJECT_REF (objnum);
409
410 if (!SCM_VARIABLEP (what))
411 {
412 SYNC_BEFORE_GC ();
413 what = resolve_variable (what, scm_program_module (program));
414 OBJECT_SET (objnum, what);
415 }
416
417 VARIABLE_SET (what, *sp);
418 DROP ();
419 NEXT;
420 }
421
422 VM_DEFINE_INSTRUCTION (33, long_toplevel_set, "long-toplevel-set", 2, 1, 0)
423 {
424 SCM what;
425 unsigned int objnum = FETCH ();
426 objnum <<= 8;
427 objnum += FETCH ();
428 CHECK_OBJECT (objnum);
429 what = OBJECT_REF (objnum);
430
431 if (!SCM_VARIABLEP (what))
432 {
433 SYNC_BEFORE_GC ();
434 what = resolve_variable (what, scm_program_module (program));
435 OBJECT_SET (objnum, what);
436 }
437
438 VARIABLE_SET (what, *sp);
439 DROP ();
440 NEXT;
441 }
442
443 \f
444 /*
445 * branch and jump
446 */
447
448 /* offset must be at least 24 bits wide, and signed */
449 #define FETCH_OFFSET(offset) \
450 { \
451 offset = FETCH () << 16; \
452 offset += FETCH () << 8; \
453 offset += FETCH (); \
454 offset -= (offset & (1<<23)) << 1; \
455 }
456
457 #define BR(p) \
458 { \
459 scm_t_int32 offset; \
460 FETCH_OFFSET (offset); \
461 if (p) \
462 ip += offset; \
463 NULLSTACK (1); \
464 DROP (); \
465 NEXT; \
466 }
467
468 VM_DEFINE_INSTRUCTION (34, br, "br", 3, 0, 0)
469 {
470 scm_t_int32 offset;
471 FETCH_OFFSET (offset);
472 ip += offset;
473 NEXT;
474 }
475
476 VM_DEFINE_INSTRUCTION (35, br_if, "br-if", 3, 0, 0)
477 {
478 BR (scm_is_true_and_not_nil (*sp));
479 }
480
481 VM_DEFINE_INSTRUCTION (36, br_if_not, "br-if-not", 3, 0, 0)
482 {
483 BR (scm_is_false_or_nil (*sp));
484 }
485
486 VM_DEFINE_INSTRUCTION (37, br_if_eq, "br-if-eq", 3, 0, 0)
487 {
488 sp--; /* underflow? */
489 BR (scm_is_eq (sp[0], sp[1]));
490 }
491
492 VM_DEFINE_INSTRUCTION (38, br_if_not_eq, "br-if-not-eq", 3, 0, 0)
493 {
494 sp--; /* underflow? */
495 BR (!scm_is_eq (sp[0], sp[1]));
496 }
497
498 VM_DEFINE_INSTRUCTION (39, br_if_null, "br-if-null", 3, 0, 0)
499 {
500 BR (scm_is_null_or_nil (*sp));
501 }
502
503 VM_DEFINE_INSTRUCTION (40, br_if_not_null, "br-if-not-null", 3, 0, 0)
504 {
505 BR (!scm_is_null_or_nil (*sp));
506 }
507
508 \f
509 /*
510 * Subprogram call
511 */
512
513 VM_DEFINE_INSTRUCTION (41, br_if_nargs_ne, "br-if-nargs-ne", 5, 0, 0)
514 {
515 scm_t_ptrdiff n;
516 scm_t_int32 offset;
517 n = FETCH () << 8;
518 n += FETCH ();
519 FETCH_OFFSET (offset);
520 if (sp - (fp - 1) != n)
521 ip += offset;
522 NEXT;
523 }
524
525 VM_DEFINE_INSTRUCTION (42, br_if_nargs_lt, "br-if-nargs-lt", 5, 0, 0)
526 {
527 scm_t_ptrdiff n;
528 scm_t_int32 offset;
529 n = FETCH () << 8;
530 n += FETCH ();
531 FETCH_OFFSET (offset);
532 if (sp - (fp - 1) < n)
533 ip += offset;
534 NEXT;
535 }
536
537 VM_DEFINE_INSTRUCTION (43, br_if_nargs_gt, "br-if-nargs-gt", 5, 0, 0)
538 {
539 scm_t_ptrdiff n;
540 scm_t_int32 offset;
541
542 n = FETCH () << 8;
543 n += FETCH ();
544 FETCH_OFFSET (offset);
545 if (sp - (fp - 1) > n)
546 ip += offset;
547 NEXT;
548 }
549
550 VM_DEFINE_INSTRUCTION (44, assert_nargs_ee, "assert-nargs-ee", 2, 0, 0)
551 {
552 scm_t_ptrdiff n;
553 n = FETCH () << 8;
554 n += FETCH ();
555 if (sp - (fp - 1) != n)
556 goto vm_error_wrong_num_args;
557 NEXT;
558 }
559
560 VM_DEFINE_INSTRUCTION (45, assert_nargs_ge, "assert-nargs-ge", 2, 0, 0)
561 {
562 scm_t_ptrdiff n;
563 n = FETCH () << 8;
564 n += FETCH ();
565 if (sp - (fp - 1) < n)
566 goto vm_error_wrong_num_args;
567 NEXT;
568 }
569
570 VM_DEFINE_INSTRUCTION (46, bind_optionals, "bind-optionals", 2, -1, -1)
571 {
572 scm_t_ptrdiff n;
573 n = FETCH () << 8;
574 n += FETCH ();
575 while (sp - (fp - 1) < n)
576 PUSH (SCM_UNDEFINED);
577 NEXT;
578 }
579
580 VM_DEFINE_INSTRUCTION (47, bind_optionals_shuffle, "bind-optionals/shuffle", 6, -1, -1)
581 {
582 SCM *walk;
583 scm_t_ptrdiff nreq, nreq_and_opt, ntotal;
584 nreq = FETCH () << 8;
585 nreq += FETCH ();
586 nreq_and_opt = FETCH () << 8;
587 nreq_and_opt += FETCH ();
588 ntotal = FETCH () << 8;
589 ntotal += FETCH ();
590
591 /* look in optionals for first keyword or last positional */
592 /* starting after the last required positional arg */
593 walk = fp + nreq;
594 while (/* while we have args */
595 walk <= sp
596 /* and we still have positionals to fill */
597 && walk - fp < nreq_and_opt
598 /* and we haven't reached a keyword yet */
599 && !scm_is_keyword (*walk))
600 /* bind this optional arg (by leaving it in place) */
601 walk++;
602 /* now shuffle up, from walk to ntotal */
603 {
604 scm_t_ptrdiff nshuf = sp - walk + 1, i;
605 sp = (fp - 1) + ntotal + nshuf;
606 CHECK_OVERFLOW ();
607 for (i = 0; i < nshuf; i++)
608 sp[-i] = walk[nshuf-i-1];
609 }
610 /* and fill optionals & keyword args with SCM_UNDEFINED */
611 while (walk <= (fp - 1) + ntotal)
612 *walk++ = SCM_UNDEFINED;
613
614 NEXT;
615 }
616
617 /* Flags that determine whether other keywords are allowed, and whether a
618 rest argument is expected. These values must match those used by the
619 glil->assembly compiler. */
620 #define F_ALLOW_OTHER_KEYS 1
621 #define F_REST 2
622
623 VM_DEFINE_INSTRUCTION (48, bind_kwargs, "bind-kwargs", 5, 0, 0)
624 {
625 scm_t_uint16 idx;
626 scm_t_ptrdiff nkw;
627 int kw_and_rest_flags;
628 SCM kw;
629 idx = FETCH () << 8;
630 idx += FETCH ();
631 /* XXX: We don't actually use NKW. */
632 nkw = FETCH () << 8;
633 nkw += FETCH ();
634 kw_and_rest_flags = FETCH ();
635
636 if (!(kw_and_rest_flags & F_REST)
637 && ((sp - (fp - 1) - nkw) % 2))
638 goto vm_error_kwargs_length_not_even;
639
640 CHECK_OBJECT (idx);
641 kw = OBJECT_REF (idx);
642
643 /* Switch NKW to be a negative index below SP. */
644 for (nkw = -(sp - (fp - 1) - nkw) + 1; nkw < 0; nkw++)
645 {
646 SCM walk;
647
648 if (scm_is_keyword (sp[nkw]))
649 {
650 for (walk = kw; scm_is_pair (walk); walk = SCM_CDR (walk))
651 {
652 if (scm_is_eq (SCM_CAAR (walk), sp[nkw]))
653 {
654 SCM si = SCM_CDAR (walk);
655 LOCAL_SET (SCM_I_INUMP (si) ? SCM_I_INUM (si) : scm_to_long (si),
656 sp[nkw + 1]);
657 break;
658 }
659 }
660 if (!(kw_and_rest_flags & F_ALLOW_OTHER_KEYS) && !scm_is_pair (walk))
661 goto vm_error_kwargs_unrecognized_keyword;
662
663 nkw++;
664 }
665 else if (!(kw_and_rest_flags & F_REST))
666 goto vm_error_kwargs_invalid_keyword;
667 }
668
669 NEXT;
670 }
671
672 #undef F_ALLOW_OTHER_KEYS
673 #undef F_REST
674
675
676 VM_DEFINE_INSTRUCTION (49, push_rest, "push-rest", 2, -1, -1)
677 {
678 scm_t_ptrdiff n;
679 SCM rest = SCM_EOL;
680 n = FETCH () << 8;
681 n += FETCH ();
682 while (sp - (fp - 1) > n)
683 /* No need to check for underflow. */
684 CONS (rest, *sp--, rest);
685 PUSH (rest);
686 NEXT;
687 }
688
689 VM_DEFINE_INSTRUCTION (50, bind_rest, "bind-rest", 4, -1, -1)
690 {
691 scm_t_ptrdiff n;
692 scm_t_uint32 i;
693 SCM rest = SCM_EOL;
694 n = FETCH () << 8;
695 n += FETCH ();
696 i = FETCH () << 8;
697 i += FETCH ();
698 while (sp - (fp - 1) > n)
699 /* No need to check for underflow. */
700 CONS (rest, *sp--, rest);
701 LOCAL_SET (i, rest);
702 NEXT;
703 }
704
705 VM_DEFINE_INSTRUCTION (51, reserve_locals, "reserve-locals", 2, -1, -1)
706 {
707 SCM *old_sp;
708 scm_t_int32 n;
709 n = FETCH () << 8;
710 n += FETCH ();
711 old_sp = sp;
712 sp = (fp - 1) + n;
713
714 if (old_sp < sp)
715 {
716 CHECK_OVERFLOW ();
717 while (old_sp < sp)
718 *++old_sp = SCM_UNDEFINED;
719 }
720 else
721 NULLSTACK (old_sp - sp);
722
723 NEXT;
724 }
725
726 VM_DEFINE_INSTRUCTION (52, new_frame, "new-frame", 0, 0, 3)
727 {
728 /* NB: if you change this, see frames.c:vm-frame-num-locals */
729 /* and frames.h, vm-engine.c, etc of course */
730 PUSH ((SCM)fp); /* dynamic link */
731 PUSH (0); /* mvra */
732 PUSH (0); /* ra */
733 NEXT;
734 }
735
736 VM_DEFINE_INSTRUCTION (53, call, "call", 1, -1, 1)
737 {
738 SCM x;
739 nargs = FETCH ();
740
741 vm_call:
742 x = sp[-nargs];
743
744 SYNC_REGISTER ();
745 SCM_TICK; /* allow interrupt here */
746
747 /*
748 * Subprogram call
749 */
750 if (SCM_PROGRAM_P (x))
751 {
752 program = x;
753 CACHE_PROGRAM ();
754 fp = sp - nargs + 1;
755 ASSERT (SCM_FRAME_RETURN_ADDRESS (fp) == 0);
756 ASSERT (SCM_FRAME_MV_RETURN_ADDRESS (fp) == 0);
757 SCM_FRAME_SET_RETURN_ADDRESS (fp, ip);
758 SCM_FRAME_SET_MV_RETURN_ADDRESS (fp, 0);
759 ip = bp->base;
760 ENTER_HOOK ();
761 APPLY_HOOK ();
762 NEXT;
763 }
764 if (SCM_STRUCTP (x) && SCM_STRUCT_APPLICABLE_P (x))
765 {
766 sp[-nargs] = SCM_STRUCT_PROCEDURE (x);
767 goto vm_call;
768 }
769 if (SCM_STRUCTP (x) && SCM_OBJ_CLASS_FLAGS (x) & SCM_CLASSF_PURE_GENERIC)
770 {
771 SCM args = SCM_EOL;
772 int n = nargs;
773 SCM* walk = sp;
774 SYNC_REGISTER ();
775 while (n--)
776 args = scm_cons (*walk--, args);
777 *walk = scm_mcache_compute_cmethod (SCM_GENERIC_METHOD_CACHE (x), args);
778 goto vm_call;
779 }
780 /*
781 * Other interpreted or compiled call
782 */
783 if (!SCM_FALSEP (scm_procedure_p (x)))
784 {
785 SCM args;
786 /* At this point, the stack contains the frame, the procedure and each one
787 of its arguments. */
788 POP_LIST (nargs);
789 POP (args);
790 DROP (); /* drop the procedure */
791 DROP_FRAME ();
792
793 SYNC_REGISTER ();
794 PUSH (scm_apply (x, args, SCM_EOL));
795 NULLSTACK_FOR_NONLOCAL_EXIT ();
796 if (SCM_UNLIKELY (SCM_VALUESP (*sp)))
797 {
798 /* truncate values */
799 SCM values;
800 POP (values);
801 values = scm_struct_ref (values, SCM_INUM0);
802 if (scm_is_null (values))
803 goto vm_error_not_enough_values;
804 PUSH (SCM_CAR (values));
805 }
806 NEXT;
807 }
808
809 program = x;
810 goto vm_error_wrong_type_apply;
811 }
812
813 VM_DEFINE_INSTRUCTION (54, goto_args, "goto/args", 1, -1, 1)
814 {
815 register SCM x;
816 nargs = FETCH ();
817 vm_goto_args:
818 x = sp[-nargs];
819
820 SYNC_REGISTER ();
821 SCM_TICK; /* allow interrupt here */
822
823 /*
824 * Tail call
825 */
826 if (SCM_PROGRAM_P (x))
827 {
828 int i;
829 #ifdef VM_ENABLE_STACK_NULLING
830 SCM *old_sp = sp;
831 CHECK_STACK_LEAK ();
832 #endif
833
834 EXIT_HOOK ();
835
836 /* switch programs */
837 program = x;
838 CACHE_PROGRAM ();
839 /* shuffle down the program and the arguments */
840 for (i = -1, sp = sp - nargs + 1; i < nargs; i++)
841 SCM_FRAME_STACK_ADDRESS (fp)[i] = sp[i];
842
843 sp = fp + i - 1;
844
845 NULLSTACK (old_sp - sp);
846
847 ip = bp->base;
848
849 ENTER_HOOK ();
850 APPLY_HOOK ();
851 NEXT;
852 }
853 if (SCM_STRUCTP (x) && SCM_STRUCT_APPLICABLE_P (x))
854 {
855 sp[-nargs] = SCM_STRUCT_PROCEDURE (x);
856 goto vm_goto_args;
857 }
858 if (SCM_STRUCTP (x) && SCM_OBJ_CLASS_FLAGS (x) & SCM_CLASSF_PURE_GENERIC)
859 {
860 SCM args = SCM_EOL;
861 int n = nargs;
862 SCM* walk = sp;
863 SYNC_REGISTER ();
864 while (n--)
865 args = scm_cons (*walk--, args);
866 *walk = scm_mcache_compute_cmethod (SCM_GENERIC_METHOD_CACHE (x), args);
867 goto vm_goto_args;
868 }
869
870 /*
871 * Other interpreted or compiled call
872 */
873 if (!SCM_FALSEP (scm_procedure_p (x)))
874 {
875 SCM args;
876 POP_LIST (nargs);
877 POP (args);
878
879 SYNC_REGISTER ();
880 *sp = scm_apply (x, args, SCM_EOL);
881 NULLSTACK_FOR_NONLOCAL_EXIT ();
882
883 if (SCM_UNLIKELY (SCM_VALUESP (*sp)))
884 {
885 /* multiple values returned to continuation */
886 SCM values;
887 POP (values);
888 values = scm_struct_ref (values, SCM_INUM0);
889 nvalues = scm_ilength (values);
890 PUSH_LIST (values, scm_is_null);
891 goto vm_return_values;
892 }
893 else
894 goto vm_return;
895 }
896
897 program = x;
898
899 goto vm_error_wrong_type_apply;
900 }
901
902 VM_DEFINE_INSTRUCTION (55, goto_nargs, "goto/nargs", 0, 0, 1)
903 {
904 SCM x;
905 POP (x);
906 nargs = scm_to_int (x);
907 /* FIXME: should truncate values? */
908 goto vm_goto_args;
909 }
910
911 VM_DEFINE_INSTRUCTION (56, call_nargs, "call/nargs", 0, 0, 1)
912 {
913 SCM x;
914 POP (x);
915 nargs = scm_to_int (x);
916 /* FIXME: should truncate values? */
917 goto vm_call;
918 }
919
920 VM_DEFINE_INSTRUCTION (57, mv_call, "mv-call", 4, -1, 1)
921 {
922 SCM x;
923 scm_t_int32 offset;
924 scm_t_uint8 *mvra;
925
926 nargs = FETCH ();
927 FETCH_OFFSET (offset);
928 mvra = ip + offset;
929
930 vm_mv_call:
931 x = sp[-nargs];
932
933 /*
934 * Subprogram call
935 */
936 if (SCM_PROGRAM_P (x))
937 {
938 program = x;
939 CACHE_PROGRAM ();
940 fp = sp - nargs + 1;
941 ASSERT (SCM_FRAME_RETURN_ADDRESS (fp) == 0);
942 ASSERT (SCM_FRAME_MV_RETURN_ADDRESS (fp) == 0);
943 SCM_FRAME_SET_RETURN_ADDRESS (fp, ip);
944 SCM_FRAME_SET_MV_RETURN_ADDRESS (fp, mvra);
945 ip = bp->base;
946 ENTER_HOOK ();
947 APPLY_HOOK ();
948 NEXT;
949 }
950 if (SCM_STRUCTP (x) && SCM_STRUCT_APPLICABLE_P (x))
951 {
952 sp[-nargs] = SCM_STRUCT_PROCEDURE (x);
953 goto vm_mv_call;
954 }
955 if (SCM_STRUCTP (x) && SCM_OBJ_CLASS_FLAGS (x) & SCM_CLASSF_PURE_GENERIC)
956 {
957 SCM args = SCM_EOL;
958 int n = nargs;
959 SCM* walk = sp;
960 SYNC_REGISTER ();
961 while (n--)
962 args = scm_cons (*walk--, args);
963 *walk = scm_mcache_compute_cmethod (SCM_GENERIC_METHOD_CACHE (x), args);
964 goto vm_mv_call;
965 }
966 /*
967 * Other interpreted or compiled call
968 */
969 if (!SCM_FALSEP (scm_procedure_p (x)))
970 {
971 SCM args;
972 /* At this point, the stack contains the procedure and each one of its
973 arguments. */
974 POP_LIST (nargs);
975 POP (args);
976 DROP (); /* drop the procedure */
977 DROP_FRAME ();
978
979 SYNC_REGISTER ();
980 PUSH (scm_apply (x, args, SCM_EOL));
981 NULLSTACK_FOR_NONLOCAL_EXIT ();
982 if (SCM_VALUESP (*sp))
983 {
984 SCM values, len;
985 POP (values);
986 values = scm_struct_ref (values, SCM_INUM0);
987 len = scm_length (values);
988 PUSH_LIST (values, scm_is_null);
989 PUSH (len);
990 ip = mvra;
991 }
992 NEXT;
993 }
994
995 program = x;
996 goto vm_error_wrong_type_apply;
997 }
998
999 VM_DEFINE_INSTRUCTION (58, apply, "apply", 1, -1, 1)
1000 {
1001 int len;
1002 SCM ls;
1003 POP (ls);
1004
1005 nargs = FETCH ();
1006 ASSERT (nargs >= 2);
1007
1008 len = scm_ilength (ls);
1009 if (len < 0)
1010 goto vm_error_wrong_type_arg;
1011
1012 PUSH_LIST (ls, SCM_NULL_OR_NIL_P);
1013
1014 nargs += len - 2;
1015 goto vm_call;
1016 }
1017
1018 VM_DEFINE_INSTRUCTION (59, goto_apply, "goto/apply", 1, -1, 1)
1019 {
1020 int len;
1021 SCM ls;
1022 POP (ls);
1023
1024 nargs = FETCH ();
1025 ASSERT (nargs >= 2);
1026
1027 len = scm_ilength (ls);
1028 if (len < 0)
1029 goto vm_error_wrong_type_arg;
1030
1031 PUSH_LIST (ls, SCM_NULL_OR_NIL_P);
1032
1033 nargs += len - 2;
1034 goto vm_goto_args;
1035 }
1036
1037 VM_DEFINE_INSTRUCTION (60, call_cc, "call/cc", 0, 1, 1)
1038 {
1039 int first;
1040 SCM proc, cont;
1041 POP (proc);
1042 SYNC_ALL ();
1043 cont = scm_make_continuation (&first);
1044 if (first)
1045 {
1046 PUSH ((SCM)fp); /* dynamic link */
1047 PUSH (0); /* mvra */
1048 PUSH (0); /* ra */
1049 PUSH (proc);
1050 PUSH (cont);
1051 nargs = 1;
1052 goto vm_call;
1053 }
1054 ASSERT (sp == vp->sp);
1055 ASSERT (fp == vp->fp);
1056 else if (SCM_VALUESP (cont))
1057 {
1058 /* multiple values returned to continuation */
1059 SCM values;
1060 values = scm_struct_ref (cont, SCM_INUM0);
1061 if (scm_is_null (values))
1062 goto vm_error_no_values;
1063 /* non-tail context does not accept multiple values? */
1064 PUSH (SCM_CAR (values));
1065 NEXT;
1066 }
1067 else
1068 {
1069 PUSH (cont);
1070 NEXT;
1071 }
1072 }
1073
1074 VM_DEFINE_INSTRUCTION (61, goto_cc, "goto/cc", 0, 1, 1)
1075 {
1076 int first;
1077 SCM proc, cont;
1078 POP (proc);
1079 SYNC_ALL ();
1080 cont = scm_make_continuation (&first);
1081 ASSERT (sp == vp->sp);
1082 ASSERT (fp == vp->fp);
1083 if (first)
1084 {
1085 PUSH (proc);
1086 PUSH (cont);
1087 nargs = 1;
1088 goto vm_goto_args;
1089 }
1090 else if (SCM_VALUESP (cont))
1091 {
1092 /* multiple values returned to continuation */
1093 SCM values;
1094 values = scm_struct_ref (cont, SCM_INUM0);
1095 nvalues = scm_ilength (values);
1096 PUSH_LIST (values, scm_is_null);
1097 goto vm_return_values;
1098 }
1099 else
1100 {
1101 PUSH (cont);
1102 goto vm_return;
1103 }
1104 }
1105
1106 VM_DEFINE_INSTRUCTION (62, return, "return", 0, 1, 1)
1107 {
1108 vm_return:
1109 EXIT_HOOK ();
1110 RETURN_HOOK ();
1111 SYNC_REGISTER ();
1112 SCM_TICK; /* allow interrupt here */
1113 {
1114 SCM ret;
1115
1116 POP (ret);
1117
1118 #ifdef VM_ENABLE_STACK_NULLING
1119 SCM *old_sp = sp;
1120 #endif
1121
1122 /* Restore registers */
1123 sp = SCM_FRAME_LOWER_ADDRESS (fp);
1124 ip = SCM_FRAME_RETURN_ADDRESS (fp);
1125 fp = SCM_FRAME_DYNAMIC_LINK (fp);
1126
1127 #ifdef VM_ENABLE_STACK_NULLING
1128 NULLSTACK (old_sp - sp);
1129 #endif
1130
1131 /* Set return value (sp is already pushed) */
1132 *sp = ret;
1133 }
1134
1135 /* Restore the last program */
1136 program = SCM_FRAME_PROGRAM (fp);
1137 CACHE_PROGRAM ();
1138 CHECK_IP ();
1139 NEXT;
1140 }
1141
1142 VM_DEFINE_INSTRUCTION (63, return_values, "return/values", 1, -1, -1)
1143 {
1144 /* nvalues declared at top level, because for some reason gcc seems to think
1145 that perhaps it might be used without declaration. Fooey to that, I say. */
1146 nvalues = FETCH ();
1147 vm_return_values:
1148 EXIT_HOOK ();
1149 RETURN_HOOK ();
1150
1151 if (nvalues != 1 && SCM_FRAME_MV_RETURN_ADDRESS (fp))
1152 {
1153 /* A multiply-valued continuation */
1154 SCM *vals = sp - nvalues;
1155 int i;
1156 /* Restore registers */
1157 sp = SCM_FRAME_LOWER_ADDRESS (fp) - 1;
1158 ip = SCM_FRAME_MV_RETURN_ADDRESS (fp);
1159 fp = SCM_FRAME_DYNAMIC_LINK (fp);
1160
1161 /* Push return values, and the number of values */
1162 for (i = 0; i < nvalues; i++)
1163 *++sp = vals[i+1];
1164 *++sp = SCM_I_MAKINUM (nvalues);
1165
1166 /* Finally null the end of the stack */
1167 NULLSTACK (vals + nvalues - sp);
1168 }
1169 else if (nvalues >= 1)
1170 {
1171 /* Multiple values for a single-valued continuation -- here's where I
1172 break with guile tradition and try and do something sensible. (Also,
1173 this block handles the single-valued return to an mv
1174 continuation.) */
1175 SCM *vals = sp - nvalues;
1176 /* Restore registers */
1177 sp = SCM_FRAME_LOWER_ADDRESS (fp) - 1;
1178 ip = SCM_FRAME_RETURN_ADDRESS (fp);
1179 fp = SCM_FRAME_DYNAMIC_LINK (fp);
1180
1181 /* Push first value */
1182 *++sp = vals[1];
1183
1184 /* Finally null the end of the stack */
1185 NULLSTACK (vals + nvalues - sp);
1186 }
1187 else
1188 goto vm_error_no_values;
1189
1190 /* Restore the last program */
1191 program = SCM_FRAME_PROGRAM (fp);
1192 CACHE_PROGRAM ();
1193 CHECK_IP ();
1194 NEXT;
1195 }
1196
1197 VM_DEFINE_INSTRUCTION (64, return_values_star, "return/values*", 1, -1, -1)
1198 {
1199 SCM l;
1200
1201 nvalues = FETCH ();
1202 ASSERT (nvalues >= 1);
1203
1204 nvalues--;
1205 POP (l);
1206 while (scm_is_pair (l))
1207 {
1208 PUSH (SCM_CAR (l));
1209 l = SCM_CDR (l);
1210 nvalues++;
1211 }
1212 if (SCM_UNLIKELY (!SCM_NULL_OR_NIL_P (l))) {
1213 finish_args = scm_list_1 (l);
1214 goto vm_error_improper_list;
1215 }
1216
1217 goto vm_return_values;
1218 }
1219
1220 VM_DEFINE_INSTRUCTION (65, truncate_values, "truncate-values", 2, -1, -1)
1221 {
1222 SCM x;
1223 int nbinds, rest;
1224 POP (x);
1225 nvalues = scm_to_int (x);
1226 nbinds = FETCH ();
1227 rest = FETCH ();
1228
1229 if (rest)
1230 nbinds--;
1231
1232 if (nvalues < nbinds)
1233 goto vm_error_not_enough_values;
1234
1235 if (rest)
1236 POP_LIST (nvalues - nbinds);
1237 else
1238 DROPN (nvalues - nbinds);
1239
1240 NEXT;
1241 }
1242
1243 VM_DEFINE_INSTRUCTION (66, box, "box", 1, 1, 0)
1244 {
1245 SCM val;
1246 POP (val);
1247 SYNC_BEFORE_GC ();
1248 LOCAL_SET (FETCH (), scm_cell (scm_tc7_variable, SCM_UNPACK (val)));
1249 NEXT;
1250 }
1251
1252 /* for letrec:
1253 (let ((a *undef*) (b *undef*) ...)
1254 (set! a (lambda () (b ...)))
1255 ...)
1256 */
1257 VM_DEFINE_INSTRUCTION (67, empty_box, "empty-box", 1, 0, 0)
1258 {
1259 SYNC_BEFORE_GC ();
1260 LOCAL_SET (FETCH (),
1261 scm_cell (scm_tc7_variable, SCM_UNPACK (SCM_UNDEFINED)));
1262 NEXT;
1263 }
1264
1265 VM_DEFINE_INSTRUCTION (68, local_boxed_ref, "local-boxed-ref", 1, 0, 1)
1266 {
1267 SCM v = LOCAL_REF (FETCH ());
1268 ASSERT_BOUND_VARIABLE (v);
1269 PUSH (VARIABLE_REF (v));
1270 NEXT;
1271 }
1272
1273 VM_DEFINE_INSTRUCTION (69, local_boxed_set, "local-boxed-set", 1, 1, 0)
1274 {
1275 SCM v, val;
1276 v = LOCAL_REF (FETCH ());
1277 POP (val);
1278 ASSERT_VARIABLE (v);
1279 VARIABLE_SET (v, val);
1280 NEXT;
1281 }
1282
1283 VM_DEFINE_INSTRUCTION (70, free_ref, "free-ref", 1, 0, 1)
1284 {
1285 scm_t_uint8 idx = FETCH ();
1286
1287 CHECK_FREE_VARIABLE (idx);
1288 PUSH (FREE_VARIABLE_REF (idx));
1289 NEXT;
1290 }
1291
1292 /* no free-set -- if a var is assigned, it should be in a box */
1293
1294 VM_DEFINE_INSTRUCTION (71, free_boxed_ref, "free-boxed-ref", 1, 0, 1)
1295 {
1296 SCM v;
1297 scm_t_uint8 idx = FETCH ();
1298 CHECK_FREE_VARIABLE (idx);
1299 v = FREE_VARIABLE_REF (idx);
1300 ASSERT_BOUND_VARIABLE (v);
1301 PUSH (VARIABLE_REF (v));
1302 NEXT;
1303 }
1304
1305 VM_DEFINE_INSTRUCTION (72, free_boxed_set, "free-boxed-set", 1, 1, 0)
1306 {
1307 SCM v, val;
1308 scm_t_uint8 idx = FETCH ();
1309 POP (val);
1310 CHECK_FREE_VARIABLE (idx);
1311 v = FREE_VARIABLE_REF (idx);
1312 ASSERT_BOUND_VARIABLE (v);
1313 VARIABLE_SET (v, val);
1314 NEXT;
1315 }
1316
1317 VM_DEFINE_INSTRUCTION (73, make_closure, "make-closure", 0, 2, 1)
1318 {
1319 SCM vect;
1320 POP (vect);
1321 SYNC_BEFORE_GC ();
1322 /* fixme underflow */
1323 *sp = scm_double_cell (scm_tc7_program, (scm_t_bits)SCM_PROGRAM_OBJCODE (*sp),
1324 (scm_t_bits)SCM_PROGRAM_OBJTABLE (*sp), (scm_t_bits)vect);
1325 NEXT;
1326 }
1327
1328 VM_DEFINE_INSTRUCTION (74, make_variable, "make-variable", 0, 0, 1)
1329 {
1330 SYNC_BEFORE_GC ();
1331 /* fixme underflow */
1332 PUSH (scm_cell (scm_tc7_variable, SCM_UNPACK (SCM_UNDEFINED)));
1333 NEXT;
1334 }
1335
1336 VM_DEFINE_INSTRUCTION (75, fix_closure, "fix-closure", 2, 0, 1)
1337 {
1338 SCM x, vect;
1339 unsigned int i = FETCH ();
1340 i <<= 8;
1341 i += FETCH ();
1342 POP (vect);
1343 /* FIXME CHECK_LOCAL (i) */
1344 x = LOCAL_REF (i);
1345 /* FIXME ASSERT_PROGRAM (x); */
1346 SCM_SET_CELL_WORD_3 (x, vect);
1347 NEXT;
1348 }
1349
1350 VM_DEFINE_INSTRUCTION (76, define, "define", 0, 0, 2)
1351 {
1352 SCM sym, val;
1353 POP (sym);
1354 POP (val);
1355 SYNC_REGISTER ();
1356 VARIABLE_SET (scm_sym2var (sym, scm_current_module_lookup_closure (),
1357 SCM_BOOL_T),
1358 val);
1359 NEXT;
1360 }
1361
1362 VM_DEFINE_INSTRUCTION (77, make_keyword, "make-keyword", 0, 1, 1)
1363 {
1364 CHECK_UNDERFLOW ();
1365 SYNC_REGISTER ();
1366 *sp = scm_symbol_to_keyword (*sp);
1367 NEXT;
1368 }
1369
1370 VM_DEFINE_INSTRUCTION (78, make_symbol, "make-symbol", 0, 1, 1)
1371 {
1372 CHECK_UNDERFLOW ();
1373 SYNC_REGISTER ();
1374 *sp = scm_string_to_symbol (*sp);
1375 NEXT;
1376 }
1377
1378
1379 /*
1380 (defun renumber-ops ()
1381 "start from top of buffer and renumber 'VM_DEFINE_FOO (\n' sequences"
1382 (interactive "")
1383 (save-excursion
1384 (let ((counter -1)) (goto-char (point-min))
1385 (while (re-search-forward "^VM_DEFINE_[^ ]+ (\\([^,]+\\)," (point-max) t)
1386 (replace-match
1387 (number-to-string (setq counter (1+ counter)))
1388 t t nil 1)))))
1389 */
1390 /*
1391 Local Variables:
1392 c-file-style: "gnu"
1393 End:
1394 */