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