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