add scm_call_n, scm_c_run_hookn
[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 230
e8c37772
AW
231#define VM_HANDLE_INTERRUPTS \
232 SCM_ASYNC_TICK_WITH_CODE (SYNC_REGISTER ())
233
3d5ee0cd 234\f
a98cef7e
KN
235/*
236 * Stack operation
237 */
238
11ea1aba
AW
239#ifdef VM_ENABLE_STACK_NULLING
240# define CHECK_STACK_LEAKN(_n) ASSERT (!sp[_n]);
241# define CHECK_STACK_LEAK() CHECK_STACK_LEAKN(1)
242# define NULLSTACK(_n) { int __x = _n; CHECK_STACK_LEAKN (_n+1); while (__x > 0) sp[__x--] = NULL; }
66db076a
AW
243/* If you have a nonlocal exit in a pre-wind proc while invoking a continuation
244 inside a dynwind (phew!), the stack is fully rewound but vm_reset_stack for
245 that continuation doesn't have a chance to run. It's not important on a
246 semantic level, but it does mess up our stack nulling -- so this macro is to
247 fix that. */
248# define NULLSTACK_FOR_NONLOCAL_EXIT() if (vp->sp > sp) NULLSTACK (vp->sp - sp);
11ea1aba
AW
249#else
250# define CHECK_STACK_LEAKN(_n)
251# define CHECK_STACK_LEAK()
252# define NULLSTACK(_n)
66db076a 253# define NULLSTACK_FOR_NONLOCAL_EXIT()
11ea1aba
AW
254#endif
255
17e90c5e 256#define CHECK_OVERFLOW() \
75d315e1 257 if (sp >= stack_limit) \
17e90c5e
KN
258 goto vm_error_stack_overflow
259
7e4760e4 260#define CHECK_UNDERFLOW() \
6c6a4439 261 if (sp < SCM_FRAME_UPPER_ADDRESS (fp)) \
7e4760e4 262 goto vm_error_stack_underflow;
a98cef7e 263
3616e9e9 264#define PUSH(x) do { sp++; CHECK_OVERFLOW (); *sp = x; } while (0)
11ea1aba
AW
265#define DROP() do { sp--; CHECK_UNDERFLOW (); NULLSTACK (1); } while (0)
266#define DROPN(_n) do { sp -= (_n); CHECK_UNDERFLOW (); NULLSTACK (_n); } while (0)
17e90c5e
KN
267#define POP(x) do { x = *sp; DROP (); } while (0)
268
2d80426a
LC
269/* A fast CONS. This has to be fast since its used, for instance, by
270 POP_LIST when fetching a function's argument list. Note: `scm_cell' is an
271 inlined function in Guile 1.7. Unfortunately, it calls
272 `scm_gc_for_newcell ()' which is _not_ inlined and allocated cells on the
273 heap. XXX */
274#define CONS(x,y,z) \
275{ \
276 SYNC_BEFORE_GC (); \
277 x = scm_cell (SCM_UNPACK (y), SCM_UNPACK (z)); \
a98cef7e
KN
278}
279
f41cb00c
LC
280/* Pop the N objects on top of the stack and push a list that contains
281 them. */
17e90c5e 282#define POP_LIST(n) \
f41cb00c
LC
283do \
284{ \
17e90c5e 285 int i; \
11ea1aba
AW
286 SCM l = SCM_EOL, x; \
287 for (i = n; i; i--) \
288 { \
289 POP (x); \
290 CONS (l, x, l); \
291 } \
3616e9e9 292 PUSH (l); \
17e90c5e
KN
293} while (0)
294
1f40459f 295/* The opposite: push all of the elements in L onto the list. */
fb10a008 296#define PUSH_LIST(l, NILP) \
1f40459f
AW
297do \
298{ \
299 for (; scm_is_pair (l); l = SCM_CDR (l)) \
300 PUSH (SCM_CAR (l)); \
fb10a008 301 if (SCM_UNLIKELY (!NILP (l))) { \
e06e857c 302 finish_args = scm_list_1 (l); \
1f40459f
AW
303 goto vm_error_improper_list; \
304 } \
305} while (0)
306
135b32ee 307\f
cb4cca12
KN
308#define POP_LIST_MARK() \
309do { \
310 SCM o; \
311 SCM l = SCM_EOL; \
312 POP (o); \
313 while (!SCM_UNBNDP (o)) \
314 { \
315 CONS (l, o, l); \
316 POP (o); \
317 } \
318 PUSH (l); \
319} while (0)
320
2bd859c8
AW
321#define POP_CONS_MARK() \
322do { \
323 SCM o, l; \
324 POP (l); \
325 POP (o); \
326 while (!SCM_UNBNDP (o)) \
327 { \
328 CONS (l, o, l); \
329 POP (o); \
330 } \
331 PUSH (l); \
332} while (0)
333
a98cef7e
KN
334\f
335/*
17e90c5e 336 * Instruction operation
a98cef7e
KN
337 */
338
17e90c5e 339#define FETCH() (*ip++)
53e28ed9 340#define FETCH_LENGTH(len) do { len=*ip++; len<<=8; len+=*ip++; len<<=8; len+=*ip++; } while (0)
17e90c5e 341
17e90c5e
KN
342#undef NEXT_JUMP
343#ifdef HAVE_LABELS_AS_VALUES
53e28ed9 344#define NEXT_JUMP() goto *jump_table[FETCH () & SCM_VM_INSTRUCTION_MASK]
17e90c5e
KN
345#else
346#define NEXT_JUMP() goto vm_start
347#endif
348
349#define NEXT \
350{ \
17e90c5e 351 NEXT_HOOK (); \
11ea1aba 352 CHECK_STACK_LEAK (); \
17e90c5e 353 NEXT_JUMP (); \
a98cef7e
KN
354}
355
356\f
ac99cb0c 357/* See frames.h for the layout of stack frames */
2cdb8cdc
AW
358/* When this is called, bp points to the new program data,
359 and the arguments are already on the stack */
03e6c165
AW
360#define DROP_FRAME() \
361 { \
362 sp -= 3; \
363 NULLSTACK (3); \
364 CHECK_UNDERFLOW (); \
365 }
366
367
17e90c5e
KN
368/*
369 Local Variables:
370 c-file-style: "gnu"
371 End:
372*/