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