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