Remove use of SCM_CRITICAL_SECTION in smob.c
[bpt/guile.git] / libguile / vm-engine.c
CommitLineData
27c7c630 1/* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
a98cef7e 2 *
560b9c25 3 * This library is free software; you can redistribute it and/or
53befeb7
NJ
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
a98cef7e 7 *
53befeb7
NJ
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
560b9c25
AW
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
a98cef7e 12 *
560b9c25
AW
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
53befeb7
NJ
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16 * 02110-1301 USA
560b9c25 17 */
a98cef7e 18
510ca126
AW
19/* This file is included in vm.c multiple times. */
20
21
6d14383e 22#if (VM_ENGINE == SCM_VM_REGULAR_ENGINE)
ff3968c2 23# define VM_USE_HOOKS 0 /* Various hooks */
6d14383e 24#elif (VM_ENGINE == SCM_VM_DEBUG_ENGINE)
ff3968c2 25# define VM_USE_HOOKS 1
6d14383e 26#else
ff3968c2 27# error unknown debug engine VM_ENGINE
6d14383e 28#endif
a98cef7e 29
8dd6bfa7
AW
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. */
eac12024 35#ifdef __GNUC__
8dd6bfa7 36# if defined __x86_64__
eac12024
AW
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. */
8dd6bfa7
AW
40# define JT_REG asm ("r12")
41# endif
eac12024
AW
42#endif
43
44#ifndef IP_REG
8dd6bfa7 45# define IP_REG
eac12024 46#endif
eac12024 47#ifndef FP_REG
8dd6bfa7 48# define FP_REG
eac12024
AW
49#endif
50#ifndef JT_REG
8dd6bfa7 51# define JT_REG
eac12024
AW
52#endif
53
27c7c630
AW
54#define VM_ASSERT(condition, handler) \
55 do { \
56 if (SCM_UNLIKELY (!(condition))) \
57 { \
58 SYNC_ALL(); \
59 handler; \
60 } \
61 } while (0)
eac12024
AW
62
63#ifdef VM_ENABLE_ASSERTIONS
64# define ASSERT(condition) VM_ASSERT (condition, abort())
65#else
66# define ASSERT(condition)
67#endif
68
c850a0ff
AW
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
510ca126
AW
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.
7396d216
AW
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.
510ca126
AW
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
7396d216 144 stack space for N locals, including the procedure, in addition to
f8085163 145 2 words to set up the next frame. Invoke after preparing the new
510ca126
AW
146 frame and setting the fp and ip. */
147#define ALLOC_FRAME(n) \
148 do { \
7396d216 149 SCM *new_sp = vp->sp = fp - 1 + n - 1; \
f8085163 150 CHECK_OVERFLOW (new_sp + 3); \
510ca126
AW
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 { \
7396d216 157 vp->sp = fp - 2 + n; \
510ca126
AW
158 } while (0)
159
160/* Compute the number of locals in the frame. This is equal to the
7396d216
AW
161 number of actual arguments when a function is first called, plus
162 one for the function. */
510ca126 163#define FRAME_LOCALS_COUNT() \
7396d216 164 (vp->sp + 1 - (fp - 1))
510ca126
AW
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
8cff7f54
AW
215#define LOCAL_REF(i) SCM_FRAME_VARIABLE ((fp - 1), i)
216#define LOCAL_SET(i,o) SCM_FRAME_VARIABLE ((fp - 1), i) = o
510ca126
AW
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))
510ca126
AW
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); \
510ca126 228 fp = vp->fp = SCM_FRAME_DYNAMIC_LINK (fp); \
af95414f
AW
229 /* Clear frame. */ \
230 sp[0] = SCM_BOOL_F; \
231 sp[1] = SCM_BOOL_F; \
af95414f 232 /* Leave proc. */ \
f8085163
AW
233 sp[3] = val; \
234 vp->sp = sp + 3; \
510ca126
AW
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; \
486013d6
AW
245 fp[-1] = vm_builtin_apply; \
246 fp[0] = vm_builtin_values; \
510ca126 247 fp[1] = vals; \
7396d216 248 RESET_FRAME (3); \
486013d6 249 ip = (scm_t_uint32 *) vm_builtin_apply_code; \
adb8d905 250 goto op_tail_apply; \
510ca126
AW
251 } while (0)
252
253#define BR_NARGS(rel) \
d2bd8fa8 254 scm_t_uint32 expected; \
510ca126
AW
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); \
af95414f 306 if ((ip[1] & 0x1) ? !(x_bits crel y_bits) : (x_bits crel y_bits)) \
510ca126
AW
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 { \
af95414f 318 SCM res; \
510ca126 319 SYNC_IP (); \
af95414f
AW
320 res = srel (x, y); \
321 if ((ip[1] & 0x1) ? scm_is_false (res) : scm_is_true (res)) \
510ca126
AW
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. */
d2295ba5
MW
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))
510ca126
AW
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 ();
d691ac20 435 ABORT_CONTINUATION_HOOK (fp, FRAME_LOCALS_COUNT () - 1);
510ca126
AW
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
f8085163
AW
448 /* Check that we have enough space: 3 words for the boot
449 continuation, 3 + nargs for the procedure application, and 3 for
510ca126
AW
450 setting up a new frame. */
451 base = vp->sp + 1;
f8085163 452 CHECK_OVERFLOW (vp->sp + 3 + 3 + nargs_ + 3);
510ca126
AW
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--)
f8085163 460 base[6 + i] = argv[i];
510ca126
AW
461 }
462
463 /* Initial frame, saving previous fp and ip, with the boot
464 continuation. */
465 base[0] = SCM_PACK (fp); /* dynamic link */
f8085163
AW
466 base[1] = SCM_PACK (ip); /* ra */
467 base[2] = rtl_boot_continuation;
468 fp = &base[3];
af95414f 469 ip = (scm_t_uint32 *) rtl_boot_continuation_code;
510ca126
AW
470
471 /* MV-call frame, function & arguments */
f8085163
AW
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];
7396d216 476 RESET_FRAME (nargs_ + 1);
510ca126
AW
477 }
478
479 apply:
480 while (!SCM_RTL_PROGRAM_P (SCM_FRAME_PROGRAM (fp)))
481 {
510ca126
AW
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
9d87158f
AW
493 /* Shuffle args up. */
494 RESET_FRAME (n + 1);
510ca126
AW
495 while (n--)
496 LOCAL_SET (n + 1, LOCAL_REF (n));
510ca126 497
9d87158f 498 LOCAL_SET (0, SCM_SMOB_DESCRIPTOR (proc).apply_trampoline);
510ca126
AW
499 continue;
500 }
501
502 SYNC_IP();
503 vm_error_wrong_type_apply (proc);
510ca126
AW
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 *
af95414f 521 * Bring the VM to a halt, returning all the values from the stack.
510ca126
AW
522 */
523 VM_DEFINE_OP (0, halt, "halt", OP1 (U8_X24))
524 {
f8085163 525 scm_t_uint32 nvals = FRAME_LOCALS_COUNT() - 4;
af95414f 526 SCM ret;
510ca126 527
f8085163 528 /* Boot closure in r0, empty frame in r1/r2, proc in r3, values from r4. */
510ca126 529
af95414f 530 if (nvals == 1)
f8085163 531 ret = LOCAL_REF (4);
af95414f
AW
532 else
533 {
534 scm_t_uint32 n;
535 ret = SCM_EOL;
536 SYNC_BEFORE_GC();
537 for (n = nvals; n > 0; n--)
f8085163 538 ret = scm_cons (LOCAL_REF (4 + n - 1), ret);
af95414f
AW
539 ret = scm_values (ret);
540 }
510ca126
AW
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
af95414f 546 return ret;
286a0fb3
AW
547 }
548
af95414f 549 /* call proc:24 _:8 nlocals:24
286a0fb3 550 *
af95414f
AW
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.
510ca126 556 *
af95414f
AW
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.
510ca126 561 */
af95414f 562 VM_DEFINE_OP (1, call, "call", OP2 (U8_U24, X8_U24))
510ca126 563 {
af95414f 564 scm_t_uint32 proc, nlocals;
510ca126
AW
565 SCM *old_fp = fp;
566
af95414f
AW
567 SCM_UNPACK_RTL_24 (op, proc);
568 SCM_UNPACK_RTL_24 (ip[1], nlocals);
510ca126
AW
569
570 VM_HANDLE_INTERRUPTS;
571
af95414f 572 fp = vp->fp = old_fp + proc;
510ca126 573 SCM_FRAME_SET_DYNAMIC_LINK (fp, old_fp);
286a0fb3 574 SCM_FRAME_SET_RTL_RETURN_ADDRESS (fp, ip + 2);
510ca126 575
af95414f
AW
576 RESET_FRAME (nlocals);
577
510ca126
AW
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
af95414f 588 /* tail-call nlocals:24
510ca126 589 *
af95414f 590 * Tail-call a procedure. Requires that the procedure and all of the
486013d6
AW
591 * arguments have already been shuffled into position. Will reset the
592 * frame to NLOCALS.
510ca126 593 */
af95414f 594 VM_DEFINE_OP (2, tail_call, "tail-call", OP1 (U8_U24))
510ca126 595 {
af95414f
AW
596 scm_t_uint32 nlocals;
597
598 SCM_UNPACK_RTL_24 (op, nlocals);
510ca126
AW
599
600 VM_HANDLE_INTERRUPTS;
601
af95414f 602 RESET_FRAME (nlocals);
486013d6
AW
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
510ca126
AW
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
af95414f 645 /* receive dst:12 proc:12 _:8 nlocals:24
510ca126 646 *
af95414f
AW
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.
510ca126 650 */
486013d6 651 VM_DEFINE_OP (4, receive, "receive", OP2 (U8_U12_U12, X8_U24) | OP_DST)
510ca126 652 {
af95414f
AW
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 }
510ca126 662
82f4bac4 663 /* receive-values proc:24 allow-extra?:1 _:7 nvalues:24
af95414f
AW
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
82f4bac4
AW
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'.
af95414f 670 */
486013d6 671 VM_DEFINE_OP (5, receive_values, "receive-values", OP2 (U8_U24, B1_X7_U24))
af95414f
AW
672 {
673 scm_t_uint32 proc, nvalues;
674 SCM_UNPACK_RTL_24 (op, proc);
675 SCM_UNPACK_RTL_24 (ip[1], nvalues);
82f4bac4
AW
676 if (ip[1] & 0x1)
677 VM_ASSERT (FRAME_LOCALS_COUNT () > proc + nvalues,
678 vm_error_not_enough_values ());
679 else
186b56c4 680 VM_ASSERT (FRAME_LOCALS_COUNT () == proc + 1 + nvalues,
82f4bac4 681 vm_error_wrong_number_of_values (nvalues));
af95414f 682 NEXT (2);
510ca126
AW
683 }
684
685 /* return src:24
686 *
687 * Return a value.
688 */
486013d6 689 VM_DEFINE_OP (6, return, "return", OP1 (U8_U24))
510ca126
AW
690 {
691 scm_t_uint32 src;
692 SCM_UNPACK_RTL_24 (op, src);
693 RETURN_ONE_VALUE (LOCAL_REF (src));
694 }
695
84cc4127 696 /* return-values _:24
510ca126
AW
697 *
698 * Return a number of values from a call frame. This opcode
699 * corresponds to an application of `values' in tail position. As
af95414f
AW
700 * with tail calls, we expect that the values have already been
701 * shuffled down to a contiguous array starting at slot 1.
84cc4127 702 * We also expect the frame has already been reset.
510ca126 703 */
486013d6 704 VM_DEFINE_OP (7, return_values, "return-values", OP1 (U8_X24))
510ca126 705 {
84cc4127 706 scm_t_uint32 nvalues _GL_UNUSED = FRAME_LOCALS_COUNT();
af95414f
AW
707 SCM *base = fp;
708
af95414f 709 VM_HANDLE_INTERRUPTS;
840ec334 710 ip = SCM_FRAME_RTL_RETURN_ADDRESS (fp);
af95414f
AW
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;
af95414f
AW
716
717 POP_CONTINUATION_HOOK (base, nvalues);
718
719 NEXT (0);
510ca126
AW
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 */
486013d6 736 VM_DEFINE_OP (8, subr_call, "subr-call", OP1 (U8_U24))
510ca126
AW
737 {
738 scm_t_uint32 ptr_idx;
739 SCM pointer, ret;
740 SCM (*subr)();
741
742 SCM_UNPACK_RTL_24 (op, ptr_idx);
743
7396d216 744 pointer = SCM_RTL_PROGRAM_FREE_VARIABLE_REF (LOCAL_REF (0), ptr_idx);
510ca126
AW
745 subr = SCM_POINTER_VALUE (pointer);
746
747 VM_HANDLE_INTERRUPTS;
748 SYNC_IP ();
749
8d23c436 750 switch (FRAME_LOCALS_COUNT () - 1)
510ca126
AW
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 */
486013d6 806 VM_DEFINE_OP (9, foreign_call, "foreign-call", OP1 (U8_U12_U12))
510ca126
AW
807 {
808 scm_t_uint16 cif_idx, ptr_idx;
7396d216 809 SCM closure, cif, pointer, ret;
510ca126
AW
810
811 SCM_UNPACK_RTL_12_12 (op, cif_idx, ptr_idx);
812
7396d216
AW
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);
510ca126
AW
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 */
486013d6 840 VM_DEFINE_OP (10, continuation_call, "continuation-call", OP1 (U8_U24))
510ca126
AW
841 {
842 SCM contregs;
843 scm_t_uint32 contregs_idx;
844
845 SCM_UNPACK_RTL_24 (op, contregs_idx);
846
7396d216
AW
847 contregs =
848 SCM_RTL_PROGRAM_FREE_VARIABLE_REF (LOCAL_REF (0), contregs_idx);
510ca126
AW
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),
d691ac20 854 FRAME_LOCALS_COUNT () - 1, fp);
510ca126
AW
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 */
486013d6 869 VM_DEFINE_OP (11, compose_continuation, "compose-continuation", OP1 (U8_U24))
510ca126
AW
870 {
871 SCM vmcont;
872 scm_t_uint32 cont_idx;
873
874 SCM_UNPACK_RTL_24 (op, cont_idx);
d76de871 875 vmcont = SCM_RTL_PROGRAM_FREE_VARIABLE_REF (LOCAL_REF (0), cont_idx);
510ca126
AW
876
877 SYNC_IP ();
878 VM_ASSERT (SCM_VM_CONT_REWINDABLE_P (vmcont),
879 vm_error_continuation_not_rewindable (vmcont));
d691ac20 880 vm_reinstate_partial_continuation (vm, vmcont, FRAME_LOCALS_COUNT () - 1, fp,
510ca126
AW
881 &current_thread->dynstack,
882 &registers);
883 CACHE_REGISTER ();
884 NEXT (0);
885 }
886
adb8d905 887 /* tail-apply _:24
510ca126
AW
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 */
486013d6 893 VM_DEFINE_OP (12, tail_apply, "tail-apply", OP1 (U8_X24))
510ca126 894 {
e93c0430 895 int i, list_idx, list_len, nlocals;
510ca126
AW
896 SCM list;
897
898 VM_HANDLE_INTERRUPTS;
899
e93c0430
AW
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;
510ca126
AW
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
e93c0430
AW
909 nlocals = nlocals - 2 + list_len;
910 ALLOC_FRAME (nlocals);
510ca126 911
e93c0430
AW
912 for (i = 1; i < list_idx; i++)
913 LOCAL_SET (i - 1, LOCAL_REF (i));
510ca126
AW
914
915 /* Null out these slots, just in case there are less than 2 elements
916 in the list. */
7396d216
AW
917 LOCAL_SET (list_idx - 1, SCM_UNDEFINED);
918 LOCAL_SET (list_idx, SCM_UNDEFINED);
510ca126
AW
919
920 for (i = 0; i < list_len; i++, list = SCM_CDR (list))
7396d216 921 LOCAL_SET (list_idx - 1 + i, SCM_CAR (list));
510ca126
AW
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
d691ac20 935 * local slot 1 to it. This instruction is part of the implementation
510ca126
AW
936 * of `call/cc', and is not generated by the compiler.
937 */
486013d6 938 VM_DEFINE_OP (13, call_cc, "call/cc", OP1 (U8_X24))
510ca126
AW
939 {
940 SCM vm_cont, cont;
941 scm_t_dynstack *dynstack;
d691ac20 942 int first;
510ca126
AW
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),
510ca126
AW
952 dynstack,
953 0);
d691ac20
AW
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);
510ca126 966
d691ac20 967 APPLY_HOOK ();
510ca126 968
d691ac20
AW
969 if (SCM_UNLIKELY (!SCM_RTL_PROGRAM_P (SCM_FRAME_PROGRAM (fp))))
970 goto apply;
510ca126 971
d691ac20
AW
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 }
510ca126 981 }
510ca126 982
486013d6
AW
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);
186b56c4
AW
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++;
486013d6
AW
998 SYNC_IP ();
999 vm_abort (vm, LOCAL_REF (1), nlocals - 2, &LOCAL_REF (2),
186b56c4 1000 SCM_EOL, &LOCAL_REF (0), &registers);
486013d6
AW
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
510ca126
AW
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 */
486013d6 1035 VM_DEFINE_OP (16, br_if_nargs_ne, "br-if-nargs-ne", OP2 (U8_U24, X8_L24))
510ca126
AW
1036 {
1037 BR_NARGS (!=);
1038 }
486013d6 1039 VM_DEFINE_OP (17, br_if_nargs_lt, "br-if-nargs-lt", OP2 (U8_U24, X8_L24))
510ca126
AW
1040 {
1041 BR_NARGS (<);
1042 }
486013d6 1043 VM_DEFINE_OP (18, br_if_nargs_gt, "br-if-nargs-gt", OP2 (U8_U24, X8_L24))
510ca126
AW
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 */
486013d6 1055 VM_DEFINE_OP (19, assert_nargs_ee, "assert-nargs-ee", OP1 (U8_U24))
510ca126
AW
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 }
486013d6 1063 VM_DEFINE_OP (20, assert_nargs_ge, "assert-nargs-ge", OP1 (U8_U24))
510ca126
AW
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 }
486013d6 1071 VM_DEFINE_OP (21, assert_nargs_le, "assert-nargs-le", OP1 (U8_U24))
510ca126
AW
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
af95414f 1080 /* alloc-frame nlocals:24
510ca126
AW
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
7396d216 1084 * were passed as arguments and procedure.
510ca126 1085 */
486013d6 1086 VM_DEFINE_OP (22, alloc_frame, "alloc-frame", OP1 (U8_U24))
510ca126
AW
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
af95414f
AW
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 */
486013d6 1105 VM_DEFINE_OP (23, reset_frame, "reset-frame", OP1 (U8_U24))
af95414f
AW
1106 {
1107 scm_t_uint32 nlocals;
1108 SCM_UNPACK_RTL_24 (op, nlocals);
1109 RESET_FRAME (nlocals);
1110 NEXT (1);
1111 }
1112
510ca126
AW
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 */
486013d6 1118 VM_DEFINE_OP (24, assert_nargs_ee_locals, "assert-nargs-ee/locals", OP1 (U8_U12_U12))
510ca126
AW
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
f90c0554
AW
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
510ca126
AW
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 */
f90c0554 1178 VM_DEFINE_OP (26, bind_kwargs, "bind-kwargs", OP4 (U8_U24, U8_U24, X8_U24, N32))
510ca126
AW
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,
28d5d253
MW
1237 vm_error_kwargs_unrecognized_keyword (SCM_FRAME_PROGRAM (fp),
1238 LOCAL_REF (ntotal + n)));
510ca126
AW
1239 n++;
1240 }
1241 else
28d5d253
MW
1242 VM_ASSERT (has_rest, vm_error_kwargs_invalid_keyword (SCM_FRAME_PROGRAM (fp),
1243 LOCAL_REF (ntotal + n)));
510ca126
AW
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 */
f90c0554 1264 VM_DEFINE_OP (27, bind_rest, "bind-rest", OP1 (U8_U24) | OP_DST)
510ca126
AW
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
234155e3 1272 if (nargs <= dst)
510ca126 1273 {
234155e3
AW
1274 ALLOC_FRAME (dst + 1);
1275 while (nargs < dst)
1276 LOCAL_SET (nargs++, SCM_UNDEFINED);
510ca126 1277 }
234155e3
AW
1278 else
1279 {
1280 while (nargs-- > dst)
1281 {
1282 rest = scm_cons (LOCAL_REF (nargs), rest);
1283 LOCAL_SET (nargs, SCM_UNDEFINED);
1284 }
510ca126 1285
234155e3
AW
1286 RESET_FRAME (dst + 1);
1287 }
510ca126 1288
234155e3 1289 LOCAL_SET (dst, rest);
510ca126
AW
1290
1291 NEXT (1);
1292 }
1293
510ca126
AW
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 */
f90c0554 1306 VM_DEFINE_OP (28, br, "br", OP1 (U8_L24))
510ca126
AW
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 */
f90c0554 1318 VM_DEFINE_OP (29, br_if_true, "br-if-true", OP2 (U8_U24, B1_X7_L24))
510ca126
AW
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 */
f90c0554 1328 VM_DEFINE_OP (30, br_if_null, "br-if-null", OP2 (U8_U24, B1_X7_L24))
510ca126
AW
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 */
f90c0554 1338 VM_DEFINE_OP (31, br_if_nil, "br-if-nil", OP2 (U8_U24, B1_X7_L24))
510ca126
AW
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 */
f90c0554 1348 VM_DEFINE_OP (32, br_if_pair, "br-if-pair", OP2 (U8_U24, B1_X7_L24))
510ca126
AW
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 */
f90c0554 1358 VM_DEFINE_OP (33, br_if_struct, "br-if-struct", OP2 (U8_U24, B1_X7_L24))
510ca126
AW
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 */
f90c0554 1368 VM_DEFINE_OP (34, br_if_char, "br-if-char", OP2 (U8_U24, B1_X7_L24))
510ca126
AW
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 */
f90c0554 1378 VM_DEFINE_OP (35, br_if_tc7, "br-if-tc7", OP2 (U8_U24, B1_U7_L24))
510ca126
AW
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 */
f90c0554 1388 VM_DEFINE_OP (36, br_if_eq, "br-if-eq", OP2 (U8_U12_U12, B1_X7_L24))
510ca126
AW
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 */
f90c0554 1398 VM_DEFINE_OP (37, br_if_eqv, "br-if-eqv", OP2 (U8_U12_U12, B1_X7_L24))
510ca126
AW
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
af95414f 1406 // FIXME: remove, have compiler inline eqv test instead
510ca126
AW
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?
f90c0554 1413 VM_DEFINE_OP (38, br_if_equal, "br-if-equal", OP2 (U8_U12_U12, B1_X7_L24))
510ca126
AW
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
af95414f 1421 /* br-if-= a:12 b:12 invert:1 _:7 offset:24
510ca126
AW
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 */
f90c0554 1426 VM_DEFINE_OP (39, br_if_ee, "br-if-=", OP2 (U8_U12_U12, B1_X7_L24))
510ca126
AW
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 */
f90c0554 1436 VM_DEFINE_OP (40, br_if_lt, "br-if-<", OP2 (U8_U12_U12, B1_X7_L24))
510ca126
AW
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 */
f90c0554 1446 VM_DEFINE_OP (41, br_if_le, "br-if-<=", OP2 (U8_U12_U12, B1_X7_L24))
510ca126
AW
1447 {
1448 BR_ARITHMETIC (<=, scm_leq_p);
1449 }
1450
510ca126
AW
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 */
f90c0554 1462 VM_DEFINE_OP (42, mov, "mov", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
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 */
f90c0554 1477 VM_DEFINE_OP (43, long_mov, "long-mov", OP2 (U8_U24, X8_U24) | OP_DST)
510ca126
AW
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 */
f90c0554 1493 VM_DEFINE_OP (44, box, "box", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
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
510ca126
AW
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 */
f90c0554 1506 VM_DEFINE_OP (45, box_ref, "box-ref", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
1507 {
1508 scm_t_uint16 dst, src;
1509 SCM var;
1510 SCM_UNPACK_RTL_12_12 (op, dst, src);
1511 var = LOCAL_REF (src);
4f406fea
AW
1512 VM_ASSERT (SCM_VARIABLEP (var),
1513 vm_error_not_a_variable ("variable-ref", var));
af95414f
AW
1514 VM_ASSERT (VARIABLE_BOUNDP (var),
1515 vm_error_unbound (SCM_FRAME_PROGRAM (fp), var));
510ca126
AW
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 */
f90c0554 1524 VM_DEFINE_OP (46, box_set, "box-set!", OP1 (U8_U12_U12))
510ca126
AW
1525 {
1526 scm_t_uint16 dst, src;
1527 SCM var;
1528 SCM_UNPACK_RTL_12_12 (op, dst, src);
1529 var = LOCAL_REF (dst);
4f406fea
AW
1530 VM_ASSERT (SCM_VARIABLEP (var),
1531 vm_error_not_a_variable ("variable-set!", var));
510ca126
AW
1532 VARIABLE_SET (var, LOCAL_REF (src));
1533 NEXT (1);
1534 }
1535
7396d216 1536 /* make-closure dst:24 offset:32 _:8 nfree:24
510ca126
AW
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
7396d216
AW
1540 * signed 32-bit integer. Space for NFREE free variables will be
1541 * allocated.
510ca126 1542 */
f90c0554 1543 VM_DEFINE_OP (47, make_closure, "make-closure", OP3 (U8_U24, L32, X8_U24) | OP_DST)
510ca126
AW
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);
7396d216 1556 // FIXME: Elide these initializations?
510ca126 1557 for (n = 0; n < nfree; n++)
7396d216 1558 SCM_RTL_PROGRAM_FREE_VARIABLE_SET (closure, n, SCM_BOOL_F);
510ca126 1559 LOCAL_SET (dst, closure);
7396d216 1560 NEXT (3);
510ca126
AW
1561 }
1562
7396d216 1563 /* free-ref dst:12 src:12 _:8 idx:24
510ca126 1564 *
7396d216 1565 * Load free variable IDX from the closure SRC into local slot DST.
510ca126 1566 */
f90c0554 1567 VM_DEFINE_OP (48, free_ref, "free-ref", OP2 (U8_U12_U12, X8_U24) | OP_DST)
510ca126 1568 {
7396d216
AW
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 }
510ca126 1577
7396d216
AW
1578 /* free-set! dst:12 src:12 _8 idx:24
1579 *
1580 * Set free variable IDX from the closure DST to SRC.
1581 */
f90c0554 1582 VM_DEFINE_OP (49, free_set, "free-set!", OP2 (U8_U12_U12, X8_U24))
7396d216
AW
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);
510ca126
AW
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 */
f90c0554 1605 VM_DEFINE_OP (50, make_short_immediate, "make-short-immediate", OP1 (U8_U8_I16) | OP_DST)
510ca126
AW
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 */
f90c0554 1620 VM_DEFINE_OP (51, make_long_immediate, "make-long-immediate", OP2 (U8_U24, I32))
510ca126 1621 {
da60ba80 1622 scm_t_uint32 dst;
510ca126
AW
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 */
f90c0554 1635 VM_DEFINE_OP (52, make_long_long_immediate, "make-long-long-immediate", OP3 (U8_U24, A32, B32) | OP_DST)
510ca126 1636 {
da60ba80 1637 scm_t_uint32 dst;
510ca126
AW
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 */
f90c0554 1666 VM_DEFINE_OP (53, make_non_immediate, "make-non-immediate", OP2 (U8_U24, N32) | OP_DST)
510ca126
AW
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 */
f90c0554 1695 VM_DEFINE_OP (54, static_ref, "static-ref", OP2 (U8_U24, S32))
510ca126
AW
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 */
f90c0554 1718 VM_DEFINE_OP (55, static_set, "static-set!", OP2 (U8_U24, LO32))
510ca126
AW
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
2ab2a10d 1734 /* static-patch! _:24 dst-offset:32 src-offset:32
510ca126 1735 *
2ab2a10d
AW
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.
510ca126 1739 */
f90c0554 1740 VM_DEFINE_OP (56, static_patch, "static-patch!", OP3 (U8_X24, LO32, L32))
510ca126 1741 {
2ab2a10d
AW
1742 scm_t_int32 dst_offset, src_offset;
1743 void *src;
1744 void** dst_loc;
510ca126 1745
2ab2a10d
AW
1746 dst_offset = ip[1];
1747 src_offset = ip[2];
510ca126 1748
2ab2a10d
AW
1749 dst_loc = (void **) (ip + dst_offset);
1750 src = ip + src_offset;
1751 VM_ASSERT (ALIGNED_P (dst_loc, void*), abort());
510ca126 1752
2ab2a10d
AW
1753 *dst_loc = src;
1754
1755 NEXT (3);
510ca126
AW
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
af95414f
AW
1785 The toplevel-box instruction is equivalent to "resolve", but
1786 caches the resulting variable in statically allocated memory.
510ca126
AW
1787
1788 3. A reference to an identifier with respect to a particular
1789 module. This can happen for primitive references, and
af95414f
AW
1790 references residualized by macro expansions. These can always
1791 be cached. Use module-box for these.
510ca126
AW
1792 */
1793
1794 /* current-module dst:24
1795 *
1796 * Store the current module in DST.
1797 */
f90c0554 1798 VM_DEFINE_OP (57, current_module, "current-module", OP1 (U8_U24) | OP_DST)
510ca126
AW
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
af95414f 1810 /* resolve dst:24 bound?:1 _:7 sym:24
510ca126 1811 *
af95414f
AW
1812 * Resolve SYM in the current module, and place the resulting variable
1813 * in DST.
510ca126 1814 */
f90c0554 1815 VM_DEFINE_OP (58, resolve, "resolve", OP2 (U8_U24, B1_X7_U24) | OP_DST)
510ca126 1816 {
af95414f
AW
1817 scm_t_uint32 dst;
1818 scm_t_uint32 sym;
1819 SCM var;
510ca126 1820
af95414f
AW
1821 SCM_UNPACK_RTL_24 (op, dst);
1822 SCM_UNPACK_RTL_24 (ip[1], sym);
510ca126
AW
1823
1824 SYNC_IP ();
af95414f
AW
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);
510ca126 1830
af95414f 1831 NEXT (2);
510ca126
AW
1832 }
1833
6165d812 1834 /* define! sym:12 val:12
510ca126
AW
1835 *
1836 * Look up a binding for SYM in the current module, creating it if
1837 * necessary. Set its value to VAL.
1838 */
f90c0554 1839 VM_DEFINE_OP (59, define, "define!", OP1 (U8_U12_U12))
510ca126
AW
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
af95414f 1848 /* toplevel-box dst:24 var-offset:32 mod-offset:32 sym-offset:32 bound?:1 _:31
510ca126
AW
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.
af95414f 1852 * VAR-OFFSET is a signed value. Up to here, toplevel-box is like
510ca126
AW
1853 * static-ref.
1854 *
af95414f
AW
1855 * Then, if the loaded value is a variable, it is placed in DST, and control
1856 * flow continues.
510ca126
AW
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 *
af95414f
AW
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.
510ca126 1866 */
f90c0554 1867 VM_DEFINE_OP (60, toplevel_box, "toplevel-box", OP5 (U8_U24, S32, S32, N32, B1_X31) | OP_DST)
510ca126
AW
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
e23f9e44
AW
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
510ca126 1903 var = scm_module_lookup (mod, sym);
af95414f
AW
1904 if (ip[4] & 0x1)
1905 VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (fp[-1], sym));
510ca126
AW
1906
1907 *var_loc = var;
1908 }
1909
af95414f
AW
1910 LOCAL_SET (dst, var);
1911 NEXT (5);
510ca126
AW
1912 }
1913
af95414f 1914 /* module-box dst:24 var-offset:32 mod-offset:32 sym-offset:32 bound?:1 _:31
510ca126 1915 *
af95414f 1916 * Like toplevel-box, except MOD-OFFSET points at the name of a module
510ca126
AW
1917 * instead of the module itself.
1918 */
f90c0554 1919 VM_DEFINE_OP (61, module_box, "module-box", OP5 (U8_U24, S32, N32, N32, B1_X31) | OP_DST)
510ca126
AW
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
e23f9e44
AW
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)))
510ca126
AW
1962 var = scm_public_lookup (SCM_CDR (modname), sym);
1963 else
1964 var = scm_private_lookup (SCM_CDR (modname), sym);
1965
af95414f
AW
1966 if (ip[4] & 0x1)
1967 VM_ASSERT (VARIABLE_BOUNDP (var), vm_error_unbound (fp[-1], sym));
510ca126
AW
1968
1969 *var_loc = var;
1970 }
1971
af95414f
AW
1972 LOCAL_SET (dst, var);
1973 NEXT (5);
510ca126
AW
1974 }
1975
1976 \f
1977
1978 /*
1979 * The dynamic environment
1980 */
1981
8d59d55e 1982 /* prompt tag:24 escape-only?:1 _:7 proc-slot:24 _:8 handler-offset:24
510ca126
AW
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
8d59d55e
AW
1986 * will expect a multiple-value return as if from a call with the
1987 * procedure at PROC-SLOT.
510ca126 1988 */
f90c0554 1989 VM_DEFINE_OP (62, prompt, "prompt", OP3 (U8_U24, B1_X7_U24, X8_L24))
510ca126 1990 {
8d59d55e 1991 scm_t_uint32 tag, proc_slot;
510ca126
AW
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);
8d59d55e
AW
1997 escape_only_p = ip[1] & 0x1;
1998 SCM_UNPACK_RTL_24 (ip[1], proc_slot);
1999 offset = ip[2];
510ca126
AW
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),
8d59d55e
AW
2006 fp,
2007 &LOCAL_REF (proc_slot),
2008 (scm_t_uint8 *)(ip + offset),
2009 &registers);
2010 NEXT (3);
510ca126 2011 }
510ca126
AW
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 */
f90c0554 2021 VM_DEFINE_OP (63, wind, "wind", OP1 (U8_U12_U12))
510ca126
AW
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
510ca126
AW
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 */
f90c0554 2035 VM_DEFINE_OP (64, unwind, "unwind", OP1 (U8_X24))
510ca126
AW
2036 {
2037 scm_dynstack_pop (&current_thread->dynstack);
2038 NEXT (1);
2039 }
2040
98eaef1b 2041 /* push-fluid fluid:12 value:12
510ca126
AW
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 */
f90c0554 2047 VM_DEFINE_OP (65, push_fluid, "push-fluid", OP1 (U8_U12_U12))
510ca126 2048 {
98eaef1b 2049 scm_t_uint32 fluid, value;
510ca126 2050
98eaef1b 2051 SCM_UNPACK_RTL_12_12 (op, fluid, value);
510ca126 2052
98eaef1b 2053 scm_dynstack_push_fluid (&current_thread->dynstack,
2a4ee2ac 2054 LOCAL_REF (fluid), LOCAL_REF (value),
98eaef1b
AW
2055 current_thread->dynamic_state);
2056 NEXT (1);
510ca126 2057 }
510ca126 2058
98eaef1b 2059 /* pop-fluid _:24
510ca126
AW
2060 *
2061 * Leave the dynamic extent of a with-fluids expression, restoring the
2062 * fluids to their previous values.
2063 */
f90c0554 2064 VM_DEFINE_OP (66, pop_fluid, "pop-fluid", OP1 (U8_X24))
510ca126
AW
2065 {
2066 /* This function must not allocate. */
98eaef1b
AW
2067 scm_dynstack_unwind_fluid (&current_thread->dynstack,
2068 current_thread->dynamic_state);
510ca126
AW
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 */
f90c0554 2076 VM_DEFINE_OP (67, fluid_ref, "fluid-ref", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
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 */
f90c0554 2109 VM_DEFINE_OP (68, fluid_set, "fluid-set", OP1 (U8_U12_U12))
510ca126
AW
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 */
f90c0554 2142 VM_DEFINE_OP (69, string_length, "string-length", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
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 */
f90c0554 2159 VM_DEFINE_OP (70, string_ref, "string-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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 */
f90c0554 2181 VM_DEFINE_OP (71, string_to_number, "string->number", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
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 */
f90c0554 2197 VM_DEFINE_OP (72, string_to_symbol, "string->symbol", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
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 */
f90c0554 2211 VM_DEFINE_OP (73, symbol_to_keyword, "symbol->keyword", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
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 */
f90c0554 2230 VM_DEFINE_OP (74, cons, "cons", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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 */
f90c0554 2240 VM_DEFINE_OP (75, car, "car", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
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 */
f90c0554 2251 VM_DEFINE_OP (76, cdr, "cdr", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
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 */
f90c0554 2262 VM_DEFINE_OP (77, set_car, "set-car!", OP1 (U8_U12_U12))
510ca126
AW
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 */
f90c0554 2278 VM_DEFINE_OP (78, set_cdr, "set-cdr!", OP1 (U8_U12_U12))
510ca126
AW
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 */
f90c0554 2301 VM_DEFINE_OP (79, add, "add", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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 */
f90c0554 2310 VM_DEFINE_OP (80, add1, "add1", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2311 {
2312 ARGS1 (x);
2313
d2295ba5
MW
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))
510ca126
AW
2317 {
2318 SCM result;
2319
d2295ba5
MW
2320 /* Add 1 to the integer without untagging. */
2321 result = SCM_PACK ((scm_t_signed_bits) SCM_UNPACK (x) + INUM_STEP);
510ca126
AW
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 */
f90c0554 2335 VM_DEFINE_OP (81, sub, "sub", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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 */
f90c0554 2344 VM_DEFINE_OP (82, sub1, "sub1", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2345 {
2346 ARGS1 (x);
2347
d2295ba5
MW
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))
510ca126
AW
2351 {
2352 SCM result;
2353
d2295ba5
MW
2354 /* Substract 1 from the integer without untagging. */
2355 result = SCM_PACK ((scm_t_signed_bits) SCM_UNPACK (x) - INUM_STEP);
510ca126
AW
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 */
f90c0554 2369 VM_DEFINE_OP (83, mul, "mul", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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 */
f90c0554 2380 VM_DEFINE_OP (84, div, "div", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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 */
f90c0554 2391 VM_DEFINE_OP (85, quo, "quo", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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 */
f90c0554 2402 VM_DEFINE_OP (86, rem, "rem", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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 */
f90c0554 2413 VM_DEFINE_OP (87, mod, "mod", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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 */
f90c0554 2424 VM_DEFINE_OP (88, ash, "ash", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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. */
0bd65965
MW
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)));
510ca126
AW
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 */
f90c0554 2460 VM_DEFINE_OP (89, logand, "logand", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2461 {
2462 ARGS2 (x, y);
2463 if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
e7f64971
MW
2464 /* Compute bitwise AND without untagging */
2465 RETURN (SCM_PACK (SCM_UNPACK (x) & SCM_UNPACK (y)));
510ca126
AW
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 */
f90c0554 2474 VM_DEFINE_OP (90, logior, "logior", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2475 {
2476 ARGS2 (x, y);
2477 if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
e7f64971
MW
2478 /* Compute bitwise OR without untagging */
2479 RETURN (SCM_PACK (SCM_UNPACK (x) | SCM_UNPACK (y)));
510ca126
AW
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 */
f90c0554 2488 VM_DEFINE_OP (91, logxor, "logxor", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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
4c906ad5 2497 /* make-vector/immediate dst:8 length:8 init:8
607fe5a6
AW
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 */
4c906ad5 2503 VM_DEFINE_OP (92, make_vector_immediate, "make-vector/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
607fe5a6
AW
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
510ca126
AW
2519 /* vector-length dst:12 src:12
2520 *
2521 * Store the length of the vector in SRC in DST.
2522 */
4c906ad5 2523 VM_DEFINE_OP (93, vector_length, "vector-length", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
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 */
4c906ad5 2540 VM_DEFINE_OP (94, vector_ref, "vector-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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
4c906ad5 2556 /* vector-ref/immediate dst:8 src:8 idx:8
510ca126
AW
2557 *
2558 * Fill DST with the item IDX elements into the vector at SRC. Useful
2559 * for building data types using vectors.
2560 */
4c906ad5 2561 VM_DEFINE_OP (95, vector_ref_immediate, "vector-ref/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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 */
4c906ad5 2580 VM_DEFINE_OP (96, vector_set, "vector-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
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
4c906ad5 2604 /* vector-set!/immediate dst:8 idx:8 src:8
8ba3f20c
AW
2605 *
2606 * Store SRC into the vector DST at index IDX. Here IDX is an
2607 * immediate value.
2608 */
4c906ad5 2609 VM_DEFINE_OP (97, vector_set_immediate, "vector-set!/immediate", OP1 (U8_U8_U8_U8))
8ba3f20c
AW
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
510ca126
AW
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 */
4c906ad5 2640 VM_DEFINE_OP (98, struct_vtable, "struct-vtable", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2641 {
2642 ARGS1 (obj);
2643 VM_VALIDATE_STRUCT (obj, "struct_vtable");
2644 RETURN (SCM_STRUCT_VTABLE (obj));
2645 }
2646
4c906ad5 2647 /* allocate-struct/immediate dst:8 vtable:8 nfields:8
510ca126 2648 *
14d10292
AW
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.
510ca126 2652 */
4c906ad5 2653 VM_DEFINE_OP (99, allocate_struct_immediate, "allocate-struct/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126 2654 {
14d10292
AW
2655 scm_t_uint8 dst, vtable, nfields;
2656 SCM ret;
510ca126 2657
14d10292 2658 SCM_UNPACK_RTL_8_8_8 (op, dst, vtable, nfields);
510ca126
AW
2659
2660 SYNC_IP ();
14d10292 2661 ret = scm_allocate_struct (LOCAL_REF (vtable), SCM_I_MAKINUM (nfields));
510ca126 2662 LOCAL_SET (dst, ret);
14d10292
AW
2663
2664 NEXT (1);
510ca126 2665 }
510ca126 2666
4c906ad5 2667 /* struct-ref/immediate dst:8 src:8 idx:8
510ca126
AW
2668 *
2669 * Fetch the item at slot IDX in the struct in SRC, and store it
4c906ad5 2670 * in DST. IDX is an immediate unsigned 8-bit value.
510ca126 2671 */
4c906ad5 2672 VM_DEFINE_OP (100, struct_ref_immediate, "struct-ref/immediate", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126 2673 {
4c906ad5
AW
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);
510ca126
AW
2680
2681 if (SCM_LIKELY (SCM_STRUCTP (obj)
2682 && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj,
2683 SCM_VTABLE_FLAG_SIMPLE)
4c906ad5
AW
2684 && idx < SCM_STRUCT_DATA_REF (SCM_STRUCT_VTABLE (obj),
2685 scm_vtable_index_size)))
2686 RETURN (SCM_STRUCT_SLOT_REF (obj, idx));
510ca126
AW
2687
2688 SYNC_IP ();
4c906ad5 2689 RETURN (scm_struct_ref (obj, SCM_I_MAKINUM (idx)));
510ca126
AW
2690 }
2691
4c906ad5 2692 /* struct-set!/immediate dst:8 idx:8 src:8
510ca126 2693 *
4c906ad5
AW
2694 * Store SRC into the struct DST at slot IDX. IDX is an immediate
2695 * unsigned 8-bit value.
510ca126 2696 */
4c906ad5 2697 VM_DEFINE_OP (101, struct_set_immediate, "struct-set!/immediate", OP1 (U8_U8_U8_U8))
510ca126
AW
2698 {
2699 scm_t_uint8 dst, idx, src;
4c906ad5
AW
2700 SCM obj, val;
2701
510ca126 2702 SCM_UNPACK_RTL_8_8_8 (op, dst, idx, src);
4c906ad5 2703
510ca126 2704 obj = LOCAL_REF (dst);
510ca126 2705 val = LOCAL_REF (src);
4c906ad5 2706
510ca126
AW
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)
4c906ad5
AW
2712 && idx < SCM_STRUCT_DATA_REF (SCM_STRUCT_VTABLE (obj),
2713 scm_vtable_index_size)))
510ca126 2714 {
4c906ad5
AW
2715 SCM_STRUCT_SLOT_SET (obj, idx, val);
2716 NEXT (1);
510ca126
AW
2717 }
2718
2719 SYNC_IP ();
4c906ad5 2720 scm_struct_set_x (obj, SCM_I_MAKINUM (idx), val);
510ca126
AW
2721 NEXT (1);
2722 }
2723
2724 /* class-of dst:12 type:12
2725 *
2726 * Store the vtable of SRC into DST.
2727 */
4c906ad5 2728 VM_DEFINE_OP (102, class_of, "class-of", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
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 */
4c906ad5 2743 VM_DEFINE_OP (103, slot_ref, "slot-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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 */
4c906ad5 2757 VM_DEFINE_OP (104, slot_set, "slot-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
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 */
4c906ad5 2778 VM_DEFINE_OP (105, load_typed_array, "load-typed-array", OP3 (U8_U8_U8_U8, N32, U32) | OP_DST)
510ca126
AW
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 */
4c906ad5 2798 VM_DEFINE_OP (106, make_array, "make-array", OP2 (U8_U12_U12, X8_U12_U12) | OP_DST)
510ca126
AW
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
4c906ad5 2896 VM_DEFINE_OP (107, bv_u8_ref, "bv-u8-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2897 BV_FIXABLE_INT_REF (u8, u8, uint8, 1);
2898
4c906ad5 2899 VM_DEFINE_OP (108, bv_s8_ref, "bv-s8-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2900 BV_FIXABLE_INT_REF (s8, s8, int8, 1);
2901
4c906ad5 2902 VM_DEFINE_OP (109, bv_u16_ref, "bv-u16-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2903 BV_FIXABLE_INT_REF (u16, u16_native, uint16, 2);
2904
4c906ad5 2905 VM_DEFINE_OP (110, bv_s16_ref, "bv-s16-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2906 BV_FIXABLE_INT_REF (s16, s16_native, int16, 2);
2907
4c906ad5 2908 VM_DEFINE_OP (111, bv_u32_ref, "bv-u32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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
4c906ad5 2915 VM_DEFINE_OP (112, bv_s32_ref, "bv-s32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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
4c906ad5 2922 VM_DEFINE_OP (113, bv_u64_ref, "bv-u64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2923 BV_INT_REF (u64, uint64, 8);
2924
4c906ad5 2925 VM_DEFINE_OP (114, bv_s64_ref, "bv-s64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2926 BV_INT_REF (s64, int64, 8);
2927
4c906ad5 2928 VM_DEFINE_OP (115, bv_f32_ref, "bv-f32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2929 BV_FLOAT_REF (f32, ieee_single, float, 4);
2930
4c906ad5 2931 VM_DEFINE_OP (116, bv_f64_ref, "bv-f64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
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); \
ecbef966 2959 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set!"); \
510ca126
AW
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); \
ecbef966 2990 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set!"); \
510ca126
AW
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); \
ecbef966 3018 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set!"); \
510ca126
AW
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
4c906ad5 3035 VM_DEFINE_OP (117, bv_u8_set, "bv-u8-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3036 BV_FIXABLE_INT_SET (u8, u8, uint8, 0, SCM_T_UINT8_MAX, 1);
3037
4c906ad5 3038 VM_DEFINE_OP (118, bv_s8_set, "bv-s8-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3039 BV_FIXABLE_INT_SET (s8, s8, int8, SCM_T_INT8_MIN, SCM_T_INT8_MAX, 1);
3040
4c906ad5 3041 VM_DEFINE_OP (119, bv_u16_set, "bv-u16-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3042 BV_FIXABLE_INT_SET (u16, u16_native, uint16, 0, SCM_T_UINT16_MAX, 2);
3043
4c906ad5 3044 VM_DEFINE_OP (120, bv_s16_set, "bv-s16-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3045 BV_FIXABLE_INT_SET (s16, s16_native, int16, SCM_T_INT16_MIN, SCM_T_INT16_MAX, 2);
3046
4c906ad5 3047 VM_DEFINE_OP (121, bv_u32_set, "bv-u32-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
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
4c906ad5 3054 VM_DEFINE_OP (122, bv_s32_set, "bv-s32-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
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
4c906ad5 3061 VM_DEFINE_OP (123, bv_u64_set, "bv-u64-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3062 BV_INT_SET (u64, uint64, 8);
3063
4c906ad5 3064 VM_DEFINE_OP (124, bv_s64_set, "bv-s64-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3065 BV_INT_SET (s64, int64, 8);
3066
4c906ad5 3067 VM_DEFINE_OP (125, bv_f32_set, "bv-f32-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3068 BV_FLOAT_SET (f32, ieee_single, float, 4);
3069
4c906ad5 3070 VM_DEFINE_OP (126, bv_f64_set, "bv-f64-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
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*/
17e90c5e
KN
3148/*
3149 Local Variables:
3150 c-file-style: "gnu"
3151 End:
3152*/