and, or, cond etc use syntax-rules, compile scheme through tree-il
[bpt/guile.git] / libguile / vm-engine.h
CommitLineData
8f5cfc81 1/* Copyright (C) 2001 Free Software Foundation, Inc.
a98cef7e
KN
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
40 * If you do not wish that, delete this exception notice. */
41
42/* This file is included in vm_engine.c */
43
a98cef7e
KN
44\f
45/*
17e90c5e 46 * Registers
a98cef7e
KN
47 */
48
17e90c5e 49/* Register optimization. [ stolen from librep/src/lispmach.h,v 1.3 ]
9df03fd0 50
17e90c5e
KN
51 Some compilers underestimate the use of the local variables representing
52 the abstract machine registers, and don't put them in hardware registers,
53 which slows down the interpreter considerably.
54 For GCC, I have hand-assigned hardware registers for several architectures.
55*/
9df03fd0 56
17e90c5e
KN
57#ifdef __GNUC__
58#ifdef __mips__
59#define IP_REG asm("$16")
60#define SP_REG asm("$17")
61#define FP_REG asm("$18")
62#endif
63#ifdef __sparc__
64#define IP_REG asm("%l0")
65#define SP_REG asm("%l1")
66#define FP_REG asm("%l2")
67#endif
68#ifdef __alpha__
69#ifdef __CRAY__
70#define IP_REG asm("r9")
71#define SP_REG asm("r10")
72#define FP_REG asm("r11")
9df03fd0 73#else
17e90c5e
KN
74#define IP_REG asm("$9")
75#define SP_REG asm("$10")
76#define FP_REG asm("$11")
77#endif
78#endif
79#ifdef __i386__
893be93f
AW
80/* gcc on lenny actually crashes if we allocate these variables in registers.
81 hopefully this is the only one of these. */
82#if !(__GNUC__==4 && __GNUC_MINOR__==1 && __GNUC_PATCHLEVEL__==2)
17e90c5e
KN
83#define IP_REG asm("%esi")
84#define SP_REG asm("%edi")
85#define FP_REG
86#endif
893be93f 87#endif
17e90c5e
KN
88#if defined(PPC) || defined(_POWER) || defined(_IBMR2)
89#define IP_REG asm("26")
90#define SP_REG asm("27")
91#define FP_REG asm("28")
92#endif
93#ifdef __hppa__
94#define IP_REG asm("%r18")
95#define SP_REG asm("%r17")
96#define FP_REG asm("%r16")
97#endif
98#ifdef __mc68000__
99#define IP_REG asm("a5")
100#define SP_REG asm("a4")
101#define FP_REG
102#endif
103#ifdef __arm__
104#define IP_REG asm("r9")
105#define SP_REG asm("r8")
106#define FP_REG asm("r7")
107#endif
9df03fd0
KN
108#endif
109
17d1b4bf
AW
110#ifndef IP_REG
111#define IP_REG
112#endif
113#ifndef SP_REG
114#define SP_REG
115#endif
116#ifndef FP_REG
117#define FP_REG
118#endif
119
9df03fd0 120\f
a98cef7e 121/*
3d5ee0cd 122 * Cache/Sync
a98cef7e
KN
123 */
124
11ea1aba 125#ifdef VM_ENABLE_ASSERTIONS
9a8cc8e7
AW
126# define ASSERT(condition) if (SCM_UNLIKELY (!(condition))) abort()
127#else
128# define ASSERT(condition)
129#endif
130
131
3d5ee0cd 132#define CACHE_REGISTER() \
17e90c5e 133{ \
3d5ee0cd
KN
134 ip = vp->ip; \
135 sp = vp->sp; \
136 fp = vp->fp; \
f13c269b 137 stack_base = fp ? SCM_FRAME_UPPER_ADDRESS (fp) - 1 : vp->stack_base; \
17e90c5e 138}
a98cef7e 139
3d5ee0cd 140#define SYNC_REGISTER() \
a98cef7e 141{ \
3d5ee0cd
KN
142 vp->ip = ip; \
143 vp->sp = sp; \
144 vp->fp = fp; \
a98cef7e
KN
145}
146
11ea1aba 147#ifdef VM_ENABLE_PARANOID_ASSERTIONS
7e4760e4 148#define CHECK_IP() \
53e28ed9 149 do { if (ip < bp->base || ip - bp->base > bp->len) abort (); } while (0)
a1a482e0
AW
150#define ASSERT_BOUND(x) \
151 do { if ((x) == SCM_UNDEFINED) { SYNC_REGISTER (); abort(); } \
152 } while (0)
7e4760e4
AW
153#else
154#define CHECK_IP()
a1a482e0 155#define ASSERT_BOUND(x)
7e4760e4
AW
156#endif
157
238e7a11
LC
158/* Get a local copy of the program's "object table" (i.e. the vector of
159 external bindings that are referenced by the program), initialized by
160 `load-program'. */
a52b2d3d
LC
161/* XXX: We could instead use the "simple vector macros", thus not having to
162 call `scm_vector_writable_elements ()' and the likes. */
163#define CACHE_PROGRAM() \
164{ \
e677365c
AW
165 if (bp != SCM_PROGRAM_DATA (program)) { \
166 bp = SCM_PROGRAM_DATA (program); \
53e28ed9
AW
167 if (SCM_I_IS_VECTOR (SCM_PROGRAM_OBJTABLE (program))) { \
168 objects = SCM_I_VECTOR_WELTS (SCM_PROGRAM_OBJTABLE (program)); \
169 object_count = SCM_I_VECTOR_LENGTH (SCM_PROGRAM_OBJTABLE (program)); \
2fda0242
AW
170 } else { \
171 objects = NULL; \
172 object_count = 0; \
173 } \
e677365c 174 } \
41f248a8
KN
175}
176
3d5ee0cd
KN
177#define SYNC_BEFORE_GC() \
178{ \
179 SYNC_REGISTER (); \
17e90c5e 180}
a98cef7e 181
17e90c5e 182#define SYNC_ALL() \
a98cef7e 183{ \
3d5ee0cd 184 SYNC_REGISTER (); \
a98cef7e
KN
185}
186
a98cef7e 187\f
ac02b386
KN
188/*
189 * Error check
190 */
191
192#undef CHECK_EXTERNAL
193#if VM_CHECK_EXTERNAL
194#define CHECK_EXTERNAL(e) \
6d14383e 195 do { if (SCM_UNLIKELY (!SCM_CONSP (e))) goto vm_error_external; } while (0)
ac02b386
KN
196#else
197#define CHECK_EXTERNAL(e)
198#endif
199
0b5f0e49
LC
200/* Accesses to a program's object table. */
201#if VM_CHECK_OBJECT
202#define CHECK_OBJECT(_num) \
6d14383e 203 do { if (SCM_UNLIKELY ((_num) >= object_count)) goto vm_error_object; } while (0)
0b5f0e49
LC
204#else
205#define CHECK_OBJECT(_num)
206#endif
207
ac02b386 208\f
3d5ee0cd
KN
209/*
210 * Hooks
211 */
212
213#undef RUN_HOOK
214#if VM_USE_HOOKS
215#define RUN_HOOK(h) \
216{ \
b1b942b7 217 if (SCM_UNLIKELY (!SCM_FALSEP (vp->hooks[h])))\
3d5ee0cd 218 { \
af988bbf 219 SYNC_REGISTER (); \
6d14383e 220 vm_dispatch_hook (vp, vp->hooks[h], hook_args); \
af988bbf 221 CACHE_REGISTER (); \
3d5ee0cd
KN
222 } \
223}
224#else
225#define RUN_HOOK(h)
226#endif
227
ac02b386
KN
228#define BOOT_HOOK() RUN_HOOK (SCM_VM_BOOT_HOOK)
229#define HALT_HOOK() RUN_HOOK (SCM_VM_HALT_HOOK)
230#define NEXT_HOOK() RUN_HOOK (SCM_VM_NEXT_HOOK)
7a0d0cee 231#define BREAK_HOOK() RUN_HOOK (SCM_VM_BREAK_HOOK)
ac02b386
KN
232#define ENTER_HOOK() RUN_HOOK (SCM_VM_ENTER_HOOK)
233#define APPLY_HOOK() RUN_HOOK (SCM_VM_APPLY_HOOK)
234#define EXIT_HOOK() RUN_HOOK (SCM_VM_EXIT_HOOK)
235#define RETURN_HOOK() RUN_HOOK (SCM_VM_RETURN_HOOK)
3d5ee0cd
KN
236
237\f
a98cef7e
KN
238/*
239 * Stack operation
240 */
241
11ea1aba
AW
242#ifdef VM_ENABLE_STACK_NULLING
243# define CHECK_STACK_LEAKN(_n) ASSERT (!sp[_n]);
244# define CHECK_STACK_LEAK() CHECK_STACK_LEAKN(1)
245# define NULLSTACK(_n) { int __x = _n; CHECK_STACK_LEAKN (_n+1); while (__x > 0) sp[__x--] = NULL; }
66db076a
AW
246/* If you have a nonlocal exit in a pre-wind proc while invoking a continuation
247 inside a dynwind (phew!), the stack is fully rewound but vm_reset_stack for
248 that continuation doesn't have a chance to run. It's not important on a
249 semantic level, but it does mess up our stack nulling -- so this macro is to
250 fix that. */
251# define NULLSTACK_FOR_NONLOCAL_EXIT() if (vp->sp > sp) NULLSTACK (vp->sp - sp);
11ea1aba
AW
252#else
253# define CHECK_STACK_LEAKN(_n)
254# define CHECK_STACK_LEAK()
255# define NULLSTACK(_n)
66db076a 256# define NULLSTACK_FOR_NONLOCAL_EXIT()
11ea1aba
AW
257#endif
258
17e90c5e 259#define CHECK_OVERFLOW() \
3616e9e9 260 if (sp > stack_limit) \
17e90c5e
KN
261 goto vm_error_stack_overflow
262
7e4760e4
AW
263#define CHECK_UNDERFLOW() \
264 if (sp < stack_base) \
265 goto vm_error_stack_underflow;
a98cef7e 266
3616e9e9 267#define PUSH(x) do { sp++; CHECK_OVERFLOW (); *sp = x; } while (0)
11ea1aba
AW
268#define DROP() do { sp--; CHECK_UNDERFLOW (); NULLSTACK (1); } while (0)
269#define DROPN(_n) do { sp -= (_n); CHECK_UNDERFLOW (); NULLSTACK (_n); } while (0)
17e90c5e
KN
270#define POP(x) do { x = *sp; DROP (); } while (0)
271
2d80426a
LC
272/* A fast CONS. This has to be fast since its used, for instance, by
273 POP_LIST when fetching a function's argument list. Note: `scm_cell' is an
274 inlined function in Guile 1.7. Unfortunately, it calls
275 `scm_gc_for_newcell ()' which is _not_ inlined and allocated cells on the
276 heap. XXX */
277#define CONS(x,y,z) \
278{ \
279 SYNC_BEFORE_GC (); \
280 x = scm_cell (SCM_UNPACK (y), SCM_UNPACK (z)); \
a98cef7e
KN
281}
282
f41cb00c
LC
283/* Pop the N objects on top of the stack and push a list that contains
284 them. */
17e90c5e 285#define POP_LIST(n) \
f41cb00c
LC
286do \
287{ \
17e90c5e 288 int i; \
11ea1aba
AW
289 SCM l = SCM_EOL, x; \
290 for (i = n; i; i--) \
291 { \
292 POP (x); \
293 CONS (l, x, l); \
294 } \
3616e9e9 295 PUSH (l); \
17e90c5e
KN
296} while (0)
297
1f40459f 298/* The opposite: push all of the elements in L onto the list. */
fb10a008 299#define PUSH_LIST(l, NILP) \
1f40459f
AW
300do \
301{ \
302 for (; scm_is_pair (l); l = SCM_CDR (l)) \
303 PUSH (SCM_CAR (l)); \
fb10a008 304 if (SCM_UNLIKELY (!NILP (l))) { \
e06e857c 305 finish_args = scm_list_1 (l); \
1f40459f
AW
306 goto vm_error_improper_list; \
307 } \
308} while (0)
309
135b32ee 310\f
cb4cca12
KN
311#define POP_LIST_MARK() \
312do { \
313 SCM o; \
314 SCM l = SCM_EOL; \
315 POP (o); \
316 while (!SCM_UNBNDP (o)) \
317 { \
318 CONS (l, o, l); \
319 POP (o); \
320 } \
321 PUSH (l); \
322} while (0)
323
2bd859c8
AW
324#define POP_CONS_MARK() \
325do { \
326 SCM o, l; \
327 POP (l); \
328 POP (o); \
329 while (!SCM_UNBNDP (o)) \
330 { \
331 CONS (l, o, l); \
332 POP (o); \
333 } \
334 PUSH (l); \
335} while (0)
336
a98cef7e
KN
337\f
338/*
17e90c5e 339 * Instruction operation
a98cef7e
KN
340 */
341
17e90c5e 342#define FETCH() (*ip++)
53e28ed9 343#define FETCH_LENGTH(len) do { len=*ip++; len<<=8; len+=*ip++; len<<=8; len+=*ip++; } while (0)
17e90c5e
KN
344
345#undef CLOCK
346#if VM_USE_CLOCK
3d5ee0cd 347#define CLOCK(n) vp->clock += n
a98cef7e 348#else
17e90c5e 349#define CLOCK(n)
a98cef7e
KN
350#endif
351
17e90c5e
KN
352#undef NEXT_JUMP
353#ifdef HAVE_LABELS_AS_VALUES
53e28ed9 354#define NEXT_JUMP() goto *jump_table[FETCH () & SCM_VM_INSTRUCTION_MASK]
17e90c5e
KN
355#else
356#define NEXT_JUMP() goto vm_start
357#endif
358
359#define NEXT \
360{ \
361 CLOCK (1); \
17e90c5e 362 NEXT_HOOK (); \
11ea1aba 363 CHECK_STACK_LEAK (); \
17e90c5e 364 NEXT_JUMP (); \
a98cef7e
KN
365}
366
367\f
368/*
ac02b386 369 * Stack frame
17e90c5e
KN
370 */
371
17e90c5e
KN
372#define INIT_ARGS() \
373{ \
7edf2001 374 if (SCM_UNLIKELY (bp->nrest)) \
17e90c5e 375 { \
5315b862 376 int n = nargs - (bp->nargs - 1); \
17e90c5e
KN
377 if (n < 0) \
378 goto vm_error_wrong_num_args; \
11ea1aba
AW
379 /* NB, can cause GC while setting up the \
380 stack frame */ \
17e90c5e
KN
381 POP_LIST (n); \
382 } \
383 else \
384 { \
7edf2001 385 if (SCM_UNLIKELY (nargs != bp->nargs)) \
17e90c5e
KN
386 goto vm_error_wrong_num_args; \
387 } \
388}
389
ac99cb0c 390/* See frames.h for the layout of stack frames */
2cdb8cdc
AW
391/* When this is called, bp points to the new program data,
392 and the arguments are already on the stack */
3616e9e9
KN
393#define NEW_FRAME() \
394{ \
24aa2715 395 int i; \
2cdb8cdc
AW
396 SCM *dl, *data; \
397 scm_byte_t *ra = ip; \
24aa2715 398 \
2cdb8cdc
AW
399 /* Save old registers */ \
400 ra = ip; \
401 dl = fp; \
402 \
403 /* New registers */ \
404 fp = sp - bp->nargs + 1; \
405 data = SCM_FRAME_DATA_ADDRESS (fp); \
b1b942b7 406 sp = data + 3; \
3616e9e9 407 CHECK_OVERFLOW (); \
2cdb8cdc
AW
408 stack_base = sp; \
409 ip = bp->base; \
24aa2715
KN
410 \
411 /* Init local variables */ \
2cdb8cdc
AW
412 for (i=bp->nlocs; i; i--) \
413 data[-i] = SCM_UNDEFINED; \
24aa2715 414 \
ac02b386 415 /* Set frame data */ \
b1b942b7
AW
416 data[3] = (SCM)ra; \
417 data[2] = 0x0; \
418 data[1] = (SCM)dl; \
11ea1aba
AW
419 \
420 /* Postpone initializing external vars, \
421 because if the CONS causes a GC, we \
422 want the stack marker to see the data \
423 array formatted as expected. */ \
424 data[0] = SCM_UNDEFINED; \
53e28ed9 425 external = SCM_PROGRAM_EXTERNALS (fp[-1]); \
11ea1aba
AW
426 for (i = 0; i < bp->nexts; i++) \
427 CONS (external, SCM_UNDEFINED, external); \
428 data[0] = external; \
3616e9e9
KN
429}
430
af988bbf
KN
431#define CACHE_EXTERNAL() external = fp[bp->nargs + bp->nlocs]
432
17e90c5e
KN
433/*
434 Local Variables:
435 c-file-style: "gnu"
436 End:
437*/