doc: Update "Multi-Threading" node.
[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 } \
41f248a8
KN
157}
158
3d5ee0cd
KN
159#define SYNC_BEFORE_GC() \
160{ \
161 SYNC_REGISTER (); \
17e90c5e 162}
a98cef7e 163
17e90c5e 164#define SYNC_ALL() \
a98cef7e 165{ \
3d5ee0cd 166 SYNC_REGISTER (); \
a98cef7e
KN
167}
168
a98cef7e 169\f
ac02b386
KN
170/*
171 * Error check
172 */
173
0b5f0e49
LC
174/* Accesses to a program's object table. */
175#if VM_CHECK_OBJECT
176#define CHECK_OBJECT(_num) \
6d14383e 177 do { if (SCM_UNLIKELY ((_num) >= object_count)) goto vm_error_object; } while (0)
0b5f0e49
LC
178#else
179#define CHECK_OBJECT(_num)
180#endif
181
57ab0671 182#if VM_CHECK_FREE_VARIABLES
6f16379e
AW
183#define CHECK_FREE_VARIABLE(_num) \
184 do { \
185 if (SCM_UNLIKELY ((_num) >= SCM_PROGRAM_NUM_FREE_VARIABLES (program))) \
186 goto vm_error_free_variable; \
187 } while (0)
8d90b356 188#else
57ab0671 189#define CHECK_FREE_VARIABLE(_num)
8d90b356
AW
190#endif
191
ac02b386 192\f
3d5ee0cd
KN
193/*
194 * Hooks
195 */
196
197#undef RUN_HOOK
45cc4867 198#undef RUN_HOOK1
3d5ee0cd 199#if VM_USE_HOOKS
7656f194
AW
200#define RUN_HOOK(h) \
201 { \
202 if (SCM_UNLIKELY (vp->trace_level > 0)) \
203 { \
204 SYNC_REGISTER (); \
205 vm_dispatch_hook (vm, h); \
206 } \
207 }
45cc4867
AW
208#define RUN_HOOK1(h, x) \
209 { \
210 if (SCM_UNLIKELY (vp->trace_level > 0)) \
211 { \
212 PUSH (x); \
213 SYNC_REGISTER (); \
214 vm_dispatch_hook (vm, h); \
215 DROP(); \
216 } \
217 }
3d5ee0cd
KN
218#else
219#define RUN_HOOK(h)
45cc4867 220#define RUN_HOOK1(h, x)
3d5ee0cd
KN
221#endif
222
ac02b386
KN
223#define BOOT_HOOK() RUN_HOOK (SCM_VM_BOOT_HOOK)
224#define HALT_HOOK() RUN_HOOK (SCM_VM_HALT_HOOK)
225#define NEXT_HOOK() RUN_HOOK (SCM_VM_NEXT_HOOK)
7a0d0cee 226#define BREAK_HOOK() RUN_HOOK (SCM_VM_BREAK_HOOK)
ac02b386
KN
227#define ENTER_HOOK() RUN_HOOK (SCM_VM_ENTER_HOOK)
228#define APPLY_HOOK() RUN_HOOK (SCM_VM_APPLY_HOOK)
229#define EXIT_HOOK() RUN_HOOK (SCM_VM_EXIT_HOOK)
45cc4867 230#define RETURN_HOOK(n) RUN_HOOK1 (SCM_VM_RETURN_HOOK, SCM_I_MAKINUM (n))
3d5ee0cd 231
e8c37772
AW
232#define VM_HANDLE_INTERRUPTS \
233 SCM_ASYNC_TICK_WITH_CODE (SYNC_REGISTER ())
234
3d5ee0cd 235\f
a98cef7e
KN
236/*
237 * Stack operation
238 */
239
11ea1aba
AW
240#ifdef VM_ENABLE_STACK_NULLING
241# define CHECK_STACK_LEAKN(_n) ASSERT (!sp[_n]);
242# define CHECK_STACK_LEAK() CHECK_STACK_LEAKN(1)
243# define NULLSTACK(_n) { int __x = _n; CHECK_STACK_LEAKN (_n+1); while (__x > 0) sp[__x--] = NULL; }
66db076a
AW
244/* If you have a nonlocal exit in a pre-wind proc while invoking a continuation
245 inside a dynwind (phew!), the stack is fully rewound but vm_reset_stack for
246 that continuation doesn't have a chance to run. It's not important on a
247 semantic level, but it does mess up our stack nulling -- so this macro is to
248 fix that. */
249# define NULLSTACK_FOR_NONLOCAL_EXIT() if (vp->sp > sp) NULLSTACK (vp->sp - sp);
11ea1aba
AW
250#else
251# define CHECK_STACK_LEAKN(_n)
252# define CHECK_STACK_LEAK()
253# define NULLSTACK(_n)
66db076a 254# define NULLSTACK_FOR_NONLOCAL_EXIT()
11ea1aba
AW
255#endif
256
17e90c5e 257#define CHECK_OVERFLOW() \
75d315e1 258 if (sp >= stack_limit) \
17e90c5e
KN
259 goto vm_error_stack_overflow
260
7e4760e4 261#define CHECK_UNDERFLOW() \
6c6a4439 262 if (sp < SCM_FRAME_UPPER_ADDRESS (fp)) \
7e4760e4 263 goto vm_error_stack_underflow;
a98cef7e 264
3616e9e9 265#define PUSH(x) do { sp++; CHECK_OVERFLOW (); *sp = x; } while (0)
11ea1aba
AW
266#define DROP() do { sp--; CHECK_UNDERFLOW (); NULLSTACK (1); } while (0)
267#define DROPN(_n) do { sp -= (_n); CHECK_UNDERFLOW (); NULLSTACK (_n); } while (0)
17e90c5e
KN
268#define POP(x) do { x = *sp; DROP (); } while (0)
269
2d80426a
LC
270/* A fast CONS. This has to be fast since its used, for instance, by
271 POP_LIST when fetching a function's argument list. Note: `scm_cell' is an
272 inlined function in Guile 1.7. Unfortunately, it calls
273 `scm_gc_for_newcell ()' which is _not_ inlined and allocated cells on the
274 heap. XXX */
275#define CONS(x,y,z) \
276{ \
277 SYNC_BEFORE_GC (); \
278 x = scm_cell (SCM_UNPACK (y), SCM_UNPACK (z)); \
a98cef7e
KN
279}
280
f41cb00c
LC
281/* Pop the N objects on top of the stack and push a list that contains
282 them. */
17e90c5e 283#define POP_LIST(n) \
f41cb00c
LC
284do \
285{ \
17e90c5e 286 int i; \
11ea1aba
AW
287 SCM l = SCM_EOL, x; \
288 for (i = n; i; i--) \
289 { \
290 POP (x); \
291 CONS (l, x, l); \
292 } \
3616e9e9 293 PUSH (l); \
17e90c5e
KN
294} while (0)
295
1f40459f 296/* The opposite: push all of the elements in L onto the list. */
fb10a008 297#define PUSH_LIST(l, NILP) \
1f40459f
AW
298do \
299{ \
300 for (; scm_is_pair (l); l = SCM_CDR (l)) \
301 PUSH (SCM_CAR (l)); \
fb10a008 302 if (SCM_UNLIKELY (!NILP (l))) { \
e06e857c 303 finish_args = scm_list_1 (l); \
1f40459f
AW
304 goto vm_error_improper_list; \
305 } \
306} while (0)
307
135b32ee 308\f
cb4cca12
KN
309#define POP_LIST_MARK() \
310do { \
311 SCM o; \
312 SCM l = SCM_EOL; \
313 POP (o); \
314 while (!SCM_UNBNDP (o)) \
315 { \
316 CONS (l, o, l); \
317 POP (o); \
318 } \
319 PUSH (l); \
320} while (0)
321
2bd859c8
AW
322#define POP_CONS_MARK() \
323do { \
324 SCM o, l; \
325 POP (l); \
326 POP (o); \
327 while (!SCM_UNBNDP (o)) \
328 { \
329 CONS (l, o, l); \
330 POP (o); \
331 } \
332 PUSH (l); \
333} while (0)
334
a98cef7e
KN
335\f
336/*
17e90c5e 337 * Instruction operation
a98cef7e
KN
338 */
339
17e90c5e 340#define FETCH() (*ip++)
53e28ed9 341#define FETCH_LENGTH(len) do { len=*ip++; len<<=8; len+=*ip++; len<<=8; len+=*ip++; } while (0)
17e90c5e 342
17e90c5e
KN
343#undef NEXT_JUMP
344#ifdef HAVE_LABELS_AS_VALUES
53e28ed9 345#define NEXT_JUMP() goto *jump_table[FETCH () & SCM_VM_INSTRUCTION_MASK]
17e90c5e
KN
346#else
347#define NEXT_JUMP() goto vm_start
348#endif
349
350#define NEXT \
351{ \
17e90c5e 352 NEXT_HOOK (); \
11ea1aba 353 CHECK_STACK_LEAK (); \
17e90c5e 354 NEXT_JUMP (); \
a98cef7e
KN
355}
356
357\f
ac99cb0c 358/* See frames.h for the layout of stack frames */
2cdb8cdc
AW
359/* When this is called, bp points to the new program data,
360 and the arguments are already on the stack */
03e6c165
AW
361#define DROP_FRAME() \
362 { \
363 sp -= 3; \
364 NULLSTACK (3); \
365 CHECK_UNDERFLOW (); \
366 }
367
368
17e90c5e
KN
369/*
370 Local Variables:
371 c-file-style: "gnu"
372 End:
373*/