remove unused (system vm profile)
[bpt/guile.git] / libguile / vm-engine.h
CommitLineData
9823fd39 1/* Copyright (C) 2001, 2009, 2010 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
9823fd39 105/* Cache the VM's instruction, stack, and frame pointer in local variables. */
3d5ee0cd 106#define CACHE_REGISTER() \
17e90c5e 107{ \
3d5ee0cd
KN
108 ip = vp->ip; \
109 sp = vp->sp; \
110 fp = vp->fp; \
17e90c5e 111}
a98cef7e 112
9823fd39
LC
113/* Update the registers in VP, a pointer to the current VM. This must be done
114 at least before any GC invocation so that `vp->sp' is up-to-date and the
115 whole stack gets marked. */
3d5ee0cd 116#define SYNC_REGISTER() \
a98cef7e 117{ \
3d5ee0cd
KN
118 vp->ip = ip; \
119 vp->sp = sp; \
120 vp->fp = fp; \
a98cef7e
KN
121}
122
8d90b356
AW
123/* FIXME */
124#define ASSERT_VARIABLE(x) \
125 do { if (!SCM_VARIABLEP (x)) { SYNC_REGISTER (); abort(); } \
126 } while (0)
127#define ASSERT_BOUND_VARIABLE(x) \
128 do { ASSERT_VARIABLE (x); \
129 if (SCM_VARIABLE_REF (x) == SCM_UNDEFINED) \
130 { SYNC_REGISTER (); abort(); } \
131 } while (0)
132
11ea1aba 133#ifdef VM_ENABLE_PARANOID_ASSERTIONS
7e4760e4 134#define CHECK_IP() \
53e28ed9 135 do { if (ip < bp->base || ip - bp->base > bp->len) abort (); } while (0)
28b119ee
AW
136#define ASSERT_ALIGNED_PROCEDURE() \
137 do { if ((scm_t_bits)bp % 8) abort (); } while (0)
a1a482e0
AW
138#define ASSERT_BOUND(x) \
139 do { if ((x) == SCM_UNDEFINED) { SYNC_REGISTER (); abort(); } \
140 } while (0)
7e4760e4
AW
141#else
142#define CHECK_IP()
28b119ee 143#define ASSERT_ALIGNED_PROCEDURE()
a1a482e0 144#define ASSERT_BOUND(x)
7e4760e4
AW
145#endif
146
20d47c39 147/* Cache the object table and free variables. */
a52b2d3d
LC
148#define CACHE_PROGRAM() \
149{ \
e677365c
AW
150 if (bp != SCM_PROGRAM_DATA (program)) { \
151 bp = SCM_PROGRAM_DATA (program); \
28b119ee 152 ASSERT_ALIGNED_PROCEDURE (); \
53e28ed9
AW
153 if (SCM_I_IS_VECTOR (SCM_PROGRAM_OBJTABLE (program))) { \
154 objects = SCM_I_VECTOR_WELTS (SCM_PROGRAM_OBJTABLE (program)); \
155 object_count = SCM_I_VECTOR_LENGTH (SCM_PROGRAM_OBJTABLE (program)); \
2fda0242
AW
156 } else { \
157 objects = NULL; \
158 object_count = 0; \
159 } \
e677365c 160 } \
41f248a8
KN
161}
162
3d5ee0cd
KN
163#define SYNC_BEFORE_GC() \
164{ \
165 SYNC_REGISTER (); \
17e90c5e 166}
a98cef7e 167
17e90c5e 168#define SYNC_ALL() \
a98cef7e 169{ \
3d5ee0cd 170 SYNC_REGISTER (); \
a98cef7e
KN
171}
172
a98cef7e 173\f
ac02b386
KN
174/*
175 * Error check
176 */
177
0b5f0e49
LC
178/* Accesses to a program's object table. */
179#if VM_CHECK_OBJECT
180#define CHECK_OBJECT(_num) \
6d14383e 181 do { if (SCM_UNLIKELY ((_num) >= object_count)) goto vm_error_object; } while (0)
0b5f0e49
LC
182#else
183#define CHECK_OBJECT(_num)
184#endif
185
57ab0671 186#if VM_CHECK_FREE_VARIABLES
6f16379e
AW
187#define CHECK_FREE_VARIABLE(_num) \
188 do { \
189 if (SCM_UNLIKELY ((_num) >= SCM_PROGRAM_NUM_FREE_VARIABLES (program))) \
190 goto vm_error_free_variable; \
191 } while (0)
8d90b356 192#else
57ab0671 193#define CHECK_FREE_VARIABLE(_num)
8d90b356
AW
194#endif
195
ac02b386 196\f
3d5ee0cd
KN
197/*
198 * Hooks
199 */
200
201#undef RUN_HOOK
45cc4867 202#undef RUN_HOOK1
3d5ee0cd 203#if VM_USE_HOOKS
7656f194
AW
204#define RUN_HOOK(h) \
205 { \
206 if (SCM_UNLIKELY (vp->trace_level > 0)) \
207 { \
208 SYNC_REGISTER (); \
209 vm_dispatch_hook (vm, h); \
210 } \
211 }
45cc4867
AW
212#define RUN_HOOK1(h, x) \
213 { \
214 if (SCM_UNLIKELY (vp->trace_level > 0)) \
215 { \
216 PUSH (x); \
217 SYNC_REGISTER (); \
218 vm_dispatch_hook (vm, h); \
219 DROP(); \
220 } \
221 }
3d5ee0cd
KN
222#else
223#define RUN_HOOK(h)
45cc4867 224#define RUN_HOOK1(h, x)
3d5ee0cd
KN
225#endif
226
ac02b386
KN
227#define BOOT_HOOK() RUN_HOOK (SCM_VM_BOOT_HOOK)
228#define HALT_HOOK() RUN_HOOK (SCM_VM_HALT_HOOK)
229#define NEXT_HOOK() RUN_HOOK (SCM_VM_NEXT_HOOK)
7a0d0cee 230#define BREAK_HOOK() RUN_HOOK (SCM_VM_BREAK_HOOK)
ac02b386
KN
231#define ENTER_HOOK() RUN_HOOK (SCM_VM_ENTER_HOOK)
232#define APPLY_HOOK() RUN_HOOK (SCM_VM_APPLY_HOOK)
233#define EXIT_HOOK() RUN_HOOK (SCM_VM_EXIT_HOOK)
45cc4867 234#define RETURN_HOOK(n) RUN_HOOK1 (SCM_VM_RETURN_HOOK, SCM_I_MAKINUM (n))
3d5ee0cd 235
e8c37772
AW
236#define VM_HANDLE_INTERRUPTS \
237 SCM_ASYNC_TICK_WITH_CODE (SYNC_REGISTER ())
238
3d5ee0cd 239\f
a98cef7e
KN
240/*
241 * Stack operation
242 */
243
11ea1aba
AW
244#ifdef VM_ENABLE_STACK_NULLING
245# define CHECK_STACK_LEAKN(_n) ASSERT (!sp[_n]);
246# define CHECK_STACK_LEAK() CHECK_STACK_LEAKN(1)
247# define NULLSTACK(_n) { int __x = _n; CHECK_STACK_LEAKN (_n+1); while (__x > 0) sp[__x--] = NULL; }
66db076a
AW
248/* If you have a nonlocal exit in a pre-wind proc while invoking a continuation
249 inside a dynwind (phew!), the stack is fully rewound but vm_reset_stack for
250 that continuation doesn't have a chance to run. It's not important on a
251 semantic level, but it does mess up our stack nulling -- so this macro is to
252 fix that. */
253# define NULLSTACK_FOR_NONLOCAL_EXIT() if (vp->sp > sp) NULLSTACK (vp->sp - sp);
11ea1aba
AW
254#else
255# define CHECK_STACK_LEAKN(_n)
256# define CHECK_STACK_LEAK()
257# define NULLSTACK(_n)
66db076a 258# define NULLSTACK_FOR_NONLOCAL_EXIT()
11ea1aba
AW
259#endif
260
17e90c5e 261#define CHECK_OVERFLOW() \
ba2d9603 262 if (SCM_UNLIKELY (sp >= stack_limit)) \
17e90c5e
KN
263 goto vm_error_stack_overflow
264
7e4760e4 265#define CHECK_UNDERFLOW() \
ba2d9603
AW
266 if (SCM_UNLIKELY (sp <= SCM_FRAME_UPPER_ADDRESS (fp))) \
267 goto vm_error_stack_underflow;
268
269#define PRE_CHECK_UNDERFLOW(N) \
270 if (SCM_UNLIKELY (sp - N <= SCM_FRAME_UPPER_ADDRESS (fp))) \
7e4760e4 271 goto vm_error_stack_underflow;
a98cef7e 272
3616e9e9 273#define PUSH(x) do { sp++; CHECK_OVERFLOW (); *sp = x; } while (0)
11ea1aba 274#define DROP() do { sp--; CHECK_UNDERFLOW (); NULLSTACK (1); } while (0)
ba2d9603
AW
275#define DROPN(_n) do { sp -= (_n); CHECK_UNDERFLOW (); NULLSTACK (_n); } while (0)
276#define POP(x) do { PRE_CHECK_UNDERFLOW (1); x = *sp--; NULLSTACK (1); } while (0)
17e90c5e 277
2d80426a
LC
278/* A fast CONS. This has to be fast since its used, for instance, by
279 POP_LIST when fetching a function's argument list. Note: `scm_cell' is an
280 inlined function in Guile 1.7. Unfortunately, it calls
281 `scm_gc_for_newcell ()' which is _not_ inlined and allocated cells on the
282 heap. XXX */
283#define CONS(x,y,z) \
284{ \
285 SYNC_BEFORE_GC (); \
286 x = scm_cell (SCM_UNPACK (y), SCM_UNPACK (z)); \
a98cef7e
KN
287}
288
f41cb00c
LC
289/* Pop the N objects on top of the stack and push a list that contains
290 them. */
17e90c5e 291#define POP_LIST(n) \
f41cb00c
LC
292do \
293{ \
17e90c5e 294 int i; \
11ea1aba
AW
295 SCM l = SCM_EOL, x; \
296 for (i = n; i; i--) \
297 { \
298 POP (x); \
299 CONS (l, x, l); \
300 } \
3616e9e9 301 PUSH (l); \
17e90c5e
KN
302} while (0)
303
1f40459f 304/* The opposite: push all of the elements in L onto the list. */
fb10a008 305#define PUSH_LIST(l, NILP) \
1f40459f
AW
306do \
307{ \
308 for (; scm_is_pair (l); l = SCM_CDR (l)) \
309 PUSH (SCM_CAR (l)); \
fb10a008 310 if (SCM_UNLIKELY (!NILP (l))) { \
e06e857c 311 finish_args = scm_list_1 (l); \
1f40459f
AW
312 goto vm_error_improper_list; \
313 } \
314} while (0)
315
135b32ee 316\f
cb4cca12
KN
317#define POP_LIST_MARK() \
318do { \
319 SCM o; \
320 SCM l = SCM_EOL; \
321 POP (o); \
322 while (!SCM_UNBNDP (o)) \
323 { \
324 CONS (l, o, l); \
325 POP (o); \
326 } \
327 PUSH (l); \
328} while (0)
329
2bd859c8
AW
330#define POP_CONS_MARK() \
331do { \
332 SCM o, l; \
333 POP (l); \
334 POP (o); \
335 while (!SCM_UNBNDP (o)) \
336 { \
337 CONS (l, o, l); \
338 POP (o); \
339 } \
340 PUSH (l); \
341} while (0)
342
a98cef7e
KN
343\f
344/*
17e90c5e 345 * Instruction operation
a98cef7e
KN
346 */
347
17e90c5e 348#define FETCH() (*ip++)
53e28ed9 349#define FETCH_LENGTH(len) do { len=*ip++; len<<=8; len+=*ip++; len<<=8; len+=*ip++; } while (0)
17e90c5e 350
17e90c5e
KN
351#undef NEXT_JUMP
352#ifdef HAVE_LABELS_AS_VALUES
53e28ed9 353#define NEXT_JUMP() goto *jump_table[FETCH () & SCM_VM_INSTRUCTION_MASK]
17e90c5e
KN
354#else
355#define NEXT_JUMP() goto vm_start
356#endif
357
358#define NEXT \
359{ \
17e90c5e 360 NEXT_HOOK (); \
11ea1aba 361 CHECK_STACK_LEAK (); \
17e90c5e 362 NEXT_JUMP (); \
a98cef7e
KN
363}
364
365\f
ac99cb0c 366/* See frames.h for the layout of stack frames */
2cdb8cdc
AW
367/* When this is called, bp points to the new program data,
368 and the arguments are already on the stack */
03e6c165
AW
369#define DROP_FRAME() \
370 { \
371 sp -= 3; \
372 NULLSTACK (3); \
373 CHECK_UNDERFLOW (); \
374 }
375
376
17e90c5e
KN
377/*
378 Local Variables:
379 c-file-style: "gnu"
380 End:
381*/