call is no longer a vararg instruction
[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
2500 /* abort tag:24 _:8 nvalues:24 val0:24 0:8 val1:24 0:8 ...
2501 *
2502 * Return a number of values to a prompt handler. The values VAL0,
2503 * VAL1, etc are 24-bit values, in the lower 24 bits of their words.
2504 * The upper 8 bits are 0.
2505 */
286a0fb3 2506 VM_DEFINE_OP (68, abort, "abort", OP2 (U8_U24, X8_R24))
510ca126
AW
2507#if 0
2508 {
2509 scm_t_uint32 tag, nvalues;
2510
2511 SCM_UNPACK_RTL_24 (op, tag);
2512 SCM_UNPACK_RTL_24 (ip[1], nvalues);
2513
2514 SYNC_IP ();
2515 vm_abort (vm, LOCAL_REF (tag), nvalues, &ip[2], &registers);
2516
2517 /* vm_abort should not return */
2518 abort ();
2519 }
2520#else
2521 abort();
2522#endif
2523
2524 /* unwind _:24
2525 *
2526 * A normal exit from the dynamic extent of an expression. Pop the top
2527 * entry off of the dynamic stack.
2528 */
286a0fb3 2529 VM_DEFINE_OP (69, unwind, "unwind", OP1 (U8_X24))
510ca126
AW
2530 {
2531 scm_dynstack_pop (&current_thread->dynstack);
2532 NEXT (1);
2533 }
2534
98eaef1b 2535 /* push-fluid fluid:12 value:12
510ca126
AW
2536 *
2537 * Dynamically bind N fluids to values. The fluids are expected to be
2538 * allocated in a continguous range on the stack, starting from
2539 * FLUID-BASE. The values do not have this restriction.
2540 */
286a0fb3 2541 VM_DEFINE_OP (70, push_fluid, "push-fluid", OP1 (U8_U12_U12))
510ca126 2542 {
98eaef1b 2543 scm_t_uint32 fluid, value;
510ca126 2544
98eaef1b 2545 SCM_UNPACK_RTL_12_12 (op, fluid, value);
510ca126 2546
98eaef1b
AW
2547 scm_dynstack_push_fluid (&current_thread->dynstack,
2548 fp[fluid], fp[value],
2549 current_thread->dynamic_state);
2550 NEXT (1);
510ca126 2551 }
510ca126 2552
98eaef1b 2553 /* pop-fluid _:24
510ca126
AW
2554 *
2555 * Leave the dynamic extent of a with-fluids expression, restoring the
2556 * fluids to their previous values.
2557 */
286a0fb3 2558 VM_DEFINE_OP (71, pop_fluid, "pop-fluid", OP1 (U8_X24))
510ca126
AW
2559 {
2560 /* This function must not allocate. */
98eaef1b
AW
2561 scm_dynstack_unwind_fluid (&current_thread->dynstack,
2562 current_thread->dynamic_state);
510ca126
AW
2563 NEXT (1);
2564 }
2565
2566 /* fluid-ref dst:12 src:12
2567 *
2568 * Reference the fluid in SRC, and place the value in DST.
2569 */
286a0fb3 2570 VM_DEFINE_OP (72, fluid_ref, "fluid-ref", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2571 {
2572 scm_t_uint16 dst, src;
2573 size_t num;
2574 SCM fluid, fluids;
2575
2576 SCM_UNPACK_RTL_12_12 (op, dst, src);
2577 fluid = LOCAL_REF (src);
2578 fluids = SCM_I_DYNAMIC_STATE_FLUIDS (current_thread->dynamic_state);
2579 if (SCM_UNLIKELY (!SCM_FLUID_P (fluid))
2580 || ((num = SCM_I_FLUID_NUM (fluid)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
2581 {
2582 /* Punt dynstate expansion and error handling to the C proc. */
2583 SYNC_IP ();
2584 LOCAL_SET (dst, scm_fluid_ref (fluid));
2585 }
2586 else
2587 {
2588 SCM val = SCM_SIMPLE_VECTOR_REF (fluids, num);
2589 if (scm_is_eq (val, SCM_UNDEFINED))
2590 val = SCM_I_FLUID_DEFAULT (fluid);
2591 VM_ASSERT (!scm_is_eq (val, SCM_UNDEFINED),
2592 vm_error_unbound_fluid (program, fluid));
2593 LOCAL_SET (dst, val);
2594 }
2595
2596 NEXT (1);
2597 }
2598
2599 /* fluid-set fluid:12 val:12
2600 *
2601 * Set the value of the fluid in DST to the value in SRC.
2602 */
286a0fb3 2603 VM_DEFINE_OP (73, fluid_set, "fluid-set", OP1 (U8_U12_U12))
510ca126
AW
2604 {
2605 scm_t_uint16 a, b;
2606 size_t num;
2607 SCM fluid, fluids;
2608
2609 SCM_UNPACK_RTL_12_12 (op, a, b);
2610 fluid = LOCAL_REF (a);
2611 fluids = SCM_I_DYNAMIC_STATE_FLUIDS (current_thread->dynamic_state);
2612 if (SCM_UNLIKELY (!SCM_FLUID_P (fluid))
2613 || ((num = SCM_I_FLUID_NUM (fluid)) >= SCM_SIMPLE_VECTOR_LENGTH (fluids)))
2614 {
2615 /* Punt dynstate expansion and error handling to the C proc. */
2616 SYNC_IP ();
2617 scm_fluid_set_x (fluid, LOCAL_REF (b));
2618 }
2619 else
2620 SCM_SIMPLE_VECTOR_SET (fluids, num, LOCAL_REF (b));
2621
2622 NEXT (1);
2623 }
2624
2625
2626 \f
2627
2628 /*
2629 * Strings, symbols, and keywords
2630 */
2631
2632 /* string-length dst:12 src:12
2633 *
2634 * Store the length of the string in SRC in DST.
2635 */
286a0fb3 2636 VM_DEFINE_OP (74, string_length, "string-length", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2637 {
2638 ARGS1 (str);
2639 if (SCM_LIKELY (scm_is_string (str)))
2640 RETURN (SCM_I_MAKINUM (scm_i_string_length (str)));
2641 else
2642 {
2643 SYNC_IP ();
2644 RETURN (scm_string_length (str));
2645 }
2646 }
2647
2648 /* string-ref dst:8 src:8 idx:8
2649 *
2650 * Fetch the character at position IDX in the string in SRC, and store
2651 * it in DST.
2652 */
286a0fb3 2653 VM_DEFINE_OP (75, string_ref, "string-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2654 {
2655 scm_t_signed_bits i = 0;
2656 ARGS2 (str, idx);
2657 if (SCM_LIKELY (scm_is_string (str)
2658 && SCM_I_INUMP (idx)
2659 && ((i = SCM_I_INUM (idx)) >= 0)
2660 && i < scm_i_string_length (str)))
2661 RETURN (SCM_MAKE_CHAR (scm_i_string_ref (str, i)));
2662 else
2663 {
2664 SYNC_IP ();
2665 RETURN (scm_string_ref (str, idx));
2666 }
2667 }
2668
2669 /* No string-set! instruction, as there is no good fast path there. */
2670
2671 /* string-to-number dst:12 src:12
2672 *
2673 * Parse a string in SRC to a number, and store in DST.
2674 */
286a0fb3 2675 VM_DEFINE_OP (76, string_to_number, "string->number", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2676 {
2677 scm_t_uint16 dst, src;
2678
2679 SCM_UNPACK_RTL_12_12 (op, dst, src);
2680 SYNC_IP ();
2681 LOCAL_SET (dst,
2682 scm_string_to_number (LOCAL_REF (src),
2683 SCM_UNDEFINED /* radix = 10 */));
2684 NEXT (1);
2685 }
2686
2687 /* string-to-symbol dst:12 src:12
2688 *
2689 * Parse a string in SRC to a symbol, and store in DST.
2690 */
286a0fb3 2691 VM_DEFINE_OP (77, string_to_symbol, "string->symbol", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2692 {
2693 scm_t_uint16 dst, src;
2694
2695 SCM_UNPACK_RTL_12_12 (op, dst, src);
2696 SYNC_IP ();
2697 LOCAL_SET (dst, scm_string_to_symbol (LOCAL_REF (src)));
2698 NEXT (1);
2699 }
2700
2701 /* symbol->keyword dst:12 src:12
2702 *
2703 * Make a keyword from the symbol in SRC, and store it in DST.
2704 */
286a0fb3 2705 VM_DEFINE_OP (78, symbol_to_keyword, "symbol->keyword", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2706 {
2707 scm_t_uint16 dst, src;
2708 SCM_UNPACK_RTL_12_12 (op, dst, src);
2709 SYNC_IP ();
2710 LOCAL_SET (dst, scm_symbol_to_keyword (LOCAL_REF (src)));
2711 NEXT (1);
2712 }
2713
2714 \f
2715
2716 /*
2717 * Pairs
2718 */
2719
2720 /* cons dst:8 car:8 cdr:8
2721 *
2722 * Cons CAR and CDR, and store the result in DST.
2723 */
286a0fb3 2724 VM_DEFINE_OP (79, cons, "cons", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2725 {
2726 ARGS2 (x, y);
2727 RETURN (scm_cons (x, y));
2728 }
2729
2730 /* car dst:12 src:12
2731 *
2732 * Place the car of SRC in DST.
2733 */
286a0fb3 2734 VM_DEFINE_OP (80, car, "car", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2735 {
2736 ARGS1 (x);
2737 VM_VALIDATE_PAIR (x, "car");
2738 RETURN (SCM_CAR (x));
2739 }
2740
2741 /* cdr dst:12 src:12
2742 *
2743 * Place the cdr of SRC in DST.
2744 */
286a0fb3 2745 VM_DEFINE_OP (81, cdr, "cdr", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2746 {
2747 ARGS1 (x);
2748 VM_VALIDATE_PAIR (x, "cdr");
2749 RETURN (SCM_CDR (x));
2750 }
2751
2752 /* set-car! pair:12 car:12
2753 *
2754 * Set the car of DST to SRC.
2755 */
286a0fb3 2756 VM_DEFINE_OP (82, set_car, "set-car!", OP1 (U8_U12_U12))
510ca126
AW
2757 {
2758 scm_t_uint16 a, b;
2759 SCM x, y;
2760 SCM_UNPACK_RTL_12_12 (op, a, b);
2761 x = LOCAL_REF (a);
2762 y = LOCAL_REF (b);
2763 VM_VALIDATE_PAIR (x, "set-car!");
2764 SCM_SETCAR (x, y);
2765 NEXT (1);
2766 }
2767
2768 /* set-cdr! pair:12 cdr:12
2769 *
2770 * Set the cdr of DST to SRC.
2771 */
286a0fb3 2772 VM_DEFINE_OP (83, set_cdr, "set-cdr!", OP1 (U8_U12_U12))
510ca126
AW
2773 {
2774 scm_t_uint16 a, b;
2775 SCM x, y;
2776 SCM_UNPACK_RTL_12_12 (op, a, b);
2777 x = LOCAL_REF (a);
2778 y = LOCAL_REF (b);
2779 VM_VALIDATE_PAIR (x, "set-car!");
2780 SCM_SETCDR (x, y);
2781 NEXT (1);
2782 }
2783
2784
2785 \f
2786
2787 /*
2788 * Numeric operations
2789 */
2790
2791 /* add dst:8 a:8 b:8
2792 *
2793 * Add A to B, and place the result in DST.
2794 */
286a0fb3 2795 VM_DEFINE_OP (84, add, "add", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2796 {
2797 BINARY_INTEGER_OP (+, scm_sum);
2798 }
2799
2800 /* add1 dst:12 src:12
2801 *
2802 * Add 1 to the value in SRC, and place the result in DST.
2803 */
286a0fb3 2804 VM_DEFINE_OP (85, add1, "add1", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2805 {
2806 ARGS1 (x);
2807
2808 /* Check for overflow. */
2809 if (SCM_LIKELY ((scm_t_intptr) SCM_UNPACK (x) < INUM_MAX))
2810 {
2811 SCM result;
2812
2813 /* Add the integers without untagging. */
2814 result = SCM_PACK ((scm_t_intptr) SCM_UNPACK (x)
2815 + (scm_t_intptr) SCM_UNPACK (SCM_I_MAKINUM (1))
2816 - scm_tc2_int);
2817
2818 if (SCM_LIKELY (SCM_I_INUMP (result)))
2819 RETURN (result);
2820 }
2821
2822 SYNC_IP ();
2823 RETURN (scm_sum (x, SCM_I_MAKINUM (1)));
2824 }
2825
2826 /* sub dst:8 a:8 b:8
2827 *
2828 * Subtract B from A, and place the result in DST.
2829 */
286a0fb3 2830 VM_DEFINE_OP (86, sub, "sub", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2831 {
2832 BINARY_INTEGER_OP (-, scm_difference);
2833 }
2834
2835 /* sub1 dst:12 src:12
2836 *
2837 * Subtract 1 from SRC, and place the result in DST.
2838 */
286a0fb3 2839 VM_DEFINE_OP (87, sub1, "sub1", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2840 {
2841 ARGS1 (x);
2842
2843 /* Check for underflow. */
2844 if (SCM_LIKELY ((scm_t_intptr) SCM_UNPACK (x) > INUM_MIN))
2845 {
2846 SCM result;
2847
2848 /* Substract the integers without untagging. */
2849 result = SCM_PACK ((scm_t_intptr) SCM_UNPACK (x)
2850 - (scm_t_intptr) SCM_UNPACK (SCM_I_MAKINUM (1))
2851 + scm_tc2_int);
2852
2853 if (SCM_LIKELY (SCM_I_INUMP (result)))
2854 RETURN (result);
2855 }
2856
2857 SYNC_IP ();
2858 RETURN (scm_difference (x, SCM_I_MAKINUM (1)));
2859 }
2860
2861 /* mul dst:8 a:8 b:8
2862 *
2863 * Multiply A and B, and place the result in DST.
2864 */
286a0fb3 2865 VM_DEFINE_OP (88, mul, "mul", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2866 {
2867 ARGS2 (x, y);
2868 SYNC_IP ();
2869 RETURN (scm_product (x, y));
2870 }
2871
2872 /* div dst:8 a:8 b:8
2873 *
2874 * Divide A by B, and place the result in DST.
2875 */
286a0fb3 2876 VM_DEFINE_OP (89, div, "div", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2877 {
2878 ARGS2 (x, y);
2879 SYNC_IP ();
2880 RETURN (scm_divide (x, y));
2881 }
2882
2883 /* quo dst:8 a:8 b:8
2884 *
2885 * Divide A by B, and place the quotient in DST.
2886 */
286a0fb3 2887 VM_DEFINE_OP (90, quo, "quo", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2888 {
2889 ARGS2 (x, y);
2890 SYNC_IP ();
2891 RETURN (scm_quotient (x, y));
2892 }
2893
2894 /* rem dst:8 a:8 b:8
2895 *
2896 * Divide A by B, and place the remainder in DST.
2897 */
286a0fb3 2898 VM_DEFINE_OP (91, rem, "rem", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2899 {
2900 ARGS2 (x, y);
2901 SYNC_IP ();
2902 RETURN (scm_remainder (x, y));
2903 }
2904
2905 /* mod dst:8 a:8 b:8
2906 *
2907 * Place the modulo of A by B in DST.
2908 */
286a0fb3 2909 VM_DEFINE_OP (92, mod, "mod", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2910 {
2911 ARGS2 (x, y);
2912 SYNC_IP ();
2913 RETURN (scm_modulo (x, y));
2914 }
2915
2916 /* ash dst:8 a:8 b:8
2917 *
2918 * Shift A arithmetically by B bits, and place the result in DST.
2919 */
286a0fb3 2920 VM_DEFINE_OP (93, ash, "ash", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2921 {
2922 ARGS2 (x, y);
2923 if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
2924 {
2925 if (SCM_I_INUM (y) < 0)
2926 /* Right shift, will be a fixnum. */
2927 RETURN (SCM_I_MAKINUM (SCM_I_INUM (x) >> -SCM_I_INUM (y)));
2928 else
2929 /* Left shift. See comments in scm_ash. */
2930 {
2931 scm_t_signed_bits nn, bits_to_shift;
2932
2933 nn = SCM_I_INUM (x);
2934 bits_to_shift = SCM_I_INUM (y);
2935
2936 if (bits_to_shift < SCM_I_FIXNUM_BIT-1
2937 && ((scm_t_bits)
2938 (SCM_SRS (nn, (SCM_I_FIXNUM_BIT-1 - bits_to_shift)) + 1)
2939 <= 1))
2940 RETURN (SCM_I_MAKINUM (nn << bits_to_shift));
2941 /* fall through */
2942 }
2943 /* fall through */
2944 }
2945 SYNC_IP ();
2946 RETURN (scm_ash (x, y));
2947 }
2948
2949 /* logand dst:8 a:8 b:8
2950 *
2951 * Place the bitwise AND of A and B into DST.
2952 */
286a0fb3 2953 VM_DEFINE_OP (94, logand, "logand", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2954 {
2955 ARGS2 (x, y);
2956 if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
2957 RETURN (SCM_I_MAKINUM (SCM_I_INUM (x) & SCM_I_INUM (y)));
2958 SYNC_IP ();
2959 RETURN (scm_logand (x, y));
2960 }
2961
2962 /* logior dst:8 a:8 b:8
2963 *
2964 * Place the bitwise inclusive OR of A with B in DST.
2965 */
286a0fb3 2966 VM_DEFINE_OP (95, logior, "logior", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2967 {
2968 ARGS2 (x, y);
2969 if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
2970 RETURN (SCM_I_MAKINUM (SCM_I_INUM (x) | SCM_I_INUM (y)));
2971 SYNC_IP ();
2972 RETURN (scm_logior (x, y));
2973 }
2974
2975 /* logxor dst:8 a:8 b:8
2976 *
2977 * Place the bitwise exclusive OR of A with B in DST.
2978 */
286a0fb3 2979 VM_DEFINE_OP (96, logxor, "logxor", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
2980 {
2981 ARGS2 (x, y);
2982 if (SCM_I_INUMP (x) && SCM_I_INUMP (y))
2983 RETURN (SCM_I_MAKINUM (SCM_I_INUM (x) ^ SCM_I_INUM (y)));
2984 SYNC_IP ();
2985 RETURN (scm_logxor (x, y));
2986 }
2987
2988 /* vector-length dst:12 src:12
2989 *
2990 * Store the length of the vector in SRC in DST.
2991 */
286a0fb3 2992 VM_DEFINE_OP (97, vector_length, "vector-length", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
2993 {
2994 ARGS1 (vect);
2995 if (SCM_LIKELY (SCM_I_IS_VECTOR (vect)))
2996 RETURN (SCM_I_MAKINUM (SCM_I_VECTOR_LENGTH (vect)));
2997 else
2998 {
2999 SYNC_IP ();
3000 RETURN (scm_vector_length (vect));
3001 }
3002 }
3003
3004 /* vector-ref dst:8 src:8 idx:8
3005 *
3006 * Fetch the item at position IDX in the vector in SRC, and store it
3007 * in DST.
3008 */
286a0fb3 3009 VM_DEFINE_OP (98, vector_ref, "vector-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3010 {
3011 scm_t_signed_bits i = 0;
3012 ARGS2 (vect, idx);
3013 if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
3014 && SCM_I_INUMP (idx)
3015 && ((i = SCM_I_INUM (idx)) >= 0)
3016 && i < SCM_I_VECTOR_LENGTH (vect)))
3017 RETURN (SCM_I_VECTOR_ELTS (vect)[i]);
3018 else
3019 {
3020 SYNC_IP ();
3021 RETURN (scm_vector_ref (vect, idx));
3022 }
3023 }
3024
3025 /* constant-vector-ref dst:8 src:8 idx:8
3026 *
3027 * Fill DST with the item IDX elements into the vector at SRC. Useful
3028 * for building data types using vectors.
3029 */
286a0fb3 3030 VM_DEFINE_OP (99, constant_vector_ref, "constant-vector-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3031 {
3032 scm_t_uint8 dst, src, idx;
3033 SCM v;
3034
3035 SCM_UNPACK_RTL_8_8_8 (op, dst, src, idx);
3036 v = LOCAL_REF (src);
3037 if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (v)
3038 && idx < SCM_I_VECTOR_LENGTH (v)))
3039 LOCAL_SET (dst, SCM_I_VECTOR_ELTS (LOCAL_REF (src))[idx]);
3040 else
3041 LOCAL_SET (dst, scm_c_vector_ref (v, idx));
3042 NEXT (1);
3043 }
3044
3045 /* vector-set! dst:8 idx:8 src:8
3046 *
3047 * Store SRC into the vector DST at index IDX.
3048 */
286a0fb3 3049 VM_DEFINE_OP (100, vector_set, "vector-set", OP1 (U8_U8_U8_U8))
510ca126
AW
3050 {
3051 scm_t_uint8 dst, idx_var, src;
3052 SCM vect, idx, val;
3053 scm_t_signed_bits i = 0;
3054
3055 SCM_UNPACK_RTL_8_8_8 (op, dst, idx_var, src);
3056 vect = LOCAL_REF (dst);
3057 idx = LOCAL_REF (idx_var);
3058 val = LOCAL_REF (src);
3059
3060 if (SCM_LIKELY (SCM_I_IS_NONWEAK_VECTOR (vect)
3061 && SCM_I_INUMP (idx)
3062 && ((i = SCM_I_INUM (idx)) >= 0)
3063 && i < SCM_I_VECTOR_LENGTH (vect)))
3064 SCM_I_VECTOR_WELTS (vect)[i] = val;
3065 else
3066 {
3067 SYNC_IP ();
3068 scm_vector_set_x (vect, idx, val);
3069 }
3070 NEXT (1);
3071 }
3072
3073
3074 \f
3075
3076 /*
3077 * Structs and GOOPS
3078 */
3079
3080 /* struct-vtable dst:12 src:12
3081 *
3082 * Store the vtable of SRC into DST.
3083 */
286a0fb3 3084 VM_DEFINE_OP (101, struct_vtable, "struct-vtable", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
3085 {
3086 ARGS1 (obj);
3087 VM_VALIDATE_STRUCT (obj, "struct_vtable");
3088 RETURN (SCM_STRUCT_VTABLE (obj));
3089 }
3090
3091 /* make-struct dst:12 vtable:12 _:8 n-init:24 init0:24 0:8 ...
3092 *
3093 * Make a new struct with VTABLE, and place it in DST. The struct
3094 * will be constructed with N-INIT initializers, which are located in
3095 * the locals given by INIT0.... The format of INIT0... is as in the
3096 * "call" opcode: unsigned 24-bit values, with 0 in the high byte.
3097 */
286a0fb3 3098 VM_DEFINE_OP (102, make_struct, "make-struct", OP2 (U8_U12_U12, X8_R24))
510ca126
AW
3099#if 0
3100 {
3101 scm_t_uint16 dst, vtable_r;
3102 scm_t_uint32 n_init, n;
3103 SCM vtable, ret;
3104
3105 SCM_UNPACK_RTL_12_12 (op, dst, vtable_r);
3106 vtable = LOCAL_REF (vtable_r);
3107 SCM_UNPACK_RTL_24 (ip[1], n_init);
3108
3109 SYNC_IP ();
3110
3111 if (SCM_LIKELY (SCM_STRUCTP (vtable)
3112 && SCM_VTABLE_FLAG_IS_SET (vtable, SCM_VTABLE_FLAG_SIMPLE)
3113 && (SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size)
3114 == n_init)
3115 && !SCM_VTABLE_INSTANCE_FINALIZER (vtable)))
3116 {
3117 /* Verily, we are making a simple struct with the right number of
3118 initializers, and no finalizer. */
3119 ret = scm_words ((scm_t_bits)SCM_STRUCT_DATA (vtable) | scm_tc3_struct,
3120 n_init + 2);
3121 SCM_SET_CELL_WORD_1 (ret, (scm_t_bits)SCM_CELL_OBJECT_LOC (ret, 2));
3122
3123 for (n = 0; n < n_init; n++)
3124 SCM_STRUCT_DATA (ret)[n] = SCM_UNPACK (LOCAL_REF (ip[n + 1]));
3125 }
3126 else
3127 ret = scm_c_make_structvs (vtable, fp, &ip[1], n_init);
3128
3129 LOCAL_SET (dst, ret);
3130 NEXT (n_init + 1);
3131 }
3132#else
3133 abort ();
3134#endif
3135
3136 /* struct-ref dst:8 src:8 idx:8
3137 *
3138 * Fetch the item at slot IDX in the struct in SRC, and store it
3139 * in DST.
3140 */
286a0fb3 3141 VM_DEFINE_OP (103, struct_ref, "struct-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3142 {
3143 ARGS2 (obj, pos);
3144
3145 if (SCM_LIKELY (SCM_STRUCTP (obj)
3146 && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj,
3147 SCM_VTABLE_FLAG_SIMPLE)
3148 && SCM_I_INUMP (pos)))
3149 {
3150 SCM vtable;
3151 scm_t_bits index, len;
3152
3153 /* True, an inum is a signed value, but cast to unsigned it will
3154 certainly be more than the length, so we will fall through if
3155 index is negative. */
3156 index = SCM_I_INUM (pos);
3157 vtable = SCM_STRUCT_VTABLE (obj);
3158 len = SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size);
3159
3160 if (SCM_LIKELY (index < len))
3161 {
3162 scm_t_bits *data = SCM_STRUCT_DATA (obj);
3163 RETURN (SCM_PACK (data[index]));
3164 }
3165 }
3166
3167 SYNC_IP ();
3168 RETURN (scm_struct_ref (obj, pos));
3169 }
3170
3171 /* struct-set! dst:8 idx:8 src:8
3172 *
3173 * Store SRC into the struct DST at slot IDX.
3174 */
286a0fb3 3175 VM_DEFINE_OP (104, struct_set, "struct-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3176 {
3177 scm_t_uint8 dst, idx, src;
3178 SCM obj, pos, val;
3179
3180 SCM_UNPACK_RTL_8_8_8 (op, dst, idx, src);
3181 obj = LOCAL_REF (dst);
3182 pos = LOCAL_REF (idx);
3183 val = LOCAL_REF (src);
3184
3185 if (SCM_LIKELY (SCM_STRUCTP (obj)
3186 && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj,
3187 SCM_VTABLE_FLAG_SIMPLE)
3188 && SCM_STRUCT_VTABLE_FLAG_IS_SET (obj,
3189 SCM_VTABLE_FLAG_SIMPLE_RW)
3190 && SCM_I_INUMP (pos)))
3191 {
3192 SCM vtable;
3193 scm_t_bits index, len;
3194
3195 /* See above regarding index being >= 0. */
3196 index = SCM_I_INUM (pos);
3197 vtable = SCM_STRUCT_VTABLE (obj);
3198 len = SCM_STRUCT_DATA_REF (vtable, scm_vtable_index_size);
3199 if (SCM_LIKELY (index < len))
3200 {
3201 scm_t_bits *data = SCM_STRUCT_DATA (obj);
3202 data[index] = SCM_UNPACK (val);
3203 NEXT (1);
3204 }
3205 }
3206
3207 SYNC_IP ();
3208 scm_struct_set_x (obj, pos, val);
3209 NEXT (1);
3210 }
3211
3212 /* class-of dst:12 type:12
3213 *
3214 * Store the vtable of SRC into DST.
3215 */
286a0fb3 3216 VM_DEFINE_OP (105, class_of, "class-of", OP1 (U8_U12_U12) | OP_DST)
510ca126
AW
3217 {
3218 ARGS1 (obj);
3219 if (SCM_INSTANCEP (obj))
3220 RETURN (SCM_CLASS_OF (obj));
3221 SYNC_IP ();
3222 RETURN (scm_class_of (obj));
3223 }
3224
3225 /* slot-ref dst:8 src:8 idx:8
3226 *
3227 * Fetch the item at slot IDX in the struct in SRC, and store it in
3228 * DST. Unlike struct-ref, IDX is an 8-bit immediate value, not an
3229 * index into the stack.
3230 */
286a0fb3 3231 VM_DEFINE_OP (106, slot_ref, "slot-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3232 {
3233 scm_t_uint8 dst, src, idx;
3234 SCM_UNPACK_RTL_8_8_8 (op, dst, src, idx);
3235 LOCAL_SET (dst,
3236 SCM_PACK (SCM_STRUCT_DATA (LOCAL_REF (src))[idx]));
3237 NEXT (1);
3238 }
3239
3240 /* slot-set! dst:8 idx:8 src:8
3241 *
3242 * Store SRC into slot IDX of the struct in DST. Unlike struct-set!,
3243 * IDX is an 8-bit immediate value, not an index into the stack.
3244 */
286a0fb3 3245 VM_DEFINE_OP (107, slot_set, "slot-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3246 {
3247 scm_t_uint8 dst, idx, src;
3248 SCM_UNPACK_RTL_8_8_8 (op, dst, idx, src);
3249 SCM_STRUCT_DATA (LOCAL_REF (dst))[idx] = SCM_UNPACK (LOCAL_REF (src));
3250 NEXT (1);
3251 }
3252
3253
3254 \f
3255
3256 /*
3257 * Arrays, packed uniform arrays, and bytevectors.
3258 */
3259
3260 /* load-typed-array dst:8 type:8 shape:8 offset:32 len:32
3261 *
3262 * Load the contiguous typed array located at OFFSET 32-bit words away
3263 * from the instruction pointer, and store into DST. LEN is a byte
3264 * length. OFFSET is signed.
3265 */
286a0fb3 3266 VM_DEFINE_OP (108, load_typed_array, "load-typed-array", OP3 (U8_U8_U8_U8, N32, U32) | OP_DST)
510ca126
AW
3267 {
3268 scm_t_uint8 dst, type, shape;
3269 scm_t_int32 offset;
3270 scm_t_uint32 len;
3271
3272 SCM_UNPACK_RTL_8_8_8 (op, dst, type, shape);
3273 offset = ip[1];
3274 len = ip[2];
3275 SYNC_IP ();
3276 LOCAL_SET (dst, scm_from_contiguous_typed_array (LOCAL_REF (type),
3277 LOCAL_REF (shape),
3278 ip + offset, len));
3279 NEXT (3);
3280 }
3281
3282 /* make-array dst:12 type:12 _:8 fill:12 bounds:12
3283 *
3284 * Make a new array with TYPE, FILL, and BOUNDS, storing it in DST.
3285 */
286a0fb3 3286 VM_DEFINE_OP (109, make_array, "make-array", OP2 (U8_U12_U12, X8_U12_U12) | OP_DST)
510ca126
AW
3287 {
3288 scm_t_uint16 dst, type, fill, bounds;
3289 SCM_UNPACK_RTL_12_12 (op, dst, type);
3290 SCM_UNPACK_RTL_12_12 (ip[1], fill, bounds);
3291 SYNC_IP ();
3292 LOCAL_SET (dst, scm_make_typed_array (LOCAL_REF (type), LOCAL_REF (fill),
3293 LOCAL_REF (bounds)));
3294 NEXT (2);
3295 }
3296
3297 /* bv-u8-ref dst:8 src:8 idx:8
3298 * bv-s8-ref dst:8 src:8 idx:8
3299 * bv-u16-ref dst:8 src:8 idx:8
3300 * bv-s16-ref dst:8 src:8 idx:8
3301 * bv-u32-ref dst:8 src:8 idx:8
3302 * bv-s32-ref dst:8 src:8 idx:8
3303 * bv-u64-ref dst:8 src:8 idx:8
3304 * bv-s64-ref dst:8 src:8 idx:8
3305 * bv-f32-ref dst:8 src:8 idx:8
3306 * bv-f64-ref dst:8 src:8 idx:8
3307 *
3308 * Fetch the item at byte offset IDX in the bytevector SRC, and store
3309 * it in DST. All accesses use native endianness.
3310 */
3311#define BV_FIXABLE_INT_REF(stem, fn_stem, type, size) \
3312 do { \
3313 scm_t_signed_bits i; \
3314 const scm_t_ ## type *int_ptr; \
3315 ARGS2 (bv, idx); \
3316 \
3317 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-ref"); \
3318 i = SCM_I_INUM (idx); \
3319 int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
3320 \
3321 if (SCM_LIKELY (SCM_I_INUMP (idx) \
3322 && (i >= 0) \
3323 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
3324 && (ALIGNED_P (int_ptr, scm_t_ ## type)))) \
3325 RETURN (SCM_I_MAKINUM (*int_ptr)); \
3326 else \
3327 { \
3328 SYNC_IP (); \
3329 RETURN (scm_bytevector_ ## fn_stem ## _ref (bv, idx)); \
3330 } \
3331 } while (0)
3332
3333#define BV_INT_REF(stem, type, size) \
3334 do { \
3335 scm_t_signed_bits i; \
3336 const scm_t_ ## type *int_ptr; \
3337 ARGS2 (bv, idx); \
3338 \
3339 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-ref"); \
3340 i = SCM_I_INUM (idx); \
3341 int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
3342 \
3343 if (SCM_LIKELY (SCM_I_INUMP (idx) \
3344 && (i >= 0) \
3345 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
3346 && (ALIGNED_P (int_ptr, scm_t_ ## type)))) \
3347 { \
3348 scm_t_ ## type x = *int_ptr; \
3349 if (SCM_FIXABLE (x)) \
3350 RETURN (SCM_I_MAKINUM (x)); \
3351 else \
3352 { \
3353 SYNC_IP (); \
3354 RETURN (scm_from_ ## type (x)); \
3355 } \
3356 } \
3357 else \
3358 { \
3359 SYNC_IP (); \
3360 RETURN (scm_bytevector_ ## stem ## _native_ref (bv, idx)); \
3361 } \
3362 } while (0)
3363
3364#define BV_FLOAT_REF(stem, fn_stem, type, size) \
3365 do { \
3366 scm_t_signed_bits i; \
3367 const type *float_ptr; \
3368 ARGS2 (bv, idx); \
3369 \
3370 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-ref"); \
3371 i = SCM_I_INUM (idx); \
3372 float_ptr = (type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
3373 \
3374 SYNC_IP (); \
3375 if (SCM_LIKELY (SCM_I_INUMP (idx) \
3376 && (i >= 0) \
3377 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
3378 && (ALIGNED_P (float_ptr, type)))) \
3379 RETURN (scm_from_double (*float_ptr)); \
3380 else \
3381 RETURN (scm_bytevector_ ## fn_stem ## _native_ref (bv, idx)); \
3382 } while (0)
3383
286a0fb3 3384 VM_DEFINE_OP (110, bv_u8_ref, "bv-u8-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3385 BV_FIXABLE_INT_REF (u8, u8, uint8, 1);
3386
286a0fb3 3387 VM_DEFINE_OP (111, bv_s8_ref, "bv-s8-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3388 BV_FIXABLE_INT_REF (s8, s8, int8, 1);
3389
286a0fb3 3390 VM_DEFINE_OP (112, bv_u16_ref, "bv-u16-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3391 BV_FIXABLE_INT_REF (u16, u16_native, uint16, 2);
3392
286a0fb3 3393 VM_DEFINE_OP (113, bv_s16_ref, "bv-s16-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3394 BV_FIXABLE_INT_REF (s16, s16_native, int16, 2);
3395
286a0fb3 3396 VM_DEFINE_OP (114, bv_u32_ref, "bv-u32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3397#if SIZEOF_VOID_P > 4
3398 BV_FIXABLE_INT_REF (u32, u32_native, uint32, 4);
3399#else
3400 BV_INT_REF (u32, uint32, 4);
3401#endif
3402
286a0fb3 3403 VM_DEFINE_OP (115, bv_s32_ref, "bv-s32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3404#if SIZEOF_VOID_P > 4
3405 BV_FIXABLE_INT_REF (s32, s32_native, int32, 4);
3406#else
3407 BV_INT_REF (s32, int32, 4);
3408#endif
3409
286a0fb3 3410 VM_DEFINE_OP (116, bv_u64_ref, "bv-u64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3411 BV_INT_REF (u64, uint64, 8);
3412
286a0fb3 3413 VM_DEFINE_OP (117, bv_s64_ref, "bv-s64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3414 BV_INT_REF (s64, int64, 8);
3415
286a0fb3 3416 VM_DEFINE_OP (118, bv_f32_ref, "bv-f32-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3417 BV_FLOAT_REF (f32, ieee_single, float, 4);
3418
286a0fb3 3419 VM_DEFINE_OP (119, bv_f64_ref, "bv-f64-ref", OP1 (U8_U8_U8_U8) | OP_DST)
510ca126
AW
3420 BV_FLOAT_REF (f64, ieee_double, double, 8);
3421
3422 /* bv-u8-set! dst:8 idx:8 src:8
3423 * bv-s8-set! dst:8 idx:8 src:8
3424 * bv-u16-set! dst:8 idx:8 src:8
3425 * bv-s16-set! dst:8 idx:8 src:8
3426 * bv-u32-set! dst:8 idx:8 src:8
3427 * bv-s32-set! dst:8 idx:8 src:8
3428 * bv-u64-set! dst:8 idx:8 src:8
3429 * bv-s64-set! dst:8 idx:8 src:8
3430 * bv-f32-set! dst:8 idx:8 src:8
3431 * bv-f64-set! dst:8 idx:8 src:8
3432 *
3433 * Store SRC into the bytevector DST at byte offset IDX. Multibyte
3434 * values are written using native endianness.
3435 */
3436#define BV_FIXABLE_INT_SET(stem, fn_stem, type, min, max, size) \
3437 do { \
3438 scm_t_uint8 dst, idx, src; \
3439 scm_t_signed_bits i, j = 0; \
3440 SCM bv, scm_idx, val; \
3441 scm_t_ ## type *int_ptr; \
3442 \
3443 SCM_UNPACK_RTL_8_8_8 (op, dst, idx, src); \
3444 bv = LOCAL_REF (dst); \
3445 scm_idx = LOCAL_REF (idx); \
3446 val = LOCAL_REF (src); \
3447 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set"); \
3448 i = SCM_I_INUM (scm_idx); \
3449 int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
3450 \
3451 if (SCM_LIKELY (SCM_I_INUMP (scm_idx) \
3452 && (i >= 0) \
3453 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
3454 && (ALIGNED_P (int_ptr, scm_t_ ## type)) \
3455 && (SCM_I_INUMP (val)) \
3456 && ((j = SCM_I_INUM (val)) >= min) \
3457 && (j <= max))) \
3458 *int_ptr = (scm_t_ ## type) j; \
3459 else \
3460 { \
3461 SYNC_IP (); \
3462 scm_bytevector_ ## fn_stem ## _set_x (bv, scm_idx, val); \
3463 } \
3464 NEXT (1); \
3465 } while (0)
3466
3467#define BV_INT_SET(stem, type, size) \
3468 do { \
3469 scm_t_uint8 dst, idx, src; \
3470 scm_t_signed_bits i; \
3471 SCM bv, scm_idx, val; \
3472 scm_t_ ## type *int_ptr; \
3473 \
3474 SCM_UNPACK_RTL_8_8_8 (op, dst, idx, src); \
3475 bv = LOCAL_REF (dst); \
3476 scm_idx = LOCAL_REF (idx); \
3477 val = LOCAL_REF (src); \
3478 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set"); \
3479 i = SCM_I_INUM (scm_idx); \
3480 int_ptr = (scm_t_ ## type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
3481 \
3482 if (SCM_LIKELY (SCM_I_INUMP (scm_idx) \
3483 && (i >= 0) \
3484 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
3485 && (ALIGNED_P (int_ptr, scm_t_ ## type)))) \
3486 *int_ptr = scm_to_ ## type (val); \
3487 else \
3488 { \
3489 SYNC_IP (); \
3490 scm_bytevector_ ## stem ## _native_set_x (bv, scm_idx, val); \
3491 } \
3492 NEXT (1); \
3493 } while (0)
3494
3495#define BV_FLOAT_SET(stem, fn_stem, type, size) \
3496 do { \
3497 scm_t_uint8 dst, idx, src; \
3498 scm_t_signed_bits i; \
3499 SCM bv, scm_idx, val; \
3500 type *float_ptr; \
3501 \
3502 SCM_UNPACK_RTL_8_8_8 (op, dst, idx, src); \
3503 bv = LOCAL_REF (dst); \
3504 scm_idx = LOCAL_REF (idx); \
3505 val = LOCAL_REF (src); \
3506 VM_VALIDATE_BYTEVECTOR (bv, "bv-" #stem "-set"); \
3507 i = SCM_I_INUM (scm_idx); \
3508 float_ptr = (type *) (SCM_BYTEVECTOR_CONTENTS (bv) + i); \
3509 \
3510 if (SCM_LIKELY (SCM_I_INUMP (scm_idx) \
3511 && (i >= 0) \
3512 && (i + size <= SCM_BYTEVECTOR_LENGTH (bv)) \
3513 && (ALIGNED_P (float_ptr, type)))) \
3514 *float_ptr = scm_to_double (val); \
3515 else \
3516 { \
3517 SYNC_IP (); \
3518 scm_bytevector_ ## fn_stem ## _native_set_x (bv, scm_idx, val); \
3519 } \
3520 NEXT (1); \
3521 } while (0)
3522
286a0fb3 3523 VM_DEFINE_OP (120, bv_u8_set, "bv-u8-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3524 BV_FIXABLE_INT_SET (u8, u8, uint8, 0, SCM_T_UINT8_MAX, 1);
3525
286a0fb3 3526 VM_DEFINE_OP (121, bv_s8_set, "bv-s8-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3527 BV_FIXABLE_INT_SET (s8, s8, int8, SCM_T_INT8_MIN, SCM_T_INT8_MAX, 1);
3528
286a0fb3 3529 VM_DEFINE_OP (122, bv_u16_set, "bv-u16-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3530 BV_FIXABLE_INT_SET (u16, u16_native, uint16, 0, SCM_T_UINT16_MAX, 2);
3531
286a0fb3 3532 VM_DEFINE_OP (123, bv_s16_set, "bv-s16-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3533 BV_FIXABLE_INT_SET (s16, s16_native, int16, SCM_T_INT16_MIN, SCM_T_INT16_MAX, 2);
3534
286a0fb3 3535 VM_DEFINE_OP (124, bv_u32_set, "bv-u32-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3536#if SIZEOF_VOID_P > 4
3537 BV_FIXABLE_INT_SET (u32, u32_native, uint32, 0, SCM_T_UINT32_MAX, 4);
3538#else
3539 BV_INT_SET (u32, uint32, 4);
3540#endif
3541
286a0fb3 3542 VM_DEFINE_OP (125, bv_s32_set, "bv-s32-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3543#if SIZEOF_VOID_P > 4
3544 BV_FIXABLE_INT_SET (s32, s32_native, int32, SCM_T_INT32_MIN, SCM_T_INT32_MAX, 4);
3545#else
3546 BV_INT_SET (s32, int32, 4);
3547#endif
3548
286a0fb3 3549 VM_DEFINE_OP (126, bv_u64_set, "bv-u64-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3550 BV_INT_SET (u64, uint64, 8);
3551
286a0fb3 3552 VM_DEFINE_OP (127, bv_s64_set, "bv-s64-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3553 BV_INT_SET (s64, int64, 8);
3554
286a0fb3 3555 VM_DEFINE_OP (128, bv_f32_set, "bv-f32-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3556 BV_FLOAT_SET (f32, ieee_single, float, 4);
3557
286a0fb3 3558 VM_DEFINE_OP (129, bv_f64_set, "bv-f64-set!", OP1 (U8_U8_U8_U8))
510ca126
AW
3559 BV_FLOAT_SET (f64, ieee_double, double, 8);
3560
3561 END_DISPATCH_SWITCH;
3562
3563 vm_error_bad_instruction:
3564 vm_error_bad_instruction (op);
3565
3566 abort (); /* never reached */
3567}
3568
3569
3570#undef ABORT_CONTINUATION_HOOK
3571#undef ALIGNED_P
3572#undef APPLY_HOOK
3573#undef ARGS1
3574#undef ARGS2
3575#undef BEGIN_DISPATCH_SWITCH
3576#undef BINARY_INTEGER_OP
3577#undef BR_ARITHMETIC
3578#undef BR_BINARY
3579#undef BR_NARGS
3580#undef BR_UNARY
3581#undef BV_FIXABLE_INT_REF
3582#undef BV_FIXABLE_INT_SET
3583#undef BV_FLOAT_REF
3584#undef BV_FLOAT_SET
3585#undef BV_INT_REF
3586#undef BV_INT_SET
3587#undef CACHE_REGISTER
3588#undef CHECK_OVERFLOW
3589#undef END_DISPATCH_SWITCH
3590#undef FREE_VARIABLE_REF
3591#undef INIT
3592#undef INUM_MAX
3593#undef INUM_MIN
3594#undef LOCAL_REF
3595#undef LOCAL_SET
3596#undef NEXT
3597#undef NEXT_HOOK
3598#undef NEXT_JUMP
3599#undef POP_CONTINUATION_HOOK
3600#undef PUSH_CONTINUATION_HOOK
3601#undef RESTORE_CONTINUATION_HOOK
3602#undef RETURN
3603#undef RETURN_ONE_VALUE
3604#undef RETURN_VALUE_LIST
3605#undef RUN_HOOK
3606#undef RUN_HOOK0
3607#undef SYNC_ALL
3608#undef SYNC_BEFORE_GC
3609#undef SYNC_IP
3610#undef SYNC_REGISTER
3611#undef VARIABLE_BOUNDP
3612#undef VARIABLE_REF
3613#undef VARIABLE_SET
3614#undef VM_CHECK_FREE_VARIABLE
3615#undef VM_CHECK_OBJECT
3616#undef VM_CHECK_UNDERFLOW
3617#undef VM_DEFINE_OP
3618#undef VM_INSTRUCTION_TO_LABEL
3619#undef VM_USE_HOOKS
3620#undef VM_VALIDATE_BYTEVECTOR
3621#undef VM_VALIDATE_PAIR
3622#undef VM_VALIDATE_STRUCT
3623
3624/*
3625(defun renumber-ops ()
3626 "start from top of buffer and renumber 'VM_DEFINE_FOO (\n' sequences"
3627 (interactive "")
3628 (save-excursion
3629 (let ((counter -1)) (goto-char (point-min))
3630 (while (re-search-forward "^ *VM_DEFINE_[^ ]+ (\\([^,]+\\)," (point-max) t)
3631 (replace-match
3632 (number-to-string (setq counter (1+ counter)))
3633 t t nil 1)))))
3634(renumber-ops)
3635*/
17e90c5e
KN
3636/*
3637 Local Variables:
3638 c-file-style: "gnu"
3639 End:
3640*/