Heap frame "stack holders" are raw scm_vm / scm_vm_cont pointers
[bpt/guile.git] / libguile / vm-engine.c
CommitLineData
27c7c630 1/* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
a98cef7e 2 *
560b9c25 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
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.
a98cef7e 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
560b9c25
AW
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
a98cef7e 12 *
560b9c25
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
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
560b9c25 17 */
a98cef7e 18
510ca126
AW
19/* This file is included in vm.c multiple times. */
20
21
6ed55e91 22#define UNPACK_8_8_8(op,a,b,c) \
20b1b913
AW
23 do \
24 { \
25 a = (op >> 8) & 0xff; \
26 b = (op >> 16) & 0xff; \
27 c = op >> 24; \
28 } \
29 while (0)
30
6ed55e91 31#define UNPACK_8_16(op,a,b) \
20b1b913
AW
32 do \
33 { \
34 a = (op >> 8) & 0xff; \
35 b = op >> 16; \
36 } \
37 while (0)
38
6ed55e91 39#define UNPACK_16_8(op,a,b) \
20b1b913
AW
40 do \
41 { \
42 a = (op >> 8) & 0xffff; \
43 b = op >> 24; \
44 } \
45 while (0)
46
6ed55e91 47#define UNPACK_12_12(op,a,b) \
20b1b913
AW
48 do \
49 { \
50 a = (op >> 8) & 0xfff; \
51 b = op >> 20; \
52 } \
53 while (0)
54
6ed55e91 55#define UNPACK_24(op,a) \
20b1b913
AW
56 do \
57 { \
58 a = op >> 8; \
59 } \
60 while (0)
61
62
8dd6bfa7
AW
63/* Assign some registers by hand. There used to be a bigger list here,
64 but it was never tested, and in the case of x86-32, was a source of
65 compilation failures. It can be revived if it's useful, but my naive
66 hope is that simply annotating the locals with "register" will be a
67 sufficient hint to the compiler. */
eac12024 68#ifdef __GNUC__
8dd6bfa7 69# if defined __x86_64__
eac12024
AW
70/* GCC 4.6 chooses %rbp for IP_REG and %rbx for SP_REG, which works
71 well. Tell it to keep the jump table in a r12, which is
72 callee-saved. */
8dd6bfa7
AW
73# define JT_REG asm ("r12")
74# endif
eac12024
AW
75#endif
76
77#ifndef IP_REG
8dd6bfa7 78# define IP_REG
eac12024 79#endif
eac12024 80#ifndef FP_REG
8dd6bfa7 81# define FP_REG
eac12024
AW
82#endif
83#ifndef JT_REG
8dd6bfa7 84# define JT_REG
eac12024
AW
85#endif
86
6ed55e91
AW
87#define VM_ASSERT(condition, handler) \
88 do { \
89 if (SCM_UNLIKELY (!(condition))) \
90 { \
91 SYNC_ALL(); \
92 handler; \
93 } \
27c7c630 94 } while (0)
eac12024
AW
95
96#ifdef VM_ENABLE_ASSERTIONS
97# define ASSERT(condition) VM_ASSERT (condition, abort())
98#else
99# define ASSERT(condition)
100#endif
101
c850a0ff 102#if VM_USE_HOOKS
ea0cd17d 103#define RUN_HOOK(exp) \
c850a0ff
AW
104 do { \
105 if (SCM_UNLIKELY (vp->trace_level > 0)) \
106 { \
107 SYNC_REGISTER (); \
ea0cd17d 108 exp; \
c850a0ff
AW
109 } \
110 } while (0)
111#else
ea0cd17d 112#define RUN_HOOK(exp)
c850a0ff 113#endif
ea0cd17d
AW
114#define RUN_HOOK0(h) RUN_HOOK (vm_dispatch_##h##_hook (vm))
115#define RUN_HOOK1(h, arg) RUN_HOOK (vm_dispatch_##h##_hook (vm, arg))
c850a0ff
AW
116
117#define APPLY_HOOK() \
ea0cd17d 118 RUN_HOOK0 (apply)
c850a0ff 119#define PUSH_CONTINUATION_HOOK() \
ea0cd17d 120 RUN_HOOK0 (push_continuation)
b636cdb0 121#define POP_CONTINUATION_HOOK(old_fp) \
ea0cd17d 122 RUN_HOOK1 (pop_continuation, old_fp)
c850a0ff 123#define NEXT_HOOK() \
ea0cd17d 124 RUN_HOOK0 (next)
b636cdb0 125#define ABORT_CONTINUATION_HOOK() \
ea0cd17d
AW
126 RUN_HOOK0 (abort)
127#define RESTORE_CONTINUATION_HOOK() \
128 RUN_HOOK0 (restore_continuation)
c850a0ff
AW
129
130#define VM_HANDLE_INTERRUPTS \
131 SCM_ASYNC_TICK_WITH_CODE (current_thread, SYNC_REGISTER ())
132
133
510ca126
AW
134/* Virtual Machine
135
136 This is Guile's new virtual machine. When I say "new", I mean
137 relative to the current virtual machine. At some point it will
138 become "the" virtual machine, and we'll delete this paragraph. As
139 such, the rest of the comments speak as if there's only one VM.
7396d216
AW
140 In difference from the old VM, local 0 is the procedure, and the
141 first argument is local 1. At some point in the future we should
142 change the fp to point to the procedure and not to local 1.
510ca126
AW
143
144 <more overview here>
145 */
146
147
148/* The VM has three state bits: the instruction pointer (IP), the frame
149 pointer (FP), and the top-of-stack pointer (SP). We cache the first
150 two of these in machine registers, local to the VM, because they are
151 used extensively by the VM. As the SP is used more by code outside
152 the VM than by the VM itself, we don't bother caching it locally.
153
154 Since the FP changes infrequently, relative to the IP, we keep vp->fp
155 in sync with the local FP. This would be a big lose for the IP,
156 though, so instead of updating vp->ip all the time, we call SYNC_IP
157 whenever we would need to know the IP of the top frame. In practice,
158 we need to SYNC_IP whenever we call out of the VM to a function that
159 would like to walk the stack, perhaps as the result of an
160 exception. */
161
162#define SYNC_IP() \
9121d9f1 163 vp->ip = (ip)
510ca126
AW
164
165#define SYNC_REGISTER() \
166 SYNC_IP()
167#define SYNC_BEFORE_GC() /* Only SP and FP needed to trace GC */
168#define SYNC_ALL() /* FP already saved */ \
169 SYNC_IP()
170
eadd9eb4
AW
171/* After advancing vp->sp, but before writing any stack slots, check
172 that it is actually in bounds. If it is not in bounds, currently we
173 signal an error. In the future we may expand the stack instead,
174 possibly by moving it elsewhere, therefore no pointer into the stack
175 besides FP is valid across a CHECK_OVERFLOW call. Be careful! */
176#define CHECK_OVERFLOW() \
177 do { \
178 if (SCM_UNLIKELY (vp->sp >= vp->stack_limit)) \
179 { \
180 vm_error_stack_overflow (vp); \
181 CACHE_REGISTER(); \
182 } \
510ca126
AW
183 } while (0)
184
185/* Reserve stack space for a frame. Will check that there is sufficient
b636cdb0
AW
186 stack space for N locals, including the procedure. Invoke after
187 preparing the new frame and setting the fp and ip. */
510ca126
AW
188#define ALLOC_FRAME(n) \
189 do { \
eadd9eb4
AW
190 vp->sp = LOCAL_ADDRESS (n - 1); \
191 CHECK_OVERFLOW (); \
510ca126
AW
192 } while (0)
193
194/* Reset the current frame to hold N locals. Used when we know that no
195 stack expansion is needed. */
196#define RESET_FRAME(n) \
197 do { \
b636cdb0 198 vp->sp = LOCAL_ADDRESS (n - 1); \
510ca126
AW
199 } while (0)
200
b636cdb0
AW
201/* Compute the number of locals in the frame. At a call, this is equal
202 to the number of actual arguments when a function is first called,
203 plus one for the function. */
204#define FRAME_LOCALS_COUNT_FROM(slot) \
205 (vp->sp + 1 - LOCAL_ADDRESS (slot))
206#define FRAME_LOCALS_COUNT() \
207 FRAME_LOCALS_COUNT_FROM (0)
510ca126
AW
208
209/* Restore registers after returning from a frame. */
210#define RESTORE_FRAME() \
211 do { \
212 } while (0)
213
214
215#define CACHE_REGISTER() \
216 do { \
217 ip = (scm_t_uint32 *) vp->ip; \
218 fp = vp->fp; \
219 } while (0)
220
221#ifdef HAVE_LABELS_AS_VALUES
222# define BEGIN_DISPATCH_SWITCH /* */
223# define END_DISPATCH_SWITCH /* */
224# define NEXT(n) \
225 do \
226 { \
227 ip += n; \
228 NEXT_HOOK (); \
229 op = *ip; \
230 goto *jump_table[op & 0xff]; \
231 } \
232 while (0)
233# define VM_DEFINE_OP(opcode, tag, name, meta) \
234 op_##tag:
235#else
236# define BEGIN_DISPATCH_SWITCH \
237 vm_start: \
238 NEXT_HOOK (); \
239 op = *ip; \
240 switch (op & 0xff) \
241 {
242# define END_DISPATCH_SWITCH \
243 default: \
244 goto vm_error_bad_instruction; \
245 }
246# define NEXT(n) \
247 do \
248 { \
249 ip += n; \
250 goto vm_start; \
251 } \
252 while (0)
253# define VM_DEFINE_OP(opcode, tag, name, meta) \
254 op_##tag: \
255 case opcode:
256#endif
257
b636cdb0
AW
258#define LOCAL_ADDRESS(i) (&SCM_FRAME_LOCAL (fp, i))
259#define LOCAL_REF(i) SCM_FRAME_LOCAL (fp, i)
260#define LOCAL_SET(i,o) SCM_FRAME_LOCAL (fp, i) = o
510ca126
AW
261
262#define VARIABLE_REF(v) SCM_VARIABLE_REF (v)
263#define VARIABLE_SET(v,o) SCM_VARIABLE_SET (v, o)
264#define VARIABLE_BOUNDP(v) (!scm_is_eq (VARIABLE_REF (v), SCM_UNDEFINED))
510ca126
AW
265
266#define RETURN_ONE_VALUE(ret) \
267 do { \
268 SCM val = ret; \
b636cdb0 269 SCM *old_fp = fp; \
510ca126 270 VM_HANDLE_INTERRUPTS; \
9121d9f1 271 ip = SCM_FRAME_RETURN_ADDRESS (fp); \
510ca126 272 fp = vp->fp = SCM_FRAME_DYNAMIC_LINK (fp); \
af95414f 273 /* Clear frame. */ \
b636cdb0
AW
274 old_fp[-1] = SCM_BOOL_F; \
275 old_fp[-2] = SCM_BOOL_F; \
af95414f 276 /* Leave proc. */ \
b636cdb0
AW
277 SCM_FRAME_LOCAL (old_fp, 1) = val; \
278 vp->sp = &SCM_FRAME_LOCAL (old_fp, 1); \
279 POP_CONTINUATION_HOOK (old_fp); \
510ca126
AW
280 NEXT (0); \
281 } while (0)
282
283/* While we could generate the list-unrolling code here, it's fine for
284 now to just tail-call (apply values vals). */
285#define RETURN_VALUE_LIST(vals_) \
286 do { \
287 SCM vals = vals_; \
288 VM_HANDLE_INTERRUPTS; \
b636cdb0
AW
289 fp[0] = vm_builtin_apply; \
290 fp[1] = vm_builtin_values; \
291 fp[2] = vals; \
7396d216 292 RESET_FRAME (3); \
486013d6 293 ip = (scm_t_uint32 *) vm_builtin_apply_code; \
adb8d905 294 goto op_tail_apply; \
510ca126
AW
295 } while (0)
296
297#define BR_NARGS(rel) \
d2bd8fa8 298 scm_t_uint32 expected; \
20b1b913 299 UNPACK_24 (op, expected); \
510ca126
AW
300 if (FRAME_LOCALS_COUNT() rel expected) \
301 { \
302 scm_t_int32 offset = ip[1]; \
303 offset >>= 8; /* Sign-extending shift. */ \
304 NEXT (offset); \
305 } \
306 NEXT (2)
307
308#define BR_UNARY(x, exp) \
309 scm_t_uint32 test; \
310 SCM x; \
20b1b913 311 UNPACK_24 (op, test); \
510ca126
AW
312 x = LOCAL_REF (test); \
313 if ((ip[1] & 0x1) ? !(exp) : (exp)) \
314 { \
315 scm_t_int32 offset = ip[1]; \
316 offset >>= 8; /* Sign-extending shift. */ \
317 if (offset < 0) \
318 VM_HANDLE_INTERRUPTS; \
319 NEXT (offset); \
320 } \
321 NEXT (2)
322
323#define BR_BINARY(x, y, exp) \
324 scm_t_uint16 a, b; \
325 SCM x, y; \
20b1b913 326 UNPACK_12_12 (op, a, b); \
510ca126
AW
327 x = LOCAL_REF (a); \
328 y = LOCAL_REF (b); \
329 if ((ip[1] & 0x1) ? !(exp) : (exp)) \
330 { \
331 scm_t_int32 offset = ip[1]; \
332 offset >>= 8; /* Sign-extending shift. */ \
333 if (offset < 0) \
334 VM_HANDLE_INTERRUPTS; \
335 NEXT (offset); \
336 } \
337 NEXT (2)
338
339#define BR_ARITHMETIC(crel,srel) \
340 { \
341 scm_t_uint16 a, b; \
342 SCM x, y; \
20b1b913 343 UNPACK_12_12 (op, a, b); \
510ca126
AW
344 x = LOCAL_REF (a); \
345 y = LOCAL_REF (b); \
346 if (SCM_I_INUMP (x) && SCM_I_INUMP (y)) \
347 { \
348 scm_t_signed_bits x_bits = SCM_UNPACK (x); \
349 scm_t_signed_bits y_bits = SCM_UNPACK (y); \
af95414f 350 if ((ip[1] & 0x1) ? !(x_bits crel y_bits) : (x_bits crel y_bits)) \
510ca126
AW
351 { \
352 scm_t_int32 offset = ip[1]; \
353 offset >>= 8; /* Sign-extending shift. */ \
354 if (offset < 0) \
355 VM_HANDLE_INTERRUPTS; \
356 NEXT (offset); \
357 } \
358 NEXT (2); \
359 } \
360 else \
361 { \
af95414f 362 SCM res; \
510ca126 363 SYNC_IP (); \
af95414f
AW
364 res = srel (x, y); \
365 if ((ip[1] & 0x1) ? scm_is_false (res) : scm_is_true (res)) \
510ca126
AW
366 { \
367 scm_t_int32 offset = ip[1]; \
368 offset >>= 8; /* Sign-extending shift. */ \
369 if (offset < 0) \
370 VM_HANDLE_INTERRUPTS; \
371 NEXT (offset); \
372 } \
373 NEXT (2); \
374 } \
375 }
376
377#define ARGS1(a1) \
378 scm_t_uint16 dst, src; \
379 SCM a1; \
20b1b913 380 UNPACK_12_12 (op, dst, src); \
510ca126
AW
381 a1 = LOCAL_REF (src)
382#define ARGS2(a1, a2) \
383 scm_t_uint8 dst, src1, src2; \
384 SCM a1, a2; \
20b1b913 385 UNPACK_8_8_8 (op, dst, src1, src2); \
510ca126
AW
386 a1 = LOCAL_REF (src1); \
387 a2 = LOCAL_REF (src2)
388#define RETURN(x) \
389 do { LOCAL_SET (dst, x); NEXT (1); } while (0)
390
391/* The maximum/minimum tagged integers. */
d2295ba5
MW
392#define INUM_MAX \
393 ((scm_t_signed_bits) SCM_UNPACK (SCM_I_MAKINUM (SCM_MOST_POSITIVE_FIXNUM)))
394#define INUM_MIN \
395 ((scm_t_signed_bits) SCM_UNPACK (SCM_I_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM)))
396#define INUM_STEP \
397 ((scm_t_signed_bits) SCM_UNPACK (SCM_INUM1) \
398 - (scm_t_signed_bits) SCM_UNPACK (SCM_INUM0))
510ca126
AW
399
400#define BINARY_INTEGER_OP(CFUNC,SFUNC) \
401 { \
402 ARGS2 (x, y); \
403 if (SCM_I_INUMP (x) && SCM_I_INUMP (y)) \
404 { \
405 scm_t_int64 n = SCM_I_INUM (x) CFUNC SCM_I_INUM (y); \
406 if (SCM_FIXABLE (n)) \
407 RETURN (SCM_I_MAKINUM (n)); \
408 } \
409 SYNC_IP (); \
410 RETURN (SFUNC (x, y)); \
411 }
412
413#define VM_VALIDATE_PAIR(x, proc) \
414 VM_ASSERT (scm_is_pair (x), vm_error_not_a_pair (proc, x))
415
416#define VM_VALIDATE_STRUCT(obj, proc) \
417 VM_ASSERT (SCM_STRUCTP (obj), vm_error_not_a_pair (proc, obj))
418
419#define VM_VALIDATE_BYTEVECTOR(x, proc) \
420 VM_ASSERT (SCM_BYTEVECTOR_P (x), vm_error_not_a_bytevector (proc, x))
421
422/* Return true (non-zero) if PTR has suitable alignment for TYPE. */
423#define ALIGNED_P(ptr, type) \
424 ((scm_t_uintptr) (ptr) % alignof_type (type) == 0)
425
426static SCM
f42cfbf0 427VM_NAME (SCM vm, SCM program, SCM *argv, size_t nargs_)
510ca126
AW
428{
429 /* Instruction pointer: A pointer to the opcode that is currently
430 running. */
431 register scm_t_uint32 *ip IP_REG;
432
433 /* Frame pointer: A pointer into the stack, off of which we index
434 arguments and local variables. Pushed at function calls, popped on
435 returns. */
436 register SCM *fp FP_REG;
437
438 /* Current opcode: A cache of *ip. */
439 register scm_t_uint32 op;
440
441 /* Cached variables. */
442 struct scm_vm *vp = SCM_VM_DATA (vm);
510ca126
AW
443 scm_i_thread *current_thread = SCM_I_CURRENT_THREAD;
444 scm_i_jmp_buf registers; /* used for prompts */
445
446#ifdef HAVE_LABELS_AS_VALUES
447 static const void **jump_table_pointer = NULL;
448 register const void **jump_table JT_REG;
449
450 if (SCM_UNLIKELY (!jump_table_pointer))
451 {
452 int i;
453 jump_table_pointer = malloc (SCM_VM_NUM_INSTRUCTIONS * sizeof (void*));
454 for (i = 0; i < SCM_VM_NUM_INSTRUCTIONS; i++)
455 jump_table_pointer[i] = &&vm_error_bad_instruction;
456#define INIT(opcode, tag, name, meta) jump_table_pointer[opcode] = &&op_##tag;
457 FOR_EACH_VM_OPERATION(INIT);
458#undef INIT
459 }
460
461 /* Attempt to keep JUMP_TABLE_POINTER in a register. This saves one
462 load instruction at each instruction dispatch. */
463 jump_table = jump_table_pointer;
464#endif
465
466 if (SCM_I_SETJMP (registers))
467 {
468 /* Non-local return. The values are on the stack, on a new frame
469 set up to call `values' to return the values to the handler.
470 Cache the VM registers back from the vp, and dispatch to the
471 body of `values'.
472
473 Note, at this point, we must assume that any variable local to
474 vm_engine that can be assigned *has* been assigned. So we need
475 to pull all our state back from the ip/fp/sp.
476 */
477 CACHE_REGISTER ();
b636cdb0 478 ABORT_CONTINUATION_HOOK ();
510ca126
AW
479 NEXT (0);
480 }
481
482 /* Load previous VM registers. */
483 CACHE_REGISTER ();
484
485 VM_HANDLE_INTERRUPTS;
486
487 /* Initialization */
488 {
489 SCM *base;
eadd9eb4 490 ptrdiff_t base_frame_size;
510ca126 491
f8085163
AW
492 /* Check that we have enough space: 3 words for the boot
493 continuation, 3 + nargs for the procedure application, and 3 for
510ca126 494 setting up a new frame. */
eadd9eb4
AW
495 base_frame_size = 3 + 3 + nargs_ + 3;
496 vp->sp += base_frame_size;
497 CHECK_OVERFLOW ();
498 base = vp->sp + 1 - base_frame_size;
510ca126
AW
499
500 /* Since it's possible to receive the arguments on the stack itself,
501 and indeed the regular VM invokes us that way, shuffle up the
502 arguments first. */
503 {
504 int i;
505 for (i = nargs_ - 1; i >= 0; i--)
f8085163 506 base[6 + i] = argv[i];
510ca126
AW
507 }
508
509 /* Initial frame, saving previous fp and ip, with the boot
510 continuation. */
511 base[0] = SCM_PACK (fp); /* dynamic link */
f8085163 512 base[1] = SCM_PACK (ip); /* ra */
ef6b7f71 513 base[2] = vm_boot_continuation;
b636cdb0 514 fp = &base[2];
ef6b7f71 515 ip = (scm_t_uint32 *) vm_boot_continuation_code;
510ca126
AW
516
517 /* MV-call frame, function & arguments */
f8085163
AW
518 base[3] = SCM_PACK (fp); /* dynamic link */
519 base[4] = SCM_PACK (ip); /* ra */
520 base[5] = program;
b636cdb0 521 fp = vp->fp = &base[5];
7396d216 522 RESET_FRAME (nargs_ + 1);
510ca126
AW
523 }
524
525 apply:
d798a895 526 while (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp)))
510ca126 527 {
510ca126
AW
528 SCM proc = SCM_FRAME_PROGRAM (fp);
529
530 if (SCM_STRUCTP (proc) && SCM_STRUCT_APPLICABLE_P (proc))
531 {
b636cdb0 532 LOCAL_SET (0, SCM_STRUCT_PROCEDURE (proc));
510ca126
AW
533 continue;
534 }
535 if (SCM_HAS_TYP7 (proc, scm_tc7_smob) && SCM_SMOB_APPLICABLE_P (proc))
536 {
537 scm_t_uint32 n = FRAME_LOCALS_COUNT();
538
9d87158f
AW
539 /* Shuffle args up. */
540 RESET_FRAME (n + 1);
510ca126
AW
541 while (n--)
542 LOCAL_SET (n + 1, LOCAL_REF (n));
510ca126 543
9d87158f 544 LOCAL_SET (0, SCM_SMOB_DESCRIPTOR (proc).apply_trampoline);
510ca126
AW
545 continue;
546 }
547
548 SYNC_IP();
549 vm_error_wrong_type_apply (proc);
510ca126
AW
550 }
551
552 /* Let's go! */
d798a895 553 ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
510ca126
AW
554 NEXT (0);
555
556 BEGIN_DISPATCH_SWITCH;
557
558
559 \f
560
561 /*
562 * Call and return
563 */
564
565 /* halt _:24
566 *
af95414f 567 * Bring the VM to a halt, returning all the values from the stack.
510ca126
AW
568 */
569 VM_DEFINE_OP (0, halt, "halt", OP1 (U8_X24))
570 {
f8085163 571 /* Boot closure in r0, empty frame in r1/r2, proc in r3, values from r4. */
510ca126 572
b636cdb0
AW
573 scm_t_uint32 nvals = FRAME_LOCALS_COUNT_FROM (4);
574 SCM ret;
575
af95414f 576 if (nvals == 1)
f8085163 577 ret = LOCAL_REF (4);
af95414f
AW
578 else
579 {
580 scm_t_uint32 n;
581 ret = SCM_EOL;
582 SYNC_BEFORE_GC();
583 for (n = nvals; n > 0; n--)
f8085163 584 ret = scm_cons (LOCAL_REF (4 + n - 1), ret);
af95414f
AW
585 ret = scm_values (ret);
586 }
510ca126
AW
587
588 vp->ip = SCM_FRAME_RETURN_ADDRESS (fp);
b636cdb0 589 vp->sp = SCM_FRAME_PREVIOUS_SP (fp);
510ca126
AW
590 vp->fp = SCM_FRAME_DYNAMIC_LINK (fp);
591
af95414f 592 return ret;
286a0fb3
AW
593 }
594
af95414f 595 /* call proc:24 _:8 nlocals:24
286a0fb3 596 *
af95414f
AW
597 * Call a procedure. PROC is the local corresponding to a procedure.
598 * The three values below PROC will be overwritten by the saved call
599 * frame data. The new frame will have space for NLOCALS locals: one
600 * for the procedure, and the rest for the arguments which should
601 * already have been pushed on.
510ca126 602 *
af95414f
AW
603 * When the call returns, execution proceeds with the next
604 * instruction. There may be any number of values on the return
605 * stack; the precise number can be had by subtracting the address of
606 * PROC from the post-call SP.
510ca126 607 */
af95414f 608 VM_DEFINE_OP (1, call, "call", OP2 (U8_U24, X8_U24))
510ca126 609 {
af95414f 610 scm_t_uint32 proc, nlocals;
510ca126
AW
611 SCM *old_fp = fp;
612
20b1b913
AW
613 UNPACK_24 (op, proc);
614 UNPACK_24 (ip[1], nlocals);
510ca126
AW
615
616 VM_HANDLE_INTERRUPTS;
617
af95414f 618 fp = vp->fp = old_fp + proc;
510ca126 619 SCM_FRAME_SET_DYNAMIC_LINK (fp, old_fp);
9121d9f1 620 SCM_FRAME_SET_RETURN_ADDRESS (fp, ip + 2);
510ca126 621
af95414f
AW
622 RESET_FRAME (nlocals);
623
510ca126
AW
624 PUSH_CONTINUATION_HOOK ();
625 APPLY_HOOK ();
626
d798a895 627 if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
510ca126
AW
628 goto apply;
629
d798a895 630 ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
510ca126
AW
631 NEXT (0);
632 }
633
af95414f 634 /* tail-call nlocals:24
510ca126 635 *
af95414f 636 * Tail-call a procedure. Requires that the procedure and all of the
486013d6
AW
637 * arguments have already been shuffled into position. Will reset the
638 * frame to NLOCALS.
510ca126 639 */
af95414f 640 VM_DEFINE_OP (2, tail_call, "tail-call", OP1 (U8_U24))
510ca126 641 {
af95414f
AW
642 scm_t_uint32 nlocals;
643
20b1b913 644 UNPACK_24 (op, nlocals);
510ca126
AW
645
646 VM_HANDLE_INTERRUPTS;
647
af95414f 648 RESET_FRAME (nlocals);
486013d6
AW
649
650 APPLY_HOOK ();
651
d798a895 652 if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
486013d6
AW
653 goto apply;
654
d798a895 655 ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
486013d6
AW
656 NEXT (0);
657 }
658
659 /* tail-call/shuffle from:24
660 *
661 * Tail-call a procedure. The procedure should already be set to slot
662 * 0. The rest of the args are taken from the frame, starting at
663 * FROM, shuffled down to start at slot 0. This is part of the
664 * implementation of the call-with-values builtin.
665 */
666 VM_DEFINE_OP (3, tail_call_shuffle, "tail-call/shuffle", OP1 (U8_U24))
667 {
668 scm_t_uint32 n, from, nlocals;
669
20b1b913 670 UNPACK_24 (op, from);
486013d6
AW
671
672 VM_HANDLE_INTERRUPTS;
673
674 VM_ASSERT (from > 0, abort ());
675 nlocals = FRAME_LOCALS_COUNT ();
676
677 for (n = 0; from + n < nlocals; n++)
678 LOCAL_SET (n + 1, LOCAL_REF (from + n));
679
680 RESET_FRAME (n + 1);
681
510ca126
AW
682 APPLY_HOOK ();
683
d798a895 684 if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
510ca126
AW
685 goto apply;
686
d798a895 687 ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
510ca126
AW
688 NEXT (0);
689 }
690
af95414f 691 /* receive dst:12 proc:12 _:8 nlocals:24
510ca126 692 *
af95414f
AW
693 * Receive a single return value from a call whose procedure was in
694 * PROC, asserting that the call actually returned at least one
695 * value. Afterwards, resets the frame to NLOCALS locals.
510ca126 696 */
486013d6 697 VM_DEFINE_OP (4, receive, "receive", OP2 (U8_U12_U12, X8_U24) | OP_DST)
510ca126 698 {
af95414f
AW
699 scm_t_uint16 dst, proc;
700 scm_t_uint32 nlocals;
20b1b913
AW
701 UNPACK_12_12 (op, dst, proc);
702 UNPACK_24 (ip[1], nlocals);
af95414f
AW
703 VM_ASSERT (FRAME_LOCALS_COUNT () > proc + 1, vm_error_no_values ());
704 LOCAL_SET (dst, LOCAL_REF (proc + 1));
705 RESET_FRAME (nlocals);
706 NEXT (2);
707 }
510ca126 708
82f4bac4 709 /* receive-values proc:24 allow-extra?:1 _:7 nvalues:24
af95414f
AW
710 *
711 * Receive a return of multiple values from a call whose procedure was
712 * in PROC. If fewer than NVALUES values were returned, signal an
82f4bac4
AW
713 * error. Unless ALLOW-EXTRA? is true, require that the number of
714 * return values equals NVALUES exactly. After receive-values has
715 * run, the values can be copied down via `mov'.
af95414f 716 */
486013d6 717 VM_DEFINE_OP (5, receive_values, "receive-values", OP2 (U8_U24, B1_X7_U24))
af95414f
AW
718 {
719 scm_t_uint32 proc, nvalues;
20b1b913
AW
720 UNPACK_24 (op, proc);
721 UNPACK_24 (ip[1], nvalues);
82f4bac4
AW
722 if (ip[1] & 0x1)
723 VM_ASSERT (FRAME_LOCALS_COUNT () > proc + nvalues,
724 vm_error_not_enough_values ());
725 else
186b56c4 726 VM_ASSERT (FRAME_LOCALS_COUNT () == proc + 1 + nvalues,
82f4bac4 727 vm_error_wrong_number_of_values (nvalues));
af95414f 728 NEXT (2);
510ca126
AW
729 }
730
731 /* return src:24
732 *
733 * Return a value.
734 */
486013d6 735 VM_DEFINE_OP (6, return, "return", OP1 (U8_U24))
510ca126
AW
736 {
737 scm_t_uint32 src;
20b1b913 738 UNPACK_24 (op, src);
510ca126
AW
739 RETURN_ONE_VALUE (LOCAL_REF (src));
740 }
741
84cc4127 742 /* return-values _:24
510ca126
AW
743 *
744 * Return a number of values from a call frame. This opcode
745 * corresponds to an application of `values' in tail position. As
af95414f
AW
746 * with tail calls, we expect that the values have already been
747 * shuffled down to a contiguous array starting at slot 1.
84cc4127 748 * We also expect the frame has already been reset.
510ca126 749 */
486013d6 750 VM_DEFINE_OP (7, return_values, "return-values", OP1 (U8_X24))
510ca126 751 {
b636cdb0 752 SCM *old_fp = fp;
af95414f 753
af95414f 754 VM_HANDLE_INTERRUPTS;
9121d9f1 755 ip = SCM_FRAME_RETURN_ADDRESS (fp);
af95414f
AW
756 fp = vp->fp = SCM_FRAME_DYNAMIC_LINK (fp);
757
758 /* Clear stack frame. */
b636cdb0
AW
759 old_fp[-1] = SCM_BOOL_F;
760 old_fp[-2] = SCM_BOOL_F;
af95414f 761
b636cdb0 762 POP_CONTINUATION_HOOK (old_fp);
af95414f
AW
763
764 NEXT (0);
510ca126
AW
765 }
766
767
768 \f
769
770 /*
771 * Specialized call stubs
772 */
773
774 /* subr-call ptr-idx:24
775 *
776 * Call a subr, passing all locals in this frame as arguments. Fetch
777 * the foreign pointer from PTR-IDX, a free variable. Return from the
778 * calling frame. This instruction is part of the trampolines
779 * created in gsubr.c, and is not generated by the compiler.
780 */
486013d6 781 VM_DEFINE_OP (8, subr_call, "subr-call", OP1 (U8_U24))
510ca126
AW
782 {
783 scm_t_uint32 ptr_idx;
784 SCM pointer, ret;
785 SCM (*subr)();
786
20b1b913 787 UNPACK_24 (op, ptr_idx);
510ca126 788
d798a895 789 pointer = SCM_PROGRAM_FREE_VARIABLE_REF (LOCAL_REF (0), ptr_idx);
510ca126
AW
790 subr = SCM_POINTER_VALUE (pointer);
791
792 VM_HANDLE_INTERRUPTS;
793 SYNC_IP ();
794
b636cdb0 795 switch (FRAME_LOCALS_COUNT_FROM (1))
510ca126
AW
796 {
797 case 0:
798 ret = subr ();
799 break;
800 case 1:
b636cdb0 801 ret = subr (fp[1]);
510ca126
AW
802 break;
803 case 2:
b636cdb0 804 ret = subr (fp[1], fp[2]);
510ca126
AW
805 break;
806 case 3:
b636cdb0 807 ret = subr (fp[1], fp[2], fp[3]);
510ca126
AW
808 break;
809 case 4:
b636cdb0 810 ret = subr (fp[1], fp[2], fp[3], fp[4]);
510ca126
AW
811 break;
812 case 5:
b636cdb0 813 ret = subr (fp[1], fp[2], fp[3], fp[4], fp[5]);
510ca126
AW
814 break;
815 case 6:
b636cdb0 816 ret = subr (fp[1], fp[2], fp[3], fp[4], fp[5], fp[6]);
510ca126
AW
817 break;
818 case 7:
b636cdb0 819 ret = subr (fp[1], fp[2], fp[3], fp[4], fp[5], fp[6], fp[7]);
510ca126
AW
820 break;
821 case 8:
b636cdb0 822 ret = subr (fp[1], fp[2], fp[3], fp[4], fp[5], fp[6], fp[7], fp[8]);
510ca126
AW
823 break;
824 case 9:
b636cdb0 825 ret = subr (fp[1], fp[2], fp[3], fp[4], fp[5], fp[6], fp[7], fp[8], fp[9]);
510ca126
AW
826 break;
827 case 10:
b636cdb0 828 ret = subr (fp[1], fp[2], fp[3], fp[4], fp[5], fp[6], fp[7], fp[8], fp[9], fp[10]);
510ca126
AW
829 break;
830 default:
831 abort ();
832 }
833
834 // NULLSTACK_FOR_NONLOCAL_EXIT ();
835
836 if (SCM_UNLIKELY (SCM_VALUESP (ret)))
837 /* multiple values returned to continuation */
838 RETURN_VALUE_LIST (scm_struct_ref (ret, SCM_INUM0));
839 else
840 RETURN_ONE_VALUE (ret);
841 }
842
843 /* foreign-call cif-idx:12 ptr-idx:12
844 *
845 * Call a foreign function. Fetch the CIF and foreign pointer from
846 * CIF-IDX and PTR-IDX, both free variables. Return from the calling
847 * frame. Arguments are taken from the stack. This instruction is
848 * part of the trampolines created by the FFI, and is not generated by
849 * the compiler.
850 */
486013d6 851 VM_DEFINE_OP (9, foreign_call, "foreign-call", OP1 (U8_U12_U12))
510ca126
AW
852 {
853 scm_t_uint16 cif_idx, ptr_idx;
7396d216 854 SCM closure, cif, pointer, ret;
510ca126 855
20b1b913 856 UNPACK_12_12 (op, cif_idx, ptr_idx);
510ca126 857
7396d216 858 closure = LOCAL_REF (0);
d798a895
AW
859 cif = SCM_PROGRAM_FREE_VARIABLE_REF (closure, cif_idx);
860 pointer = SCM_PROGRAM_FREE_VARIABLE_REF (closure, ptr_idx);
510ca126
AW
861
862 SYNC_IP ();
863 VM_HANDLE_INTERRUPTS;
864
865 // FIXME: separate args
b636cdb0 866 ret = scm_i_foreign_call (scm_cons (cif, pointer), LOCAL_ADDRESS (1));
510ca126
AW
867
868 // NULLSTACK_FOR_NONLOCAL_EXIT ();
869
870 if (SCM_UNLIKELY (SCM_VALUESP (ret)))
871 /* multiple values returned to continuation */
872 RETURN_VALUE_LIST (scm_struct_ref (ret, SCM_INUM0));
873 else
874 RETURN_ONE_VALUE (ret);
875 }
876
877 /* continuation-call contregs:24
878 *
879 * Return to a continuation, nonlocally. The arguments to the
880 * continuation are taken from the stack. CONTREGS is a free variable
881 * containing the reified continuation. This instruction is part of
882 * the implementation of undelimited continuations, and is not
883 * generated by the compiler.
884 */
486013d6 885 VM_DEFINE_OP (10, continuation_call, "continuation-call", OP1 (U8_U24))
510ca126
AW
886 {
887 SCM contregs;
888 scm_t_uint32 contregs_idx;
889
20b1b913 890 UNPACK_24 (op, contregs_idx);
510ca126 891
7396d216 892 contregs =
d798a895 893 SCM_PROGRAM_FREE_VARIABLE_REF (LOCAL_REF (0), contregs_idx);
510ca126
AW
894
895 SYNC_IP ();
896 scm_i_check_continuation (contregs);
897 vm_return_to_continuation (scm_i_contregs_vm (contregs),
898 scm_i_contregs_vm_cont (contregs),
b636cdb0
AW
899 FRAME_LOCALS_COUNT_FROM (1),
900 LOCAL_ADDRESS (1));
510ca126
AW
901 scm_i_reinstate_continuation (contregs);
902
903 /* no NEXT */
904 abort ();
905 }
906
907 /* compose-continuation cont:24
908 *
909 * Compose a partial continution with the current continuation. The
910 * arguments to the continuation are taken from the stack. CONT is a
911 * free variable containing the reified continuation. This
912 * instruction is part of the implementation of partial continuations,
913 * and is not generated by the compiler.
914 */
486013d6 915 VM_DEFINE_OP (11, compose_continuation, "compose-continuation", OP1 (U8_U24))
510ca126
AW
916 {
917 SCM vmcont;
918 scm_t_uint32 cont_idx;
919
20b1b913 920 UNPACK_24 (op, cont_idx);
d798a895 921 vmcont = SCM_PROGRAM_FREE_VARIABLE_REF (LOCAL_REF (0), cont_idx);
510ca126
AW
922
923 SYNC_IP ();
924 VM_ASSERT (SCM_VM_CONT_REWINDABLE_P (vmcont),
925 vm_error_continuation_not_rewindable (vmcont));
b636cdb0
AW
926 vm_reinstate_partial_continuation (vm, vmcont, FRAME_LOCALS_COUNT_FROM (1),
927 LOCAL_ADDRESS (1),
510ca126
AW
928 &current_thread->dynstack,
929 &registers);
930 CACHE_REGISTER ();
931 NEXT (0);
932 }
933
adb8d905 934 /* tail-apply _:24
510ca126
AW
935 *
936 * Tail-apply the procedure in local slot 0 to the rest of the
937 * arguments. This instruction is part of the implementation of
938 * `apply', and is not generated by the compiler.
939 */
486013d6 940 VM_DEFINE_OP (12, tail_apply, "tail-apply", OP1 (U8_X24))
510ca126 941 {
e93c0430 942 int i, list_idx, list_len, nlocals;
510ca126
AW
943 SCM list;
944
945 VM_HANDLE_INTERRUPTS;
946
e93c0430
AW
947 nlocals = FRAME_LOCALS_COUNT ();
948 // At a minimum, there should be apply, f, and the list.
949 VM_ASSERT (nlocals >= 3, abort ());
950 list_idx = nlocals - 1;
510ca126
AW
951 list = LOCAL_REF (list_idx);
952 list_len = scm_ilength (list);
953
954 VM_ASSERT (list_len >= 0, vm_error_apply_to_non_list (list));
955
e93c0430
AW
956 nlocals = nlocals - 2 + list_len;
957 ALLOC_FRAME (nlocals);
510ca126 958
e93c0430
AW
959 for (i = 1; i < list_idx; i++)
960 LOCAL_SET (i - 1, LOCAL_REF (i));
510ca126
AW
961
962 /* Null out these slots, just in case there are less than 2 elements
963 in the list. */
7396d216
AW
964 LOCAL_SET (list_idx - 1, SCM_UNDEFINED);
965 LOCAL_SET (list_idx, SCM_UNDEFINED);
510ca126
AW
966
967 for (i = 0; i < list_len; i++, list = SCM_CDR (list))
7396d216 968 LOCAL_SET (list_idx - 1 + i, SCM_CAR (list));
510ca126
AW
969
970 APPLY_HOOK ();
971
d798a895 972 if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
510ca126
AW
973 goto apply;
974
d798a895 975 ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
510ca126
AW
976 NEXT (0);
977 }
978
979 /* call/cc _:24
980 *
981 * Capture the current continuation, and tail-apply the procedure in
d691ac20 982 * local slot 1 to it. This instruction is part of the implementation
510ca126
AW
983 * of `call/cc', and is not generated by the compiler.
984 */
486013d6 985 VM_DEFINE_OP (13, call_cc, "call/cc", OP1 (U8_X24))
510ca126
AW
986 {
987 SCM vm_cont, cont;
988 scm_t_dynstack *dynstack;
d691ac20 989 int first;
510ca126
AW
990
991 VM_HANDLE_INTERRUPTS;
992
993 SYNC_IP ();
994 dynstack = scm_dynstack_capture_all (&current_thread->dynstack);
995 vm_cont = scm_i_vm_capture_stack (vp->stack_base,
996 SCM_FRAME_DYNAMIC_LINK (fp),
b636cdb0 997 SCM_FRAME_PREVIOUS_SP (fp),
510ca126 998 SCM_FRAME_RETURN_ADDRESS (fp),
510ca126
AW
999 dynstack,
1000 0);
d691ac20
AW
1001 /* FIXME: Seems silly to capture the registers here, when they are
1002 already captured in the registers local, which here we are
1003 copying out to the heap; and likewise, the setjmp(&registers)
1004 code already has the non-local return handler. But oh
1005 well! */
1006 cont = scm_i_make_continuation (&first, vm, vm_cont);
1007
1008 if (first)
1009 {
1010 LOCAL_SET (0, LOCAL_REF (1));
1011 LOCAL_SET (1, cont);
1012 RESET_FRAME (2);
510ca126 1013
d691ac20 1014 APPLY_HOOK ();
510ca126 1015
d798a895 1016 if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
d691ac20 1017 goto apply;
510ca126 1018
d798a895 1019 ip = SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp));
d691ac20
AW
1020 NEXT (0);
1021 }
1022 else
1023 {
1024 CACHE_REGISTER ();
b636cdb0 1025 ABORT_CONTINUATION_HOOK ();
d691ac20
AW
1026 NEXT (0);
1027 }
510ca126 1028 }
510ca126 1029
486013d6
AW
1030 /* abort _:24
1031 *
1032 * Abort to a prompt handler. The tag is expected in r1, and the rest
1033 * of the values in the frame are returned to the prompt handler.
1034 * This corresponds to a tail application of abort-to-prompt.
1035 */
1036 VM_DEFINE_OP (14, abort, "abort", OP1 (U8_X24))
1037 {
1038 scm_t_uint32 nlocals = FRAME_LOCALS_COUNT ();
1039
1040 ASSERT (nlocals >= 2);
186b56c4
AW
1041 /* FIXME: Really we should capture the caller's registers. Until
1042 then, manually advance the IP so that when the prompt resumes,
1043 it continues with the next instruction. */
1044 ip++;
486013d6 1045 SYNC_IP ();
b636cdb0
AW
1046 vm_abort (vm, LOCAL_REF (1), nlocals - 2, LOCAL_ADDRESS (2),
1047 SCM_EOL, LOCAL_ADDRESS (0), &registers);
486013d6
AW
1048
1049 /* vm_abort should not return */
1050 abort ();
1051 }
1052
1053 /* builtin-ref dst:12 idx:12
1054 *
1055 * Load a builtin stub by index into DST.
1056 */
1057 VM_DEFINE_OP (15, builtin_ref, "builtin-ref", OP1 (U8_U12_U12) | OP_DST)
1058 {
1059 scm_t_uint16 dst, idx;
1060
20b1b913 1061 UNPACK_12_12 (op, dst, idx);
486013d6
AW
1062 LOCAL_SET (dst, scm_vm_builtin_ref (idx));
1063
1064 NEXT (1);
1065 }
1066
510ca126
AW
1067
1068 \f
1069
1070 /*
1071 * Function prologues
1072 */
1073
1074 /* br-if-nargs-ne expected:24 _:8 offset:24
1075 * br-if-nargs-lt expected:24 _:8 offset:24
1076 * br-if-nargs-gt expected:24 _:8 offset:24
1077 *
1078 * If the number of actual arguments is not equal, less than, or greater
1079 * than EXPECTED, respectively, add OFFSET, a signed 24-bit number, to
1080 * the current instruction pointer.
1081 */
486013d6 1082 VM_DEFINE_OP (16, br_if_nargs_ne, "br-if-nargs-ne", OP2 (U8_U24, X8_L24))
510ca126
AW
1083 {
1084 BR_NARGS (!=);
1085 }
486013d6 1086 VM_DEFINE_OP (17, br_if_nargs_lt, "br-if-nargs-lt", OP2 (U8_U24, X8_L24))
510ca126
AW
1087 {
1088 BR_NARGS (<);
1089 }
486013d6 1090 VM_DEFINE_OP (18, br_if_nargs_gt, "br-if-nargs-gt", OP2 (U8_U24, X8_L24))
510ca126
AW
1091 {
1092 BR_NARGS (>);
1093 }
1094
1095 /* assert-nargs-ee expected:24
1096 * assert-nargs-ge expected:24
1097 * assert-nargs-le expected:24
1098 *
1099 * If the number of actual arguments is not ==, >=, or <= EXPECTED,
1100 * respectively, signal an error.
1101 */
486013d6 1102 VM_DEFINE_OP (19, assert_nargs_ee, "assert-nargs-ee", OP1 (U8_U24))
510ca126
AW
1103 {
1104 scm_t_uint32 expected;
20b1b913 1105 UNPACK_24 (op, expected);
510ca126
AW
1106 VM_ASSERT (FRAME_LOCALS_COUNT () == expected,
1107 vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp)));
1108 NEXT (1);
1109 }
486013d6 1110 VM_DEFINE_OP (20, assert_nargs_ge, "assert-nargs-ge", OP1 (U8_U24))
510ca126
AW
1111 {
1112 scm_t_uint32 expected;
20b1b913 1113 UNPACK_24 (op, expected);
510ca126
AW
1114 VM_ASSERT (FRAME_LOCALS_COUNT () >= expected,
1115 vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp)));
1116 NEXT (1);
1117 }
486013d6 1118 VM_DEFINE_OP (21, assert_nargs_le, "assert-nargs-le", OP1 (U8_U24))
510ca126
AW
1119 {
1120 scm_t_uint32 expected;
20b1b913 1121 UNPACK_24 (op, expected);
510ca126
AW
1122 VM_ASSERT (FRAME_LOCALS_COUNT () <= expected,
1123 vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp)));
1124 NEXT (1);
1125 }
1126
af95414f 1127 /* alloc-frame nlocals:24
510ca126
AW
1128 *
1129 * Ensure that there is space on the stack for NLOCALS local variables,
1130 * setting them all to SCM_UNDEFINED, except those nargs values that
7396d216 1131 * were passed as arguments and procedure.
510ca126 1132 */
486013d6 1133 VM_DEFINE_OP (22, alloc_frame, "alloc-frame", OP1 (U8_U24))
510ca126
AW
1134 {
1135 scm_t_uint32 nlocals, nargs;
20b1b913 1136 UNPACK_24 (op, nlocals);
510ca126
AW
1137
1138 nargs = FRAME_LOCALS_COUNT ();
1139 ALLOC_FRAME (nlocals);
1140 while (nlocals-- > nargs)
1141 LOCAL_SET (nlocals, SCM_UNDEFINED);
1142
1143 NEXT (1);
1144 }
1145
af95414f
AW
1146 /* reset-frame nlocals:24
1147 *
1148 * Like alloc-frame, but doesn't check that the stack is big enough.
1149 * Used to reset the frame size to something less than the size that
1150 * was previously set via alloc-frame.
1151 */
486013d6 1152 VM_DEFINE_OP (23, reset_frame, "reset-frame", OP1 (U8_U24))
af95414f
AW
1153 {
1154 scm_t_uint32 nlocals;
20b1b913 1155 UNPACK_24 (op, nlocals);
af95414f
AW
1156 RESET_FRAME (nlocals);
1157 NEXT (1);
1158 }
1159
510ca126
AW
1160 /* assert-nargs-ee/locals expected:12 nlocals:12
1161 *
1162 * Equivalent to a sequence of assert-nargs-ee and reserve-locals. The
1163 * number of locals reserved is EXPECTED + NLOCALS.
1164 */
486013d6 1165 VM_DEFINE_OP (24, assert_nargs_ee_locals, "assert-nargs-ee/locals", OP1 (U8_U12_U12))
510ca126
AW
1166 {
1167 scm_t_uint16 expected, nlocals;
20b1b913 1168 UNPACK_12_12 (op, expected, nlocals);
510ca126
AW
1169 VM_ASSERT (FRAME_LOCALS_COUNT () == expected,
1170 vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp)));
1171 ALLOC_FRAME (expected + nlocals);
1172 while (nlocals--)
1173 LOCAL_SET (expected + nlocals, SCM_UNDEFINED);
1174
1175 NEXT (1);
1176 }
1177
f90c0554
AW
1178 /* br-if-npos-gt nreq:24 _:8 npos:24 _:8 offset:24
1179 *
1180 * Find the first positional argument after NREQ. If it is greater
1181 * than NPOS, jump to OFFSET.
1182 *
1183 * This instruction is only emitted for functions with multiple
1184 * clauses, and an earlier clause has keywords and no rest arguments.
1185 * See "Case-lambda" in the manual, for more on how case-lambda
1186 * chooses the clause to apply.
1187 */
1188 VM_DEFINE_OP (25, br_if_npos_gt, "br-if-npos-gt", OP3 (U8_U24, X8_U24, X8_L24))
1189 {
1190 scm_t_uint32 nreq, npos;
1191
20b1b913
AW
1192 UNPACK_24 (op, nreq);
1193 UNPACK_24 (ip[1], npos);
f90c0554
AW
1194
1195 /* We can only have too many positionals if there are more
1196 arguments than NPOS. */
1197 if (FRAME_LOCALS_COUNT() > npos)
1198 {
1199 scm_t_uint32 n;
1200 for (n = nreq; n < npos; n++)
1201 if (scm_is_keyword (LOCAL_REF (n)))
1202 break;
1203 if (n == npos && !scm_is_keyword (LOCAL_REF (n)))
1204 {
1205 scm_t_int32 offset = ip[2];
1206 offset >>= 8; /* Sign-extending shift. */
1207 NEXT (offset);
1208 }
1209 }
1210 NEXT (3);
1211 }
1212
510ca126
AW
1213 /* bind-kwargs nreq:24 allow-other-keys:1 has-rest:1 _:6 nreq-and-opt:24
1214 * _:8 ntotal:24 kw-offset:32
1215 *
1216 * Find the last positional argument, and shuffle all the rest above
1217 * NTOTAL. Initialize the intervening locals to SCM_UNDEFINED. Then
1218 * load the constant at KW-OFFSET words from the current IP, and use it
1219 * to bind keyword arguments. If HAS-REST, collect all shuffled
1220 * arguments into a list, and store it in NREQ-AND-OPT. Finally, clear
1221 * the arguments that we shuffled up.
1222 *
1223 * A macro-mega-instruction.
1224 */
f90c0554 1225 VM_DEFINE_OP (26, bind_kwargs, "bind-kwargs", OP4 (U8_U24, U8_U24, X8_U24, N32))
510ca126
AW
1226 {
1227 scm_t_uint32 nreq, nreq_and_opt, ntotal, npositional, nkw, n, nargs;
1228 scm_t_int32 kw_offset;
1229 scm_t_bits kw_bits;
1230 SCM kw;
1231 char allow_other_keys, has_rest;
1232
20b1b913 1233 UNPACK_24 (op, nreq);
510ca126
AW
1234 allow_other_keys = ip[1] & 0x1;
1235 has_rest = ip[1] & 0x2;
20b1b913
AW
1236 UNPACK_24 (ip[1], nreq_and_opt);
1237 UNPACK_24 (ip[2], ntotal);
510ca126
AW
1238 kw_offset = ip[3];
1239 kw_bits = (scm_t_bits) (ip + kw_offset);
1240 VM_ASSERT (!(kw_bits & 0x7), abort());
1241 kw = SCM_PACK (kw_bits);
1242
1243 nargs = FRAME_LOCALS_COUNT ();
1244
1245 /* look in optionals for first keyword or last positional */
1246 /* starting after the last required positional arg */
1247 npositional = nreq;
1248 while (/* while we have args */
1249 npositional < nargs
1250 /* and we still have positionals to fill */
1251 && npositional < nreq_and_opt
1252 /* and we haven't reached a keyword yet */
1253 && !scm_is_keyword (LOCAL_REF (npositional)))
1254 /* bind this optional arg (by leaving it in place) */
1255 npositional++;
1256 nkw = nargs - npositional;
1257 /* shuffle non-positional arguments above ntotal */
1258 ALLOC_FRAME (ntotal + nkw);
1259 n = nkw;
1260 while (n--)
1261 LOCAL_SET (ntotal + n, LOCAL_REF (npositional + n));
1262 /* and fill optionals & keyword args with SCM_UNDEFINED */
1263 n = npositional;
1264 while (n < ntotal)
1265 LOCAL_SET (n++, SCM_UNDEFINED);
1266
1267 VM_ASSERT (has_rest || (nkw % 2) == 0,
1268 vm_error_kwargs_length_not_even (SCM_FRAME_PROGRAM (fp)));
1269
1270 /* Now bind keywords, in the order given. */
1271 for (n = 0; n < nkw; n++)
1272 if (scm_is_keyword (LOCAL_REF (ntotal + n)))
1273 {
1274 SCM walk;
1275 for (walk = kw; scm_is_pair (walk); walk = SCM_CDR (walk))
1276 if (scm_is_eq (SCM_CAAR (walk), LOCAL_REF (ntotal + n)))
1277 {
1278 SCM si = SCM_CDAR (walk);
1279 LOCAL_SET (SCM_I_INUMP (si) ? SCM_I_INUM (si) : scm_to_uint32 (si),
1280 LOCAL_REF (ntotal + n + 1));
1281 break;
1282 }
1283 VM_ASSERT (scm_is_pair (walk) || allow_other_keys,
28d5d253
MW
1284 vm_error_kwargs_unrecognized_keyword (SCM_FRAME_PROGRAM (fp),
1285 LOCAL_REF (ntotal + n)));
510ca126
AW
1286 n++;
1287 }
1288 else
28d5d253
MW
1289 VM_ASSERT (has_rest, vm_error_kwargs_invalid_keyword (SCM_FRAME_PROGRAM (fp),
1290 LOCAL_REF (ntotal + n)));
510ca126
AW
1291
1292 if (has_rest)
1293 {
1294 SCM rest = SCM_EOL;
1295 n = nkw;
1296 while (n--)
1297 rest = scm_cons (LOCAL_REF (ntotal + n), rest);
1298 LOCAL_SET (nreq_and_opt, rest);
1299 }
1300
1301 RESET_FRAME (ntotal);
1302
1303 NEXT (4);
1304 }
1305
1306 /* bind-rest dst:24
1307 *
1308 * Collect any arguments at or above DST into a list, and store that
1309 * list at DST.
1310 */
f90c0554 1311 VM_DEFINE_OP (27, bind_rest, "bind-rest", OP1 (U8_U24) | OP_DST)
510ca126
AW
1312 {
1313 scm_t_uint32 dst, nargs;
1314 SCM rest = SCM_EOL;
1315
20b1b913 1316 UNPACK_24 (op, dst);
510ca126
AW
1317 nargs = FRAME_LOCALS_COUNT ();
1318
234155e3 1319 if (nargs <= dst)
510ca126 1320 {
234155e3
AW
1321 ALLOC_FRAME (dst + 1);
1322 while (nargs < dst)
1323 LOCAL_SET (nargs++, SCM_UNDEFINED);
510ca126 1324 }
234155e3
AW
1325 else
1326 {
1327 while (nargs-- > dst)
1328 {
1329 rest = scm_cons (LOCAL_REF (nargs), rest);
1330 LOCAL_SET (nargs, SCM_UNDEFINED);
1331 }
510ca126 1332
234155e3
AW
1333 RESET_FRAME (dst + 1);
1334 }
510ca126 1335
234155e3 1336 LOCAL_SET (dst, rest);
510ca126
AW
1337
1338 NEXT (1);
1339 }
1340
510ca126
AW
1341
1342 \f
1343
1344 /*
1345 * Branching instructions
1346 */
1347
1348 /* br offset:24
1349 *
1350 * Add OFFSET, a signed 24-bit number, to the current instruction
1351 * pointer.
1352 */
f90c0554 1353 VM_DEFINE_OP (28, br, "br", OP1 (U8_L24))
510ca126
AW
1354 {
1355 scm_t_int32 offset = op;
1356 offset >>= 8; /* Sign-extending shift. */
1357 NEXT (offset);
1358 }
1359
1360 /* br-if-true test:24 invert:1 _:7 offset:24
1361 *
1362 * If the value in TEST is true for the purposes of Scheme, add
1363 * OFFSET, a signed 24-bit number, to the current instruction pointer.
1364 */
f90c0554 1365 VM_DEFINE_OP (29, br_if_true, "br-if-true", OP2 (U8_U24, B1_X7_L24))
510ca126
AW
1366 {
1367 BR_UNARY (x, scm_is_true (x));
1368 }
1369
1370 /* br-if-null test:24 invert:1 _:7 offset:24
1371 *
1372 * If the value in TEST is the end-of-list or Lisp nil, add OFFSET, a
1373 * signed 24-bit number, to the current instruction pointer.
1374 */
f90c0554 1375 VM_DEFINE_OP (30, br_if_null, "br-if-null", OP2 (U8_U24, B1_X7_L24))
510ca126
AW
1376 {
1377 BR_UNARY (x, scm_is_null (x));
1378 }
1379
1380 /* br-if-nil test:24 invert:1 _:7 offset:24
1381 *
1382 * If the value in TEST is false to Lisp, add OFFSET, a signed 24-bit
1383 * number, to the current instruction pointer.
1384 */
f90c0554 1385 VM_DEFINE_OP (31, br_if_nil, "br-if-nil", OP2 (U8_U24, B1_X7_L24))
510ca126
AW
1386 {
1387 BR_UNARY (x, scm_is_lisp_false (x));
1388 }
1389
1390 /* br-if-pair test:24 invert:1 _:7 offset:24
1391 *
1392 * If the value in TEST is a pair, add OFFSET, a signed 24-bit number,
1393 * to the current instruction pointer.
1394 */
f90c0554 1395 VM_DEFINE_OP (32, br_if_pair, "br-if-pair", OP2 (U8_U24, B1_X7_L24))
510ca126
AW
1396 {
1397 BR_UNARY (x, scm_is_pair (x));
1398 }
1399
1400 /* br-if-struct test:24 invert:1 _:7 offset:24
1401 *
1402 * If the value in TEST is a struct, add OFFSET, a signed 24-bit
1403 * number, to the current instruction pointer.
1404 */
f90c0554 1405 VM_DEFINE_OP (33, br_if_struct, "br-if-struct", OP2 (U8_U24, B1_X7_L24))
510ca126
AW
1406 {
1407 BR_UNARY (x, SCM_STRUCTP (x));
1408 }
1409
1410 /* br-if-char test:24 invert:1 _:7 offset:24
1411 *
1412 * If the value in TEST is a char, add OFFSET, a signed 24-bit number,
1413 * to the current instruction pointer.
1414 */
f90c0554 1415 VM_DEFINE_OP (34, br_if_char, "br-if-char", OP2 (U8_U24, B1_X7_L24))
510ca126
AW
1416 {
1417 BR_UNARY (x, SCM_CHARP (x));
1418 }
1419
1420 /* br-if-tc7 test:24 invert:1 tc7:7 offset:24
1421 *
1422 * If the value in TEST has the TC7 given in the second word, add
1423 * OFFSET, a signed 24-bit number, to the current instruction pointer.
1424 */
f90c0554 1425 VM_DEFINE_OP (35, br_if_tc7, "br-if-tc7", OP2 (U8_U24, B1_U7_L24))
510ca126
AW
1426 {
1427 BR_UNARY (x, SCM_HAS_TYP7 (x, (ip[1] >> 1) & 0x7f));
1428 }
1429
1430 /* br-if-eq a:12 b:12 invert:1 _:7 offset:24
1431 *
1432 * If the value in A is eq? to the value in B, add OFFSET, a signed
1433 * 24-bit number, to the current instruction pointer.
1434 */
f90c0554 1435 VM_DEFINE_OP (36, br_if_eq, "br-if-eq", OP2 (U8_U12_U12, B1_X7_L24))
510ca126
AW
1436 {
1437 BR_BINARY (x, y, scm_is_eq (x, y));
1438 }
1439
1440 /* br-if-eqv a:12 b:12 invert:1 _:7 offset:24
1441 *
1442 * If the value in A is eqv? to the value in B, add OFFSET, a signed
1443 * 24-bit number, to the current instruction pointer.
1444 */
f90c0554 1445 VM_DEFINE_OP (37, br_if_eqv, "br-if-eqv", OP2 (U8_U12_U12, B1_X7_L24))
510ca126
AW
1446 {
1447 BR_BINARY (x, y,
1448 scm_is_eq (x, y)
1449 || (SCM_NIMP (x) && SCM_NIMP (y)
1450 && scm_is_true (scm_eqv_p (x, y))));
1451 }
1452
af95414f 1453 // FIXME: remove, have compiler inline eqv test instead
510ca126
AW
1454 /* br-if-equal a:12 b:12 invert:1 _:7 offset:24
1455 *
1456 * If the value in A is equal? to the value in B, add OFFSET, a signed
1457 * 24-bit number, to the current instruction pointer.
1458 */
1459 // FIXME: should sync_ip before calling out?
f90c0554 1460 VM_DEFINE_OP (38, br_if_equal, "br-if-equal", OP2 (U8_U12_U12, B1_X7_L24))
510ca126
AW
1461 {
1462 BR_BINARY (x, y,
1463 scm_is_eq (x, y)
1464 || (SCM_NIMP (x) && SCM_NIMP (y)
1465 && scm_is_true (scm_equal_p (x, y))));
1466 }
1467
af95414f 1468 /* br-if-= a:12 b:12 invert:1 _:7 offset:24
510ca126
AW
1469 *
1470 * If the value in A is = to the value in B, add OFFSET, a signed
1471 * 24-bit number, to the current instruction pointer.
1472 */
f90c0554 1473 VM_DEFINE_OP (39, br_if_ee, "br-if-=", OP2 (U8_U12_U12, B1_X7_L24))
510ca126
AW
1474 {
1475 BR_ARITHMETIC (==, scm_num_eq_p);
1476 }
1477
1478 /* br-if-< a:12 b:12 _:8 offset:24
1479 *
1480 * If the value in A is < to the value in B, add OFFSET, a signed
1481 * 24-bit number, to the current instruction pointer.
1482 */
f90c0554 1483 VM_DEFINE_OP (40, br_if_lt, "br-if-<", OP2 (U8_U12_U12, B1_X7_L24))
510ca126
AW
1484 {
1485 BR_ARITHMETIC (<, scm_less_p);
1486 }
1487
1488 /* br-if-<= a:12 b:12 _:8 offset:24
1489 *
1490 * If the value in A is <= to the value in B, add OFFSET, a signed
1491 * 24-bit number, to the current instruction pointer.
1492 */
f90c0554 1493 VM_DEFINE_OP (41, br_if_le, "br-if-<=", OP2 (U8_U12_U12, B1_X7_L24))
510ca126
AW
1494 {
1495 BR_ARITHMETIC (<=, scm_leq_p);
1496 }
1497
510ca126
AW
1498
1499 \f
1500
1501 /*
1502 * Lexical binding instructions
1503 */
1504
1505 /* mov dst:12 src:12
1506 *
1507 * Copy a value from one local slot to another.
1508 */
f90c0554 1509 VM_DEFINE_OP (42, mov, "mov", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
1510 {
1511 scm_t_uint16 dst;
1512 scm_t_uint16 src;
1513
20b1b913 1514 UNPACK_12_12 (op, dst, src);
510ca126
AW
1515 LOCAL_SET (dst, LOCAL_REF (src));
1516
1517 NEXT (1);
1518 }
1519
1520 /* long-mov dst:24 _:8 src:24
1521 *
1522 * Copy a value from one local slot to another.
1523 */
f90c0554 1524 VM_DEFINE_OP (43, long_mov, "long-mov", OP2 (U8_U24, X8_U24) | OP_DST)
510ca126
AW
1525 {
1526 scm_t_uint32 dst;
1527 scm_t_uint32 src;
1528
20b1b913
AW
1529 UNPACK_24 (op, dst);
1530 UNPACK_24 (ip[1], src);
510ca126
AW
1531 LOCAL_SET (dst, LOCAL_REF (src));
1532
1533 NEXT (2);
1534 }
1535
1536 /* box dst:12 src:12
1537 *
1538 * Create a new variable holding SRC, and place it in DST.
1539 */
f90c0554 1540 VM_DEFINE_OP (44, box, "box", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
1541 {
1542 scm_t_uint16 dst, src;
20b1b913 1543 UNPACK_12_12 (op, dst, src);
510ca126
AW
1544 LOCAL_SET (dst, scm_cell (scm_tc7_variable, SCM_UNPACK (LOCAL_REF (src))));
1545 NEXT (1);
1546 }
1547
510ca126
AW
1548 /* box-ref dst:12 src:12
1549 *
1550 * Unpack the variable at SRC into DST, asserting that the variable is
1551 * actually bound.
1552 */
f90c0554 1553 VM_DEFINE_OP (45, box_ref, "box-ref", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
1554 {
1555 scm_t_uint16 dst, src;
1556 SCM var;
20b1b913 1557 UNPACK_12_12 (op, dst, src);
510ca126 1558 var = LOCAL_REF (src);
4f406fea
AW
1559 VM_ASSERT (SCM_VARIABLEP (var),
1560 vm_error_not_a_variable ("variable-ref", var));
af95414f
AW
1561 VM_ASSERT (VARIABLE_BOUNDP (var),
1562 vm_error_unbound (SCM_FRAME_PROGRAM (fp), var));
510ca126
AW
1563 LOCAL_SET (dst, VARIABLE_REF (var));
1564 NEXT (1);
1565 }
1566
1567 /* box-set! dst:12 src:12
1568 *
1569 * Set the contents of the variable at DST to SET.
1570 */
f90c0554 1571 VM_DEFINE_OP (46, box_set, "box-set!", OP1 (U8_U12_U12))
510ca126
AW
1572 {
1573 scm_t_uint16 dst, src;
1574 SCM var;
20b1b913 1575 UNPACK_12_12 (op, dst, src);
510ca126 1576 var = LOCAL_REF (dst);
4f406fea
AW
1577 VM_ASSERT (SCM_VARIABLEP (var),
1578 vm_error_not_a_variable ("variable-set!", var));
510ca126
AW
1579 VARIABLE_SET (var, LOCAL_REF (src));
1580 NEXT (1);
1581 }
1582
7396d216 1583 /* make-closure dst:24 offset:32 _:8 nfree:24
510ca126
AW
1584 *
1585 * Make a new closure, and write it to DST. The code for the closure
1586 * will be found at OFFSET words from the current IP. OFFSET is a
7396d216
AW
1587 * signed 32-bit integer. Space for NFREE free variables will be
1588 * allocated.
510ca126 1589 */
f90c0554 1590 VM_DEFINE_OP (47, make_closure, "make-closure", OP3 (U8_U24, L32, X8_U24) | OP_DST)
510ca126
AW
1591 {
1592 scm_t_uint32 dst, nfree, n;
1593 scm_t_int32 offset;
1594 SCM closure;
1595
20b1b913 1596 UNPACK_24 (op, dst);
510ca126 1597 offset = ip[1];
20b1b913 1598 UNPACK_24 (ip[2], nfree);
510ca126
AW
1599
1600 // FIXME: Assert range of nfree?
e0755cd1 1601 closure = scm_words (scm_tc7_program | (nfree << 16), nfree + 2);
510ca126 1602 SCM_SET_CELL_WORD_1 (closure, ip + offset);
7396d216 1603 // FIXME: Elide these initializations?
510ca126 1604 for (n = 0; n < nfree; n++)
d798a895 1605 SCM_PROGRAM_FREE_VARIABLE_SET (closure, n, SCM_BOOL_F);
510ca126 1606 LOCAL_SET (dst, closure);
7396d216 1607 NEXT (3);
510ca126
AW
1608 }
1609
7396d216 1610 /* free-ref dst:12 src:12 _:8 idx:24
510ca126 1611 *
7396d216 1612 * Load free variable IDX from the closure SRC into local slot DST.
510ca126 1613 */
f90c0554 1614 VM_DEFINE_OP (48, free_ref, "free-ref", OP2 (U8_U12_U12, X8_U24) | OP_DST)
510ca126 1615 {
7396d216
AW
1616 scm_t_uint16 dst, src;
1617 scm_t_uint32 idx;
20b1b913
AW
1618 UNPACK_12_12 (op, dst, src);
1619 UNPACK_24 (ip[1], idx);
7396d216 1620 /* CHECK_FREE_VARIABLE (src); */
d798a895 1621 LOCAL_SET (dst, SCM_PROGRAM_FREE_VARIABLE_REF (LOCAL_REF (src), idx));
7396d216
AW
1622 NEXT (2);
1623 }
510ca126 1624
7396d216
AW
1625 /* free-set! dst:12 src:12 _8 idx:24
1626 *
1627 * Set free variable IDX from the closure DST to SRC.
1628 */
f90c0554 1629 VM_DEFINE_OP (49, free_set, "free-set!", OP2 (U8_U12_U12, X8_U24))
7396d216
AW
1630 {
1631 scm_t_uint16 dst, src;
1632 scm_t_uint32 idx;
20b1b913
AW
1633 UNPACK_12_12 (op, dst, src);
1634 UNPACK_24 (ip[1], idx);
7396d216 1635 /* CHECK_FREE_VARIABLE (src); */
d798a895 1636 SCM_PROGRAM_FREE_VARIABLE_SET (LOCAL_REF (dst), idx, LOCAL_REF (src));
7396d216 1637 NEXT (2);
510ca126
AW
1638 }
1639
1640
1641 \f
1642
1643 /*
1644 * Immediates and statically allocated non-immediates
1645 */
1646
1647 /* make-short-immediate dst:8 low-bits:16
1648 *
1649 * Make an immediate whose low bits are LOW-BITS, and whose top bits are
1650 * 0.
1651 */
f90c0554 1652 VM_DEFINE_OP (50, make_short_immediate, "make-short-immediate", OP1 (U8_U8_I16) | OP_DST)
510ca126
AW
1653 {
1654 scm_t_uint8 dst;
1655 scm_t_bits val;
1656
20b1b913 1657 UNPACK_8_16 (op, dst, val);
510ca126
AW
1658 LOCAL_SET (dst, SCM_PACK (val));
1659 NEXT (1);
1660 }
1661
1662 /* make-long-immediate dst:24 low-bits:32
1663 *
1664 * Make an immediate whose low bits are LOW-BITS, and whose top bits are
1665 * 0.
1666 */
f90c0554 1667 VM_DEFINE_OP (51, make_long_immediate, "make-long-immediate", OP2 (U8_U24, I32))
510ca126 1668 {
da60ba80 1669 scm_t_uint32 dst;
510ca126
AW
1670 scm_t_bits val;
1671
20b1b913 1672 UNPACK_24 (op, dst);
510ca126
AW
1673 val = ip[1];
1674 LOCAL_SET (dst, SCM_PACK (val));
1675 NEXT (2);
1676 }
1677
1678 /* make-long-long-immediate dst:24 high-bits:32 low-bits:32
1679 *
1680 * Make an immediate with HIGH-BITS and LOW-BITS.
1681 */
f90c0554 1682 VM_DEFINE_OP (52, make_long_long_immediate, "make-long-long-immediate", OP3 (U8_U24, A32, B32) | OP_DST)
510ca126 1683 {
da60ba80 1684 scm_t_uint32 dst;
510ca126
AW
1685 scm_t_bits val;
1686
20b1b913 1687 UNPACK_24 (op, dst);
510ca126
AW
1688#if SIZEOF_SCM_T_BITS > 4
1689 val = ip[1];
1690 val <<= 32;
1691 val |= ip[2];
1692#else
1693 ASSERT (ip[1] == 0);
1694 val = ip[2];
1695#endif
1696 LOCAL_SET (dst, SCM_PACK (val));
1697 NEXT (3);
1698 }
1699
1700 /* make-non-immediate dst:24 offset:32
1701 *
1702 * Load a pointer to statically allocated memory into DST. The
1703 * object's memory is will be found OFFSET 32-bit words away from the
1704 * current instruction pointer. OFFSET is a signed value. The
1705 * intention here is that the compiler would produce an object file
1706 * containing the words of a non-immediate object, and this
1707 * instruction creates a pointer to that memory, effectively
1708 * resurrecting that object.
1709 *
1710 * Whether the object is mutable or immutable depends on where it was
1711 * allocated by the compiler, and loaded by the loader.
1712 */
f90c0554 1713 VM_DEFINE_OP (53, make_non_immediate, "make-non-immediate", OP2 (U8_U24, N32) | OP_DST)
510ca126
AW
1714 {
1715 scm_t_uint32 dst;
1716 scm_t_int32 offset;
1717 scm_t_uint32* loc;
1718 scm_t_bits unpacked;
1719
20b1b913 1720 UNPACK_24 (op, dst);
510ca126
AW
1721 offset = ip[1];
1722 loc = ip + offset;
1723 unpacked = (scm_t_bits) loc;
1724
1725 VM_ASSERT (!(unpacked & 0x7), abort());
1726
1727 LOCAL_SET (dst, SCM_PACK (unpacked));
1728
1729 NEXT (2);
1730 }
1731
1732 /* static-ref dst:24 offset:32
1733 *
1734 * Load a SCM value into DST. The SCM value will be fetched from
1735 * memory, OFFSET 32-bit words away from the current instruction
1736 * pointer. OFFSET is a signed value.
1737 *
1738 * The intention is for this instruction to be used to load constants
1739 * that the compiler is unable to statically allocate, like symbols.
1740 * These values would be initialized when the object file loads.
1741 */
f90c0554 1742 VM_DEFINE_OP (54, static_ref, "static-ref", OP2 (U8_U24, S32))
510ca126
AW
1743 {
1744 scm_t_uint32 dst;
1745 scm_t_int32 offset;
1746 scm_t_uint32* loc;
1747 scm_t_uintptr loc_bits;
1748
20b1b913 1749 UNPACK_24 (op, dst);
510ca126
AW
1750 offset = ip[1];
1751 loc = ip + offset;
1752 loc_bits = (scm_t_uintptr) loc;
1753 VM_ASSERT (ALIGNED_P (loc, SCM), abort());
1754
1755 LOCAL_SET (dst, *((SCM *) loc_bits));
1756
1757 NEXT (2);
1758 }
1759
1760 /* static-set! src:24 offset:32
1761 *
1762 * Store a SCM value into memory, OFFSET 32-bit words away from the
1763 * current instruction pointer. OFFSET is a signed value.
1764 */
f90c0554 1765 VM_DEFINE_OP (55, static_set, "static-set!", OP2 (U8_U24, LO32))
510ca126
AW
1766 {
1767 scm_t_uint32 src;
1768 scm_t_int32 offset;
1769 scm_t_uint32* loc;
1770
20b1b913 1771 UNPACK_24 (op, src);
510ca126
AW
1772 offset = ip[1];
1773 loc = ip + offset;
1774 VM_ASSERT (ALIGNED_P (loc, SCM), abort());
1775
1776 *((SCM *) loc) = LOCAL_REF (src);
1777
1778 NEXT (2);
1779 }
1780
2ab2a10d 1781 /* static-patch! _:24 dst-offset:32 src-offset:32
510ca126 1782 *
2ab2a10d
AW
1783 * Patch a pointer at DST-OFFSET to point to SRC-OFFSET. Both offsets
1784 * are signed 32-bit values, indicating a memory address as a number
1785 * of 32-bit words away from the current instruction pointer.
510ca126 1786 */
f90c0554 1787 VM_DEFINE_OP (56, static_patch, "static-patch!", OP3 (U8_X24, LO32, L32))
510ca126 1788 {
2ab2a10d
AW
1789 scm_t_int32 dst_offset, src_offset;
1790 void *src;
1791 void** dst_loc;
510ca126 1792
2ab2a10d
AW
1793 dst_offset = ip[1];
1794 src_offset = ip[2];
510ca126 1795
2ab2a10d
AW
1796 dst_loc = (void **) (ip + dst_offset);
1797 src = ip + src_offset;
1798 VM_ASSERT (ALIGNED_P (dst_loc, void*), abort());
510ca126 1799
2ab2a10d
AW
1800 *dst_loc = src;
1801
1802 NEXT (3);
510ca126
AW
1803 }
1804
1805 \f
1806
1807 /*
1808 * Mutable top-level bindings
1809 */
1810
1811 /* There are three slightly different ways to resolve toplevel
1812 variables.
1813
1814 1. A toplevel reference outside of a function. These need to be
1815 looked up when the expression is evaluated -- no later, and no
1816 before. They are looked up relative to the module that is
1817 current when the expression is evaluated. For example:
1818
1819 (if (foo) a b)
1820
1821 The "resolve" instruction resolves the variable (box), and then
1822 access is via box-ref or box-set!.
1823
1824 2. A toplevel reference inside a function. These are looked up
1825 relative to the module that was current when the function was
1826 defined. Unlike code at the toplevel, which is usually run only
1827 once, these bindings benefit from memoized lookup, in which the
1828 variable resulting from the lookup is cached in the function.
1829
1830 (lambda () (if (foo) a b))
1831
af95414f
AW
1832 The toplevel-box instruction is equivalent to "resolve", but
1833 caches the resulting variable in statically allocated memory.
510ca126
AW
1834
1835 3. A reference to an identifier with respect to a particular
1836 module. This can happen for primitive references, and
af95414f
AW
1837 references residualized by macro expansions. These can always
1838 be cached. Use module-box for these.
510ca126
AW
1839 */
1840
1841 /* current-module dst:24
1842 *
1843 * Store the current module in DST.
1844 */
f90c0554 1845 VM_DEFINE_OP (57, current_module, "current-module", OP1 (U8_U24) | OP_DST)
510ca126
AW
1846 {
1847 scm_t_uint32 dst;
1848
20b1b913 1849 UNPACK_24 (op, dst);
510ca126
AW
1850
1851 SYNC_IP ();
1852 LOCAL_SET (dst, scm_current_module ());
1853
1854 NEXT (1);
1855 }
1856
af95414f 1857 /* resolve dst:24 bound?:1 _:7 sym:24
510ca126 1858 *
af95414f
AW
1859 * Resolve SYM in the current module, and place the resulting variable
1860 * in DST.
510ca126 1861 */
f90c0554 1862 VM_DEFINE_OP (58, resolve, "resolve", OP2 (U8_U24, B1_X7_U24) | OP_DST)
510ca126 1863 {
af95414f
AW
1864 scm_t_uint32 dst;
1865 scm_t_uint32 sym;
1866 SCM var;
510ca126 1867
20b1b913
AW
1868 UNPACK_24 (op, dst);
1869 UNPACK_24 (ip[1], sym);
510ca126
AW
1870
1871 SYNC_IP ();
af95414f
AW
1872 var = scm_lookup (LOCAL_REF (sym));
1873 if (ip[1] & 0x1)
1874 VM_ASSERT (VARIABLE_BOUNDP (var),
b636cdb0 1875 vm_error_unbound (fp[0], LOCAL_REF (sym)));
af95414f 1876 LOCAL_SET (dst, var);
510ca126 1877
af95414f 1878 NEXT (2);
510ca126
AW
1879 }
1880
6165d812 1881 /* define! sym:12 val:12
510ca126
AW
1882 *
1883 * Look up a binding for SYM in the current module, creating it if
1884 * necessary. Set its value to VAL.
1885 */
f90c0554 1886 VM_DEFINE_OP (59, define, "define!", OP1 (U8_U12_U12))
510ca126
AW
1887 {
1888 scm_t_uint16 sym, val;
20b1b913 1889 UNPACK_12_12 (op, sym, val);
510ca126
AW
1890 SYNC_IP ();
1891 scm_define (LOCAL_REF (sym), LOCAL_REF (val));
1892 NEXT (1);
1893 }
1894
af95414f 1895 /* toplevel-box dst:24 var-offset:32 mod-offset:32 sym-offset:32 bound?:1 _:31
510ca126
AW
1896 *
1897 * Load a SCM value. The SCM value will be fetched from memory,
1898 * VAR-OFFSET 32-bit words away from the current instruction pointer.
af95414f 1899 * VAR-OFFSET is a signed value. Up to here, toplevel-box is like
510ca126
AW
1900 * static-ref.
1901 *
af95414f
AW
1902 * Then, if the loaded value is a variable, it is placed in DST, and control
1903 * flow continues.
510ca126
AW
1904 *
1905 * Otherwise, we have to resolve the variable. In that case we load
1906 * the module from MOD-OFFSET, just as we loaded the variable.
1907 * Usually the module gets set when the closure is created. The name
1908 * is an offset to a symbol.
1909 *
af95414f
AW
1910 * We use the module and the symbol to resolve the variable, placing it in
1911 * DST, and caching the resolved variable so that we will hit the cache next
1912 * time.
510ca126 1913 */
f90c0554 1914 VM_DEFINE_OP (60, toplevel_box, "toplevel-box", OP5 (U8_U24, S32, S32, N32, B1_X31) | OP_DST)
510ca126
AW
1915 {
1916 scm_t_uint32 dst;
1917 scm_t_int32 var_offset;
1918 scm_t_uint32* var_loc_u32;
1919 SCM *var_loc;
1920 SCM var;
1921
20b1b913 1922 UNPACK_24 (op, dst);
510ca126
AW
1923 var_offset = ip[1];
1924 var_loc_u32 = ip + var_offset;
1925 VM_ASSERT (ALIGNED_P (var_loc_u32, SCM), abort());
1926 var_loc = (SCM *) var_loc_u32;
1927 var = *var_loc;
1928
1929 if (SCM_UNLIKELY (!SCM_VARIABLEP (var)))
1930 {
1931 SCM mod, sym;
1932 scm_t_int32 mod_offset = ip[2]; /* signed */
1933 scm_t_int32 sym_offset = ip[3]; /* signed */
1934 scm_t_uint32 *mod_loc = ip + mod_offset;
1935 scm_t_uint32 *sym_loc = ip + sym_offset;
1936
1937 SYNC_IP ();
1938
1939 VM_ASSERT (ALIGNED_P (mod_loc, SCM), abort());
1940 VM_ASSERT (ALIGNED_P (sym_loc, SCM), abort());
1941
1942 mod = *((SCM *) mod_loc);
1943 sym = *((SCM *) sym_loc);
1944
e23f9e44
AW
1945 /* If the toplevel scope was captured before modules were
1946 booted, use the root module. */
1947 if (scm_is_false (mod))
1948 mod = scm_the_root_module ();
1949
510ca126 1950 var = scm_module_lookup (mod, sym);
af95414f 1951 if (ip[4] & 0x1)
b636cdb0 1952 VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (fp[0], sym));
510ca126
AW
1953
1954 *var_loc = var;
1955 }
1956
af95414f
AW
1957 LOCAL_SET (dst, var);
1958 NEXT (5);
510ca126
AW
1959 }
1960
af95414f 1961 /* module-box dst:24 var-offset:32 mod-offset:32 sym-offset:32 bound?:1 _:31
510ca126 1962 *
af95414f 1963 * Like toplevel-box, except MOD-OFFSET points at the name of a module
510ca126
AW
1964 * instead of the module itself.
1965 */
f90c0554 1966 VM_DEFINE_OP (61, module_box, "module-box", OP5 (U8_U24, S32, N32, N32, B1_X31) | OP_DST)
510ca126
AW
1967 {
1968 scm_t_uint32 dst;
1969 scm_t_int32 var_offset;
1970 scm_t_uint32* var_loc_u32;
1971 SCM *var_loc;
1972 SCM var;
1973
20b1b913 1974 UNPACK_24 (op, dst);
510ca126
AW
1975 var_offset = ip[1];
1976 var_loc_u32 = ip + var_offset;
1977 VM_ASSERT (ALIGNED_P (var_loc_u32, SCM), abort());
1978 var_loc = (SCM *) var_loc_u32;
1979 var = *var_loc;
1980
1981 if (SCM_UNLIKELY (!SCM_VARIABLEP (var)))
1982 {
1983 SCM modname, sym;
1984 scm_t_int32 modname_offset = ip[2]; /* signed */
1985 scm_t_int32 sym_offset = ip[3]; /* signed */
1986 scm_t_uint32 *modname_words = ip + modname_offset;
1987 scm_t_uint32 *sym_loc = ip + sym_offset;
1988
1989 SYNC_IP ();
1990
1991 VM_ASSERT (!(((scm_t_uintptr) modname_words) & 0x7), abort());
1992 VM_ASSERT (ALIGNED_P (sym_loc, SCM), abort());
1993
1994 modname = SCM_PACK ((scm_t_bits) modname_words);
1995 sym = *((SCM *) sym_loc);
1996
e23f9e44
AW
1997 if (!scm_module_system_booted_p)
1998 {
1999#ifdef VM_ENABLE_PARANOID_ASSERTIONS
2000 ASSERT
2001 (scm_is_true
2002 scm_equal_p (modname,
2003 scm_list_2 (SCM_BOOL_T,
2004 scm_from_utf8_symbol ("guile"))));
2005#endif
2006 var = scm_lookup (sym);
2007 }
2008 else if (scm_is_true (SCM_CAR (modname)))
510ca126
AW
2009 var = scm_public_lookup (SCM_CDR (modname), sym);
2010 else
2011 var = scm_private_lookup (SCM_CDR (modname), sym);
2012
af95414f 2013 if (ip[4] & 0x1)
b636cdb0 2014 VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (fp[0], sym));
510ca126
AW
2015
2016 *var_loc = var;
2017 }
2018
af95414f
AW
2019 LOCAL_SET (dst, var);
2020 NEXT (5);
510ca126
AW
2021 }
2022
2023 \f
2024
2025 /*
2026 * The dynamic environment
2027 */
2028
8d59d55e 2029 /* prompt tag:24 escape-only?:1 _:7 proc-slot:24 _:8 handler-offset:24
510ca126
AW
2030 *
2031 * Push a new prompt on the dynamic stack, with a tag from TAG and a
2032 * handler at HANDLER-OFFSET words from the current IP. The handler
8d59d55e
AW
2033 * will expect a multiple-value return as if from a call with the
2034 * procedure at PROC-SLOT.
510ca126 2035 */
f90c0554 2036 VM_DEFINE_OP (62, prompt, "prompt", OP3 (U8_U24, B1_X7_U24, X8_L24))
510ca126 2037 {
8d59d55e 2038 scm_t_uint32 tag, proc_slot;
510ca126
AW
2039 scm_t_int32 offset;
2040 scm_t_uint8 escape_only_p;
2041 scm_t_dynstack_prompt_flags flags;
2042
20b1b913 2043 UNPACK_24 (op, tag);
8d59d55e 2044 escape_only_p = ip[1] & 0x1;
20b1b913 2045 UNPACK_24 (ip[1], proc_slot);
8d59d55e 2046 offset = ip[2];
510ca126
AW
2047 offset >>= 8; /* Sign extension */
2048
2049 /* Push the prompt onto the dynamic stack. */
2050 flags = escape_only_p ? SCM_F_DYNSTACK_PROMPT_ESCAPE_ONLY : 0;
2051 scm_dynstack_push_prompt (&current_thread->dynstack, flags,
2052 LOCAL_REF (tag),
0bca90aa
AW
2053 fp - vp->stack_base,
2054 LOCAL_ADDRESS (proc_slot) - vp->stack_base,
9121d9f1 2055 ip + offset,
8d59d55e
AW
2056 &registers);
2057 NEXT (3);
510ca126 2058 }
510ca126
AW
2059
2060 /* wind winder:12 unwinder:12
2061 *
2062 * Push wind and unwind procedures onto the dynamic stack. Note that
2063 * neither are actually called; the compiler should emit calls to wind
2064 * and unwind for the normal dynamic-wind control flow. Also note that
2065 * the compiler should have inserted checks that they wind and unwind
2066 * procs are thunks, if it could not prove that to be the case.
2067 */
f90c0554 2068 VM_DEFINE_OP (63, wind, "wind", OP1 (U8_U12_U12))
510ca126
AW
2069 {
2070 scm_t_uint16 winder, unwinder;
20b1b913 2071 UNPACK_12_12 (op, winder, unwinder);
510ca126
AW
2072 scm_dynstack_push_dynwind (&current_thread->dynstack,
2073 LOCAL_REF (winder), LOCAL_REF (unwinder));
2074 NEXT (1);
2075 }
2076
510ca126
AW
2077 /* unwind _:24
2078 *
2079 * A normal exit from the dynamic extent of an expression. Pop the top
2080 * entry off of the dynamic stack.
2081 */
f90c0554 2082 VM_DEFINE_OP (64, unwind, "unwind", OP1 (U8_X24))
510ca126
AW
2083 {
2084 scm_dynstack_pop (&current_thread->dynstack);
2085 NEXT (1);
2086 }
2087
98eaef1b 2088 /* push-fluid fluid:12 value:12
510ca126
AW
2089 *
2090 * Dynamically bind N fluids to values. The fluids are expected to be
2091 * allocated in a continguous range on the stack, starting from
2092 * FLUID-BASE. The values do not have this restriction.
2093 */
f90c0554 2094 VM_DEFINE_OP (65, push_fluid, "push-fluid", OP1 (U8_U12_U12))
510ca126 2095 {
98eaef1b 2096 scm_t_uint32 fluid, value;
510ca126 2097
20b1b913 2098 UNPACK_12_12 (op, fluid, value);
510ca126 2099
98eaef1b 2100 scm_dynstack_push_fluid (&current_thread->dynstack,
2a4ee2ac 2101 LOCAL_REF (fluid), LOCAL_REF (value),
98eaef1b
AW
2102 current_thread->dynamic_state);
2103 NEXT (1);
510ca126 2104 }
510ca126 2105
98eaef1b 2106 /* pop-fluid _:24
510ca126
AW
2107 *
2108 * Leave the dynamic extent of a with-fluids expression, restoring the
2109 * fluids to their previous values.
2110 */
f90c0554 2111 VM_DEFINE_OP (66, pop_fluid, "pop-fluid", OP1 (U8_X24))
510ca126
AW
2112 {
2113 /* This function must not allocate. */
98eaef1b
AW
2114 scm_dynstack_unwind_fluid (&current_thread->dynstack,
2115 current_thread->dynamic_state);
510ca126
AW
2116 NEXT (1);
2117 }
2118
2119 /* fluid-ref dst:12 src:12
2120 *
2121 * Reference the fluid in SRC, and place the value in DST.
2122 */
f90c0554 2123 VM_DEFINE_OP (67, fluid_ref, "fluid-ref", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2124 {
2125 scm_t_uint16 dst, src;
2126 size_t num;
2127 SCM fluid, fluids;
2128
20b1b913 2129 UNPACK_12_12 (op, dst, src);
510ca126
AW
2130 fluid = LOCAL_REF (src);
2131 fluids = SCM_I_DYNAMIC_STATE_FLUIDS (current_thread->dynamic_state);
2132 if (SCM_UNLIKELY (!SCM_FLUID_P (fluid))
2133 || ((num = SCM_I_FLUID_NUM (fluid)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
2134 {
2135 /* Punt dynstate expansion and error handling to the C proc. */
2136 SYNC_IP ();
2137 LOCAL_SET (dst, scm_fluid_ref (fluid));
2138 }
2139 else
2140 {
2141 SCM val = SCM_SIMPLE_VECTOR_REF (fluids, num);
2142 if (scm_is_eq (val, SCM_UNDEFINED))
2143 val = SCM_I_FLUID_DEFAULT (fluid);
2144 VM_ASSERT (!scm_is_eq (val, SCM_UNDEFINED),
2145 vm_error_unbound_fluid (program, fluid));
2146 LOCAL_SET (dst, val);
2147 }
2148
2149 NEXT (1);
2150 }
2151
2152 /* fluid-set fluid:12 val:12
2153 *
2154 * Set the value of the fluid in DST to the value in SRC.
2155 */
f90c0554 2156 VM_DEFINE_OP (68, fluid_set, "fluid-set", OP1 (U8_U12_U12))
510ca126
AW
2157 {
2158 scm_t_uint16 a, b;
2159 size_t num;
2160 SCM fluid, fluids;
2161
20b1b913 2162 UNPACK_12_12 (op, a, b);
510ca126
AW
2163 fluid = LOCAL_REF (a);
2164 fluids = SCM_I_DYNAMIC_STATE_FLUIDS (current_thread->dynamic_state);
2165 if (SCM_UNLIKELY (!SCM_FLUID_P (fluid))
2166 || ((num = SCM_I_FLUID_NUM (fluid)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
2167 {
2168 /* Punt dynstate expansion and error handling to the C proc. */
2169 SYNC_IP ();
2170 scm_fluid_set_x (fluid, LOCAL_REF (b));
2171 }
2172 else
2173 SCM_SIMPLE_VECTOR_SET (fluids, num, LOCAL_REF (b));
2174
2175 NEXT (1);
2176 }
2177
2178
2179 \f
2180
2181 /*
2182 * Strings, symbols, and keywords
2183 */
2184
2185 /* string-length dst:12 src:12
2186 *
2187 * Store the length of the string in SRC in DST.
2188 */
f90c0554 2189 VM_DEFINE_OP (69, string_length, "string-length", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2190 {
2191 ARGS1 (str);
2192 if (SCM_LIKELY (scm_is_string (str)))
2193 RETURN (SCM_I_MAKINUM (scm_i_string_length (str)));
2194 else
2195 {
2196 SYNC_IP ();
2197 RETURN (scm_string_length (str));
2198 }
2199 }
2200
2201 /* string-ref dst:8 src:8 idx:8
2202 *
2203 * Fetch the character at position IDX in the string in SRC, and store
2204 * it in DST.
2205 */
f90c0554 2206 VM_DEFINE_OP (70, string_ref, "string-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2207 {
2208 scm_t_signed_bits i = 0;
2209 ARGS2 (str, idx);
2210 if (SCM_LIKELY (scm_is_string (str)
2211 && SCM_I_INUMP (idx)
2212 && ((i = SCM_I_INUM (idx)) >= 0)
2213 && i < scm_i_string_length (str)))
2214 RETURN (SCM_MAKE_CHAR (scm_i_string_ref (str, i)));
2215 else
2216 {
2217 SYNC_IP ();
2218 RETURN (scm_string_ref (str, idx));
2219 }
2220 }
2221
2222 /* No string-set! instruction, as there is no good fast path there. */
2223
2224 /* string-to-number dst:12 src:12
2225 *
2226 * Parse a string in SRC to a number, and store in DST.
2227 */
f90c0554 2228 VM_DEFINE_OP (71, string_to_number, "string->number", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2229 {
2230 scm_t_uint16 dst, src;
2231
20b1b913 2232 UNPACK_12_12 (op, dst, src);
510ca126
AW
2233 SYNC_IP ();
2234 LOCAL_SET (dst,
2235 scm_string_to_number (LOCAL_REF (src),
2236 SCM_UNDEFINED /* radix = 10 */));
2237 NEXT (1);
2238 }
2239
2240 /* string-to-symbol dst:12 src:12
2241 *
2242 * Parse a string in SRC to a symbol, and store in DST.
2243 */
f90c0554 2244 VM_DEFINE_OP (72, string_to_symbol, "string->symbol", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2245 {
2246 scm_t_uint16 dst, src;
2247
20b1b913 2248 UNPACK_12_12 (op, dst, src);
510ca126
AW
2249 SYNC_IP ();
2250 LOCAL_SET (dst, scm_string_to_symbol (LOCAL_REF (src)));
2251 NEXT (1);
2252 }
2253
2254 /* symbol->keyword dst:12 src:12
2255 *
2256 * Make a keyword from the symbol in SRC, and store it in DST.
2257 */
f90c0554 2258 VM_DEFINE_OP (73, symbol_to_keyword, "symbol->keyword", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2259 {
2260 scm_t_uint16 dst, src;
20b1b913 2261 UNPACK_12_12 (op, dst, src);
510ca126
AW
2262 SYNC_IP ();
2263 LOCAL_SET (dst, scm_symbol_to_keyword (LOCAL_REF (src)));
2264 NEXT (1);
2265 }
2266
2267 \f
2268
2269 /*
2270 * Pairs
2271 */
2272
2273 /* cons dst:8 car:8 cdr:8
2274 *
2275 * Cons CAR and CDR, and store the result in DST.
2276 */
f90c0554 2277 VM_DEFINE_OP (74, cons, "cons", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2278 {
2279 ARGS2 (x, y);
2280 RETURN (scm_cons (x, y));
2281 }
2282
2283 /* car dst:12 src:12
2284 *
2285 * Place the car of SRC in DST.
2286 */
f90c0554 2287 VM_DEFINE_OP (75, car, "car", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2288 {
2289 ARGS1 (x);
2290 VM_VALIDATE_PAIR (x, "car");
2291 RETURN (SCM_CAR (x));
2292 }
2293
2294 /* cdr dst:12 src:12
2295 *
2296 * Place the cdr of SRC in DST.
2297 */
f90c0554 2298 VM_DEFINE_OP (76, cdr, "cdr", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2299 {
2300 ARGS1 (x);
2301 VM_VALIDATE_PAIR (x, "cdr");
2302 RETURN (SCM_CDR (x));
2303 }
2304
2305 /* set-car! pair:12 car:12
2306 *
2307 * Set the car of DST to SRC.
2308 */
f90c0554 2309 VM_DEFINE_OP (77, set_car, "set-car!", OP1 (U8_U12_U12))
510ca126
AW
2310 {
2311 scm_t_uint16 a, b;
2312 SCM x, y;
20b1b913 2313 UNPACK_12_12 (op, a, b);
510ca126
AW
2314 x = LOCAL_REF (a);
2315 y = LOCAL_REF (b);
2316 VM_VALIDATE_PAIR (x, "set-car!");
2317 SCM_SETCAR (x, y);
2318 NEXT (1);
2319 }
2320
2321 /* set-cdr! pair:12 cdr:12
2322 *
2323 * Set the cdr of DST to SRC.
2324 */
f90c0554 2325 VM_DEFINE_OP (78, set_cdr, "set-cdr!", OP1 (U8_U12_U12))
510ca126
AW
2326 {
2327 scm_t_uint16 a, b;
2328 SCM x, y;
20b1b913 2329 UNPACK_12_12 (op, a, b);
510ca126
AW
2330 x = LOCAL_REF (a);
2331 y = LOCAL_REF (b);
2332 VM_VALIDATE_PAIR (x, "set-car!");
2333 SCM_SETCDR (x, y);
2334 NEXT (1);
2335 }
2336
2337
2338 \f
2339
2340 /*
2341 * Numeric operations
2342 */
2343
2344 /* add dst:8 a:8 b:8
2345 *
2346 * Add A to B, and place the result in DST.
2347 */
f90c0554 2348 VM_DEFINE_OP (79, add, "add", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2349 {
2350 BINARY_INTEGER_OP (+, scm_sum);
2351 }
2352
2353 /* add1 dst:12 src:12
2354 *
2355 * Add 1 to the value in SRC, and place the result in DST.
2356 */
f90c0554 2357 VM_DEFINE_OP (80, add1, "add1", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2358 {
2359 ARGS1 (x);
2360
d2295ba5
MW
2361 /* Check for overflow. We must avoid overflow in the signed
2362 addition below, even if X is not an inum. */
2363 if (SCM_LIKELY ((scm_t_signed_bits) SCM_UNPACK (x) <= INUM_MAX - INUM_STEP))
510ca126
AW
2364 {
2365 SCM result;
2366
d2295ba5
MW
2367 /* Add 1 to the integer without untagging. */
2368 result = SCM_PACK ((scm_t_signed_bits) SCM_UNPACK (x) + INUM_STEP);
510ca126
AW
2369
2370 if (SCM_LIKELY (SCM_I_INUMP (result)))
2371 RETURN (result);
2372 }
2373
2374 SYNC_IP ();
2375 RETURN (scm_sum (x, SCM_I_MAKINUM (1)));
2376 }
2377
2378 /* sub dst:8 a:8 b:8
2379 *
2380 * Subtract B from A, and place the result in DST.
2381 */
f90c0554 2382 VM_DEFINE_OP (81, sub, "sub", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2383 {
2384 BINARY_INTEGER_OP (-, scm_difference);
2385 }
2386
2387 /* sub1 dst:12 src:12
2388 *
2389 * Subtract 1 from SRC, and place the result in DST.
2390 */
f90c0554 2391 VM_DEFINE_OP (82, sub1, "sub1", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2392 {
2393 ARGS1 (x);
2394
d2295ba5
MW
2395 /* Check for overflow. We must avoid overflow in the signed
2396 subtraction below, even if X is not an inum. */
2397 if (SCM_LIKELY ((scm_t_signed_bits) SCM_UNPACK (x) >= INUM_MIN + INUM_STEP))
510ca126
AW
2398 {
2399 SCM result;
2400
d2295ba5
MW
2401 /* Substract 1 from the integer without untagging. */
2402 result = SCM_PACK ((scm_t_signed_bits) SCM_UNPACK (x) - INUM_STEP);
510ca126
AW
2403
2404 if (SCM_LIKELY (SCM_I_INUMP (result)))
2405 RETURN (result);
2406 }
2407
2408 SYNC_IP ();
2409 RETURN (scm_difference (x, SCM_I_MAKINUM (1)));
2410 }
2411
2412 /* mul dst:8 a:8 b:8
2413 *
2414 * Multiply A and B, and place the result in DST.
2415 */
f90c0554 2416 VM_DEFINE_OP (83, mul, "mul", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2417 {
2418 ARGS2 (x, y);
2419 SYNC_IP ();
2420 RETURN (scm_product (x, y));
2421 }
2422
2423 /* div dst:8 a:8 b:8
2424 *
2425 * Divide A by B, and place the result in DST.
2426 */
f90c0554 2427 VM_DEFINE_OP (84, div, "div", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2428 {
2429 ARGS2 (x, y);
2430 SYNC_IP ();
2431 RETURN (scm_divide (x, y));
2432 }
2433
2434 /* quo dst:8 a:8 b:8
2435 *
2436 * Divide A by B, and place the quotient in DST.
2437 */
f90c0554 2438 VM_DEFINE_OP (85, quo, "quo", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2439 {
2440 ARGS2 (x, y);
2441 SYNC_IP ();
2442 RETURN (scm_quotient (x, y));
2443 }
2444
2445 /* rem dst:8 a:8 b:8
2446 *
2447 * Divide A by B, and place the remainder in DST.
2448 */
f90c0554 2449 VM_DEFINE_OP (86, rem, "rem", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2450 {
2451 ARGS2 (x, y);
2452 SYNC_IP ();
2453 RETURN (scm_remainder (x, y));
2454 }
2455
2456 /* mod dst:8 a:8 b:8
2457 *
2458 * Place the modulo of A by B in DST.
2459 */
f90c0554 2460 VM_DEFINE_OP (87, mod, "mod", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2461 {
2462 ARGS2 (x, y);
2463 SYNC_IP ();
2464 RETURN (scm_modulo (x, y));
2465 }
2466
2467 /* ash dst:8 a:8 b:8
2468 *
2469 * Shift A arithmetically by B bits, and place the result in DST.
2470 */
f90c0554 2471 VM_DEFINE_OP (88, ash, "ash", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2472 {
2473 ARGS2 (x, y);
2474 if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
2475 {
2476 if (SCM_I_INUM (y) < 0)
2477 /* Right shift, will be a fixnum. */
0bd65965
MW
2478 RETURN (SCM_I_MAKINUM
2479 (SCM_SRS (SCM_I_INUM (x),
2480 (-SCM_I_INUM (y) <= SCM_I_FIXNUM_BIT-1)
2481 ? -SCM_I_INUM (y) : SCM_I_FIXNUM_BIT-1)));
510ca126
AW
2482 else
2483 /* Left shift. See comments in scm_ash. */
2484 {
2485 scm_t_signed_bits nn, bits_to_shift;
2486
2487 nn = SCM_I_INUM (x);
2488 bits_to_shift = SCM_I_INUM (y);
2489
2490 if (bits_to_shift < SCM_I_FIXNUM_BIT-1
2491 && ((scm_t_bits)
2492 (SCM_SRS (nn, (SCM_I_FIXNUM_BIT-1 - bits_to_shift)) + 1)
2493 <= 1))
2494 RETURN (SCM_I_MAKINUM (nn << bits_to_shift));
2495 /* fall through */
2496 }
2497 /* fall through */
2498 }
2499 SYNC_IP ();
2500 RETURN (scm_ash (x, y));
2501 }
2502
2503 /* logand dst:8 a:8 b:8
2504 *
2505 * Place the bitwise AND of A and B into DST.
2506 */
f90c0554 2507 VM_DEFINE_OP (89, logand, "logand", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2508 {
2509 ARGS2 (x, y);
2510 if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
e7f64971
MW
2511 /* Compute bitwise AND without untagging */
2512 RETURN (SCM_PACK (SCM_UNPACK (x) & SCM_UNPACK (y)));
510ca126
AW
2513 SYNC_IP ();
2514 RETURN (scm_logand (x, y));
2515 }
2516
2517 /* logior dst:8 a:8 b:8
2518 *
2519 * Place the bitwise inclusive OR of A with B in DST.
2520 */
f90c0554 2521 VM_DEFINE_OP (90, logior, "logior", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2522 {
2523 ARGS2 (x, y);
2524 if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
e7f64971
MW
2525 /* Compute bitwise OR without untagging */
2526 RETURN (SCM_PACK (SCM_UNPACK (x) | SCM_UNPACK (y)));
510ca126
AW
2527 SYNC_IP ();
2528 RETURN (scm_logior (x, y));
2529 }
2530
2531 /* logxor dst:8 a:8 b:8
2532 *
2533 * Place the bitwise exclusive OR of A with B in DST.
2534 */
f90c0554 2535 VM_DEFINE_OP (91, logxor, "logxor", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2536 {
2537 ARGS2 (x, y);
2538 if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
2539 RETURN (SCM_I_MAKINUM (SCM_I_INUM (x) ^ SCM_I_INUM (y)));
2540 SYNC_IP ();
2541 RETURN (scm_logxor (x, y));
2542 }
2543
4c906ad5 2544 /* make-vector/immediate dst:8 length:8 init:8
607fe5a6
AW
2545 *
2546 * Make a short vector of known size and write it to DST. The vector
2547 * will have space for LENGTH slots, an immediate value. They will be
2548 * filled with the value in slot INIT.
2549 */
4c906ad5 2550 VM_DEFINE_OP (92, make_vector_immediate, "make-vector/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
607fe5a6
AW
2551 {
2552 scm_t_uint8 dst, init;
2553 scm_t_int32 length, n;
2554 SCM val, vector;
2555
20b1b913 2556 UNPACK_8_8_8 (op, dst, length, init);
607fe5a6
AW
2557
2558 val = LOCAL_REF (init);
2559 vector = scm_words (scm_tc7_vector | (length << 8), length + 1);
2560 for (n = 0; n < length; n++)
2561 SCM_SIMPLE_VECTOR_SET (vector, n, val);
2562 LOCAL_SET (dst, vector);
2563 NEXT (1);
2564 }
2565
510ca126
AW
2566 /* vector-length dst:12 src:12
2567 *
2568 * Store the length of the vector in SRC in DST.
2569 */
4c906ad5 2570 VM_DEFINE_OP (93, vector_length, "vector-length", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2571 {
2572 ARGS1 (vect);
2573 if (SCM_LIKELY (SCM_I_IS_VECTOR (vect)))
2574 RETURN (SCM_I_MAKINUM (SCM_I_VECTOR_LENGTH (vect)));
2575 else
2576 {
2577 SYNC_IP ();
2578 RETURN (scm_vector_length (vect));
2579 }
2580 }
2581
2582 /* vector-ref dst:8 src:8 idx:8
2583 *
2584 * Fetch the item at position IDX in the vector in SRC, and store it
2585 * in DST.
2586 */
4c906ad5 2587 VM_DEFINE_OP (94, vector_ref, "vector-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2588 {
2589 scm_t_signed_bits i = 0;
2590 ARGS2 (vect, idx);
2591 if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
2592 && SCM_I_INUMP (idx)
2593 && ((i = SCM_I_INUM (idx)) >= 0)
2594 && i < SCM_I_VECTOR_LENGTH (vect)))
2595 RETURN (SCM_I_VECTOR_ELTS (vect)[i]);
2596 else
2597 {
2598 SYNC_IP ();
2599 RETURN (scm_vector_ref (vect, idx));
2600 }
2601 }
2602
4c906ad5 2603 /* vector-ref/immediate dst:8 src:8 idx:8
510ca126
AW
2604 *
2605 * Fill DST with the item IDX elements into the vector at SRC. Useful
2606 * for building data types using vectors.
2607 */
4c906ad5 2608 VM_DEFINE_OP (95, vector_ref_immediate, "vector-ref/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2609 {
2610 scm_t_uint8 dst, src, idx;
2611 SCM v;
2612
20b1b913 2613 UNPACK_8_8_8 (op, dst, src, idx);
510ca126
AW
2614 v = LOCAL_REF (src);
2615 if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (v)
2616 && idx < SCM_I_VECTOR_LENGTH (v)))
2617 LOCAL_SET (dst, SCM_I_VECTOR_ELTS (LOCAL_REF (src))[idx]);
2618 else
2619 LOCAL_SET (dst, scm_c_vector_ref (v, idx));
2620 NEXT (1);
2621 }
2622
2623 /* vector-set! dst:8 idx:8 src:8
2624 *
2625 * Store SRC into the vector DST at index IDX.
2626 */
4c906ad5 2627 VM_DEFINE_OP (96, vector_set, "vector-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
2628 {
2629 scm_t_uint8 dst, idx_var, src;
2630 SCM vect, idx, val;
2631 scm_t_signed_bits i = 0;
2632
20b1b913 2633 UNPACK_8_8_8 (op, dst, idx_var, src);
510ca126
AW
2634 vect = LOCAL_REF (dst);
2635 idx = LOCAL_REF (idx_var);
2636 val = LOCAL_REF (src);
2637
2638 if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
2639 && SCM_I_INUMP (idx)
2640 && ((i = SCM_I_INUM (idx)) >= 0)
2641 && i < SCM_I_VECTOR_LENGTH (vect)))
2642 SCM_I_VECTOR_WELTS (vect)[i] = val;
2643 else
2644 {
2645 SYNC_IP ();
2646 scm_vector_set_x (vect, idx, val);
2647 }
2648 NEXT (1);
2649 }
2650
4c906ad5 2651 /* vector-set!/immediate dst:8 idx:8 src:8
8ba3f20c
AW
2652 *
2653 * Store SRC into the vector DST at index IDX. Here IDX is an
2654 * immediate value.
2655 */
4c906ad5 2656 VM_DEFINE_OP (97, vector_set_immediate, "vector-set!/immediate", OP1 (U8_U8_U8_U8))
8ba3f20c
AW
2657 {
2658 scm_t_uint8 dst, idx, src;
2659 SCM vect, val;
2660
20b1b913 2661 UNPACK_8_8_8 (op, dst, idx, src);
8ba3f20c
AW
2662 vect = LOCAL_REF (dst);
2663 val = LOCAL_REF (src);
2664
2665 if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
2666 && idx < SCM_I_VECTOR_LENGTH (vect)))
2667 SCM_I_VECTOR_WELTS (vect)[idx] = val;
2668 else
2669 {
2670 SYNC_IP ();
2671 scm_vector_set_x (vect, scm_from_uint8 (idx), val);
2672 }
2673 NEXT (1);
2674 }
2675
510ca126
AW
2676
2677 \f
2678
2679 /*
2680 * Structs and GOOPS
2681 */
2682
2683 /* struct-vtable dst:12 src:12
2684 *
2685 * Store the vtable of SRC into DST.
2686 */
4c906ad5 2687 VM_DEFINE_OP (98, struct_vtable, "struct-vtable", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2688 {
2689 ARGS1 (obj);
2690 VM_VALIDATE_STRUCT (obj, "struct_vtable");
2691 RETURN (SCM_STRUCT_VTABLE (obj));
2692 }
2693
4c906ad5 2694 /* allocate-struct/immediate dst:8 vtable:8 nfields:8
510ca126 2695 *
14d10292
AW
2696 * Allocate a new struct with VTABLE, and place it in DST. The struct
2697 * will be constructed with space for NFIELDS fields, which should
2698 * correspond to the field count of the VTABLE.
510ca126 2699 */
4c906ad5 2700 VM_DEFINE_OP (99, allocate_struct_immediate, "allocate-struct/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126 2701 {
14d10292
AW
2702 scm_t_uint8 dst, vtable, nfields;
2703 SCM ret;
510ca126 2704
20b1b913 2705 UNPACK_8_8_8 (op, dst, vtable, nfields);
510ca126
AW
2706
2707 SYNC_IP ();
14d10292 2708 ret = scm_allocate_struct (LOCAL_REF (vtable), SCM_I_MAKINUM (nfields));
510ca126 2709 LOCAL_SET (dst, ret);
14d10292
AW
2710
2711 NEXT (1);
510ca126 2712 }
510ca126 2713
4c906ad5 2714 /* struct-ref/immediate dst:8 src:8 idx:8
510ca126
AW
2715 *
2716 * Fetch the item at slot IDX in the struct in SRC, and store it
4c906ad5 2717 * in DST. IDX is an immediate unsigned 8-bit value.
510ca126 2718 */
4c906ad5 2719 VM_DEFINE_OP (100, struct_ref_immediate, "struct-ref/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126 2720 {
4c906ad5
AW
2721 scm_t_uint8 dst, src, idx;
2722 SCM obj;
2723
20b1b913 2724 UNPACK_8_8_8 (op, dst, src, idx);
4c906ad5
AW
2725
2726 obj = LOCAL_REF (src);
510ca126
AW
2727
2728 if (SCM_LIKELY (SCM_STRUCTP (obj)
2729 && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj,
2730 SCM_VTABLE_FLAG_SIMPLE)
4c906ad5
AW
2731 && idx < SCM_STRUCT_DATA_REF (SCM_STRUCT_VTABLE (obj),
2732 scm_vtable_index_size)))
2733 RETURN (SCM_STRUCT_SLOT_REF (obj, idx));
510ca126
AW
2734
2735 SYNC_IP ();
4c906ad5 2736 RETURN (scm_struct_ref (obj, SCM_I_MAKINUM (idx)));
510ca126
AW
2737 }
2738
4c906ad5 2739 /* struct-set!/immediate dst:8 idx:8 src:8
510ca126 2740 *
4c906ad5
AW
2741 * Store SRC into the struct DST at slot IDX. IDX is an immediate
2742 * unsigned 8-bit value.
510ca126 2743 */
4c906ad5 2744 VM_DEFINE_OP (101, struct_set_immediate, "struct-set!/immediate", OP1 (U8_U8_U8_U8))
510ca126
AW
2745 {
2746 scm_t_uint8 dst, idx, src;
4c906ad5
AW
2747 SCM obj, val;
2748
20b1b913 2749 UNPACK_8_8_8 (op, dst, idx, src);
4c906ad5 2750
510ca126 2751 obj = LOCAL_REF (dst);
510ca126 2752 val = LOCAL_REF (src);
4c906ad5 2753
510ca126
AW
2754 if (SCM_LIKELY (SCM_STRUCTP (obj)
2755 && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj,
2756 SCM_VTABLE_FLAG_SIMPLE)
2757 && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj,
2758 SCM_VTABLE_FLAG_SIMPLE_RW)
4c906ad5
AW
2759 && idx < SCM_STRUCT_DATA_REF (SCM_STRUCT_VTABLE (obj),
2760 scm_vtable_index_size)))
510ca126 2761 {
4c906ad5
AW
2762 SCM_STRUCT_SLOT_SET (obj, idx, val);
2763 NEXT (1);
510ca126
AW
2764 }
2765
2766 SYNC_IP ();
4c906ad5 2767 scm_struct_set_x (obj, SCM_I_MAKINUM (idx), val);
510ca126
AW
2768 NEXT (1);
2769 }
2770
2771 /* class-of dst:12 type:12
2772 *
2773 * Store the vtable of SRC into DST.
2774 */
4c906ad5 2775 VM_DEFINE_OP (102, class_of, "class-of", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2776 {
2777 ARGS1 (obj);
2778 if (SCM_INSTANCEP (obj))
2779 RETURN (SCM_CLASS_OF (obj));
2780 SYNC_IP ();
2781 RETURN (scm_class_of (obj));
2782 }
2783
2784 /* slot-ref dst:8 src:8 idx:8
2785 *
2786 * Fetch the item at slot IDX in the struct in SRC, and store it in
2787 * DST. Unlike struct-ref, IDX is an 8-bit immediate value, not an
2788 * index into the stack.
2789 */
4c906ad5 2790 VM_DEFINE_OP (103, slot_ref, "slot-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2791 {
2792 scm_t_uint8 dst, src, idx;
20b1b913 2793 UNPACK_8_8_8 (op, dst, src, idx);
510ca126
AW
2794 LOCAL_SET (dst,
2795 SCM_PACK (SCM_STRUCT_DATA (LOCAL_REF (src))[idx]));
2796 NEXT (1);
2797 }
2798
2799 /* slot-set! dst:8 idx:8 src:8
2800 *
2801 * Store SRC into slot IDX of the struct in DST. Unlike struct-set!,
2802 * IDX is an 8-bit immediate value, not an index into the stack.
2803 */
4c906ad5 2804 VM_DEFINE_OP (104, slot_set, "slot-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
2805 {
2806 scm_t_uint8 dst, idx, src;
20b1b913 2807 UNPACK_8_8_8 (op, dst, idx, src);
510ca126
AW
2808 SCM_STRUCT_DATA (LOCAL_REF (dst))[idx] = SCM_UNPACK (LOCAL_REF (src));
2809 NEXT (1);
2810 }
2811
2812
2813 \f
2814
2815 /*
2816 * Arrays, packed uniform arrays, and bytevectors.
2817 */
2818
2819 /* load-typed-array dst:8 type:8 shape:8 offset:32 len:32
2820 *
2821 * Load the contiguous typed array located at OFFSET 32-bit words away
2822 * from the instruction pointer, and store into DST. LEN is a byte
2823 * length. OFFSET is signed.
2824 */
4c906ad5 2825 VM_DEFINE_OP (105, load_typed_array, "load-typed-array", OP3 (U8_U8_U8_U8, N32, U32) | OP_DST)
510ca126
AW
2826 {
2827 scm_t_uint8 dst, type, shape;
2828 scm_t_int32 offset;
2829 scm_t_uint32 len;
2830
20b1b913 2831 UNPACK_8_8_8 (op, dst, type, shape);
510ca126
AW
2832 offset = ip[1];
2833 len = ip[2];
2834 SYNC_IP ();
2835 LOCAL_SET (dst, scm_from_contiguous_typed_array (LOCAL_REF (type),
2836 LOCAL_REF (shape),
2837 ip + offset, len));
2838 NEXT (3);
2839 }
2840
2841 /* make-array dst:12 type:12 _:8 fill:12 bounds:12
2842 *
2843 * Make a new array with TYPE, FILL, and BOUNDS, storing it in DST.
2844 */
4c906ad5 2845 VM_DEFINE_OP (106, make_array, "make-array", OP2 (U8_U12_U12, X8_U12_U12) | OP_DST)
510ca126
AW
2846 {
2847 scm_t_uint16 dst, type, fill, bounds;
20b1b913
AW
2848 UNPACK_12_12 (op, dst, type);
2849 UNPACK_12_12 (ip[1], fill, bounds);
510ca126
AW
2850 SYNC_IP ();
2851 LOCAL_SET (dst, scm_make_typed_array (LOCAL_REF (type), LOCAL_REF (fill),
2852 LOCAL_REF (bounds)));
2853 NEXT (2);
2854 }
2855
2856 /* bv-u8-ref dst:8 src:8 idx:8
2857 * bv-s8-ref dst:8 src:8 idx:8
2858 * bv-u16-ref dst:8 src:8 idx:8
2859 * bv-s16-ref dst:8 src:8 idx:8
2860 * bv-u32-ref dst:8 src:8 idx:8
2861 * bv-s32-ref dst:8 src:8 idx:8
2862 * bv-u64-ref dst:8 src:8 idx:8
2863 * bv-s64-ref dst:8 src:8 idx:8
2864 * bv-f32-ref dst:8 src:8 idx:8
2865 * bv-f64-ref dst:8 src:8 idx:8
2866 *
2867 * Fetch the item at byte offset IDX in the bytevector SRC, and store
2868 * it in DST. All accesses use native endianness.
2869 */
2870#define BV_FIXABLE_INT_REF(stem, fn_stem, type, size) \
2871 do { \
2872 scm_t_signed_bits i; \
2873 const scm_t_ ## type *int_ptr; \
2874 ARGS2 (bv, idx); \
2875 \
2876 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-ref"); \
2877 i = SCM_I_INUM (idx); \
2878 int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
2879 \
2880 if (SCM_LIKELY (SCM_I_INUMP (idx) \
2881 && (i >= 0) \
2882 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
2883 && (ALIGNED_P (int_ptr, scm_t_ ## type)))) \
2884 RETURN (SCM_I_MAKINUM (*int_ptr)); \
2885 else \
2886 { \
2887 SYNC_IP (); \
2888 RETURN (scm_bytevector_ ## fn_stem ## _ref (bv, idx)); \
2889 } \
2890 } while (0)
2891
2892#define BV_INT_REF(stem, type, size) \
2893 do { \
2894 scm_t_signed_bits i; \
2895 const scm_t_ ## type *int_ptr; \
2896 ARGS2 (bv, idx); \
2897 \
2898 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-ref"); \
2899 i = SCM_I_INUM (idx); \
2900 int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
2901 \
2902 if (SCM_LIKELY (SCM_I_INUMP (idx) \
2903 && (i >= 0) \
2904 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
2905 && (ALIGNED_P (int_ptr, scm_t_ ## type)))) \
2906 { \
2907 scm_t_ ## type x = *int_ptr; \
2908 if (SCM_FIXABLE (x)) \
2909 RETURN (SCM_I_MAKINUM (x)); \
2910 else \
2911 { \
2912 SYNC_IP (); \
2913 RETURN (scm_from_ ## type (x)); \
2914 } \
2915 } \
2916 else \
2917 { \
2918 SYNC_IP (); \
2919 RETURN (scm_bytevector_ ## stem ## _native_ref (bv, idx)); \
2920 } \
2921 } while (0)
2922
2923#define BV_FLOAT_REF(stem, fn_stem, type, size) \
2924 do { \
2925 scm_t_signed_bits i; \
2926 const type *float_ptr; \
2927 ARGS2 (bv, idx); \
2928 \
2929 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-ref"); \
2930 i = SCM_I_INUM (idx); \
2931 float_ptr = (type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
2932 \
2933 SYNC_IP (); \
2934 if (SCM_LIKELY (SCM_I_INUMP (idx) \
2935 && (i >= 0) \
2936 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
2937 && (ALIGNED_P (float_ptr, type)))) \
2938 RETURN (scm_from_double (*float_ptr)); \
2939 else \
2940 RETURN (scm_bytevector_ ## fn_stem ## _native_ref (bv, idx)); \
2941 } while (0)
2942
4c906ad5 2943 VM_DEFINE_OP (107, bv_u8_ref, "bv-u8-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2944 BV_FIXABLE_INT_REF (u8, u8, uint8, 1);
2945
4c906ad5 2946 VM_DEFINE_OP (108, bv_s8_ref, "bv-s8-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2947 BV_FIXABLE_INT_REF (s8, s8, int8, 1);
2948
4c906ad5 2949 VM_DEFINE_OP (109, bv_u16_ref, "bv-u16-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2950 BV_FIXABLE_INT_REF (u16, u16_native, uint16, 2);
2951
4c906ad5 2952 VM_DEFINE_OP (110, bv_s16_ref, "bv-s16-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2953 BV_FIXABLE_INT_REF (s16, s16_native, int16, 2);
2954
4c906ad5 2955 VM_DEFINE_OP (111, bv_u32_ref, "bv-u32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2956#if SIZEOF_VOID_P > 4
2957 BV_FIXABLE_INT_REF (u32, u32_native, uint32, 4);
2958#else
2959 BV_INT_REF (u32, uint32, 4);
2960#endif
2961
4c906ad5 2962 VM_DEFINE_OP (112, bv_s32_ref, "bv-s32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2963#if SIZEOF_VOID_P > 4
2964 BV_FIXABLE_INT_REF (s32, s32_native, int32, 4);
2965#else
2966 BV_INT_REF (s32, int32, 4);
2967#endif
2968
4c906ad5 2969 VM_DEFINE_OP (113, bv_u64_ref, "bv-u64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2970 BV_INT_REF (u64, uint64, 8);
2971
4c906ad5 2972 VM_DEFINE_OP (114, bv_s64_ref, "bv-s64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2973 BV_INT_REF (s64, int64, 8);
2974
4c906ad5 2975 VM_DEFINE_OP (115, bv_f32_ref, "bv-f32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2976 BV_FLOAT_REF (f32, ieee_single, float, 4);
2977
4c906ad5 2978 VM_DEFINE_OP (116, bv_f64_ref, "bv-f64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2979 BV_FLOAT_REF (f64, ieee_double, double, 8);
2980
2981 /* bv-u8-set! dst:8 idx:8 src:8
2982 * bv-s8-set! dst:8 idx:8 src:8
2983 * bv-u16-set! dst:8 idx:8 src:8
2984 * bv-s16-set! dst:8 idx:8 src:8
2985 * bv-u32-set! dst:8 idx:8 src:8
2986 * bv-s32-set! dst:8 idx:8 src:8
2987 * bv-u64-set! dst:8 idx:8 src:8
2988 * bv-s64-set! dst:8 idx:8 src:8
2989 * bv-f32-set! dst:8 idx:8 src:8
2990 * bv-f64-set! dst:8 idx:8 src:8
2991 *
2992 * Store SRC into the bytevector DST at byte offset IDX. Multibyte
2993 * values are written using native endianness.
2994 */
2995#define BV_FIXABLE_INT_SET(stem, fn_stem, type, min, max, size) \
2996 do { \
2997 scm_t_uint8 dst, idx, src; \
2998 scm_t_signed_bits i, j = 0; \
2999 SCM bv, scm_idx, val; \
3000 scm_t_ ## type *int_ptr; \
3001 \
20b1b913 3002 UNPACK_8_8_8 (op, dst, idx, src); \
510ca126
AW
3003 bv = LOCAL_REF (dst); \
3004 scm_idx = LOCAL_REF (idx); \
3005 val = LOCAL_REF (src); \
ecbef966 3006 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set!"); \
510ca126
AW
3007 i = SCM_I_INUM (scm_idx); \
3008 int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
3009 \
3010 if (SCM_LIKELY (SCM_I_INUMP (scm_idx) \
3011 && (i >= 0) \
3012 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
3013 && (ALIGNED_P (int_ptr, scm_t_ ## type)) \
3014 && (SCM_I_INUMP (val)) \
3015 && ((j = SCM_I_INUM (val)) >= min) \
3016 && (j <= max))) \
3017 *int_ptr = (scm_t_ ## type) j; \
3018 else \
3019 { \
3020 SYNC_IP (); \
3021 scm_bytevector_ ## fn_stem ## _set_x (bv, scm_idx, val); \
3022 } \
3023 NEXT (1); \
3024 } while (0)
3025
3026#define BV_INT_SET(stem, type, size) \
3027 do { \
3028 scm_t_uint8 dst, idx, src; \
3029 scm_t_signed_bits i; \
3030 SCM bv, scm_idx, val; \
3031 scm_t_ ## type *int_ptr; \
3032 \
20b1b913 3033 UNPACK_8_8_8 (op, dst, idx, src); \
510ca126
AW
3034 bv = LOCAL_REF (dst); \
3035 scm_idx = LOCAL_REF (idx); \
3036 val = LOCAL_REF (src); \
ecbef966 3037 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set!"); \
510ca126
AW
3038 i = SCM_I_INUM (scm_idx); \
3039 int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
3040 \
3041 if (SCM_LIKELY (SCM_I_INUMP (scm_idx) \
3042 && (i >= 0) \
3043 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
3044 && (ALIGNED_P (int_ptr, scm_t_ ## type)))) \
3045 *int_ptr = scm_to_ ## type (val); \
3046 else \
3047 { \
3048 SYNC_IP (); \
3049 scm_bytevector_ ## stem ## _native_set_x (bv, scm_idx, val); \
3050 } \
3051 NEXT (1); \
3052 } while (0)
3053
3054#define BV_FLOAT_SET(stem, fn_stem, type, size) \
3055 do { \
3056 scm_t_uint8 dst, idx, src; \
3057 scm_t_signed_bits i; \
3058 SCM bv, scm_idx, val; \
3059 type *float_ptr; \
3060 \
20b1b913 3061 UNPACK_8_8_8 (op, dst, idx, src); \
510ca126
AW
3062 bv = LOCAL_REF (dst); \
3063 scm_idx = LOCAL_REF (idx); \
3064 val = LOCAL_REF (src); \
ecbef966 3065 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set!"); \
510ca126
AW
3066 i = SCM_I_INUM (scm_idx); \
3067 float_ptr = (type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
3068 \
3069 if (SCM_LIKELY (SCM_I_INUMP (scm_idx) \
3070 && (i >= 0) \
3071 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
3072 && (ALIGNED_P (float_ptr, type)))) \
3073 *float_ptr = scm_to_double (val); \
3074 else \
3075 { \
3076 SYNC_IP (); \
3077 scm_bytevector_ ## fn_stem ## _native_set_x (bv, scm_idx, val); \
3078 } \
3079 NEXT (1); \
3080 } while (0)
3081
4c906ad5 3082 VM_DEFINE_OP (117, bv_u8_set, "bv-u8-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3083 BV_FIXABLE_INT_SET (u8, u8, uint8, 0, SCM_T_UINT8_MAX, 1);
3084
4c906ad5 3085 VM_DEFINE_OP (118, bv_s8_set, "bv-s8-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3086 BV_FIXABLE_INT_SET (s8, s8, int8, SCM_T_INT8_MIN, SCM_T_INT8_MAX, 1);
3087
4c906ad5 3088 VM_DEFINE_OP (119, bv_u16_set, "bv-u16-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3089 BV_FIXABLE_INT_SET (u16, u16_native, uint16, 0, SCM_T_UINT16_MAX, 2);
3090
4c906ad5 3091 VM_DEFINE_OP (120, bv_s16_set, "bv-s16-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3092 BV_FIXABLE_INT_SET (s16, s16_native, int16, SCM_T_INT16_MIN, SCM_T_INT16_MAX, 2);
3093
4c906ad5 3094 VM_DEFINE_OP (121, bv_u32_set, "bv-u32-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3095#if SIZEOF_VOID_P > 4
3096 BV_FIXABLE_INT_SET (u32, u32_native, uint32, 0, SCM_T_UINT32_MAX, 4);
3097#else
3098 BV_INT_SET (u32, uint32, 4);
3099#endif
3100
4c906ad5 3101 VM_DEFINE_OP (122, bv_s32_set, "bv-s32-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3102#if SIZEOF_VOID_P > 4
3103 BV_FIXABLE_INT_SET (s32, s32_native, int32, SCM_T_INT32_MIN, SCM_T_INT32_MAX, 4);
3104#else
3105 BV_INT_SET (s32, int32, 4);
3106#endif
3107
4c906ad5 3108 VM_DEFINE_OP (123, bv_u64_set, "bv-u64-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3109 BV_INT_SET (u64, uint64, 8);
3110
4c906ad5 3111 VM_DEFINE_OP (124, bv_s64_set, "bv-s64-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3112 BV_INT_SET (s64, int64, 8);
3113
4c906ad5 3114 VM_DEFINE_OP (125, bv_f32_set, "bv-f32-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3115 BV_FLOAT_SET (f32, ieee_single, float, 4);
3116
4c906ad5 3117 VM_DEFINE_OP (126, bv_f64_set, "bv-f64-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3118 BV_FLOAT_SET (f64, ieee_double, double, 8);
3119
3120 END_DISPATCH_SWITCH;
3121
3122 vm_error_bad_instruction:
3123 vm_error_bad_instruction (op);
3124
3125 abort (); /* never reached */
3126}
3127
3128
3129#undef ABORT_CONTINUATION_HOOK
3130#undef ALIGNED_P
3131#undef APPLY_HOOK
3132#undef ARGS1
3133#undef ARGS2
3134#undef BEGIN_DISPATCH_SWITCH
3135#undef BINARY_INTEGER_OP
3136#undef BR_ARITHMETIC
3137#undef BR_BINARY
3138#undef BR_NARGS
3139#undef BR_UNARY
3140#undef BV_FIXABLE_INT_REF
3141#undef BV_FIXABLE_INT_SET
3142#undef BV_FLOAT_REF
3143#undef BV_FLOAT_SET
3144#undef BV_INT_REF
3145#undef BV_INT_SET
3146#undef CACHE_REGISTER
3147#undef CHECK_OVERFLOW
3148#undef END_DISPATCH_SWITCH
3149#undef FREE_VARIABLE_REF
3150#undef INIT
3151#undef INUM_MAX
3152#undef INUM_MIN
3153#undef LOCAL_REF
3154#undef LOCAL_SET
3155#undef NEXT
3156#undef NEXT_HOOK
3157#undef NEXT_JUMP
3158#undef POP_CONTINUATION_HOOK
3159#undef PUSH_CONTINUATION_HOOK
3160#undef RESTORE_CONTINUATION_HOOK
3161#undef RETURN
3162#undef RETURN_ONE_VALUE
3163#undef RETURN_VALUE_LIST
3164#undef RUN_HOOK
3165#undef RUN_HOOK0
ea0cd17d 3166#undef RUN_HOOK1
510ca126
AW
3167#undef SYNC_ALL
3168#undef SYNC_BEFORE_GC
3169#undef SYNC_IP
3170#undef SYNC_REGISTER
20b1b913
AW
3171#undef UNPACK_8_8_8
3172#undef UNPACK_8_16
3173#undef UNPACK_16_8
3174#undef UNPACK_12_12
3175#undef UNPACK_24
510ca126
AW
3176#undef VARIABLE_BOUNDP
3177#undef VARIABLE_REF
3178#undef VARIABLE_SET
3179#undef VM_CHECK_FREE_VARIABLE
3180#undef VM_CHECK_OBJECT
3181#undef VM_CHECK_UNDERFLOW
3182#undef VM_DEFINE_OP
3183#undef VM_INSTRUCTION_TO_LABEL
3184#undef VM_USE_HOOKS
3185#undef VM_VALIDATE_BYTEVECTOR
3186#undef VM_VALIDATE_PAIR
3187#undef VM_VALIDATE_STRUCT
3188
3189/*
3190(defun renumber-ops ()
3191 "start from top of buffer and renumber 'VM_DEFINE_FOO (\n' sequences"
3192 (interactive "")
3193 (save-excursion
3194 (let ((counter -1)) (goto-char (point-min))
3195 (while (re-search-forward "^ *VM_DEFINE_[^ ]+ (\\([^,]+\\)," (point-max) t)
3196 (replace-match
3197 (number-to-string (setq counter (1+ counter)))
3198 t t nil 1)))))
3199(renumber-ops)
3200*/
17e90c5e
KN
3201/*
3202 Local Variables:
3203 c-file-style: "gnu"
3204 End:
3205*/