add partial support for tail patterns in syntax-rules/syntax-case
[bpt/guile.git] / libguile / vm-engine.h
CommitLineData
e6eb2467 1/* Copyright (C) 2001, 2009 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
KN
18
19/* This file is included in vm_engine.c */
20
a98cef7e
KN
21\f
22/*
17e90c5e 23 * Registers
a98cef7e
KN
24 */
25
17e90c5e 26/* Register optimization. [ stolen from librep/src/lispmach.h,v 1.3 ]
9df03fd0 27
17e90c5e
KN
28 Some compilers underestimate the use of the local variables representing
29 the abstract machine registers, and don't put them in hardware registers,
30 which slows down the interpreter considerably.
31 For GCC, I have hand-assigned hardware registers for several architectures.
32*/
9df03fd0 33
17e90c5e
KN
34#ifdef __GNUC__
35#ifdef __mips__
36#define IP_REG asm("$16")
37#define SP_REG asm("$17")
38#define FP_REG asm("$18")
39#endif
40#ifdef __sparc__
41#define IP_REG asm("%l0")
42#define SP_REG asm("%l1")
43#define FP_REG asm("%l2")
44#endif
45#ifdef __alpha__
46#ifdef __CRAY__
47#define IP_REG asm("r9")
48#define SP_REG asm("r10")
49#define FP_REG asm("r11")
9df03fd0 50#else
17e90c5e
KN
51#define IP_REG asm("$9")
52#define SP_REG asm("$10")
53#define FP_REG asm("$11")
54#endif
55#endif
56#ifdef __i386__
e6eb2467
AW
57/* too few registers! because of register allocation errors with various gcs,
58 just punt on explicit assignments on i386, hoping that the "register"
59 declaration will be sufficient. */
893be93f 60#endif
17e90c5e
KN
61#if defined(PPC) || defined(_POWER) || defined(_IBMR2)
62#define IP_REG asm("26")
63#define SP_REG asm("27")
64#define FP_REG asm("28")
65#endif
66#ifdef __hppa__
67#define IP_REG asm("%r18")
68#define SP_REG asm("%r17")
69#define FP_REG asm("%r16")
70#endif
71#ifdef __mc68000__
72#define IP_REG asm("a5")
73#define SP_REG asm("a4")
74#define FP_REG
75#endif
76#ifdef __arm__
77#define IP_REG asm("r9")
78#define SP_REG asm("r8")
79#define FP_REG asm("r7")
80#endif
9df03fd0
KN
81#endif
82
17d1b4bf
AW
83#ifndef IP_REG
84#define IP_REG
85#endif
86#ifndef SP_REG
87#define SP_REG
88#endif
89#ifndef FP_REG
90#define FP_REG
91#endif
92
9df03fd0 93\f
a98cef7e 94/*
3d5ee0cd 95 * Cache/Sync
a98cef7e
KN
96 */
97
11ea1aba 98#ifdef VM_ENABLE_ASSERTIONS
9a8cc8e7
AW
99# define ASSERT(condition) if (SCM_UNLIKELY (!(condition))) abort()
100#else
101# define ASSERT(condition)
102#endif
103
104
3d5ee0cd 105#define CACHE_REGISTER() \
17e90c5e 106{ \
3d5ee0cd
KN
107 ip = vp->ip; \
108 sp = vp->sp; \
109 fp = vp->fp; \
17e90c5e 110}
a98cef7e 111
3d5ee0cd 112#define SYNC_REGISTER() \
a98cef7e 113{ \
3d5ee0cd
KN
114 vp->ip = ip; \
115 vp->sp = sp; \
116 vp->fp = fp; \
a98cef7e
KN
117}
118
8d90b356
AW
119/* FIXME */
120#define ASSERT_VARIABLE(x) \
121 do { if (!SCM_VARIABLEP (x)) { SYNC_REGISTER (); abort(); } \
122 } while (0)
123#define ASSERT_BOUND_VARIABLE(x) \
124 do { ASSERT_VARIABLE (x); \
125 if (SCM_VARIABLE_REF (x) == SCM_UNDEFINED) \
126 { SYNC_REGISTER (); abort(); } \
127 } while (0)
128
11ea1aba 129#ifdef VM_ENABLE_PARANOID_ASSERTIONS
7e4760e4 130#define CHECK_IP() \
53e28ed9 131 do { if (ip < bp->base || ip - bp->base > bp->len) abort (); } while (0)
28b119ee
AW
132#define ASSERT_ALIGNED_PROCEDURE() \
133 do { if ((scm_t_bits)bp % 8) abort (); } while (0)
a1a482e0
AW
134#define ASSERT_BOUND(x) \
135 do { if ((x) == SCM_UNDEFINED) { SYNC_REGISTER (); abort(); } \
136 } while (0)
7e4760e4
AW
137#else
138#define CHECK_IP()
28b119ee 139#define ASSERT_ALIGNED_PROCEDURE()
a1a482e0 140#define ASSERT_BOUND(x)
7e4760e4
AW
141#endif
142
20d47c39 143/* Cache the object table and free variables. */
a52b2d3d
LC
144#define CACHE_PROGRAM() \
145{ \
e677365c
AW
146 if (bp != SCM_PROGRAM_DATA (program)) { \
147 bp = SCM_PROGRAM_DATA (program); \
28b119ee 148 ASSERT_ALIGNED_PROCEDURE (); \
53e28ed9
AW
149 if (SCM_I_IS_VECTOR (SCM_PROGRAM_OBJTABLE (program))) { \
150 objects = SCM_I_VECTOR_WELTS (SCM_PROGRAM_OBJTABLE (program)); \
151 object_count = SCM_I_VECTOR_LENGTH (SCM_PROGRAM_OBJTABLE (program)); \
2fda0242
AW
152 } else { \
153 objects = NULL; \
154 object_count = 0; \
155 } \
e677365c 156 } \
8d90b356 157 { \
57ab0671 158 SCM c = SCM_PROGRAM_FREE_VARIABLES (program); \
8d90b356
AW
159 if (SCM_I_IS_VECTOR (c)) \
160 { \
57ab0671
AW
161 free_vars = SCM_I_VECTOR_WELTS (c); \
162 free_vars_count = SCM_I_VECTOR_LENGTH (c); \
8d90b356
AW
163 } \
164 else \
165 { \
57ab0671
AW
166 free_vars = NULL; \
167 free_vars_count = 0; \
8d90b356
AW
168 } \
169 } \
41f248a8
KN
170}
171
3d5ee0cd
KN
172#define SYNC_BEFORE_GC() \
173{ \
174 SYNC_REGISTER (); \
17e90c5e 175}
a98cef7e 176
17e90c5e 177#define SYNC_ALL() \
a98cef7e 178{ \
3d5ee0cd 179 SYNC_REGISTER (); \
a98cef7e
KN
180}
181
a98cef7e 182\f
ac02b386
KN
183/*
184 * Error check
185 */
186
0b5f0e49
LC
187/* Accesses to a program's object table. */
188#if VM_CHECK_OBJECT
189#define CHECK_OBJECT(_num) \
6d14383e 190 do { if (SCM_UNLIKELY ((_num) >= object_count)) goto vm_error_object; } while (0)
0b5f0e49
LC
191#else
192#define CHECK_OBJECT(_num)
193#endif
194
57ab0671
AW
195#if VM_CHECK_FREE_VARIABLES
196#define CHECK_FREE_VARIABLE(_num) \
197 do { if (SCM_UNLIKELY ((_num) >= free_vars_count)) goto vm_error_free_variable; } while (0)
8d90b356 198#else
57ab0671 199#define CHECK_FREE_VARIABLE(_num)
8d90b356
AW
200#endif
201
ac02b386 202\f
3d5ee0cd
KN
203/*
204 * Hooks
205 */
206
207#undef RUN_HOOK
208#if VM_USE_HOOKS
209#define RUN_HOOK(h) \
210{ \
8b22ed7a 211 if (SCM_UNLIKELY (scm_is_true (vp->hooks[h])))\
3d5ee0cd 212 { \
af988bbf 213 SYNC_REGISTER (); \
6d14383e 214 vm_dispatch_hook (vp, vp->hooks[h], hook_args); \
af988bbf 215 CACHE_REGISTER (); \
3d5ee0cd
KN
216 } \
217}
218#else
219#define RUN_HOOK(h)
220#endif
221
ac02b386
KN
222#define BOOT_HOOK() RUN_HOOK (SCM_VM_BOOT_HOOK)
223#define HALT_HOOK() RUN_HOOK (SCM_VM_HALT_HOOK)
224#define NEXT_HOOK() RUN_HOOK (SCM_VM_NEXT_HOOK)
7a0d0cee 225#define BREAK_HOOK() RUN_HOOK (SCM_VM_BREAK_HOOK)
ac02b386
KN
226#define ENTER_HOOK() RUN_HOOK (SCM_VM_ENTER_HOOK)
227#define APPLY_HOOK() RUN_HOOK (SCM_VM_APPLY_HOOK)
228#define EXIT_HOOK() RUN_HOOK (SCM_VM_EXIT_HOOK)
229#define RETURN_HOOK() RUN_HOOK (SCM_VM_RETURN_HOOK)
3d5ee0cd
KN
230
231\f
a98cef7e
KN
232/*
233 * Stack operation
234 */
235
11ea1aba
AW
236#ifdef VM_ENABLE_STACK_NULLING
237# define CHECK_STACK_LEAKN(_n) ASSERT (!sp[_n]);
238# define CHECK_STACK_LEAK() CHECK_STACK_LEAKN(1)
239# define NULLSTACK(_n) { int __x = _n; CHECK_STACK_LEAKN (_n+1); while (__x > 0) sp[__x--] = NULL; }
66db076a
AW
240/* If you have a nonlocal exit in a pre-wind proc while invoking a continuation
241 inside a dynwind (phew!), the stack is fully rewound but vm_reset_stack for
242 that continuation doesn't have a chance to run. It's not important on a
243 semantic level, but it does mess up our stack nulling -- so this macro is to
244 fix that. */
245# define NULLSTACK_FOR_NONLOCAL_EXIT() if (vp->sp > sp) NULLSTACK (vp->sp - sp);
11ea1aba
AW
246#else
247# define CHECK_STACK_LEAKN(_n)
248# define CHECK_STACK_LEAK()
249# define NULLSTACK(_n)
66db076a 250# define NULLSTACK_FOR_NONLOCAL_EXIT()
11ea1aba
AW
251#endif
252
17e90c5e 253#define CHECK_OVERFLOW() \
75d315e1 254 if (sp >= stack_limit) \
17e90c5e
KN
255 goto vm_error_stack_overflow
256
7e4760e4 257#define CHECK_UNDERFLOW() \
6c6a4439 258 if (sp < SCM_FRAME_UPPER_ADDRESS (fp)) \
7e4760e4 259 goto vm_error_stack_underflow;
a98cef7e 260
3616e9e9 261#define PUSH(x) do { sp++; CHECK_OVERFLOW (); *sp = x; } while (0)
11ea1aba
AW
262#define DROP() do { sp--; CHECK_UNDERFLOW (); NULLSTACK (1); } while (0)
263#define DROPN(_n) do { sp -= (_n); CHECK_UNDERFLOW (); NULLSTACK (_n); } while (0)
17e90c5e
KN
264#define POP(x) do { x = *sp; DROP (); } while (0)
265
2d80426a
LC
266/* A fast CONS. This has to be fast since its used, for instance, by
267 POP_LIST when fetching a function's argument list. Note: `scm_cell' is an
268 inlined function in Guile 1.7. Unfortunately, it calls
269 `scm_gc_for_newcell ()' which is _not_ inlined and allocated cells on the
270 heap. XXX */
271#define CONS(x,y,z) \
272{ \
273 SYNC_BEFORE_GC (); \
274 x = scm_cell (SCM_UNPACK (y), SCM_UNPACK (z)); \
a98cef7e
KN
275}
276
f41cb00c
LC
277/* Pop the N objects on top of the stack and push a list that contains
278 them. */
17e90c5e 279#define POP_LIST(n) \
f41cb00c
LC
280do \
281{ \
17e90c5e 282 int i; \
11ea1aba
AW
283 SCM l = SCM_EOL, x; \
284 for (i = n; i; i--) \
285 { \
286 POP (x); \
287 CONS (l, x, l); \
288 } \
3616e9e9 289 PUSH (l); \
17e90c5e
KN
290} while (0)
291
1f40459f 292/* The opposite: push all of the elements in L onto the list. */
fb10a008 293#define PUSH_LIST(l, NILP) \
1f40459f
AW
294do \
295{ \
296 for (; scm_is_pair (l); l = SCM_CDR (l)) \
297 PUSH (SCM_CAR (l)); \
fb10a008 298 if (SCM_UNLIKELY (!NILP (l))) { \
e06e857c 299 finish_args = scm_list_1 (l); \
1f40459f
AW
300 goto vm_error_improper_list; \
301 } \
302} while (0)
303
135b32ee 304\f
cb4cca12
KN
305#define POP_LIST_MARK() \
306do { \
307 SCM o; \
308 SCM l = SCM_EOL; \
309 POP (o); \
310 while (!SCM_UNBNDP (o)) \
311 { \
312 CONS (l, o, l); \
313 POP (o); \
314 } \
315 PUSH (l); \
316} while (0)
317
2bd859c8
AW
318#define POP_CONS_MARK() \
319do { \
320 SCM o, l; \
321 POP (l); \
322 POP (o); \
323 while (!SCM_UNBNDP (o)) \
324 { \
325 CONS (l, o, l); \
326 POP (o); \
327 } \
328 PUSH (l); \
329} while (0)
330
a98cef7e
KN
331\f
332/*
17e90c5e 333 * Instruction operation
a98cef7e
KN
334 */
335
17e90c5e 336#define FETCH() (*ip++)
53e28ed9 337#define FETCH_LENGTH(len) do { len=*ip++; len<<=8; len+=*ip++; len<<=8; len+=*ip++; } while (0)
17e90c5e
KN
338
339#undef CLOCK
340#if VM_USE_CLOCK
3d5ee0cd 341#define CLOCK(n) vp->clock += n
a98cef7e 342#else
17e90c5e 343#define CLOCK(n)
a98cef7e
KN
344#endif
345
17e90c5e
KN
346#undef NEXT_JUMP
347#ifdef HAVE_LABELS_AS_VALUES
53e28ed9 348#define NEXT_JUMP() goto *jump_table[FETCH () & SCM_VM_INSTRUCTION_MASK]
17e90c5e
KN
349#else
350#define NEXT_JUMP() goto vm_start
351#endif
352
353#define NEXT \
354{ \
355 CLOCK (1); \
17e90c5e 356 NEXT_HOOK (); \
11ea1aba 357 CHECK_STACK_LEAK (); \
17e90c5e 358 NEXT_JUMP (); \
a98cef7e
KN
359}
360
361\f
ac99cb0c 362/* See frames.h for the layout of stack frames */
2cdb8cdc
AW
363/* When this is called, bp points to the new program data,
364 and the arguments are already on the stack */
03e6c165
AW
365#define DROP_FRAME() \
366 { \
367 sp -= 3; \
368 NULLSTACK (3); \
369 CHECK_UNDERFLOW (); \
370 }
371
372
17e90c5e
KN
373/*
374 Local Variables:
375 c-file-style: "gnu"
376 End:
377*/