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