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