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