1 /* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 /* This file is included in vm.c multiple times. */
22 #define UNPACK_8_8_8(op,a,b,c) \
25 a = (op >> 8) & 0xff; \
26 b = (op >> 16) & 0xff; \
31 #define UNPACK_8_16(op,a,b) \
34 a = (op >> 8) & 0xff; \
39 #define UNPACK_16_8(op,a,b) \
42 a = (op >> 8) & 0xffff; \
47 #define UNPACK_12_12(op,a,b) \
50 a = (op >> 8) & 0xfff; \
55 #define UNPACK_24(op,a) \
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. */
69 # if defined __x86_64__
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
73 # define JT_REG asm ("r12")
87 #define VM_ASSERT(condition, handler) \
89 if (SCM_UNLIKELY (!(condition))) \
96 #ifdef VM_ENABLE_ASSERTIONS
97 # define ASSERT(condition) VM_ASSERT (condition, abort())
99 # define ASSERT(condition)
103 #define RUN_HOOK(exp) \
105 if (SCM_UNLIKELY (vp->trace_level > 0)) \
112 #define RUN_HOOK(exp)
114 #define RUN_HOOK0(h) RUN_HOOK (vm_dispatch_##h##_hook (vp))
115 #define RUN_HOOK1(h, arg) RUN_HOOK (vm_dispatch_##h##_hook (vp, arg))
117 #define APPLY_HOOK() \
119 #define PUSH_CONTINUATION_HOOK() \
120 RUN_HOOK0 (push_continuation)
121 #define POP_CONTINUATION_HOOK(old_fp) \
122 RUN_HOOK1 (pop_continuation, old_fp)
123 #define NEXT_HOOK() \
125 #define ABORT_CONTINUATION_HOOK() \
127 #define RESTORE_CONTINUATION_HOOK() \
128 RUN_HOOK0 (restore_continuation)
130 #define VM_HANDLE_INTERRUPTS \
131 SCM_ASYNC_TICK_WITH_CODE (current_thread, SYNC_REGISTER ())
136 This is Guile's new virtual machine. When I say "new", I mean
137 relative to the current virtual machine. At some point it will
138 become "the" virtual machine, and we'll delete this paragraph. As
139 such, the rest of the comments speak as if there's only one VM.
140 In difference from the old VM, local 0 is the procedure, and the
141 first argument is local 1. At some point in the future we should
142 change the fp to point to the procedure and not to local 1.
148 /* The VM has three state bits: the instruction pointer (IP), the frame
149 pointer (FP), and the top-of-stack pointer (SP). We cache the first
150 two of these in machine registers, local to the VM, because they are
151 used extensively by the VM. As the SP is used more by code outside
152 the VM than by the VM itself, we don't bother caching it locally.
154 Since the FP changes infrequently, relative to the IP, we keep vp->fp
155 in sync with the local FP. This would be a big lose for the IP,
156 though, so instead of updating vp->ip all the time, we call SYNC_IP
157 whenever we would need to know the IP of the top frame. In practice,
158 we need to SYNC_IP whenever we call out of the VM to a function that
159 would like to walk the stack, perhaps as the result of an
165 #define SYNC_REGISTER() \
167 #define SYNC_BEFORE_GC() /* Only SP and FP needed to trace GC */
168 #define SYNC_ALL() /* FP already saved */ \
171 /* After advancing vp->sp, but before writing any stack slots, check
172 that it is actually in bounds. If it is not in bounds, currently we
173 signal an error. In the future we may expand the stack instead,
174 possibly by moving it elsewhere, therefore no pointer into the stack
175 besides FP is valid across a CHECK_OVERFLOW call. Be careful! */
176 #define CHECK_OVERFLOW() \
178 if (SCM_UNLIKELY (vp->sp >= vp->stack_limit)) \
180 vm_error_stack_overflow (vp); \
185 /* Reserve stack space for a frame. Will check that there is sufficient
186 stack space for N locals, including the procedure. Invoke after
187 preparing the new frame and setting the fp and ip. */
188 #define ALLOC_FRAME(n) \
190 vp->sp = LOCAL_ADDRESS (n - 1); \
194 /* Reset the current frame to hold N locals. Used when we know that no
195 stack expansion is needed. */
196 #define RESET_FRAME(n) \
198 vp->sp = LOCAL_ADDRESS (n - 1); \
201 /* Compute the number of locals in the frame. At a call, this is equal
202 to the number of actual arguments when a function is first called,
203 plus one for the function. */
204 #define FRAME_LOCALS_COUNT_FROM(slot) \
205 (vp->sp + 1 - LOCAL_ADDRESS (slot))
206 #define FRAME_LOCALS_COUNT() \
207 FRAME_LOCALS_COUNT_FROM (0)
209 /* Restore registers after returning from a frame. */
210 #define RESTORE_FRAME() \
215 #define CACHE_REGISTER() \
221 #ifdef HAVE_LABELS_AS_VALUES
222 # define BEGIN_DISPATCH_SWITCH /* */
223 # define END_DISPATCH_SWITCH /* */
230 goto *jump_table[op & 0xff]; \
233 # define VM_DEFINE_OP(opcode, tag, name, meta) \
236 # define BEGIN_DISPATCH_SWITCH \
242 # define END_DISPATCH_SWITCH \
244 goto vm_error_bad_instruction; \
253 # define VM_DEFINE_OP(opcode, tag, name, meta) \
258 #define LOCAL_ADDRESS(i) (&SCM_FRAME_LOCAL (fp, i))
259 #define LOCAL_REF(i) SCM_FRAME_LOCAL (fp, i)
260 #define LOCAL_SET(i,o) SCM_FRAME_LOCAL (fp, i) = o
262 #define VARIABLE_REF(v) SCM_VARIABLE_REF (v)
263 #define VARIABLE_SET(v,o) SCM_VARIABLE_SET (v, o)
264 #define VARIABLE_BOUNDP(v) (!scm_is_eq (VARIABLE_REF (v), SCM_UNDEFINED))
266 #define RETURN_ONE_VALUE(ret) \
270 VM_HANDLE_INTERRUPTS; \
271 ip = SCM_FRAME_RETURN_ADDRESS (fp); \
272 fp = vp->fp = SCM_FRAME_DYNAMIC_LINK (fp); \
274 old_fp[-1] = SCM_BOOL_F; \
275 old_fp[-2] = SCM_BOOL_F; \
277 SCM_FRAME_LOCAL (old_fp, 1) = val; \
278 vp->sp = &SCM_FRAME_LOCAL (old_fp, 1); \
279 POP_CONTINUATION_HOOK (old_fp); \
283 /* While we could generate the list-unrolling code here, it's fine for
284 now to just tail-call (apply values vals). */
285 #define RETURN_VALUE_LIST(vals_) \
288 VM_HANDLE_INTERRUPTS; \
289 fp[0] = vm_builtin_apply; \
290 fp[1] = vm_builtin_values; \
293 ip = (scm_t_uint32 *) vm_builtin_apply_code; \
294 goto op_tail_apply; \
297 #define BR_NARGS(rel) \
298 scm_t_uint32 expected; \
299 UNPACK_24 (op, expected); \
300 if (FRAME_LOCALS_COUNT() rel expected) \
302 scm_t_int32 offset = ip[1]; \
303 offset >>= 8; /* Sign-extending shift. */ \
308 #define BR_UNARY(x, exp) \
311 UNPACK_24 (op, test); \
312 x = LOCAL_REF (test); \
313 if ((ip[1] & 0x1) ? !(exp) : (exp)) \
315 scm_t_int32 offset = ip[1]; \
316 offset >>= 8; /* Sign-extending shift. */ \
318 VM_HANDLE_INTERRUPTS; \
323 #define BR_BINARY(x, y, exp) \
326 UNPACK_12_12 (op, a, b); \
329 if ((ip[1] & 0x1) ? !(exp) : (exp)) \
331 scm_t_int32 offset = ip[1]; \
332 offset >>= 8; /* Sign-extending shift. */ \
334 VM_HANDLE_INTERRUPTS; \
339 #define BR_ARITHMETIC(crel,srel) \
343 UNPACK_12_12 (op, a, b); \
346 if (SCM_I_INUMP (x) && SCM_I_INUMP (y)) \
348 scm_t_signed_bits x_bits = SCM_UNPACK (x); \
349 scm_t_signed_bits y_bits = SCM_UNPACK (y); \
350 if ((ip[1] & 0x1) ? !(x_bits crel y_bits) : (x_bits crel y_bits)) \
352 scm_t_int32 offset = ip[1]; \
353 offset >>= 8; /* Sign-extending shift. */ \
355 VM_HANDLE_INTERRUPTS; \
365 if ((ip[1] & 0x1) ? scm_is_false (res) : scm_is_true (res)) \
367 scm_t_int32 offset = ip[1]; \
368 offset >>= 8; /* Sign-extending shift. */ \
370 VM_HANDLE_INTERRUPTS; \
378 scm_t_uint16 dst, src; \
380 UNPACK_12_12 (op, dst, src); \
382 #define ARGS2(a1, a2) \
383 scm_t_uint8 dst, src1, src2; \
385 UNPACK_8_8_8 (op, dst, src1, src2); \
386 a1 = LOCAL_REF (src1); \
387 a2 = LOCAL_REF (src2)
389 do { LOCAL_SET (dst, x); NEXT (1); } while (0)
391 /* The maximum/minimum tagged integers. */
393 ((scm_t_signed_bits) SCM_UNPACK (SCM_I_MAKINUM (SCM_MOST_POSITIVE_FIXNUM)))
395 ((scm_t_signed_bits) SCM_UNPACK (SCM_I_MAKINUM (SCM_MOST_NEGATIVE_FIXNUM)))
397 ((scm_t_signed_bits) SCM_UNPACK (SCM_INUM1) \
398 - (scm_t_signed_bits) SCM_UNPACK (SCM_INUM0))
400 #define BINARY_INTEGER_OP(CFUNC,SFUNC) \
403 if (SCM_I_INUMP (x) && SCM_I_INUMP (y)) \
405 scm_t_int64 n = SCM_I_INUM (x) CFUNC SCM_I_INUM (y); \
406 if (SCM_FIXABLE (n)) \
407 RETURN (SCM_I_MAKINUM (n)); \
410 RETURN (SFUNC (x, y)); \
413 #define VM_VALIDATE_PAIR(x, proc) \
414 VM_ASSERT (scm_is_pair (x), vm_error_not_a_pair (proc, x))
416 #define VM_VALIDATE_STRUCT(obj, proc) \
417 VM_ASSERT (SCM_STRUCTP (obj), vm_error_not_a_pair (proc, obj))
419 #define VM_VALIDATE_BYTEVECTOR(x, proc) \
420 VM_ASSERT (SCM_BYTEVECTOR_P (x), vm_error_not_a_bytevector (proc, x))
422 /* Return true (non-zero) if PTR has suitable alignment for TYPE. */
423 #define ALIGNED_P(ptr, type) \
424 ((scm_t_uintptr) (ptr) % alignof_type (type) == 0)
427 VM_NAME (scm_i_thread
*current_thread
, struct scm_vm
*vp
,
428 scm_i_jmp_buf
*registers
, int resume
)
430 /* Instruction pointer: A pointer to the opcode that is currently
432 register scm_t_uint32
*ip IP_REG
;
434 /* Frame pointer: A pointer into the stack, off of which we index
435 arguments and local variables. Pushed at function calls, popped on
437 register SCM
*fp FP_REG
;
439 /* Current opcode: A cache of *ip. */
440 register scm_t_uint32 op
;
442 #ifdef HAVE_LABELS_AS_VALUES
443 static const void **jump_table_pointer
= NULL
;
444 register const void **jump_table JT_REG
;
446 if (SCM_UNLIKELY (!jump_table_pointer
))
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
);
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
;
462 /* Load VM registers. */
465 VM_HANDLE_INTERRUPTS
;
467 /* Usually a call to the VM happens on application, with the boot
468 continuation on the next frame. Sometimes it happens after a
469 non-local exit however; in that case the VM state is all set up,
470 and we have but to jump to the next opcode. */
471 if (SCM_UNLIKELY (resume
))
475 while (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp
)))
477 SCM proc
= SCM_FRAME_PROGRAM (fp
);
479 if (SCM_STRUCTP (proc
) && SCM_STRUCT_APPLICABLE_P (proc
))
481 LOCAL_SET (0, SCM_STRUCT_PROCEDURE (proc
));
484 if (SCM_HAS_TYP7 (proc
, scm_tc7_smob
) && SCM_SMOB_APPLICABLE_P (proc
))
486 scm_t_uint32 n
= FRAME_LOCALS_COUNT();
488 /* Shuffle args up. */
491 LOCAL_SET (n
+ 1, LOCAL_REF (n
));
493 LOCAL_SET (0, SCM_SMOB_DESCRIPTOR (proc
).apply_trampoline
);
498 vm_error_wrong_type_apply (proc
);
502 ip
= SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp
));
505 BEGIN_DISPATCH_SWITCH
;
516 * Bring the VM to a halt, returning all the values from the stack.
518 VM_DEFINE_OP (0, halt
, "halt", OP1 (U8_X24
))
520 /* Boot closure in r0, empty frame in r1/r2, proc in r3, values from r4. */
522 scm_t_uint32 nvals
= FRAME_LOCALS_COUNT_FROM (4);
532 for (n
= nvals
; n
> 0; n
--)
533 ret
= scm_cons (LOCAL_REF (4 + n
- 1), ret
);
534 ret
= scm_values (ret
);
537 vp
->ip
= SCM_FRAME_RETURN_ADDRESS (fp
);
538 vp
->sp
= SCM_FRAME_PREVIOUS_SP (fp
);
539 vp
->fp
= SCM_FRAME_DYNAMIC_LINK (fp
);
544 /* call proc:24 _:8 nlocals:24
546 * Call a procedure. PROC is the local corresponding to a procedure.
547 * The three values below PROC will be overwritten by the saved call
548 * frame data. The new frame will have space for NLOCALS locals: one
549 * for the procedure, and the rest for the arguments which should
550 * already have been pushed on.
552 * When the call returns, execution proceeds with the next
553 * instruction. There may be any number of values on the return
554 * stack; the precise number can be had by subtracting the address of
555 * PROC from the post-call SP.
557 VM_DEFINE_OP (1, call
, "call", OP2 (U8_U24
, X8_U24
))
559 scm_t_uint32 proc
, nlocals
;
562 UNPACK_24 (op
, proc
);
563 UNPACK_24 (ip
[1], nlocals
);
565 VM_HANDLE_INTERRUPTS
;
567 fp
= vp
->fp
= old_fp
+ proc
;
568 SCM_FRAME_SET_DYNAMIC_LINK (fp
, old_fp
);
569 SCM_FRAME_SET_RETURN_ADDRESS (fp
, ip
+ 2);
571 RESET_FRAME (nlocals
);
573 PUSH_CONTINUATION_HOOK ();
576 if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp
))))
579 ip
= SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp
));
583 /* tail-call nlocals:24
585 * Tail-call a procedure. Requires that the procedure and all of the
586 * arguments have already been shuffled into position. Will reset the
589 VM_DEFINE_OP (2, tail_call
, "tail-call", OP1 (U8_U24
))
591 scm_t_uint32 nlocals
;
593 UNPACK_24 (op
, nlocals
);
595 VM_HANDLE_INTERRUPTS
;
597 RESET_FRAME (nlocals
);
601 if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp
))))
604 ip
= SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp
));
608 /* tail-call/shuffle from:24
610 * Tail-call a procedure. The procedure should already be set to slot
611 * 0. The rest of the args are taken from the frame, starting at
612 * FROM, shuffled down to start at slot 0. This is part of the
613 * implementation of the call-with-values builtin.
615 VM_DEFINE_OP (3, tail_call_shuffle
, "tail-call/shuffle", OP1 (U8_U24
))
617 scm_t_uint32 n
, from
, nlocals
;
619 UNPACK_24 (op
, from
);
621 VM_HANDLE_INTERRUPTS
;
623 VM_ASSERT (from
> 0, abort ());
624 nlocals
= FRAME_LOCALS_COUNT ();
626 for (n
= 0; from
+ n
< nlocals
; n
++)
627 LOCAL_SET (n
+ 1, LOCAL_REF (from
+ n
));
633 if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp
))))
636 ip
= SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp
));
640 /* receive dst:12 proc:12 _:8 nlocals:24
642 * Receive a single return value from a call whose procedure was in
643 * PROC, asserting that the call actually returned at least one
644 * value. Afterwards, resets the frame to NLOCALS locals.
646 VM_DEFINE_OP (4, receive
, "receive", OP2 (U8_U12_U12
, X8_U24
) | OP_DST
)
648 scm_t_uint16 dst
, proc
;
649 scm_t_uint32 nlocals
;
650 UNPACK_12_12 (op
, dst
, proc
);
651 UNPACK_24 (ip
[1], nlocals
);
652 VM_ASSERT (FRAME_LOCALS_COUNT () > proc
+ 1, vm_error_no_values ());
653 LOCAL_SET (dst
, LOCAL_REF (proc
+ 1));
654 RESET_FRAME (nlocals
);
658 /* receive-values proc:24 allow-extra?:1 _:7 nvalues:24
660 * Receive a return of multiple values from a call whose procedure was
661 * in PROC. If fewer than NVALUES values were returned, signal an
662 * error. Unless ALLOW-EXTRA? is true, require that the number of
663 * return values equals NVALUES exactly. After receive-values has
664 * run, the values can be copied down via `mov'.
666 VM_DEFINE_OP (5, receive_values
, "receive-values", OP2 (U8_U24
, B1_X7_U24
))
668 scm_t_uint32 proc
, nvalues
;
669 UNPACK_24 (op
, proc
);
670 UNPACK_24 (ip
[1], nvalues
);
672 VM_ASSERT (FRAME_LOCALS_COUNT () > proc
+ nvalues
,
673 vm_error_not_enough_values ());
675 VM_ASSERT (FRAME_LOCALS_COUNT () == proc
+ 1 + nvalues
,
676 vm_error_wrong_number_of_values (nvalues
));
684 VM_DEFINE_OP (6, return, "return", OP1 (U8_U24
))
688 RETURN_ONE_VALUE (LOCAL_REF (src
));
691 /* return-values _:24
693 * Return a number of values from a call frame. This opcode
694 * corresponds to an application of `values' in tail position. As
695 * with tail calls, we expect that the values have already been
696 * shuffled down to a contiguous array starting at slot 1.
697 * We also expect the frame has already been reset.
699 VM_DEFINE_OP (7, return_values
, "return-values", OP1 (U8_X24
))
703 VM_HANDLE_INTERRUPTS
;
704 ip
= SCM_FRAME_RETURN_ADDRESS (fp
);
705 fp
= vp
->fp
= SCM_FRAME_DYNAMIC_LINK (fp
);
707 /* Clear stack frame. */
708 old_fp
[-1] = SCM_BOOL_F
;
709 old_fp
[-2] = SCM_BOOL_F
;
711 POP_CONTINUATION_HOOK (old_fp
);
720 * Specialized call stubs
723 /* subr-call ptr-idx:24
725 * Call a subr, passing all locals in this frame as arguments. Fetch
726 * the foreign pointer from PTR-IDX, a free variable. Return from the
727 * calling frame. This instruction is part of the trampolines
728 * created in gsubr.c, and is not generated by the compiler.
730 VM_DEFINE_OP (8, subr_call
, "subr-call", OP1 (U8_U24
))
732 scm_t_uint32 ptr_idx
;
736 UNPACK_24 (op
, ptr_idx
);
738 pointer
= SCM_PROGRAM_FREE_VARIABLE_REF (LOCAL_REF (0), ptr_idx
);
739 subr
= SCM_POINTER_VALUE (pointer
);
741 VM_HANDLE_INTERRUPTS
;
744 switch (FRAME_LOCALS_COUNT_FROM (1))
753 ret
= subr (fp
[1], fp
[2]);
756 ret
= subr (fp
[1], fp
[2], fp
[3]);
759 ret
= subr (fp
[1], fp
[2], fp
[3], fp
[4]);
762 ret
= subr (fp
[1], fp
[2], fp
[3], fp
[4], fp
[5]);
765 ret
= subr (fp
[1], fp
[2], fp
[3], fp
[4], fp
[5], fp
[6]);
768 ret
= subr (fp
[1], fp
[2], fp
[3], fp
[4], fp
[5], fp
[6], fp
[7]);
771 ret
= subr (fp
[1], fp
[2], fp
[3], fp
[4], fp
[5], fp
[6], fp
[7], fp
[8]);
774 ret
= subr (fp
[1], fp
[2], fp
[3], fp
[4], fp
[5], fp
[6], fp
[7], fp
[8], fp
[9]);
777 ret
= subr (fp
[1], fp
[2], fp
[3], fp
[4], fp
[5], fp
[6], fp
[7], fp
[8], fp
[9], fp
[10]);
783 // NULLSTACK_FOR_NONLOCAL_EXIT ();
785 if (SCM_UNLIKELY (SCM_VALUESP (ret
)))
786 /* multiple values returned to continuation */
787 RETURN_VALUE_LIST (scm_struct_ref (ret
, SCM_INUM0
));
789 RETURN_ONE_VALUE (ret
);
792 /* foreign-call cif-idx:12 ptr-idx:12
794 * Call a foreign function. Fetch the CIF and foreign pointer from
795 * CIF-IDX and PTR-IDX, both free variables. Return from the calling
796 * frame. Arguments are taken from the stack. This instruction is
797 * part of the trampolines created by the FFI, and is not generated by
800 VM_DEFINE_OP (9, foreign_call
, "foreign-call", OP1 (U8_U12_U12
))
802 scm_t_uint16 cif_idx
, ptr_idx
;
803 SCM closure
, cif
, pointer
, ret
;
805 UNPACK_12_12 (op
, cif_idx
, ptr_idx
);
807 closure
= LOCAL_REF (0);
808 cif
= SCM_PROGRAM_FREE_VARIABLE_REF (closure
, cif_idx
);
809 pointer
= SCM_PROGRAM_FREE_VARIABLE_REF (closure
, ptr_idx
);
812 VM_HANDLE_INTERRUPTS
;
814 // FIXME: separate args
815 ret
= scm_i_foreign_call (scm_cons (cif
, pointer
), LOCAL_ADDRESS (1));
817 // NULLSTACK_FOR_NONLOCAL_EXIT ();
819 if (SCM_UNLIKELY (SCM_VALUESP (ret
)))
820 /* multiple values returned to continuation */
821 RETURN_VALUE_LIST (scm_struct_ref (ret
, SCM_INUM0
));
823 RETURN_ONE_VALUE (ret
);
826 /* continuation-call contregs:24
828 * Return to a continuation, nonlocally. The arguments to the
829 * continuation are taken from the stack. CONTREGS is a free variable
830 * containing the reified continuation. This instruction is part of
831 * the implementation of undelimited continuations, and is not
832 * generated by the compiler.
834 VM_DEFINE_OP (10, continuation_call
, "continuation-call", OP1 (U8_U24
))
837 scm_t_uint32 contregs_idx
;
839 UNPACK_24 (op
, contregs_idx
);
842 SCM_PROGRAM_FREE_VARIABLE_REF (LOCAL_REF (0), contregs_idx
);
845 scm_i_check_continuation (contregs
);
846 vm_return_to_continuation (scm_i_contregs_vp (contregs
),
847 scm_i_contregs_vm_cont (contregs
),
848 FRAME_LOCALS_COUNT_FROM (1),
850 scm_i_reinstate_continuation (contregs
);
856 /* compose-continuation cont:24
858 * Compose a partial continution with the current continuation. The
859 * arguments to the continuation are taken from the stack. CONT is a
860 * free variable containing the reified continuation. This
861 * instruction is part of the implementation of partial continuations,
862 * and is not generated by the compiler.
864 VM_DEFINE_OP (11, compose_continuation
, "compose-continuation", OP1 (U8_U24
))
867 scm_t_uint32 cont_idx
;
869 UNPACK_24 (op
, cont_idx
);
870 vmcont
= SCM_PROGRAM_FREE_VARIABLE_REF (LOCAL_REF (0), cont_idx
);
873 VM_ASSERT (SCM_VM_CONT_REWINDABLE_P (vmcont
),
874 vm_error_continuation_not_rewindable (vmcont
));
875 vm_reinstate_partial_continuation (vp
, vmcont
, FRAME_LOCALS_COUNT_FROM (1),
877 ¤t_thread
->dynstack
,
885 * Tail-apply the procedure in local slot 0 to the rest of the
886 * arguments. This instruction is part of the implementation of
887 * `apply', and is not generated by the compiler.
889 VM_DEFINE_OP (12, tail_apply
, "tail-apply", OP1 (U8_X24
))
891 int i
, list_idx
, list_len
, nlocals
;
894 VM_HANDLE_INTERRUPTS
;
896 nlocals
= FRAME_LOCALS_COUNT ();
897 // At a minimum, there should be apply, f, and the list.
898 VM_ASSERT (nlocals
>= 3, abort ());
899 list_idx
= nlocals
- 1;
900 list
= LOCAL_REF (list_idx
);
901 list_len
= scm_ilength (list
);
903 VM_ASSERT (list_len
>= 0, vm_error_apply_to_non_list (list
));
905 nlocals
= nlocals
- 2 + list_len
;
906 ALLOC_FRAME (nlocals
);
908 for (i
= 1; i
< list_idx
; i
++)
909 LOCAL_SET (i
- 1, LOCAL_REF (i
));
911 /* Null out these slots, just in case there are less than 2 elements
913 LOCAL_SET (list_idx
- 1, SCM_UNDEFINED
);
914 LOCAL_SET (list_idx
, SCM_UNDEFINED
);
916 for (i
= 0; i
< list_len
; i
++, list
= SCM_CDR (list
))
917 LOCAL_SET (list_idx
- 1 + i
, SCM_CAR (list
));
921 if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp
))))
924 ip
= SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp
));
930 * Capture the current continuation, and tail-apply the procedure in
931 * local slot 1 to it. This instruction is part of the implementation
932 * of `call/cc', and is not generated by the compiler.
934 VM_DEFINE_OP (13, call_cc
, "call/cc", OP1 (U8_X24
))
937 scm_t_dynstack
*dynstack
;
940 VM_HANDLE_INTERRUPTS
;
943 dynstack
= scm_dynstack_capture_all (¤t_thread
->dynstack
);
944 vm_cont
= scm_i_vm_capture_stack (vp
->stack_base
,
945 SCM_FRAME_DYNAMIC_LINK (fp
),
946 SCM_FRAME_PREVIOUS_SP (fp
),
947 SCM_FRAME_RETURN_ADDRESS (fp
),
950 /* FIXME: Seems silly to capture the registers here, when they are
951 already captured in the registers local, which here we are
952 copying out to the heap; and likewise, the setjmp(®isters)
953 code already has the non-local return handler. But oh
955 cont
= scm_i_make_continuation (&first
, vp
, vm_cont
);
959 LOCAL_SET (0, LOCAL_REF (1));
965 if (SCM_UNLIKELY (!SCM_PROGRAM_P (SCM_FRAME_PROGRAM (fp
))))
968 ip
= SCM_PROGRAM_CODE (SCM_FRAME_PROGRAM (fp
));
974 ABORT_CONTINUATION_HOOK ();
981 * Abort to a prompt handler. The tag is expected in r1, and the rest
982 * of the values in the frame are returned to the prompt handler.
983 * This corresponds to a tail application of abort-to-prompt.
985 VM_DEFINE_OP (14, abort
, "abort", OP1 (U8_X24
))
987 scm_t_uint32 nlocals
= FRAME_LOCALS_COUNT ();
989 ASSERT (nlocals
>= 2);
990 /* FIXME: Really we should capture the caller's registers. Until
991 then, manually advance the IP so that when the prompt resumes,
992 it continues with the next instruction. */
995 vm_abort (vp
, LOCAL_REF (1), nlocals
- 2, LOCAL_ADDRESS (2),
996 SCM_EOL
, LOCAL_ADDRESS (0), registers
);
998 /* vm_abort should not return */
1002 /* builtin-ref dst:12 idx:12
1004 * Load a builtin stub by index into DST.
1006 VM_DEFINE_OP (15, builtin_ref
, "builtin-ref", OP1 (U8_U12_U12
) | OP_DST
)
1008 scm_t_uint16 dst
, idx
;
1010 UNPACK_12_12 (op
, dst
, idx
);
1011 LOCAL_SET (dst
, scm_vm_builtin_ref (idx
));
1020 * Function prologues
1023 /* br-if-nargs-ne expected:24 _:8 offset:24
1024 * br-if-nargs-lt expected:24 _:8 offset:24
1025 * br-if-nargs-gt expected:24 _:8 offset:24
1027 * If the number of actual arguments is not equal, less than, or greater
1028 * than EXPECTED, respectively, add OFFSET, a signed 24-bit number, to
1029 * the current instruction pointer.
1031 VM_DEFINE_OP (16, br_if_nargs_ne
, "br-if-nargs-ne", OP2 (U8_U24
, X8_L24
))
1035 VM_DEFINE_OP (17, br_if_nargs_lt
, "br-if-nargs-lt", OP2 (U8_U24
, X8_L24
))
1039 VM_DEFINE_OP (18, br_if_nargs_gt
, "br-if-nargs-gt", OP2 (U8_U24
, X8_L24
))
1044 /* assert-nargs-ee expected:24
1045 * assert-nargs-ge expected:24
1046 * assert-nargs-le expected:24
1048 * If the number of actual arguments is not ==, >=, or <= EXPECTED,
1049 * respectively, signal an error.
1051 VM_DEFINE_OP (19, assert_nargs_ee
, "assert-nargs-ee", OP1 (U8_U24
))
1053 scm_t_uint32 expected
;
1054 UNPACK_24 (op
, expected
);
1055 VM_ASSERT (FRAME_LOCALS_COUNT () == expected
,
1056 vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp
)));
1059 VM_DEFINE_OP (20, assert_nargs_ge
, "assert-nargs-ge", OP1 (U8_U24
))
1061 scm_t_uint32 expected
;
1062 UNPACK_24 (op
, expected
);
1063 VM_ASSERT (FRAME_LOCALS_COUNT () >= expected
,
1064 vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp
)));
1067 VM_DEFINE_OP (21, assert_nargs_le
, "assert-nargs-le", OP1 (U8_U24
))
1069 scm_t_uint32 expected
;
1070 UNPACK_24 (op
, expected
);
1071 VM_ASSERT (FRAME_LOCALS_COUNT () <= expected
,
1072 vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp
)));
1076 /* alloc-frame nlocals:24
1078 * Ensure that there is space on the stack for NLOCALS local variables,
1079 * setting them all to SCM_UNDEFINED, except those nargs values that
1080 * were passed as arguments and procedure.
1082 VM_DEFINE_OP (22, alloc_frame
, "alloc-frame", OP1 (U8_U24
))
1084 scm_t_uint32 nlocals
, nargs
;
1085 UNPACK_24 (op
, nlocals
);
1087 nargs
= FRAME_LOCALS_COUNT ();
1088 ALLOC_FRAME (nlocals
);
1089 while (nlocals
-- > nargs
)
1090 LOCAL_SET (nlocals
, SCM_UNDEFINED
);
1095 /* reset-frame nlocals:24
1097 * Like alloc-frame, but doesn't check that the stack is big enough.
1098 * Used to reset the frame size to something less than the size that
1099 * was previously set via alloc-frame.
1101 VM_DEFINE_OP (23, reset_frame
, "reset-frame", OP1 (U8_U24
))
1103 scm_t_uint32 nlocals
;
1104 UNPACK_24 (op
, nlocals
);
1105 RESET_FRAME (nlocals
);
1109 /* assert-nargs-ee/locals expected:12 nlocals:12
1111 * Equivalent to a sequence of assert-nargs-ee and reserve-locals. The
1112 * number of locals reserved is EXPECTED + NLOCALS.
1114 VM_DEFINE_OP (24, assert_nargs_ee_locals
, "assert-nargs-ee/locals", OP1 (U8_U12_U12
))
1116 scm_t_uint16 expected
, nlocals
;
1117 UNPACK_12_12 (op
, expected
, nlocals
);
1118 VM_ASSERT (FRAME_LOCALS_COUNT () == expected
,
1119 vm_error_wrong_num_args (SCM_FRAME_PROGRAM (fp
)));
1120 ALLOC_FRAME (expected
+ nlocals
);
1122 LOCAL_SET (expected
+ nlocals
, SCM_UNDEFINED
);
1127 /* br-if-npos-gt nreq:24 _:8 npos:24 _:8 offset:24
1129 * Find the first positional argument after NREQ. If it is greater
1130 * than NPOS, jump to OFFSET.
1132 * This instruction is only emitted for functions with multiple
1133 * clauses, and an earlier clause has keywords and no rest arguments.
1134 * See "Case-lambda" in the manual, for more on how case-lambda
1135 * chooses the clause to apply.
1137 VM_DEFINE_OP (25, br_if_npos_gt
, "br-if-npos-gt", OP3 (U8_U24
, X8_U24
, X8_L24
))
1139 scm_t_uint32 nreq
, npos
;
1141 UNPACK_24 (op
, nreq
);
1142 UNPACK_24 (ip
[1], npos
);
1144 /* We can only have too many positionals if there are more
1145 arguments than NPOS. */
1146 if (FRAME_LOCALS_COUNT() > npos
)
1149 for (n
= nreq
; n
< npos
; n
++)
1150 if (scm_is_keyword (LOCAL_REF (n
)))
1152 if (n
== npos
&& !scm_is_keyword (LOCAL_REF (n
)))
1154 scm_t_int32 offset
= ip
[2];
1155 offset
>>= 8; /* Sign-extending shift. */
1162 /* bind-kwargs nreq:24 allow-other-keys:1 has-rest:1 _:6 nreq-and-opt:24
1163 * _:8 ntotal:24 kw-offset:32
1165 * Find the last positional argument, and shuffle all the rest above
1166 * NTOTAL. Initialize the intervening locals to SCM_UNDEFINED. Then
1167 * load the constant at KW-OFFSET words from the current IP, and use it
1168 * to bind keyword arguments. If HAS-REST, collect all shuffled
1169 * arguments into a list, and store it in NREQ-AND-OPT. Finally, clear
1170 * the arguments that we shuffled up.
1172 * A macro-mega-instruction.
1174 VM_DEFINE_OP (26, bind_kwargs
, "bind-kwargs", OP4 (U8_U24
, U8_U24
, X8_U24
, N32
))
1176 scm_t_uint32 nreq
, nreq_and_opt
, ntotal
, npositional
, nkw
, n
, nargs
;
1177 scm_t_int32 kw_offset
;
1180 char allow_other_keys
, has_rest
;
1182 UNPACK_24 (op
, nreq
);
1183 allow_other_keys
= ip
[1] & 0x1;
1184 has_rest
= ip
[1] & 0x2;
1185 UNPACK_24 (ip
[1], nreq_and_opt
);
1186 UNPACK_24 (ip
[2], ntotal
);
1188 kw_bits
= (scm_t_bits
) (ip
+ kw_offset
);
1189 VM_ASSERT (!(kw_bits
& 0x7), abort());
1190 kw
= SCM_PACK (kw_bits
);
1192 nargs
= FRAME_LOCALS_COUNT ();
1194 /* look in optionals for first keyword or last positional */
1195 /* starting after the last required positional arg */
1197 while (/* while we have args */
1199 /* and we still have positionals to fill */
1200 && npositional
< nreq_and_opt
1201 /* and we haven't reached a keyword yet */
1202 && !scm_is_keyword (LOCAL_REF (npositional
)))
1203 /* bind this optional arg (by leaving it in place) */
1205 nkw
= nargs
- npositional
;
1206 /* shuffle non-positional arguments above ntotal */
1207 ALLOC_FRAME (ntotal
+ nkw
);
1210 LOCAL_SET (ntotal
+ n
, LOCAL_REF (npositional
+ n
));
1211 /* and fill optionals & keyword args with SCM_UNDEFINED */
1214 LOCAL_SET (n
++, SCM_UNDEFINED
);
1216 VM_ASSERT (has_rest
|| (nkw
% 2) == 0,
1217 vm_error_kwargs_length_not_even (SCM_FRAME_PROGRAM (fp
)));
1219 /* Now bind keywords, in the order given. */
1220 for (n
= 0; n
< nkw
; n
++)
1221 if (scm_is_keyword (LOCAL_REF (ntotal
+ n
)))
1224 for (walk
= kw
; scm_is_pair (walk
); walk
= SCM_CDR (walk
))
1225 if (scm_is_eq (SCM_CAAR (walk
), LOCAL_REF (ntotal
+ n
)))
1227 SCM si
= SCM_CDAR (walk
);
1228 LOCAL_SET (SCM_I_INUMP (si
) ? SCM_I_INUM (si
) : scm_to_uint32 (si
),
1229 LOCAL_REF (ntotal
+ n
+ 1));
1232 VM_ASSERT (scm_is_pair (walk
) || allow_other_keys
,
1233 vm_error_kwargs_unrecognized_keyword (SCM_FRAME_PROGRAM (fp
),
1234 LOCAL_REF (ntotal
+ n
)));
1238 VM_ASSERT (has_rest
, vm_error_kwargs_invalid_keyword (SCM_FRAME_PROGRAM (fp
),
1239 LOCAL_REF (ntotal
+ n
)));
1246 rest
= scm_cons (LOCAL_REF (ntotal
+ n
), rest
);
1247 LOCAL_SET (nreq_and_opt
, rest
);
1250 RESET_FRAME (ntotal
);
1257 * Collect any arguments at or above DST into a list, and store that
1260 VM_DEFINE_OP (27, bind_rest
, "bind-rest", OP1 (U8_U24
) | OP_DST
)
1262 scm_t_uint32 dst
, nargs
;
1265 UNPACK_24 (op
, dst
);
1266 nargs
= FRAME_LOCALS_COUNT ();
1270 ALLOC_FRAME (dst
+ 1);
1272 LOCAL_SET (nargs
++, SCM_UNDEFINED
);
1276 while (nargs
-- > dst
)
1278 rest
= scm_cons (LOCAL_REF (nargs
), rest
);
1279 LOCAL_SET (nargs
, SCM_UNDEFINED
);
1282 RESET_FRAME (dst
+ 1);
1285 LOCAL_SET (dst
, rest
);
1294 * Branching instructions
1299 * Add OFFSET, a signed 24-bit number, to the current instruction
1302 VM_DEFINE_OP (28, br
, "br", OP1 (U8_L24
))
1304 scm_t_int32 offset
= op
;
1305 offset
>>= 8; /* Sign-extending shift. */
1309 /* br-if-true test:24 invert:1 _:7 offset:24
1311 * If the value in TEST is true for the purposes of Scheme, add
1312 * OFFSET, a signed 24-bit number, to the current instruction pointer.
1314 VM_DEFINE_OP (29, br_if_true
, "br-if-true", OP2 (U8_U24
, B1_X7_L24
))
1316 BR_UNARY (x
, scm_is_true (x
));
1319 /* br-if-null test:24 invert:1 _:7 offset:24
1321 * If the value in TEST is the end-of-list or Lisp nil, add OFFSET, a
1322 * signed 24-bit number, to the current instruction pointer.
1324 VM_DEFINE_OP (30, br_if_null
, "br-if-null", OP2 (U8_U24
, B1_X7_L24
))
1326 BR_UNARY (x
, scm_is_null (x
));
1329 /* br-if-nil test:24 invert:1 _:7 offset:24
1331 * If the value in TEST is false to Lisp, add OFFSET, a signed 24-bit
1332 * number, to the current instruction pointer.
1334 VM_DEFINE_OP (31, br_if_nil
, "br-if-nil", OP2 (U8_U24
, B1_X7_L24
))
1336 BR_UNARY (x
, scm_is_lisp_false (x
));
1339 /* br-if-pair test:24 invert:1 _:7 offset:24
1341 * If the value in TEST is a pair, add OFFSET, a signed 24-bit number,
1342 * to the current instruction pointer.
1344 VM_DEFINE_OP (32, br_if_pair
, "br-if-pair", OP2 (U8_U24
, B1_X7_L24
))
1346 BR_UNARY (x
, scm_is_pair (x
));
1349 /* br-if-struct test:24 invert:1 _:7 offset:24
1351 * If the value in TEST is a struct, add OFFSET, a signed 24-bit
1352 * number, to the current instruction pointer.
1354 VM_DEFINE_OP (33, br_if_struct
, "br-if-struct", OP2 (U8_U24
, B1_X7_L24
))
1356 BR_UNARY (x
, SCM_STRUCTP (x
));
1359 /* br-if-char test:24 invert:1 _:7 offset:24
1361 * If the value in TEST is a char, add OFFSET, a signed 24-bit number,
1362 * to the current instruction pointer.
1364 VM_DEFINE_OP (34, br_if_char
, "br-if-char", OP2 (U8_U24
, B1_X7_L24
))
1366 BR_UNARY (x
, SCM_CHARP (x
));
1369 /* br-if-tc7 test:24 invert:1 tc7:7 offset:24
1371 * If the value in TEST has the TC7 given in the second word, add
1372 * OFFSET, a signed 24-bit number, to the current instruction pointer.
1374 VM_DEFINE_OP (35, br_if_tc7
, "br-if-tc7", OP2 (U8_U24
, B1_U7_L24
))
1376 BR_UNARY (x
, SCM_HAS_TYP7 (x
, (ip
[1] >> 1) & 0x7f));
1379 /* br-if-eq a:12 b:12 invert:1 _:7 offset:24
1381 * If the value in A is eq? to the value in B, add OFFSET, a signed
1382 * 24-bit number, to the current instruction pointer.
1384 VM_DEFINE_OP (36, br_if_eq
, "br-if-eq", OP2 (U8_U12_U12
, B1_X7_L24
))
1386 BR_BINARY (x
, y
, scm_is_eq (x
, y
));
1389 /* br-if-eqv a:12 b:12 invert:1 _:7 offset:24
1391 * If the value in A is eqv? to the value in B, add OFFSET, a signed
1392 * 24-bit number, to the current instruction pointer.
1394 VM_DEFINE_OP (37, br_if_eqv
, "br-if-eqv", OP2 (U8_U12_U12
, B1_X7_L24
))
1398 || (SCM_NIMP (x
) && SCM_NIMP (y
)
1399 && scm_is_true (scm_eqv_p (x
, y
))));
1402 // FIXME: remove, have compiler inline eqv test instead
1403 /* br-if-equal a:12 b:12 invert:1 _:7 offset:24
1405 * If the value in A is equal? to the value in B, add OFFSET, a signed
1406 * 24-bit number, to the current instruction pointer.
1408 // FIXME: should sync_ip before calling out?
1409 VM_DEFINE_OP (38, br_if_equal
, "br-if-equal", OP2 (U8_U12_U12
, B1_X7_L24
))
1413 || (SCM_NIMP (x
) && SCM_NIMP (y
)
1414 && scm_is_true (scm_equal_p (x
, y
))));
1417 /* br-if-= a:12 b:12 invert:1 _:7 offset:24
1419 * If the value in A is = to the value in B, add OFFSET, a signed
1420 * 24-bit number, to the current instruction pointer.
1422 VM_DEFINE_OP (39, br_if_ee
, "br-if-=", OP2 (U8_U12_U12
, B1_X7_L24
))
1424 BR_ARITHMETIC (==, scm_num_eq_p
);
1427 /* br-if-< a:12 b:12 _:8 offset:24
1429 * If the value in A is < to the value in B, add OFFSET, a signed
1430 * 24-bit number, to the current instruction pointer.
1432 VM_DEFINE_OP (40, br_if_lt
, "br-if-<", OP2 (U8_U12_U12
, B1_X7_L24
))
1434 BR_ARITHMETIC (<, scm_less_p
);
1437 /* br-if-<= a:12 b:12 _:8 offset:24
1439 * If the value in A is <= to the value in B, add OFFSET, a signed
1440 * 24-bit number, to the current instruction pointer.
1442 VM_DEFINE_OP (41, br_if_le
, "br-if-<=", OP2 (U8_U12_U12
, B1_X7_L24
))
1444 BR_ARITHMETIC (<=, scm_leq_p
);
1451 * Lexical binding instructions
1454 /* mov dst:12 src:12
1456 * Copy a value from one local slot to another.
1458 VM_DEFINE_OP (42, mov
, "mov", OP1 (U8_U12_U12
) | OP_DST
)
1463 UNPACK_12_12 (op
, dst
, src
);
1464 LOCAL_SET (dst
, LOCAL_REF (src
));
1469 /* long-mov dst:24 _:8 src:24
1471 * Copy a value from one local slot to another.
1473 VM_DEFINE_OP (43, long_mov
, "long-mov", OP2 (U8_U24
, X8_U24
) | OP_DST
)
1478 UNPACK_24 (op
, dst
);
1479 UNPACK_24 (ip
[1], src
);
1480 LOCAL_SET (dst
, LOCAL_REF (src
));
1485 /* box dst:12 src:12
1487 * Create a new variable holding SRC, and place it in DST.
1489 VM_DEFINE_OP (44, box
, "box", OP1 (U8_U12_U12
) | OP_DST
)
1491 scm_t_uint16 dst
, src
;
1492 UNPACK_12_12 (op
, dst
, src
);
1493 LOCAL_SET (dst
, scm_cell (scm_tc7_variable
, SCM_UNPACK (LOCAL_REF (src
))));
1497 /* box-ref dst:12 src:12
1499 * Unpack the variable at SRC into DST, asserting that the variable is
1502 VM_DEFINE_OP (45, box_ref
, "box-ref", OP1 (U8_U12_U12
) | OP_DST
)
1504 scm_t_uint16 dst
, src
;
1506 UNPACK_12_12 (op
, dst
, src
);
1507 var
= LOCAL_REF (src
);
1508 VM_ASSERT (SCM_VARIABLEP (var
),
1509 vm_error_not_a_variable ("variable-ref", var
));
1510 VM_ASSERT (VARIABLE_BOUNDP (var
),
1511 vm_error_unbound (SCM_FRAME_PROGRAM (fp
), var
));
1512 LOCAL_SET (dst
, VARIABLE_REF (var
));
1516 /* box-set! dst:12 src:12
1518 * Set the contents of the variable at DST to SET.
1520 VM_DEFINE_OP (46, box_set
, "box-set!", OP1 (U8_U12_U12
))
1522 scm_t_uint16 dst
, src
;
1524 UNPACK_12_12 (op
, dst
, src
);
1525 var
= LOCAL_REF (dst
);
1526 VM_ASSERT (SCM_VARIABLEP (var
),
1527 vm_error_not_a_variable ("variable-set!", var
));
1528 VARIABLE_SET (var
, LOCAL_REF (src
));
1532 /* make-closure dst:24 offset:32 _:8 nfree:24
1534 * Make a new closure, and write it to DST. The code for the closure
1535 * will be found at OFFSET words from the current IP. OFFSET is a
1536 * signed 32-bit integer. Space for NFREE free variables will be
1539 VM_DEFINE_OP (47, make_closure
, "make-closure", OP3 (U8_U24
, L32
, X8_U24
) | OP_DST
)
1541 scm_t_uint32 dst
, nfree
, n
;
1545 UNPACK_24 (op
, dst
);
1547 UNPACK_24 (ip
[2], nfree
);
1549 // FIXME: Assert range of nfree?
1550 closure
= scm_words (scm_tc7_program
| (nfree
<< 16), nfree
+ 2);
1551 SCM_SET_CELL_WORD_1 (closure
, ip
+ offset
);
1552 // FIXME: Elide these initializations?
1553 for (n
= 0; n
< nfree
; n
++)
1554 SCM_PROGRAM_FREE_VARIABLE_SET (closure
, n
, SCM_BOOL_F
);
1555 LOCAL_SET (dst
, closure
);
1559 /* free-ref dst:12 src:12 _:8 idx:24
1561 * Load free variable IDX from the closure SRC into local slot DST.
1563 VM_DEFINE_OP (48, free_ref
, "free-ref", OP2 (U8_U12_U12
, X8_U24
) | OP_DST
)
1565 scm_t_uint16 dst
, src
;
1567 UNPACK_12_12 (op
, dst
, src
);
1568 UNPACK_24 (ip
[1], idx
);
1569 /* CHECK_FREE_VARIABLE (src); */
1570 LOCAL_SET (dst
, SCM_PROGRAM_FREE_VARIABLE_REF (LOCAL_REF (src
), idx
));
1574 /* free-set! dst:12 src:12 _8 idx:24
1576 * Set free variable IDX from the closure DST to SRC.
1578 VM_DEFINE_OP (49, free_set
, "free-set!", OP2 (U8_U12_U12
, X8_U24
))
1580 scm_t_uint16 dst
, src
;
1582 UNPACK_12_12 (op
, dst
, src
);
1583 UNPACK_24 (ip
[1], idx
);
1584 /* CHECK_FREE_VARIABLE (src); */
1585 SCM_PROGRAM_FREE_VARIABLE_SET (LOCAL_REF (dst
), idx
, LOCAL_REF (src
));
1593 * Immediates and statically allocated non-immediates
1596 /* make-short-immediate dst:8 low-bits:16
1598 * Make an immediate whose low bits are LOW-BITS, and whose top bits are
1601 VM_DEFINE_OP (50, make_short_immediate
, "make-short-immediate", OP1 (U8_U8_I16
) | OP_DST
)
1606 UNPACK_8_16 (op
, dst
, val
);
1607 LOCAL_SET (dst
, SCM_PACK (val
));
1611 /* make-long-immediate dst:24 low-bits:32
1613 * Make an immediate whose low bits are LOW-BITS, and whose top bits are
1616 VM_DEFINE_OP (51, make_long_immediate
, "make-long-immediate", OP2 (U8_U24
, I32
))
1621 UNPACK_24 (op
, dst
);
1623 LOCAL_SET (dst
, SCM_PACK (val
));
1627 /* make-long-long-immediate dst:24 high-bits:32 low-bits:32
1629 * Make an immediate with HIGH-BITS and LOW-BITS.
1631 VM_DEFINE_OP (52, make_long_long_immediate
, "make-long-long-immediate", OP3 (U8_U24
, A32
, B32
) | OP_DST
)
1636 UNPACK_24 (op
, dst
);
1637 #if SIZEOF_SCM_T_BITS > 4
1642 ASSERT (ip
[1] == 0);
1645 LOCAL_SET (dst
, SCM_PACK (val
));
1649 /* make-non-immediate dst:24 offset:32
1651 * Load a pointer to statically allocated memory into DST. The
1652 * object's memory is will be found OFFSET 32-bit words away from the
1653 * current instruction pointer. OFFSET is a signed value. The
1654 * intention here is that the compiler would produce an object file
1655 * containing the words of a non-immediate object, and this
1656 * instruction creates a pointer to that memory, effectively
1657 * resurrecting that object.
1659 * Whether the object is mutable or immutable depends on where it was
1660 * allocated by the compiler, and loaded by the loader.
1662 VM_DEFINE_OP (53, make_non_immediate
, "make-non-immediate", OP2 (U8_U24
, N32
) | OP_DST
)
1667 scm_t_bits unpacked
;
1669 UNPACK_24 (op
, dst
);
1672 unpacked
= (scm_t_bits
) loc
;
1674 VM_ASSERT (!(unpacked
& 0x7), abort());
1676 LOCAL_SET (dst
, SCM_PACK (unpacked
));
1681 /* static-ref dst:24 offset:32
1683 * Load a SCM value into DST. The SCM value will be fetched from
1684 * memory, OFFSET 32-bit words away from the current instruction
1685 * pointer. OFFSET is a signed value.
1687 * The intention is for this instruction to be used to load constants
1688 * that the compiler is unable to statically allocate, like symbols.
1689 * These values would be initialized when the object file loads.
1691 VM_DEFINE_OP (54, static_ref
, "static-ref", OP2 (U8_U24
, S32
))
1696 scm_t_uintptr loc_bits
;
1698 UNPACK_24 (op
, dst
);
1701 loc_bits
= (scm_t_uintptr
) loc
;
1702 VM_ASSERT (ALIGNED_P (loc
, SCM
), abort());
1704 LOCAL_SET (dst
, *((SCM
*) loc_bits
));
1709 /* static-set! src:24 offset:32
1711 * Store a SCM value into memory, OFFSET 32-bit words away from the
1712 * current instruction pointer. OFFSET is a signed value.
1714 VM_DEFINE_OP (55, static_set
, "static-set!", OP2 (U8_U24
, LO32
))
1720 UNPACK_24 (op
, src
);
1723 VM_ASSERT (ALIGNED_P (loc
, SCM
), abort());
1725 *((SCM
*) loc
) = LOCAL_REF (src
);
1730 /* static-patch! _:24 dst-offset:32 src-offset:32
1732 * Patch a pointer at DST-OFFSET to point to SRC-OFFSET. Both offsets
1733 * are signed 32-bit values, indicating a memory address as a number
1734 * of 32-bit words away from the current instruction pointer.
1736 VM_DEFINE_OP (56, static_patch
, "static-patch!", OP3 (U8_X24
, LO32
, L32
))
1738 scm_t_int32 dst_offset
, src_offset
;
1745 dst_loc
= (void **) (ip
+ dst_offset
);
1746 src
= ip
+ src_offset
;
1747 VM_ASSERT (ALIGNED_P (dst_loc
, void*), abort());
1757 * Mutable top-level bindings
1760 /* There are three slightly different ways to resolve toplevel
1763 1. A toplevel reference outside of a function. These need to be
1764 looked up when the expression is evaluated -- no later, and no
1765 before. They are looked up relative to the module that is
1766 current when the expression is evaluated. For example:
1770 The "resolve" instruction resolves the variable (box), and then
1771 access is via box-ref or box-set!.
1773 2. A toplevel reference inside a function. These are looked up
1774 relative to the module that was current when the function was
1775 defined. Unlike code at the toplevel, which is usually run only
1776 once, these bindings benefit from memoized lookup, in which the
1777 variable resulting from the lookup is cached in the function.
1779 (lambda () (if (foo) a b))
1781 The toplevel-box instruction is equivalent to "resolve", but
1782 caches the resulting variable in statically allocated memory.
1784 3. A reference to an identifier with respect to a particular
1785 module. This can happen for primitive references, and
1786 references residualized by macro expansions. These can always
1787 be cached. Use module-box for these.
1790 /* current-module dst:24
1792 * Store the current module in DST.
1794 VM_DEFINE_OP (57, current_module
, "current-module", OP1 (U8_U24
) | OP_DST
)
1798 UNPACK_24 (op
, dst
);
1801 LOCAL_SET (dst
, scm_current_module ());
1806 /* resolve dst:24 bound?:1 _:7 sym:24
1808 * Resolve SYM in the current module, and place the resulting variable
1811 VM_DEFINE_OP (58, resolve
, "resolve", OP2 (U8_U24
, B1_X7_U24
) | OP_DST
)
1817 UNPACK_24 (op
, dst
);
1818 UNPACK_24 (ip
[1], sym
);
1821 var
= scm_lookup (LOCAL_REF (sym
));
1823 VM_ASSERT (VARIABLE_BOUNDP (var
),
1824 vm_error_unbound (fp
[0], LOCAL_REF (sym
)));
1825 LOCAL_SET (dst
, var
);
1830 /* define! sym:12 val:12
1832 * Look up a binding for SYM in the current module, creating it if
1833 * necessary. Set its value to VAL.
1835 VM_DEFINE_OP (59, define
, "define!", OP1 (U8_U12_U12
))
1837 scm_t_uint16 sym
, val
;
1838 UNPACK_12_12 (op
, sym
, val
);
1840 scm_define (LOCAL_REF (sym
), LOCAL_REF (val
));
1844 /* toplevel-box dst:24 var-offset:32 mod-offset:32 sym-offset:32 bound?:1 _:31
1846 * Load a SCM value. The SCM value will be fetched from memory,
1847 * VAR-OFFSET 32-bit words away from the current instruction pointer.
1848 * VAR-OFFSET is a signed value. Up to here, toplevel-box is like
1851 * Then, if the loaded value is a variable, it is placed in DST, and control
1854 * Otherwise, we have to resolve the variable. In that case we load
1855 * the module from MOD-OFFSET, just as we loaded the variable.
1856 * Usually the module gets set when the closure is created. The name
1857 * is an offset to a symbol.
1859 * We use the module and the symbol to resolve the variable, placing it in
1860 * DST, and caching the resolved variable so that we will hit the cache next
1863 VM_DEFINE_OP (60, toplevel_box
, "toplevel-box", OP5 (U8_U24
, S32
, S32
, N32
, B1_X31
) | OP_DST
)
1866 scm_t_int32 var_offset
;
1867 scm_t_uint32
* var_loc_u32
;
1871 UNPACK_24 (op
, dst
);
1873 var_loc_u32
= ip
+ var_offset
;
1874 VM_ASSERT (ALIGNED_P (var_loc_u32
, SCM
), abort());
1875 var_loc
= (SCM
*) var_loc_u32
;
1878 if (SCM_UNLIKELY (!SCM_VARIABLEP (var
)))
1881 scm_t_int32 mod_offset
= ip
[2]; /* signed */
1882 scm_t_int32 sym_offset
= ip
[3]; /* signed */
1883 scm_t_uint32
*mod_loc
= ip
+ mod_offset
;
1884 scm_t_uint32
*sym_loc
= ip
+ sym_offset
;
1888 VM_ASSERT (ALIGNED_P (mod_loc
, SCM
), abort());
1889 VM_ASSERT (ALIGNED_P (sym_loc
, SCM
), abort());
1891 mod
= *((SCM
*) mod_loc
);
1892 sym
= *((SCM
*) sym_loc
);
1894 /* If the toplevel scope was captured before modules were
1895 booted, use the root module. */
1896 if (scm_is_false (mod
))
1897 mod
= scm_the_root_module ();
1899 var
= scm_module_lookup (mod
, sym
);
1901 VM_ASSERT (VARIABLE_BOUNDP (var
), vm_error_unbound (fp
[0], sym
));
1906 LOCAL_SET (dst
, var
);
1910 /* module-box dst:24 var-offset:32 mod-offset:32 sym-offset:32 bound?:1 _:31
1912 * Like toplevel-box, except MOD-OFFSET points at the name of a module
1913 * instead of the module itself.
1915 VM_DEFINE_OP (61, module_box
, "module-box", OP5 (U8_U24
, S32
, N32
, N32
, B1_X31
) | OP_DST
)
1918 scm_t_int32 var_offset
;
1919 scm_t_uint32
* var_loc_u32
;
1923 UNPACK_24 (op
, dst
);
1925 var_loc_u32
= ip
+ var_offset
;
1926 VM_ASSERT (ALIGNED_P (var_loc_u32
, SCM
), abort());
1927 var_loc
= (SCM
*) var_loc_u32
;
1930 if (SCM_UNLIKELY (!SCM_VARIABLEP (var
)))
1933 scm_t_int32 modname_offset
= ip
[2]; /* signed */
1934 scm_t_int32 sym_offset
= ip
[3]; /* signed */
1935 scm_t_uint32
*modname_words
= ip
+ modname_offset
;
1936 scm_t_uint32
*sym_loc
= ip
+ sym_offset
;
1940 VM_ASSERT (!(((scm_t_uintptr
) modname_words
) & 0x7), abort());
1941 VM_ASSERT (ALIGNED_P (sym_loc
, SCM
), abort());
1943 modname
= SCM_PACK ((scm_t_bits
) modname_words
);
1944 sym
= *((SCM
*) sym_loc
);
1946 if (!scm_module_system_booted_p
)
1948 #ifdef VM_ENABLE_PARANOID_ASSERTIONS
1951 scm_equal_p (modname
,
1952 scm_list_2 (SCM_BOOL_T
,
1953 scm_from_utf8_symbol ("guile"))));
1955 var
= scm_lookup (sym
);
1957 else if (scm_is_true (SCM_CAR (modname
)))
1958 var
= scm_public_lookup (SCM_CDR (modname
), sym
);
1960 var
= scm_private_lookup (SCM_CDR (modname
), sym
);
1963 VM_ASSERT (VARIABLE_BOUNDP (var
), vm_error_unbound (fp
[0], sym
));
1968 LOCAL_SET (dst
, var
);
1975 * The dynamic environment
1978 /* prompt tag:24 escape-only?:1 _:7 proc-slot:24 _:8 handler-offset:24
1980 * Push a new prompt on the dynamic stack, with a tag from TAG and a
1981 * handler at HANDLER-OFFSET words from the current IP. The handler
1982 * will expect a multiple-value return as if from a call with the
1983 * procedure at PROC-SLOT.
1985 VM_DEFINE_OP (62, prompt
, "prompt", OP3 (U8_U24
, B1_X7_U24
, X8_L24
))
1987 scm_t_uint32 tag
, proc_slot
;
1989 scm_t_uint8 escape_only_p
;
1990 scm_t_dynstack_prompt_flags flags
;
1992 UNPACK_24 (op
, tag
);
1993 escape_only_p
= ip
[1] & 0x1;
1994 UNPACK_24 (ip
[1], proc_slot
);
1996 offset
>>= 8; /* Sign extension */
1998 /* Push the prompt onto the dynamic stack. */
1999 flags
= escape_only_p
? SCM_F_DYNSTACK_PROMPT_ESCAPE_ONLY
: 0;
2000 scm_dynstack_push_prompt (¤t_thread
->dynstack
, flags
,
2002 fp
- vp
->stack_base
,
2003 LOCAL_ADDRESS (proc_slot
) - vp
->stack_base
,
2009 /* wind winder:12 unwinder:12
2011 * Push wind and unwind procedures onto the dynamic stack. Note that
2012 * neither are actually called; the compiler should emit calls to wind
2013 * and unwind for the normal dynamic-wind control flow. Also note that
2014 * the compiler should have inserted checks that they wind and unwind
2015 * procs are thunks, if it could not prove that to be the case.
2017 VM_DEFINE_OP (63, wind
, "wind", OP1 (U8_U12_U12
))
2019 scm_t_uint16 winder
, unwinder
;
2020 UNPACK_12_12 (op
, winder
, unwinder
);
2021 scm_dynstack_push_dynwind (¤t_thread
->dynstack
,
2022 LOCAL_REF (winder
), LOCAL_REF (unwinder
));
2028 * A normal exit from the dynamic extent of an expression. Pop the top
2029 * entry off of the dynamic stack.
2031 VM_DEFINE_OP (64, unwind
, "unwind", OP1 (U8_X24
))
2033 scm_dynstack_pop (¤t_thread
->dynstack
);
2037 /* push-fluid fluid:12 value:12
2039 * Dynamically bind N fluids to values. The fluids are expected to be
2040 * allocated in a continguous range on the stack, starting from
2041 * FLUID-BASE. The values do not have this restriction.
2043 VM_DEFINE_OP (65, push_fluid
, "push-fluid", OP1 (U8_U12_U12
))
2045 scm_t_uint32 fluid
, value
;
2047 UNPACK_12_12 (op
, fluid
, value
);
2049 scm_dynstack_push_fluid (¤t_thread
->dynstack
,
2050 LOCAL_REF (fluid
), LOCAL_REF (value
),
2051 current_thread
->dynamic_state
);
2057 * Leave the dynamic extent of a with-fluids expression, restoring the
2058 * fluids to their previous values.
2060 VM_DEFINE_OP (66, pop_fluid
, "pop-fluid", OP1 (U8_X24
))
2062 /* This function must not allocate. */
2063 scm_dynstack_unwind_fluid (¤t_thread
->dynstack
,
2064 current_thread
->dynamic_state
);
2068 /* fluid-ref dst:12 src:12
2070 * Reference the fluid in SRC, and place the value in DST.
2072 VM_DEFINE_OP (67, fluid_ref
, "fluid-ref", OP1 (U8_U12_U12
) | OP_DST
)
2074 scm_t_uint16 dst
, src
;
2078 UNPACK_12_12 (op
, dst
, src
);
2079 fluid
= LOCAL_REF (src
);
2080 fluids
= SCM_I_DYNAMIC_STATE_FLUIDS (current_thread
->dynamic_state
);
2081 if (SCM_UNLIKELY (!SCM_FLUID_P (fluid
))
2082 || ((num
= SCM_I_FLUID_NUM (fluid
)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids
)))
2084 /* Punt dynstate expansion and error handling to the C proc. */
2086 LOCAL_SET (dst
, scm_fluid_ref (fluid
));
2090 SCM val
= SCM_SIMPLE_VECTOR_REF (fluids
, num
);
2091 if (scm_is_eq (val
, SCM_UNDEFINED
))
2092 val
= SCM_I_FLUID_DEFAULT (fluid
);
2093 VM_ASSERT (!scm_is_eq (val
, SCM_UNDEFINED
),
2094 vm_error_unbound_fluid (SCM_FRAME_PROGRAM (fp
), fluid
));
2095 LOCAL_SET (dst
, val
);
2101 /* fluid-set fluid:12 val:12
2103 * Set the value of the fluid in DST to the value in SRC.
2105 VM_DEFINE_OP (68, fluid_set
, "fluid-set", OP1 (U8_U12_U12
))
2111 UNPACK_12_12 (op
, a
, b
);
2112 fluid
= LOCAL_REF (a
);
2113 fluids
= SCM_I_DYNAMIC_STATE_FLUIDS (current_thread
->dynamic_state
);
2114 if (SCM_UNLIKELY (!SCM_FLUID_P (fluid
))
2115 || ((num
= SCM_I_FLUID_NUM (fluid
)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids
)))
2117 /* Punt dynstate expansion and error handling to the C proc. */
2119 scm_fluid_set_x (fluid
, LOCAL_REF (b
));
2122 SCM_SIMPLE_VECTOR_SET (fluids
, num
, LOCAL_REF (b
));
2131 * Strings, symbols, and keywords
2134 /* string-length dst:12 src:12
2136 * Store the length of the string in SRC in DST.
2138 VM_DEFINE_OP (69, string_length
, "string-length", OP1 (U8_U12_U12
) | OP_DST
)
2141 if (SCM_LIKELY (scm_is_string (str
)))
2142 RETURN (SCM_I_MAKINUM (scm_i_string_length (str
)));
2146 RETURN (scm_string_length (str
));
2150 /* string-ref dst:8 src:8 idx:8
2152 * Fetch the character at position IDX in the string in SRC, and store
2155 VM_DEFINE_OP (70, string_ref
, "string-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2157 scm_t_signed_bits i
= 0;
2159 if (SCM_LIKELY (scm_is_string (str
)
2160 && SCM_I_INUMP (idx
)
2161 && ((i
= SCM_I_INUM (idx
)) >= 0)
2162 && i
< scm_i_string_length (str
)))
2163 RETURN (SCM_MAKE_CHAR (scm_i_string_ref (str
, i
)));
2167 RETURN (scm_string_ref (str
, idx
));
2171 /* No string-set! instruction, as there is no good fast path there. */
2173 /* string-to-number dst:12 src:12
2175 * Parse a string in SRC to a number, and store in DST.
2177 VM_DEFINE_OP (71, string_to_number
, "string->number", OP1 (U8_U12_U12
) | OP_DST
)
2179 scm_t_uint16 dst
, src
;
2181 UNPACK_12_12 (op
, dst
, src
);
2184 scm_string_to_number (LOCAL_REF (src
),
2185 SCM_UNDEFINED
/* radix = 10 */));
2189 /* string-to-symbol dst:12 src:12
2191 * Parse a string in SRC to a symbol, and store in DST.
2193 VM_DEFINE_OP (72, string_to_symbol
, "string->symbol", OP1 (U8_U12_U12
) | OP_DST
)
2195 scm_t_uint16 dst
, src
;
2197 UNPACK_12_12 (op
, dst
, src
);
2199 LOCAL_SET (dst
, scm_string_to_symbol (LOCAL_REF (src
)));
2203 /* symbol->keyword dst:12 src:12
2205 * Make a keyword from the symbol in SRC, and store it in DST.
2207 VM_DEFINE_OP (73, symbol_to_keyword
, "symbol->keyword", OP1 (U8_U12_U12
) | OP_DST
)
2209 scm_t_uint16 dst
, src
;
2210 UNPACK_12_12 (op
, dst
, src
);
2212 LOCAL_SET (dst
, scm_symbol_to_keyword (LOCAL_REF (src
)));
2222 /* cons dst:8 car:8 cdr:8
2224 * Cons CAR and CDR, and store the result in DST.
2226 VM_DEFINE_OP (74, cons
, "cons", OP1 (U8_U8_U8_U8
) | OP_DST
)
2229 RETURN (scm_cons (x
, y
));
2232 /* car dst:12 src:12
2234 * Place the car of SRC in DST.
2236 VM_DEFINE_OP (75, car
, "car", OP1 (U8_U12_U12
) | OP_DST
)
2239 VM_VALIDATE_PAIR (x
, "car");
2240 RETURN (SCM_CAR (x
));
2243 /* cdr dst:12 src:12
2245 * Place the cdr of SRC in DST.
2247 VM_DEFINE_OP (76, cdr
, "cdr", OP1 (U8_U12_U12
) | OP_DST
)
2250 VM_VALIDATE_PAIR (x
, "cdr");
2251 RETURN (SCM_CDR (x
));
2254 /* set-car! pair:12 car:12
2256 * Set the car of DST to SRC.
2258 VM_DEFINE_OP (77, set_car
, "set-car!", OP1 (U8_U12_U12
))
2262 UNPACK_12_12 (op
, a
, b
);
2265 VM_VALIDATE_PAIR (x
, "set-car!");
2270 /* set-cdr! pair:12 cdr:12
2272 * Set the cdr of DST to SRC.
2274 VM_DEFINE_OP (78, set_cdr
, "set-cdr!", OP1 (U8_U12_U12
))
2278 UNPACK_12_12 (op
, a
, b
);
2281 VM_VALIDATE_PAIR (x
, "set-car!");
2290 * Numeric operations
2293 /* add dst:8 a:8 b:8
2295 * Add A to B, and place the result in DST.
2297 VM_DEFINE_OP (79, add
, "add", OP1 (U8_U8_U8_U8
) | OP_DST
)
2299 BINARY_INTEGER_OP (+, scm_sum
);
2302 /* add1 dst:12 src:12
2304 * Add 1 to the value in SRC, and place the result in DST.
2306 VM_DEFINE_OP (80, add1
, "add1", OP1 (U8_U12_U12
) | OP_DST
)
2310 /* Check for overflow. We must avoid overflow in the signed
2311 addition below, even if X is not an inum. */
2312 if (SCM_LIKELY ((scm_t_signed_bits
) SCM_UNPACK (x
) <= INUM_MAX
- INUM_STEP
))
2316 /* Add 1 to the integer without untagging. */
2317 result
= SCM_PACK ((scm_t_signed_bits
) SCM_UNPACK (x
) + INUM_STEP
);
2319 if (SCM_LIKELY (SCM_I_INUMP (result
)))
2324 RETURN (scm_sum (x
, SCM_I_MAKINUM (1)));
2327 /* sub dst:8 a:8 b:8
2329 * Subtract B from A, and place the result in DST.
2331 VM_DEFINE_OP (81, sub
, "sub", OP1 (U8_U8_U8_U8
) | OP_DST
)
2333 BINARY_INTEGER_OP (-, scm_difference
);
2336 /* sub1 dst:12 src:12
2338 * Subtract 1 from SRC, and place the result in DST.
2340 VM_DEFINE_OP (82, sub1
, "sub1", OP1 (U8_U12_U12
) | OP_DST
)
2344 /* Check for overflow. We must avoid overflow in the signed
2345 subtraction below, even if X is not an inum. */
2346 if (SCM_LIKELY ((scm_t_signed_bits
) SCM_UNPACK (x
) >= INUM_MIN
+ INUM_STEP
))
2350 /* Substract 1 from the integer without untagging. */
2351 result
= SCM_PACK ((scm_t_signed_bits
) SCM_UNPACK (x
) - INUM_STEP
);
2353 if (SCM_LIKELY (SCM_I_INUMP (result
)))
2358 RETURN (scm_difference (x
, SCM_I_MAKINUM (1)));
2361 /* mul dst:8 a:8 b:8
2363 * Multiply A and B, and place the result in DST.
2365 VM_DEFINE_OP (83, mul
, "mul", OP1 (U8_U8_U8_U8
) | OP_DST
)
2369 RETURN (scm_product (x
, y
));
2372 /* div dst:8 a:8 b:8
2374 * Divide A by B, and place the result in DST.
2376 VM_DEFINE_OP (84, div
, "div", OP1 (U8_U8_U8_U8
) | OP_DST
)
2380 RETURN (scm_divide (x
, y
));
2383 /* quo dst:8 a:8 b:8
2385 * Divide A by B, and place the quotient in DST.
2387 VM_DEFINE_OP (85, quo
, "quo", OP1 (U8_U8_U8_U8
) | OP_DST
)
2391 RETURN (scm_quotient (x
, y
));
2394 /* rem dst:8 a:8 b:8
2396 * Divide A by B, and place the remainder in DST.
2398 VM_DEFINE_OP (86, rem
, "rem", OP1 (U8_U8_U8_U8
) | OP_DST
)
2402 RETURN (scm_remainder (x
, y
));
2405 /* mod dst:8 a:8 b:8
2407 * Place the modulo of A by B in DST.
2409 VM_DEFINE_OP (87, mod
, "mod", OP1 (U8_U8_U8_U8
) | OP_DST
)
2413 RETURN (scm_modulo (x
, y
));
2416 /* ash dst:8 a:8 b:8
2418 * Shift A arithmetically by B bits, and place the result in DST.
2420 VM_DEFINE_OP (88, ash
, "ash", OP1 (U8_U8_U8_U8
) | OP_DST
)
2423 if (SCM_I_INUMP (x
) && SCM_I_INUMP (y
))
2425 if (SCM_I_INUM (y
) < 0)
2426 /* Right shift, will be a fixnum. */
2427 RETURN (SCM_I_MAKINUM
2428 (SCM_SRS (SCM_I_INUM (x
),
2429 (-SCM_I_INUM (y
) <= SCM_I_FIXNUM_BIT
-1)
2430 ? -SCM_I_INUM (y
) : SCM_I_FIXNUM_BIT
-1)));
2432 /* Left shift. See comments in scm_ash. */
2434 scm_t_signed_bits nn
, bits_to_shift
;
2436 nn
= SCM_I_INUM (x
);
2437 bits_to_shift
= SCM_I_INUM (y
);
2439 if (bits_to_shift
< SCM_I_FIXNUM_BIT
-1
2441 (SCM_SRS (nn
, (SCM_I_FIXNUM_BIT
-1 - bits_to_shift
)) + 1)
2443 RETURN (SCM_I_MAKINUM (nn
<< bits_to_shift
));
2449 RETURN (scm_ash (x
, y
));
2452 /* logand dst:8 a:8 b:8
2454 * Place the bitwise AND of A and B into DST.
2456 VM_DEFINE_OP (89, logand
, "logand", OP1 (U8_U8_U8_U8
) | OP_DST
)
2459 if (SCM_I_INUMP (x
) && SCM_I_INUMP (y
))
2460 /* Compute bitwise AND without untagging */
2461 RETURN (SCM_PACK (SCM_UNPACK (x
) & SCM_UNPACK (y
)));
2463 RETURN (scm_logand (x
, y
));
2466 /* logior dst:8 a:8 b:8
2468 * Place the bitwise inclusive OR of A with B in DST.
2470 VM_DEFINE_OP (90, logior
, "logior", OP1 (U8_U8_U8_U8
) | OP_DST
)
2473 if (SCM_I_INUMP (x
) && SCM_I_INUMP (y
))
2474 /* Compute bitwise OR without untagging */
2475 RETURN (SCM_PACK (SCM_UNPACK (x
) | SCM_UNPACK (y
)));
2477 RETURN (scm_logior (x
, y
));
2480 /* logxor dst:8 a:8 b:8
2482 * Place the bitwise exclusive OR of A with B in DST.
2484 VM_DEFINE_OP (91, logxor
, "logxor", OP1 (U8_U8_U8_U8
) | OP_DST
)
2487 if (SCM_I_INUMP (x
) && SCM_I_INUMP (y
))
2488 RETURN (SCM_I_MAKINUM (SCM_I_INUM (x
) ^ SCM_I_INUM (y
)));
2490 RETURN (scm_logxor (x
, y
));
2493 /* make-vector/immediate dst:8 length:8 init:8
2495 * Make a short vector of known size and write it to DST. The vector
2496 * will have space for LENGTH slots, an immediate value. They will be
2497 * filled with the value in slot INIT.
2499 VM_DEFINE_OP (92, make_vector_immediate
, "make-vector/immediate", OP1 (U8_U8_U8_U8
) | OP_DST
)
2501 scm_t_uint8 dst
, init
;
2502 scm_t_int32 length
, n
;
2505 UNPACK_8_8_8 (op
, dst
, length
, init
);
2507 val
= LOCAL_REF (init
);
2508 vector
= scm_words (scm_tc7_vector
| (length
<< 8), length
+ 1);
2509 for (n
= 0; n
< length
; n
++)
2510 SCM_SIMPLE_VECTOR_SET (vector
, n
, val
);
2511 LOCAL_SET (dst
, vector
);
2515 /* vector-length dst:12 src:12
2517 * Store the length of the vector in SRC in DST.
2519 VM_DEFINE_OP (93, vector_length
, "vector-length", OP1 (U8_U12_U12
) | OP_DST
)
2522 if (SCM_LIKELY (SCM_I_IS_VECTOR (vect
)))
2523 RETURN (SCM_I_MAKINUM (SCM_I_VECTOR_LENGTH (vect
)));
2527 RETURN (scm_vector_length (vect
));
2531 /* vector-ref dst:8 src:8 idx:8
2533 * Fetch the item at position IDX in the vector in SRC, and store it
2536 VM_DEFINE_OP (94, vector_ref
, "vector-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2538 scm_t_signed_bits i
= 0;
2540 if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect
)
2541 && SCM_I_INUMP (idx
)
2542 && ((i
= SCM_I_INUM (idx
)) >= 0)
2543 && i
< SCM_I_VECTOR_LENGTH (vect
)))
2544 RETURN (SCM_I_VECTOR_ELTS (vect
)[i
]);
2548 RETURN (scm_vector_ref (vect
, idx
));
2552 /* vector-ref/immediate dst:8 src:8 idx:8
2554 * Fill DST with the item IDX elements into the vector at SRC. Useful
2555 * for building data types using vectors.
2557 VM_DEFINE_OP (95, vector_ref_immediate
, "vector-ref/immediate", OP1 (U8_U8_U8_U8
) | OP_DST
)
2559 scm_t_uint8 dst
, src
, idx
;
2562 UNPACK_8_8_8 (op
, dst
, src
, idx
);
2563 v
= LOCAL_REF (src
);
2564 if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (v
)
2565 && idx
< SCM_I_VECTOR_LENGTH (v
)))
2566 LOCAL_SET (dst
, SCM_I_VECTOR_ELTS (LOCAL_REF (src
))[idx
]);
2568 LOCAL_SET (dst
, scm_c_vector_ref (v
, idx
));
2572 /* vector-set! dst:8 idx:8 src:8
2574 * Store SRC into the vector DST at index IDX.
2576 VM_DEFINE_OP (96, vector_set
, "vector-set!", OP1 (U8_U8_U8_U8
))
2578 scm_t_uint8 dst
, idx_var
, src
;
2580 scm_t_signed_bits i
= 0;
2582 UNPACK_8_8_8 (op
, dst
, idx_var
, src
);
2583 vect
= LOCAL_REF (dst
);
2584 idx
= LOCAL_REF (idx_var
);
2585 val
= LOCAL_REF (src
);
2587 if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect
)
2588 && SCM_I_INUMP (idx
)
2589 && ((i
= SCM_I_INUM (idx
)) >= 0)
2590 && i
< SCM_I_VECTOR_LENGTH (vect
)))
2591 SCM_I_VECTOR_WELTS (vect
)[i
] = val
;
2595 scm_vector_set_x (vect
, idx
, val
);
2600 /* vector-set!/immediate dst:8 idx:8 src:8
2602 * Store SRC into the vector DST at index IDX. Here IDX is an
2605 VM_DEFINE_OP (97, vector_set_immediate
, "vector-set!/immediate", OP1 (U8_U8_U8_U8
))
2607 scm_t_uint8 dst
, idx
, src
;
2610 UNPACK_8_8_8 (op
, dst
, idx
, src
);
2611 vect
= LOCAL_REF (dst
);
2612 val
= LOCAL_REF (src
);
2614 if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect
)
2615 && idx
< SCM_I_VECTOR_LENGTH (vect
)))
2616 SCM_I_VECTOR_WELTS (vect
)[idx
] = val
;
2620 scm_vector_set_x (vect
, scm_from_uint8 (idx
), val
);
2632 /* struct-vtable dst:12 src:12
2634 * Store the vtable of SRC into DST.
2636 VM_DEFINE_OP (98, struct_vtable
, "struct-vtable", OP1 (U8_U12_U12
) | OP_DST
)
2639 VM_VALIDATE_STRUCT (obj
, "struct_vtable");
2640 RETURN (SCM_STRUCT_VTABLE (obj
));
2643 /* allocate-struct/immediate dst:8 vtable:8 nfields:8
2645 * Allocate a new struct with VTABLE, and place it in DST. The struct
2646 * will be constructed with space for NFIELDS fields, which should
2647 * correspond to the field count of the VTABLE.
2649 VM_DEFINE_OP (99, allocate_struct_immediate
, "allocate-struct/immediate", OP1 (U8_U8_U8_U8
) | OP_DST
)
2651 scm_t_uint8 dst
, vtable
, nfields
;
2654 UNPACK_8_8_8 (op
, dst
, vtable
, nfields
);
2657 ret
= scm_allocate_struct (LOCAL_REF (vtable
), SCM_I_MAKINUM (nfields
));
2658 LOCAL_SET (dst
, ret
);
2663 /* struct-ref/immediate dst:8 src:8 idx:8
2665 * Fetch the item at slot IDX in the struct in SRC, and store it
2666 * in DST. IDX is an immediate unsigned 8-bit value.
2668 VM_DEFINE_OP (100, struct_ref_immediate
, "struct-ref/immediate", OP1 (U8_U8_U8_U8
) | OP_DST
)
2670 scm_t_uint8 dst
, src
, idx
;
2673 UNPACK_8_8_8 (op
, dst
, src
, idx
);
2675 obj
= LOCAL_REF (src
);
2677 if (SCM_LIKELY (SCM_STRUCTP (obj
)
2678 && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj
,
2679 SCM_VTABLE_FLAG_SIMPLE
)
2680 && idx
< SCM_STRUCT_DATA_REF (SCM_STRUCT_VTABLE (obj
),
2681 scm_vtable_index_size
)))
2682 RETURN (SCM_STRUCT_SLOT_REF (obj
, idx
));
2685 RETURN (scm_struct_ref (obj
, SCM_I_MAKINUM (idx
)));
2688 /* struct-set!/immediate dst:8 idx:8 src:8
2690 * Store SRC into the struct DST at slot IDX. IDX is an immediate
2691 * unsigned 8-bit value.
2693 VM_DEFINE_OP (101, struct_set_immediate
, "struct-set!/immediate", OP1 (U8_U8_U8_U8
))
2695 scm_t_uint8 dst
, idx
, src
;
2698 UNPACK_8_8_8 (op
, dst
, idx
, src
);
2700 obj
= LOCAL_REF (dst
);
2701 val
= LOCAL_REF (src
);
2703 if (SCM_LIKELY (SCM_STRUCTP (obj
)
2704 && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj
,
2705 SCM_VTABLE_FLAG_SIMPLE
)
2706 && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj
,
2707 SCM_VTABLE_FLAG_SIMPLE_RW
)
2708 && idx
< SCM_STRUCT_DATA_REF (SCM_STRUCT_VTABLE (obj
),
2709 scm_vtable_index_size
)))
2711 SCM_STRUCT_SLOT_SET (obj
, idx
, val
);
2716 scm_struct_set_x (obj
, SCM_I_MAKINUM (idx
), val
);
2720 /* class-of dst:12 type:12
2722 * Store the vtable of SRC into DST.
2724 VM_DEFINE_OP (102, class_of
, "class-of", OP1 (U8_U12_U12
) | OP_DST
)
2727 if (SCM_INSTANCEP (obj
))
2728 RETURN (SCM_CLASS_OF (obj
));
2730 RETURN (scm_class_of (obj
));
2733 /* slot-ref dst:8 src:8 idx:8
2735 * Fetch the item at slot IDX in the struct in SRC, and store it in
2736 * DST. Unlike struct-ref, IDX is an 8-bit immediate value, not an
2737 * index into the stack.
2739 VM_DEFINE_OP (103, slot_ref
, "slot-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2741 scm_t_uint8 dst
, src
, idx
;
2742 UNPACK_8_8_8 (op
, dst
, src
, idx
);
2744 SCM_PACK (SCM_STRUCT_DATA (LOCAL_REF (src
))[idx
]));
2748 /* slot-set! dst:8 idx:8 src:8
2750 * Store SRC into slot IDX of the struct in DST. Unlike struct-set!,
2751 * IDX is an 8-bit immediate value, not an index into the stack.
2753 VM_DEFINE_OP (104, slot_set
, "slot-set!", OP1 (U8_U8_U8_U8
))
2755 scm_t_uint8 dst
, idx
, src
;
2756 UNPACK_8_8_8 (op
, dst
, idx
, src
);
2757 SCM_STRUCT_DATA (LOCAL_REF (dst
))[idx
] = SCM_UNPACK (LOCAL_REF (src
));
2765 * Arrays, packed uniform arrays, and bytevectors.
2768 /* load-typed-array dst:8 type:8 shape:8 offset:32 len:32
2770 * Load the contiguous typed array located at OFFSET 32-bit words away
2771 * from the instruction pointer, and store into DST. LEN is a byte
2772 * length. OFFSET is signed.
2774 VM_DEFINE_OP (105, load_typed_array
, "load-typed-array", OP3 (U8_U8_U8_U8
, N32
, U32
) | OP_DST
)
2776 scm_t_uint8 dst
, type
, shape
;
2780 UNPACK_8_8_8 (op
, dst
, type
, shape
);
2784 LOCAL_SET (dst
, scm_from_contiguous_typed_array (LOCAL_REF (type
),
2790 /* make-array dst:12 type:12 _:8 fill:12 bounds:12
2792 * Make a new array with TYPE, FILL, and BOUNDS, storing it in DST.
2794 VM_DEFINE_OP (106, make_array
, "make-array", OP2 (U8_U12_U12
, X8_U12_U12
) | OP_DST
)
2796 scm_t_uint16 dst
, type
, fill
, bounds
;
2797 UNPACK_12_12 (op
, dst
, type
);
2798 UNPACK_12_12 (ip
[1], fill
, bounds
);
2800 LOCAL_SET (dst
, scm_make_typed_array (LOCAL_REF (type
), LOCAL_REF (fill
),
2801 LOCAL_REF (bounds
)));
2805 /* bv-u8-ref dst:8 src:8 idx:8
2806 * bv-s8-ref dst:8 src:8 idx:8
2807 * bv-u16-ref dst:8 src:8 idx:8
2808 * bv-s16-ref dst:8 src:8 idx:8
2809 * bv-u32-ref dst:8 src:8 idx:8
2810 * bv-s32-ref dst:8 src:8 idx:8
2811 * bv-u64-ref dst:8 src:8 idx:8
2812 * bv-s64-ref dst:8 src:8 idx:8
2813 * bv-f32-ref dst:8 src:8 idx:8
2814 * bv-f64-ref dst:8 src:8 idx:8
2816 * Fetch the item at byte offset IDX in the bytevector SRC, and store
2817 * it in DST. All accesses use native endianness.
2819 #define BV_FIXABLE_INT_REF(stem, fn_stem, type, size) \
2821 scm_t_signed_bits i; \
2822 const scm_t_ ## type *int_ptr; \
2825 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-ref"); \
2826 i = SCM_I_INUM (idx); \
2827 int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
2829 if (SCM_LIKELY (SCM_I_INUMP (idx) \
2831 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
2832 && (ALIGNED_P (int_ptr, scm_t_ ## type)))) \
2833 RETURN (SCM_I_MAKINUM (*int_ptr)); \
2837 RETURN (scm_bytevector_ ## fn_stem ## _ref (bv, idx)); \
2841 #define BV_INT_REF(stem, type, size) \
2843 scm_t_signed_bits i; \
2844 const scm_t_ ## type *int_ptr; \
2847 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-ref"); \
2848 i = SCM_I_INUM (idx); \
2849 int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
2851 if (SCM_LIKELY (SCM_I_INUMP (idx) \
2853 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
2854 && (ALIGNED_P (int_ptr, scm_t_ ## type)))) \
2856 scm_t_ ## type x = *int_ptr; \
2857 if (SCM_FIXABLE (x)) \
2858 RETURN (SCM_I_MAKINUM (x)); \
2862 RETURN (scm_from_ ## type (x)); \
2868 RETURN (scm_bytevector_ ## stem ## _native_ref (bv, idx)); \
2872 #define BV_FLOAT_REF(stem, fn_stem, type, size) \
2874 scm_t_signed_bits i; \
2875 const type *float_ptr; \
2878 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-ref"); \
2879 i = SCM_I_INUM (idx); \
2880 float_ptr = (type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
2883 if (SCM_LIKELY (SCM_I_INUMP (idx) \
2885 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
2886 && (ALIGNED_P (float_ptr, type)))) \
2887 RETURN (scm_from_double (*float_ptr)); \
2889 RETURN (scm_bytevector_ ## fn_stem ## _native_ref (bv, idx)); \
2892 VM_DEFINE_OP (107, bv_u8_ref
, "bv-u8-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2893 BV_FIXABLE_INT_REF (u8
, u8
, uint8
, 1);
2895 VM_DEFINE_OP (108, bv_s8_ref
, "bv-s8-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2896 BV_FIXABLE_INT_REF (s8
, s8
, int8
, 1);
2898 VM_DEFINE_OP (109, bv_u16_ref
, "bv-u16-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2899 BV_FIXABLE_INT_REF (u16
, u16_native
, uint16
, 2);
2901 VM_DEFINE_OP (110, bv_s16_ref
, "bv-s16-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2902 BV_FIXABLE_INT_REF (s16
, s16_native
, int16
, 2);
2904 VM_DEFINE_OP (111, bv_u32_ref
, "bv-u32-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2905 #if SIZEOF_VOID_P > 4
2906 BV_FIXABLE_INT_REF (u32
, u32_native
, uint32
, 4);
2908 BV_INT_REF (u32
, uint32
, 4);
2911 VM_DEFINE_OP (112, bv_s32_ref
, "bv-s32-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2912 #if SIZEOF_VOID_P > 4
2913 BV_FIXABLE_INT_REF (s32
, s32_native
, int32
, 4);
2915 BV_INT_REF (s32
, int32
, 4);
2918 VM_DEFINE_OP (113, bv_u64_ref
, "bv-u64-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2919 BV_INT_REF (u64
, uint64
, 8);
2921 VM_DEFINE_OP (114, bv_s64_ref
, "bv-s64-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2922 BV_INT_REF (s64
, int64
, 8);
2924 VM_DEFINE_OP (115, bv_f32_ref
, "bv-f32-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2925 BV_FLOAT_REF (f32
, ieee_single
, float, 4);
2927 VM_DEFINE_OP (116, bv_f64_ref
, "bv-f64-ref", OP1 (U8_U8_U8_U8
) | OP_DST
)
2928 BV_FLOAT_REF (f64
, ieee_double
, double, 8);
2930 /* bv-u8-set! dst:8 idx:8 src:8
2931 * bv-s8-set! dst:8 idx:8 src:8
2932 * bv-u16-set! dst:8 idx:8 src:8
2933 * bv-s16-set! dst:8 idx:8 src:8
2934 * bv-u32-set! dst:8 idx:8 src:8
2935 * bv-s32-set! dst:8 idx:8 src:8
2936 * bv-u64-set! dst:8 idx:8 src:8
2937 * bv-s64-set! dst:8 idx:8 src:8
2938 * bv-f32-set! dst:8 idx:8 src:8
2939 * bv-f64-set! dst:8 idx:8 src:8
2941 * Store SRC into the bytevector DST at byte offset IDX. Multibyte
2942 * values are written using native endianness.
2944 #define BV_FIXABLE_INT_SET(stem, fn_stem, type, min, max, size) \
2946 scm_t_uint8 dst, idx, src; \
2947 scm_t_signed_bits i, j = 0; \
2948 SCM bv, scm_idx, val; \
2949 scm_t_ ## type *int_ptr; \
2951 UNPACK_8_8_8 (op, dst, idx, src); \
2952 bv = LOCAL_REF (dst); \
2953 scm_idx = LOCAL_REF (idx); \
2954 val = LOCAL_REF (src); \
2955 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set!"); \
2956 i = SCM_I_INUM (scm_idx); \
2957 int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
2959 if (SCM_LIKELY (SCM_I_INUMP (scm_idx) \
2961 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
2962 && (ALIGNED_P (int_ptr, scm_t_ ## type)) \
2963 && (SCM_I_INUMP (val)) \
2964 && ((j = SCM_I_INUM (val)) >= min) \
2966 *int_ptr = (scm_t_ ## type) j; \
2970 scm_bytevector_ ## fn_stem ## _set_x (bv, scm_idx, val); \
2975 #define BV_INT_SET(stem, type, size) \
2977 scm_t_uint8 dst, idx, src; \
2978 scm_t_signed_bits i; \
2979 SCM bv, scm_idx, val; \
2980 scm_t_ ## type *int_ptr; \
2982 UNPACK_8_8_8 (op, dst, idx, src); \
2983 bv = LOCAL_REF (dst); \
2984 scm_idx = LOCAL_REF (idx); \
2985 val = LOCAL_REF (src); \
2986 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set!"); \
2987 i = SCM_I_INUM (scm_idx); \
2988 int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
2990 if (SCM_LIKELY (SCM_I_INUMP (scm_idx) \
2992 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
2993 && (ALIGNED_P (int_ptr, scm_t_ ## type)))) \
2994 *int_ptr = scm_to_ ## type (val); \
2998 scm_bytevector_ ## stem ## _native_set_x (bv, scm_idx, val); \
3003 #define BV_FLOAT_SET(stem, fn_stem, type, size) \
3005 scm_t_uint8 dst, idx, src; \
3006 scm_t_signed_bits i; \
3007 SCM bv, scm_idx, val; \
3010 UNPACK_8_8_8 (op, dst, idx, src); \
3011 bv = LOCAL_REF (dst); \
3012 scm_idx = LOCAL_REF (idx); \
3013 val = LOCAL_REF (src); \
3014 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set!"); \
3015 i = SCM_I_INUM (scm_idx); \
3016 float_ptr = (type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
3018 if (SCM_LIKELY (SCM_I_INUMP (scm_idx) \
3020 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
3021 && (ALIGNED_P (float_ptr, type)))) \
3022 *float_ptr = scm_to_double (val); \
3026 scm_bytevector_ ## fn_stem ## _native_set_x (bv, scm_idx, val); \
3031 VM_DEFINE_OP (117, bv_u8_set
, "bv-u8-set!", OP1 (U8_U8_U8_U8
))
3032 BV_FIXABLE_INT_SET (u8
, u8
, uint8
, 0, SCM_T_UINT8_MAX
, 1);
3034 VM_DEFINE_OP (118, bv_s8_set
, "bv-s8-set!", OP1 (U8_U8_U8_U8
))
3035 BV_FIXABLE_INT_SET (s8
, s8
, int8
, SCM_T_INT8_MIN
, SCM_T_INT8_MAX
, 1);
3037 VM_DEFINE_OP (119, bv_u16_set
, "bv-u16-set!", OP1 (U8_U8_U8_U8
))
3038 BV_FIXABLE_INT_SET (u16
, u16_native
, uint16
, 0, SCM_T_UINT16_MAX
, 2);
3040 VM_DEFINE_OP (120, bv_s16_set
, "bv-s16-set!", OP1 (U8_U8_U8_U8
))
3041 BV_FIXABLE_INT_SET (s16
, s16_native
, int16
, SCM_T_INT16_MIN
, SCM_T_INT16_MAX
, 2);
3043 VM_DEFINE_OP (121, bv_u32_set
, "bv-u32-set!", OP1 (U8_U8_U8_U8
))
3044 #if SIZEOF_VOID_P > 4
3045 BV_FIXABLE_INT_SET (u32
, u32_native
, uint32
, 0, SCM_T_UINT32_MAX
, 4);
3047 BV_INT_SET (u32
, uint32
, 4);
3050 VM_DEFINE_OP (122, bv_s32_set
, "bv-s32-set!", OP1 (U8_U8_U8_U8
))
3051 #if SIZEOF_VOID_P > 4
3052 BV_FIXABLE_INT_SET (s32
, s32_native
, int32
, SCM_T_INT32_MIN
, SCM_T_INT32_MAX
, 4);
3054 BV_INT_SET (s32
, int32
, 4);
3057 VM_DEFINE_OP (123, bv_u64_set
, "bv-u64-set!", OP1 (U8_U8_U8_U8
))
3058 BV_INT_SET (u64
, uint64
, 8);
3060 VM_DEFINE_OP (124, bv_s64_set
, "bv-s64-set!", OP1 (U8_U8_U8_U8
))
3061 BV_INT_SET (s64
, int64
, 8);
3063 VM_DEFINE_OP (125, bv_f32_set
, "bv-f32-set!", OP1 (U8_U8_U8_U8
))
3064 BV_FLOAT_SET (f32
, ieee_single
, float, 4);
3066 VM_DEFINE_OP (126, bv_f64_set
, "bv-f64-set!", OP1 (U8_U8_U8_U8
))
3067 BV_FLOAT_SET (f64
, ieee_double
, double, 8);
3069 END_DISPATCH_SWITCH
;
3071 vm_error_bad_instruction
:
3072 vm_error_bad_instruction (op
);
3074 abort (); /* never reached */
3078 #undef ABORT_CONTINUATION_HOOK
3083 #undef BEGIN_DISPATCH_SWITCH
3084 #undef BINARY_INTEGER_OP
3085 #undef BR_ARITHMETIC
3089 #undef BV_FIXABLE_INT_REF
3090 #undef BV_FIXABLE_INT_SET
3095 #undef CACHE_REGISTER
3096 #undef CHECK_OVERFLOW
3097 #undef END_DISPATCH_SWITCH
3098 #undef FREE_VARIABLE_REF
3107 #undef POP_CONTINUATION_HOOK
3108 #undef PUSH_CONTINUATION_HOOK
3109 #undef RESTORE_CONTINUATION_HOOK
3111 #undef RETURN_ONE_VALUE
3112 #undef RETURN_VALUE_LIST
3117 #undef SYNC_BEFORE_GC
3119 #undef SYNC_REGISTER
3125 #undef VARIABLE_BOUNDP
3128 #undef VM_CHECK_FREE_VARIABLE
3129 #undef VM_CHECK_OBJECT
3130 #undef VM_CHECK_UNDERFLOW
3132 #undef VM_INSTRUCTION_TO_LABEL
3134 #undef VM_VALIDATE_BYTEVECTOR
3135 #undef VM_VALIDATE_PAIR
3136 #undef VM_VALIDATE_STRUCT
3139 (defun renumber-ops ()
3140 "start from top of buffer and renumber 'VM_DEFINE_FOO (\n' sequences"
3143 (let ((counter -1)) (goto-char (point-min))
3144 (while (re-search-forward "^ *VM_DEFINE_[^ ]+ (\\([^,]+\\)," (point-max) t)
3146 (number-to-string (setq counter (1+ counter)))