enable multiple vm engines (regular, debug, ...)
[bpt/guile.git] / libguile / vm-i-system.c
CommitLineData
53e28ed9 1/* Copyright (C) 2001,2008,2009 Free Software Foundation, Inc.
a98cef7e 2 *
53e28ed9
AW
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
a98cef7e 7 *
53e28ed9
AW
8 * This library 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 GNU
11 * Lesser General Public License for more details.
a98cef7e 12 *
53e28ed9
AW
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 02110-1301 USA
16 */
17
a98cef7e
KN
18
19/* This file is included in vm_engine.c */
20
a98cef7e
KN
21\f
22/*
23 * Basic operations
24 */
25
53e28ed9 26VM_DEFINE_INSTRUCTION (0, nop, "nop", 0, 0, 0)
a98cef7e
KN
27{
28 NEXT;
29}
30
53e28ed9 31VM_DEFINE_INSTRUCTION (1, halt, "halt", 0, 0, 0)
a98cef7e 32{
a6df585a 33 SCM ret;
3d5ee0cd 34 vp->time += scm_c_get_internal_run_time () - start_time;
17e90c5e 35 HALT_HOOK ();
a222b0fa 36 nvalues = SCM_I_INUM (*sp--);
11ea1aba 37 NULLSTACK (1);
a222b0fa
AW
38 if (nvalues == 1)
39 POP (ret);
40 else
41 {
42 POP_LIST (nvalues);
43 POP (ret);
877ffa3f 44 SYNC_REGISTER ();
a222b0fa
AW
45 ret = scm_values (ret);
46 }
47
1dc8f851 48 {
11ea1aba
AW
49 ASSERT (sp == stack_base);
50 ASSERT (stack_base == SCM_FRAME_UPPER_ADDRESS (fp) - 1);
1dc8f851
AW
51
52 /* Restore registers */
53 sp = SCM_FRAME_LOWER_ADDRESS (fp) - 1;
54 ip = NULL;
55 fp = SCM_FRAME_DYNAMIC_LINK (fp);
11ea1aba 56 NULLSTACK (stack_base - sp);
1dc8f851 57 }
17e90c5e
KN
58 SYNC_ALL ();
59 return ret;
a98cef7e
KN
60}
61
53e28ed9 62VM_DEFINE_INSTRUCTION (2, break, "break", 0, 0, 0)
7a0d0cee
KN
63{
64 BREAK_HOOK ();
65 NEXT;
66}
67
53e28ed9 68VM_DEFINE_INSTRUCTION (3, drop, "drop", 0, 0, 0)
a98cef7e 69{
17e90c5e 70 DROP ();
a98cef7e
KN
71 NEXT;
72}
73
53e28ed9 74VM_DEFINE_INSTRUCTION (4, mark, "mark", 0, 0, 1)
cb4cca12
KN
75{
76 PUSH (SCM_UNDEFINED);
77 NEXT;
78}
79
53e28ed9 80VM_DEFINE_INSTRUCTION (5, dup, "dup", 0, 0, 1)
26403690 81{
f349065e
KN
82 SCM x = *sp;
83 PUSH (x);
26403690
KN
84 NEXT;
85}
86
17e90c5e
KN
87\f
88/*
89 * Object creation
90 */
a98cef7e 91
53e28ed9 92VM_DEFINE_INSTRUCTION (6, void, "void", 0, 0, 1)
a98cef7e 93{
17e90c5e 94 PUSH (SCM_UNSPECIFIED);
a98cef7e
KN
95 NEXT;
96}
97
53e28ed9 98VM_DEFINE_INSTRUCTION (7, make_true, "make-true", 0, 0, 1)
a98cef7e 99{
17e90c5e 100 PUSH (SCM_BOOL_T);
a98cef7e
KN
101 NEXT;
102}
103
53e28ed9 104VM_DEFINE_INSTRUCTION (8, make_false, "make-false", 0, 0, 1)
a98cef7e 105{
17e90c5e 106 PUSH (SCM_BOOL_F);
a98cef7e
KN
107 NEXT;
108}
109
53e28ed9 110VM_DEFINE_INSTRUCTION (9, make_eol, "make-eol", 0, 0, 1)
a98cef7e 111{
17e90c5e 112 PUSH (SCM_EOL);
a98cef7e
KN
113 NEXT;
114}
115
53e28ed9 116VM_DEFINE_INSTRUCTION (10, make_int8, "make-int8", 1, 0, 1)
a98cef7e 117{
2d80426a 118 PUSH (SCM_I_MAKINUM ((signed char) FETCH ()));
a98cef7e
KN
119 NEXT;
120}
121
53e28ed9 122VM_DEFINE_INSTRUCTION (11, make_int8_0, "make-int8:0", 0, 0, 1)
a98cef7e 123{
238e7a11 124 PUSH (SCM_INUM0);
a98cef7e
KN
125 NEXT;
126}
127
53e28ed9 128VM_DEFINE_INSTRUCTION (12, make_int8_1, "make-int8:1", 0, 0, 1)
a98cef7e 129{
238e7a11 130 PUSH (SCM_I_MAKINUM (1));
a98cef7e
KN
131 NEXT;
132}
133
53e28ed9 134VM_DEFINE_INSTRUCTION (13, make_int16, "make-int16", 2, 0, 1)
a98cef7e 135{
ea9b4b29
KN
136 int h = FETCH ();
137 int l = FETCH ();
2d80426a 138 PUSH (SCM_I_MAKINUM ((signed short) (h << 8) + l));
a98cef7e
KN
139 NEXT;
140}
141
53e28ed9 142VM_DEFINE_INSTRUCTION (14, make_char8, "make-char8", 1, 0, 1)
a98cef7e 143{
17e90c5e 144 PUSH (SCM_MAKE_CHAR (FETCH ()));
a98cef7e
KN
145 NEXT;
146}
147
53e28ed9 148VM_DEFINE_INSTRUCTION (15, list, "list", 2, -1, 1)
cb4cca12 149{
23b587b0
LC
150 unsigned h = FETCH ();
151 unsigned l = FETCH ();
152 unsigned len = ((h << 8) + l);
153 POP_LIST (len);
cb4cca12
KN
154 NEXT;
155}
156
53e28ed9 157VM_DEFINE_INSTRUCTION (16, vector, "vector", 2, -1, 1)
cb4cca12 158{
23b587b0
LC
159 unsigned h = FETCH ();
160 unsigned l = FETCH ();
161 unsigned len = ((h << 8) + l);
5338b62b
AW
162 SCM vect;
163
877ffa3f 164 SYNC_REGISTER ();
5338b62b
AW
165 sp++; sp -= len;
166 CHECK_UNDERFLOW ();
167 vect = scm_make_vector (scm_from_uint (len), SCM_BOOL_F);
168 memcpy (SCM_I_VECTOR_WELTS(vect), sp, sizeof(SCM) * len);
169 NULLSTACK (len);
170 *sp = vect;
171
cb4cca12
KN
172 NEXT;
173}
174
53e28ed9 175VM_DEFINE_INSTRUCTION (17, list_mark, "list-mark", 0, 0, 0)
cb4cca12
KN
176{
177 POP_LIST_MARK ();
178 NEXT;
179}
180
53e28ed9 181VM_DEFINE_INSTRUCTION (18, cons_mark, "cons-mark", 0, 0, 0)
2bd859c8
AW
182{
183 POP_CONS_MARK ();
184 NEXT;
185}
186
53e28ed9 187VM_DEFINE_INSTRUCTION (19, vector_mark, "vector-mark", 0, 0, 0)
cb4cca12
KN
188{
189 POP_LIST_MARK ();
877ffa3f 190 SYNC_REGISTER ();
cb4cca12
KN
191 *sp = scm_vector (*sp);
192 NEXT;
193}
194
53e28ed9 195VM_DEFINE_INSTRUCTION (20, list_break, "list-break", 0, 0, 0)
cb4cca12
KN
196{
197 SCM l;
198 POP (l);
fb10a008 199 PUSH_LIST (l, SCM_NULLP);
cb4cca12
KN
200 NEXT;
201}
202
a98cef7e
KN
203\f
204/*
17e90c5e 205 * Variable access
a98cef7e
KN
206 */
207
17e90c5e
KN
208#define OBJECT_REF(i) objects[i]
209#define OBJECT_SET(i,o) objects[i] = o
a98cef7e 210
af988bbf
KN
211#define LOCAL_REF(i) SCM_FRAME_VARIABLE (fp, i)
212#define LOCAL_SET(i,o) SCM_FRAME_VARIABLE (fp, i) = o
a98cef7e 213
2d80426a
LC
214/* For the variable operations, we _must_ obviously avoid function calls to
215 `scm_variable_ref ()', `scm_variable_bound_p ()' and friends which do
216 nothing more than the corresponding macros. */
217#define VARIABLE_REF(v) SCM_VARIABLE_REF (v)
218#define VARIABLE_SET(v,o) SCM_VARIABLE_SET (v, o)
219#define VARIABLE_BOUNDP(v) (VARIABLE_REF (v) != SCM_UNDEFINED)
a98cef7e 220
17e90c5e 221/* ref */
a98cef7e 222
53e28ed9 223VM_DEFINE_INSTRUCTION (21, object_ref, "object-ref", 1, 0, 1)
a98cef7e 224{
a52b2d3d 225 register unsigned objnum = FETCH ();
0b5f0e49
LC
226 CHECK_OBJECT (objnum);
227 PUSH (OBJECT_REF (objnum));
17e90c5e 228 NEXT;
a98cef7e
KN
229}
230
53e28ed9 231VM_DEFINE_INSTRUCTION (22, local_ref, "local-ref", 1, 0, 1)
a98cef7e 232{
17e90c5e
KN
233 PUSH (LOCAL_REF (FETCH ()));
234 NEXT;
a98cef7e
KN
235}
236
53e28ed9 237VM_DEFINE_INSTRUCTION (23, external_ref, "external-ref", 1, 0, 1)
a98cef7e 238{
17e90c5e
KN
239 unsigned int i;
240 SCM e = external;
241 for (i = FETCH (); i; i--)
2a63758b
KN
242 {
243 CHECK_EXTERNAL(e);
244 e = SCM_CDR (e);
245 }
246 CHECK_EXTERNAL(e);
17e90c5e 247 PUSH (SCM_CAR (e));
a98cef7e
KN
248 NEXT;
249}
250
53e28ed9 251VM_DEFINE_INSTRUCTION (24, variable_ref, "variable-ref", 0, 0, 1)
a98cef7e 252{
17e90c5e 253 SCM x = *sp;
238e7a11 254
2d80426a 255 if (!VARIABLE_BOUNDP (x))
17e90c5e 256 {
238e7a11
LC
257 err_args = SCM_LIST1 (x);
258 /* Was: err_args = SCM_LIST1 (SCM_CAR (x)); */
17e90c5e
KN
259 goto vm_error_unbound;
260 }
238e7a11
LC
261 else
262 {
2d80426a 263 SCM o = VARIABLE_REF (x);
238e7a11
LC
264 *sp = o;
265 }
266
a98cef7e
KN
267 NEXT;
268}
269
53e28ed9 270VM_DEFINE_INSTRUCTION (25, toplevel_ref, "toplevel-ref", 1, 0, 1)
9cc649b8 271{
6297d229 272 unsigned objnum = FETCH ();
fd358575 273 SCM what;
9cc649b8 274 CHECK_OBJECT (objnum);
fd358575 275 what = OBJECT_REF (objnum);
9cc649b8 276
fd358575 277 if (!SCM_VARIABLEP (what))
9cc649b8 278 {
d0168f3d 279 SYNC_REGISTER ();
fd358575 280 if (SCM_LIKELY (SCM_SYMBOLP (what)))
3aabb7b7 281 {
2fda0242 282 SCM mod;
fd358575 283 if (SCM_LIKELY (scm_module_system_booted_p
2fda0242 284 && scm_is_true ((mod = scm_program_module (program)))))
fd358575 285 /* might longjmp */
2fda0242 286 what = scm_module_lookup (mod, what);
fd358575
AW
287 else
288 what = scm_sym2var (what, SCM_BOOL_F, SCM_BOOL_F);
3aabb7b7
AW
289 }
290 else
291 {
fd358575
AW
292 SCM mod;
293 /* compilation of @ or @@
294 `what' is a three-element list: (MODNAME SYM INTERFACE?)
295 INTERFACE? is #t if we compiled @ or #f if we compiled @@
296 */
297 mod = scm_resolve_module (SCM_CAR (what));
298 if (scm_is_true (SCM_CADDR (what)))
299 mod = scm_module_public_interface (mod);
300 if (SCM_FALSEP (mod))
301 {
302 err_args = SCM_LIST1 (mod);
303 goto vm_error_no_such_module;
304 }
305 /* might longjmp */
306 what = scm_module_lookup (mod, SCM_CADR (what));
3aabb7b7
AW
307 }
308
fd358575 309 if (!VARIABLE_BOUNDP (what))
9cc649b8 310 {
fd358575 311 err_args = SCM_LIST1 (what);
9cc649b8
AW
312 goto vm_error_unbound;
313 }
3aabb7b7 314
fd358575 315 OBJECT_SET (objnum, what);
9cc649b8
AW
316 }
317
fd358575 318 PUSH (VARIABLE_REF (what));
9cc649b8
AW
319 NEXT;
320}
321
17e90c5e
KN
322/* set */
323
53e28ed9 324VM_DEFINE_INSTRUCTION (26, local_set, "local-set", 1, 1, 0)
a98cef7e 325{
17e90c5e
KN
326 LOCAL_SET (FETCH (), *sp);
327 DROP ();
a98cef7e
KN
328 NEXT;
329}
330
53e28ed9 331VM_DEFINE_INSTRUCTION (27, external_set, "external-set", 1, 1, 0)
a98cef7e 332{
17e90c5e
KN
333 unsigned int i;
334 SCM e = external;
335 for (i = FETCH (); i; i--)
ac02b386
KN
336 {
337 CHECK_EXTERNAL(e);
338 e = SCM_CDR (e);
339 }
340 CHECK_EXTERNAL(e);
17e90c5e
KN
341 SCM_SETCAR (e, *sp);
342 DROP ();
a98cef7e
KN
343 NEXT;
344}
345
53e28ed9 346VM_DEFINE_INSTRUCTION (28, variable_set, "variable-set", 0, 1, 0)
a98cef7e 347{
2d80426a 348 VARIABLE_SET (sp[0], sp[-1]);
11ea1aba 349 DROPN (2);
a98cef7e
KN
350 NEXT;
351}
352
53e28ed9 353VM_DEFINE_INSTRUCTION (29, toplevel_set, "toplevel-set", 1, 1, 0)
9cc649b8 354{
6297d229 355 unsigned objnum = FETCH ();
fd358575 356 SCM what;
9cc649b8 357 CHECK_OBJECT (objnum);
fd358575 358 what = OBJECT_REF (objnum);
9cc649b8 359
fd358575 360 if (!SCM_VARIABLEP (what))
9cc649b8 361 {
6287726a 362 SYNC_BEFORE_GC ();
fd358575 363 if (SCM_LIKELY (SCM_SYMBOLP (what)))
3aabb7b7 364 {
2fda0242 365 SCM mod;
fd358575 366 if (SCM_LIKELY (scm_module_system_booted_p
2fda0242 367 && scm_is_true ((mod = scm_program_module (program)))))
fd358575 368 /* might longjmp */
2fda0242 369 what = scm_module_lookup (mod, what);
fd358575
AW
370 else
371 what = scm_sym2var (what, SCM_BOOL_F, SCM_BOOL_F);
3aabb7b7
AW
372 }
373 else
374 {
fd358575
AW
375 SCM mod;
376 /* compilation of @ or @@
377 `what' is a three-element list: (MODNAME SYM INTERFACE?)
378 INTERFACE? is #t if we compiled @ or #f if we compiled @@
379 */
380 mod = scm_resolve_module (SCM_CAR (what));
381 if (scm_is_true (SCM_CADDR (what)))
382 mod = scm_module_public_interface (mod);
383 if (SCM_FALSEP (mod))
384 {
385 err_args = SCM_LIST1 (what);
386 goto vm_error_no_such_module;
387 }
388 /* might longjmp */
389 what = scm_module_lookup (mod, SCM_CADR (what));
3aabb7b7
AW
390 }
391
fd358575 392 OBJECT_SET (objnum, what);
9cc649b8
AW
393 }
394
fd358575 395 VARIABLE_SET (what, *sp);
9cc649b8
AW
396 DROP ();
397 NEXT;
398}
399
53e28ed9 400VM_DEFINE_INSTRUCTION (30, externals, "externals", 0, 0, 1)
3de80ed5
AW
401{
402 PUSH (external);
403 NEXT;
404}
405
a98cef7e
KN
406\f
407/*
408 * branch and jump
409 */
410
efbd5892
AW
411/* offset must be a signed short!!! */
412#define FETCH_OFFSET(offset) \
17e90c5e 413{ \
41f248a8
KN
414 int h = FETCH (); \
415 int l = FETCH (); \
efbd5892
AW
416 offset = (h << 8) + l; \
417}
418
419#define BR(p) \
420{ \
421 signed short offset; \
422 FETCH_OFFSET (offset); \
17e90c5e
KN
423 if (p) \
424 ip += offset; \
11ea1aba 425 NULLSTACK (1); \
17e90c5e
KN
426 DROP (); \
427 NEXT; \
428}
429
53e28ed9 430VM_DEFINE_INSTRUCTION (31, br, "br", 2, 0, 0)
41f248a8
KN
431{
432 int h = FETCH ();
433 int l = FETCH ();
434 ip += (signed short) (h << 8) + l;
435 NEXT;
436}
437
53e28ed9 438VM_DEFINE_INSTRUCTION (32, br_if, "br-if", 2, 0, 0)
a98cef7e 439{
17e90c5e 440 BR (!SCM_FALSEP (*sp));
a98cef7e
KN
441}
442
53e28ed9 443VM_DEFINE_INSTRUCTION (33, br_if_not, "br-if-not", 2, 0, 0)
a98cef7e 444{
17e90c5e 445 BR (SCM_FALSEP (*sp));
a98cef7e
KN
446}
447
53e28ed9 448VM_DEFINE_INSTRUCTION (34, br_if_eq, "br-if-eq", 2, 0, 0)
a98cef7e 449{
17e90c5e 450 BR (SCM_EQ_P (sp[0], sp--[1]));
a98cef7e
KN
451}
452
53e28ed9 453VM_DEFINE_INSTRUCTION (35, br_if_not_eq, "br-if-not-eq", 2, 0, 0)
a98cef7e 454{
17e90c5e
KN
455 BR (!SCM_EQ_P (sp[0], sp--[1]));
456}
457
53e28ed9 458VM_DEFINE_INSTRUCTION (36, br_if_null, "br-if-null", 2, 0, 0)
17e90c5e
KN
459{
460 BR (SCM_NULLP (*sp));
461}
462
53e28ed9 463VM_DEFINE_INSTRUCTION (37, br_if_not_null, "br-if-not-null", 2, 0, 0)
17e90c5e
KN
464{
465 BR (!SCM_NULLP (*sp));
a98cef7e
KN
466}
467
a98cef7e
KN
468\f
469/*
470 * Subprogram call
471 */
472
53e28ed9 473VM_DEFINE_INSTRUCTION (38, make_closure, "make-closure", 0, 1, 1)
a98cef7e 474{
3d5ee0cd 475 SYNC_BEFORE_GC ();
53e28ed9
AW
476 *sp = scm_make_program (SCM_PROGRAM_OBJCODE (*sp),
477 SCM_PROGRAM_OBJTABLE (*sp),
478 external);
17e90c5e 479 NEXT;
a98cef7e
KN
480}
481
53e28ed9 482VM_DEFINE_INSTRUCTION (39, call, "call", 1, -1, 1)
a98cef7e 483{
3616e9e9 484 SCM x;
17e90c5e 485 nargs = FETCH ();
a98cef7e
KN
486
487 vm_call:
c8b9df71
KN
488 x = sp[-nargs];
489
e311f5fa
AW
490 SYNC_REGISTER ();
491 SCM_TICK; /* allow interrupt here */
492
a98cef7e
KN
493 /*
494 * Subprogram call
495 */
3616e9e9 496 if (SCM_PROGRAM_P (x))
a98cef7e 497 {
3616e9e9 498 program = x;
499a4c07 499 CACHE_PROGRAM ();
17e90c5e
KN
500 INIT_ARGS ();
501 NEW_FRAME ();
17e90c5e
KN
502 ENTER_HOOK ();
503 APPLY_HOOK ();
a98cef7e
KN
504 NEXT;
505 }
d507b25f
AW
506#ifdef ENABLE_TRAMPOLINE
507 /* Seems to slow down the fibo test, dunno why */
a98cef7e 508 /*
659b4611
AW
509 * Subr call
510 */
511 switch (nargs)
512 {
513 case 0:
514 {
515 scm_t_trampoline_0 call = scm_trampoline_0 (x);
516 if (call)
517 {
518 SYNC_ALL ();
519 *sp = call (x);
520 NEXT;
521 }
522 break;
523 }
524 case 1:
525 {
526 scm_t_trampoline_1 call = scm_trampoline_1 (x);
527 if (call)
528 {
529 SCM arg1;
530 POP (arg1);
531 SYNC_ALL ();
532 *sp = call (x, arg1);
533 NEXT;
534 }
535 break;
536 }
537 case 2:
538 {
539 scm_t_trampoline_2 call = scm_trampoline_2 (x);
540 if (call)
541 {
542 SCM arg1, arg2;
543 POP (arg2);
544 POP (arg1);
545 SYNC_ALL ();
546 *sp = call (x, arg1, arg2);
547 NEXT;
548 }
549 break;
550 }
551 }
d507b25f 552#endif
659b4611
AW
553 /*
554 * Other interpreted or compiled call
a98cef7e 555 */
3616e9e9 556 if (!SCM_FALSEP (scm_procedure_p (x)))
a98cef7e 557 {
f41cb00c
LC
558 /* At this point, the stack contains the procedure and each one of its
559 arguments. */
17e90c5e 560 POP_LIST (nargs);
1865ad56 561 SYNC_REGISTER ();
887ce75a
AW
562 /* keep args on stack so they are marked */
563 sp[-1] = scm_apply (x, sp[0], SCM_EOL);
66db076a 564 NULLSTACK_FOR_NONLOCAL_EXIT ();
887ce75a 565 DROP ();
42906d74
AW
566 if (SCM_UNLIKELY (SCM_VALUESP (*sp)))
567 {
568 /* truncate values */
569 SCM values;
570 POP (values);
571 values = scm_struct_ref (values, SCM_INUM0);
572 if (scm_is_null (values))
573 goto vm_error_not_enough_values;
574 PUSH (SCM_CAR (values));
575 }
17e90c5e 576 NEXT;
a98cef7e
KN
577 }
578 /*
579 * Continuation call
580 */
3616e9e9 581 if (SCM_VM_CONT_P (x))
a98cef7e 582 {
fcd4901b 583 program = x;
f03c31db 584 vm_call_continuation:
a98cef7e 585 /* Check the number of arguments */
f03c31db 586 /* FIXME multiple args */
382693fe 587 if (nargs != 1)
fcd4901b 588 scm_wrong_num_args (program);
a98cef7e
KN
589
590 /* Reinstate the continuation */
17e90c5e 591 EXIT_HOOK ();
fcd4901b 592 reinstate_vm_cont (vp, program);
3d5ee0cd 593 CACHE_REGISTER ();
af988bbf 594 program = SCM_FRAME_PROGRAM (fp);
3616e9e9 595 CACHE_PROGRAM ();
a98cef7e
KN
596 NEXT;
597 }
598
66292535 599 program = x;
17e90c5e 600 goto vm_error_wrong_type_apply;
a98cef7e
KN
601}
602
53e28ed9 603VM_DEFINE_INSTRUCTION (40, goto_args, "goto/args", 1, -1, 1)
a98cef7e 604{
f41cb00c 605 register SCM x;
17e90c5e 606 nargs = FETCH ();
f03c31db 607 vm_goto_args:
3616e9e9 608 x = sp[-nargs];
17e90c5e 609
28a2f57b 610 SYNC_REGISTER ();
17e90c5e 611 SCM_TICK; /* allow interrupt here */
a98cef7e
KN
612
613 /*
17e90c5e 614 * Tail recursive call
a98cef7e 615 */
17e90c5e 616 if (SCM_EQ_P (x, program))
a98cef7e 617 {
f21dfea6 618 int i;
17e90c5e
KN
619
620 /* Move arguments */
f21dfea6
KN
621 INIT_ARGS ();
622 sp -= bp->nargs - 1;
623 for (i = 0; i < bp->nargs; i++)
624 LOCAL_SET (i, sp[i]);
f41cb00c
LC
625
626 /* Drop the first argument and the program itself. */
627 sp -= 2;
5e390de6
AW
628 NULLSTACK (bp->nargs + 1);
629
630 /* Freshen the externals */
53e28ed9 631 external = SCM_PROGRAM_EXTERNALS (x);
5e390de6
AW
632 for (i = 0; i < bp->nexts; i++)
633 CONS (external, SCM_UNDEFINED, external);
634 SCM_FRAME_DATA_ADDRESS (fp)[0] = external;
a98cef7e 635
f21dfea6 636 /* Call itself */
17e90c5e 637 ip = bp->base;
17e90c5e 638 APPLY_HOOK ();
a98cef7e
KN
639 NEXT;
640 }
28106f54 641
17e90c5e 642 /*
28106f54 643 * Tail call, but not to self -- reuse the frame, keeping the ra and dl
17e90c5e 644 */
3616e9e9 645 if (SCM_PROGRAM_P (x))
17e90c5e 646 {
28106f54
AW
647 SCM *data, *tail_args, *dl;
648 int i;
da320011 649 scm_byte_t *ra, *mvra;
11ea1aba
AW
650#ifdef VM_ENABLE_STACK_NULLING
651 SCM *old_sp;
652#endif
28106f54 653
17e90c5e 654 EXIT_HOOK ();
28106f54
AW
655
656 /* save registers */
657 tail_args = stack_base + 2;
658 ra = SCM_FRAME_RETURN_ADDRESS (fp);
da320011 659 mvra = SCM_FRAME_MV_RETURN_ADDRESS (fp);
28106f54
AW
660 dl = SCM_FRAME_DYNAMIC_LINK (fp);
661
662 /* switch programs */
11ea1aba 663 program = x;
28106f54
AW
664 CACHE_PROGRAM ();
665 INIT_ARGS ();
11ea1aba
AW
666 /* delay updating the frame so that if INIT_ARGS has to cons up a rest
667 arg, going into GC, the stack still makes sense */
668 fp[-1] = program;
28106f54
AW
669 nargs = bp->nargs;
670
11ea1aba
AW
671#ifdef VM_ENABLE_STACK_NULLING
672 old_sp = sp;
673 CHECK_STACK_LEAK ();
674#endif
675
28106f54
AW
676 /* new registers -- logically this would be better later, but let's make
677 sure we have space for the locals now */
678 data = SCM_FRAME_DATA_ADDRESS (fp);
679 ip = bp->base;
b1b942b7 680 stack_base = data + 3;
28106f54
AW
681 sp = stack_base;
682 CHECK_OVERFLOW ();
683
684 /* copy args, bottom-up */
685 for (i = 0; i < nargs; i++)
686 fp[i] = tail_args[i];
687
11ea1aba
AW
688 NULLSTACK (old_sp - sp);
689
28106f54
AW
690 /* init locals */
691 for (i = bp->nlocs; i; i--)
692 data[-i] = SCM_UNDEFINED;
693
28106f54 694 /* Set frame data */
b1b942b7
AW
695 data[3] = (SCM)ra;
696 data[2] = (SCM)mvra;
697 data[1] = (SCM)dl;
11ea1aba
AW
698
699 /* Postpone initializing external vars, because if the CONS causes a GC,
700 we want the stack marker to see the data array formatted as expected. */
701 data[0] = SCM_UNDEFINED;
53e28ed9 702 external = SCM_PROGRAM_EXTERNALS (fp[-1]);
11ea1aba
AW
703 for (i = 0; i < bp->nexts; i++)
704 CONS (external, SCM_UNDEFINED, external);
28106f54 705 data[0] = external;
11ea1aba 706
28106f54
AW
707 ENTER_HOOK ();
708 APPLY_HOOK ();
709 NEXT;
17e90c5e 710 }
d507b25f
AW
711#ifdef ENABLE_TRAMPOLINE
712 /* This seems to actually slow down the fibo test -- dunno why */
a98cef7e 713 /*
659b4611
AW
714 * Subr call
715 */
716 switch (nargs)
717 {
718 case 0:
719 {
720 scm_t_trampoline_0 call = scm_trampoline_0 (x);
721 if (call)
722 {
723 SYNC_ALL ();
724 *sp = call (x);
725 goto vm_return;
726 }
727 break;
728 }
729 case 1:
730 {
731 scm_t_trampoline_1 call = scm_trampoline_1 (x);
732 if (call)
733 {
734 SCM arg1;
735 POP (arg1);
736 SYNC_ALL ();
737 *sp = call (x, arg1);
738 goto vm_return;
739 }
740 break;
741 }
742 case 2:
743 {
744 scm_t_trampoline_2 call = scm_trampoline_2 (x);
745 if (call)
746 {
747 SCM arg1, arg2;
748 POP (arg2);
749 POP (arg1);
750 SYNC_ALL ();
751 *sp = call (x, arg1, arg2);
752 goto vm_return;
753 }
754 break;
755 }
756 }
d507b25f 757#endif
659b4611
AW
758
759 /*
760 * Other interpreted or compiled call
a98cef7e 761 */
3616e9e9 762 if (!SCM_FALSEP (scm_procedure_p (x)))
a98cef7e 763 {
17e90c5e 764 POP_LIST (nargs);
1865ad56 765 SYNC_REGISTER ();
887ce75a 766 sp[-1] = scm_apply (x, sp[0], SCM_EOL);
66db076a 767 NULLSTACK_FOR_NONLOCAL_EXIT ();
887ce75a 768 DROP ();
42906d74
AW
769 if (SCM_UNLIKELY (SCM_VALUESP (*sp)))
770 {
771 /* multiple values returned to continuation */
772 SCM values;
773 POP (values);
774 values = scm_struct_ref (values, SCM_INUM0);
775 nvalues = scm_ilength (values);
fb10a008 776 PUSH_LIST (values, SCM_NULLP);
42906d74
AW
777 goto vm_return_values;
778 }
a98cef7e
KN
779 goto vm_return;
780 }
fcd4901b
AW
781
782 program = x;
783
a98cef7e
KN
784 /*
785 * Continuation call
786 */
fcd4901b 787 if (SCM_VM_CONT_P (program))
f03c31db 788 goto vm_call_continuation;
a98cef7e 789
17e90c5e
KN
790 goto vm_error_wrong_type_apply;
791}
792
53e28ed9 793VM_DEFINE_INSTRUCTION (41, goto_nargs, "goto/nargs", 0, 0, 1)
efbd5892
AW
794{
795 SCM x;
796 POP (x);
797 nargs = scm_to_int (x);
d51406fe 798 /* FIXME: should truncate values? */
efbd5892
AW
799 goto vm_goto_args;
800}
801
53e28ed9 802VM_DEFINE_INSTRUCTION (42, call_nargs, "call/nargs", 0, 0, 1)
efbd5892
AW
803{
804 SCM x;
805 POP (x);
806 nargs = scm_to_int (x);
d51406fe 807 /* FIXME: should truncate values? */
efbd5892
AW
808 goto vm_call;
809}
810
53e28ed9 811VM_DEFINE_INSTRUCTION (43, mv_call, "mv-call", 3, -1, 1)
a222b0fa
AW
812{
813 SCM x;
efbd5892 814 signed short offset;
a222b0fa
AW
815
816 nargs = FETCH ();
efbd5892 817 FETCH_OFFSET (offset);
a222b0fa
AW
818
819 x = sp[-nargs];
820
821 /*
822 * Subprogram call
823 */
824 if (SCM_PROGRAM_P (x))
825 {
826 program = x;
827 CACHE_PROGRAM ();
828 INIT_ARGS ();
829 NEW_FRAME ();
b1b942b7 830 SCM_FRAME_DATA_ADDRESS (fp)[2] = (SCM)(SCM_FRAME_RETURN_ADDRESS (fp) + offset);
a222b0fa
AW
831 ENTER_HOOK ();
832 APPLY_HOOK ();
833 NEXT;
834 }
835 /*
836 * Other interpreted or compiled call
837 */
838 if (!SCM_FALSEP (scm_procedure_p (x)))
839 {
840 /* At this point, the stack contains the procedure and each one of its
841 arguments. */
a222b0fa 842 POP_LIST (nargs);
a222b0fa 843 SYNC_REGISTER ();
887ce75a 844 sp[-1] = scm_apply (x, sp[0], SCM_EOL);
66db076a 845 NULLSTACK_FOR_NONLOCAL_EXIT ();
887ce75a 846 DROP ();
a222b0fa
AW
847 if (SCM_VALUESP (*sp))
848 {
849 SCM values, len;
850 POP (values);
851 values = scm_struct_ref (values, SCM_INUM0);
852 len = scm_length (values);
fb10a008 853 PUSH_LIST (values, SCM_NULLP);
a222b0fa
AW
854 PUSH (len);
855 ip += offset;
856 }
857 NEXT;
858 }
859 /*
860 * Continuation call
861 */
862 if (SCM_VM_CONT_P (x))
863 {
864 program = x;
865 goto vm_call_continuation;
866 }
867
868 program = x;
869 goto vm_error_wrong_type_apply;
870}
871
53e28ed9 872VM_DEFINE_INSTRUCTION (44, apply, "apply", 1, -1, 1)
3616e9e9 873{
c8b9df71
KN
874 int len;
875 SCM ls;
876 POP (ls);
877
878 nargs = FETCH ();
9a8cc8e7 879 ASSERT (nargs >= 2);
c8b9df71
KN
880
881 len = scm_ilength (ls);
882 if (len < 0)
883 goto vm_error_wrong_type_arg;
884
fb10a008 885 PUSH_LIST (ls, SCM_NULL_OR_NIL_P);
c8b9df71
KN
886
887 nargs += len - 2;
888 goto vm_call;
3616e9e9
KN
889}
890
53e28ed9 891VM_DEFINE_INSTRUCTION (45, goto_apply, "goto/apply", 1, -1, 1)
f03c31db
AW
892{
893 int len;
894 SCM ls;
895 POP (ls);
896
897 nargs = FETCH ();
9a8cc8e7 898 ASSERT (nargs >= 2);
f03c31db
AW
899
900 len = scm_ilength (ls);
901 if (len < 0)
902 goto vm_error_wrong_type_arg;
903
fb10a008 904 PUSH_LIST (ls, SCM_NULL_OR_NIL_P);
f03c31db
AW
905
906 nargs += len - 2;
907 goto vm_goto_args;
908}
909
53e28ed9 910VM_DEFINE_INSTRUCTION (46, call_cc, "call/cc", 0, 1, 1)
17e90c5e 911{
76282387
AW
912 int first;
913 SCM proc, cont;
914 POP (proc);
915 SYNC_ALL ();
916 cont = scm_make_continuation (&first);
917 if (first)
918 {
919 PUSH (proc);
920 PUSH (cont);
921 nargs = 1;
922 goto vm_call;
923 }
11ea1aba
AW
924 ASSERT (sp == vp->sp);
925 ASSERT (fp == vp->fp);
76282387
AW
926 else if (SCM_VALUESP (cont))
927 {
928 /* multiple values returned to continuation */
929 SCM values;
930 values = scm_struct_ref (cont, SCM_INUM0);
931 if (SCM_NULLP (values))
9a8cc8e7 932 goto vm_error_no_values;
76282387
AW
933 /* non-tail context does not accept multiple values? */
934 PUSH (SCM_CAR (values));
935 NEXT;
936 }
937 else
938 {
939 PUSH (cont);
940 NEXT;
941 }
a98cef7e
KN
942}
943
53e28ed9 944VM_DEFINE_INSTRUCTION (47, goto_cc, "goto/cc", 0, 1, 1)
f03c31db 945{
76282387
AW
946 int first;
947 SCM proc, cont;
948 POP (proc);
949 SYNC_ALL ();
950 cont = scm_make_continuation (&first);
66db076a
AW
951 ASSERT (sp == vp->sp);
952 ASSERT (fp == vp->fp);
76282387
AW
953 if (first)
954 {
955 PUSH (proc);
956 PUSH (cont);
957 nargs = 1;
958 goto vm_goto_args;
959 }
960 else if (SCM_VALUESP (cont))
961 {
962 /* multiple values returned to continuation */
963 SCM values;
964 values = scm_struct_ref (cont, SCM_INUM0);
965 nvalues = scm_ilength (values);
fb10a008 966 PUSH_LIST (values, SCM_NULLP);
76282387
AW
967 goto vm_return_values;
968 }
969 else
970 {
971 PUSH (cont);
972 goto vm_return;
973 }
f03c31db
AW
974}
975
53e28ed9 976VM_DEFINE_INSTRUCTION (48, return, "return", 0, 0, 1)
a98cef7e 977{
a98cef7e 978 vm_return:
17e90c5e
KN
979 EXIT_HOOK ();
980 RETURN_HOOK ();
ef7e1868
AW
981 SYNC_REGISTER ();
982 SCM_TICK; /* allow interrupt here */
f13c269b
AW
983 {
984 SCM ret, *data;
985 data = SCM_FRAME_DATA_ADDRESS (fp);
986
987 POP (ret);
11ea1aba 988 ASSERT (sp == stack_base);
b1b942b7 989 ASSERT (stack_base == data + 3);
f13c269b
AW
990
991 /* Restore registers */
992 sp = SCM_FRAME_LOWER_ADDRESS (fp);
b1b942b7
AW
993 ip = SCM_FRAME_BYTE_CAST (data[3]);
994 fp = SCM_FRAME_STACK_CAST (data[1]);
11ea1aba
AW
995 {
996#ifdef VM_ENABLE_STACK_NULLING
997 int nullcount = stack_base - sp;
998#endif
999 stack_base = SCM_FRAME_UPPER_ADDRESS (fp) - 1;
1000 NULLSTACK (nullcount);
1001 }
f13c269b
AW
1002
1003 /* Set return value (sp is already pushed) */
1004 *sp = ret;
1005 }
17e90c5e 1006
15df3447 1007 /* Restore the last program */
af988bbf 1008 program = SCM_FRAME_PROGRAM (fp);
499a4c07 1009 CACHE_PROGRAM ();
af988bbf 1010 CACHE_EXTERNAL ();
7e4760e4 1011 CHECK_IP ();
a98cef7e
KN
1012 NEXT;
1013}
17e90c5e 1014
53e28ed9 1015VM_DEFINE_INSTRUCTION (49, return_values, "return/values", 1, -1, -1)
a222b0fa 1016{
ef24c01b
AW
1017 /* nvalues declared at top level, because for some reason gcc seems to think
1018 that perhaps it might be used without declaration. Fooey to that, I say. */
1019 SCM *data;
1020
1021 nvalues = FETCH ();
1022 vm_return_values:
a222b0fa
AW
1023 EXIT_HOOK ();
1024 RETURN_HOOK ();
ef24c01b
AW
1025
1026 data = SCM_FRAME_DATA_ADDRESS (fp);
b1b942b7 1027 ASSERT (stack_base == data + 3);
a222b0fa 1028
b1b942b7
AW
1029 /* data[2] is the mv return address */
1030 if (nvalues != 1 && data[2])
ef24c01b
AW
1031 {
1032 int i;
1033 /* Restore registers */
1034 sp = SCM_FRAME_LOWER_ADDRESS (fp) - 1;
b1b942b7
AW
1035 ip = SCM_FRAME_BYTE_CAST (data[2]); /* multiple value ra */
1036 fp = SCM_FRAME_STACK_CAST (data[1]);
a222b0fa 1037
ef24c01b
AW
1038 /* Push return values, and the number of values */
1039 for (i = 0; i < nvalues; i++)
1040 *++sp = stack_base[1+i];
1041 *++sp = SCM_I_MAKINUM (nvalues);
a222b0fa 1042
ef24c01b 1043 /* Finally set new stack_base */
11ea1aba 1044 NULLSTACK (stack_base - sp + nvalues + 1);
ef24c01b
AW
1045 stack_base = SCM_FRAME_UPPER_ADDRESS (fp) - 1;
1046 }
1047 else if (nvalues >= 1)
1048 {
1049 /* Multiple values for a single-valued continuation -- here's where I
1050 break with guile tradition and try and do something sensible. (Also,
1051 this block handles the single-valued return to an mv
1052 continuation.) */
1053 /* Restore registers */
1054 sp = SCM_FRAME_LOWER_ADDRESS (fp) - 1;
b1b942b7
AW
1055 ip = SCM_FRAME_BYTE_CAST (data[3]); /* single value ra */
1056 fp = SCM_FRAME_STACK_CAST (data[1]);
a222b0fa 1057
ef24c01b
AW
1058 /* Push first value */
1059 *++sp = stack_base[1];
a222b0fa 1060
ef24c01b 1061 /* Finally set new stack_base */
9b10d0bc 1062 NULLSTACK (stack_base - sp + nvalues + 1);
ef24c01b
AW
1063 stack_base = SCM_FRAME_UPPER_ADDRESS (fp) - 1;
1064 }
1065 else
1066 goto vm_error_no_values;
a222b0fa
AW
1067
1068 /* Restore the last program */
1069 program = SCM_FRAME_PROGRAM (fp);
1070 CACHE_PROGRAM ();
1071 CACHE_EXTERNAL ();
1072 CHECK_IP ();
1073 NEXT;
1074}
1075
53e28ed9 1076VM_DEFINE_INSTRUCTION (50, return_values_star, "return/values*", 1, -1, -1)
ef24c01b
AW
1077{
1078 SCM l;
1079
1080 nvalues = FETCH ();
11ea1aba 1081 ASSERT (nvalues >= 1);
ef24c01b
AW
1082
1083 nvalues--;
1084 POP (l);
1085 while (SCM_CONSP (l))
1086 {
1087 PUSH (SCM_CAR (l));
1088 l = SCM_CDR (l);
1089 nvalues++;
1090 }
fb10a008
AW
1091 if (SCM_UNLIKELY (!SCM_NULL_OR_NIL_P (l))) {
1092 err_args = scm_list_1 (l);
1093 goto vm_error_improper_list;
1094 }
ef24c01b
AW
1095
1096 goto vm_return_values;
1097}
1098
53e28ed9 1099VM_DEFINE_INSTRUCTION (51, truncate_values, "truncate-values", 2, -1, -1)
d51406fe
AW
1100{
1101 SCM x;
1102 int nbinds, rest;
1103 POP (x);
1104 nvalues = scm_to_int (x);
1105 nbinds = FETCH ();
1106 rest = FETCH ();
1107
1108 if (rest)
1109 nbinds--;
1110
1111 if (nvalues < nbinds)
1112 goto vm_error_not_enough_values;
1113
1114 if (rest)
1115 POP_LIST (nvalues - nbinds);
1116 else
1117 DROPN (nvalues - nbinds);
1118
1119 NEXT;
1120}
1121
53e28ed9
AW
1122/*
1123(defun renumber-ops ()
1124 "start from top of buffer and renumber 'VM_DEFINE_FOO (\n' sequences"
1125 (interactive "")
1126 (save-excursion
1127 (let ((counter -1)) (goto-char (point-min))
1128 (while (re-search-forward "^VM_DEFINE_[^ ]+ (\\([^,]+\\)," (point-max) t)
1129 (replace-match
1130 (number-to-string (setq counter (1+ counter)))
1131 t t nil 1)))))
1132*/
17e90c5e
KN
1133/*
1134 Local Variables:
1135 c-file-style: "gnu"
1136 End:
1137*/