1 /* Copyright (C) 2001, 2009 Free Software Foundation, Inc.
3 * This library is free software; you can redistribute it and/or
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.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
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
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 /* This file is included in vm_engine.c */
26 /* Register optimization. [ stolen from librep/src/lispmach.h,v 1.3 ]
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.
36 #define IP_REG asm("$16")
37 #define SP_REG asm("$17")
38 #define FP_REG asm("$18")
41 #define IP_REG asm("%l0")
42 #define SP_REG asm("%l1")
43 #define FP_REG asm("%l2")
47 #define IP_REG asm("r9")
48 #define SP_REG asm("r10")
49 #define FP_REG asm("r11")
51 #define IP_REG asm("$9")
52 #define SP_REG asm("$10")
53 #define FP_REG asm("$11")
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. */
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")
67 #define IP_REG asm("%r18")
68 #define SP_REG asm("%r17")
69 #define FP_REG asm("%r16")
72 #define IP_REG asm("a5")
73 #define SP_REG asm("a4")
77 #define IP_REG asm("r9")
78 #define SP_REG asm("r8")
79 #define FP_REG asm("r7")
98 #ifdef VM_ENABLE_ASSERTIONS
99 # define ASSERT(condition) if (SCM_UNLIKELY (!(condition))) abort()
101 # define ASSERT(condition)
105 #define CACHE_REGISTER() \
112 #define SYNC_REGISTER() \
120 #define ASSERT_VARIABLE(x) \
121 do { if (!SCM_VARIABLEP (x)) { SYNC_REGISTER (); abort(); } \
123 #define ASSERT_BOUND_VARIABLE(x) \
124 do { ASSERT_VARIABLE (x); \
125 if (SCM_VARIABLE_REF (x) == SCM_UNDEFINED) \
126 { SYNC_REGISTER (); abort(); } \
129 #ifdef VM_ENABLE_PARANOID_ASSERTIONS
131 do { if (ip < bp->base || ip - bp->base > bp->len) abort (); } while (0)
132 #define ASSERT_ALIGNED_PROCEDURE() \
133 do { if ((scm_t_bits)bp % 8) abort (); } while (0)
134 #define ASSERT_BOUND(x) \
135 do { if ((x) == SCM_UNDEFINED) { SYNC_REGISTER (); abort(); } \
139 #define ASSERT_ALIGNED_PROCEDURE()
140 #define ASSERT_BOUND(x)
143 /* Cache the object table and free variables. */
144 #define CACHE_PROGRAM() \
146 if (bp != SCM_PROGRAM_DATA (program)) { \
147 bp = SCM_PROGRAM_DATA (program); \
148 ASSERT_ALIGNED_PROCEDURE (); \
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)); \
158 SCM c = SCM_PROGRAM_FREE_VARIABLES (program); \
159 if (SCM_I_IS_VECTOR (c)) \
161 free_vars = SCM_I_VECTOR_WELTS (c); \
162 free_vars_count = SCM_I_VECTOR_LENGTH (c); \
167 free_vars_count = 0; \
172 #define SYNC_BEFORE_GC() \
187 /* Accesses to a program's object table. */
189 #define CHECK_OBJECT(_num) \
190 do { if (SCM_UNLIKELY ((_num) >= object_count)) goto vm_error_object; } while (0)
192 #define CHECK_OBJECT(_num)
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)
199 #define CHECK_FREE_VARIABLE(_num)
209 #define RUN_HOOK(h) \
211 if (SCM_UNLIKELY (!SCM_FALSEP (vp->hooks[h])))\
214 vm_dispatch_hook (vp, vp->hooks[h], hook_args); \
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)
225 #define BREAK_HOOK() RUN_HOOK (SCM_VM_BREAK_HOOK)
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)
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; }
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
245 # define NULLSTACK_FOR_NONLOCAL_EXIT() if (vp->sp > sp) NULLSTACK (vp->sp - sp);
247 # define CHECK_STACK_LEAKN(_n)
248 # define CHECK_STACK_LEAK()
249 # define NULLSTACK(_n)
250 # define NULLSTACK_FOR_NONLOCAL_EXIT()
253 #define CHECK_OVERFLOW() \
254 if (sp >= stack_limit) \
255 goto vm_error_stack_overflow
257 #define CHECK_UNDERFLOW() \
258 if (sp < SCM_FRAME_UPPER_ADDRESS (fp)) \
259 goto vm_error_stack_underflow;
261 #define PUSH(x) do { sp++; CHECK_OVERFLOW (); *sp = x; } while (0)
262 #define DROP() do { sp--; CHECK_UNDERFLOW (); NULLSTACK (1); } while (0)
263 #define DROPN(_n) do { sp -= (_n); CHECK_UNDERFLOW (); NULLSTACK (_n); } while (0)
264 #define POP(x) do { x = *sp; DROP (); } while (0)
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
271 #define CONS(x,y,z) \
274 x = scm_cell (SCM_UNPACK (y), SCM_UNPACK (z)); \
277 /* Pop the N objects on top of the stack and push a list that contains
279 #define POP_LIST(n) \
283 SCM l = SCM_EOL, x; \
284 for (i = n; i; i--) \
292 /* The opposite: push all of the elements in L onto the list. */
293 #define PUSH_LIST(l, NILP) \
296 for (; scm_is_pair (l); l = SCM_CDR (l)) \
297 PUSH (SCM_CAR (l)); \
298 if (SCM_UNLIKELY (!NILP (l))) { \
299 finish_args = scm_list_1 (l); \
300 goto vm_error_improper_list; \
305 #define POP_LIST_MARK() \
310 while (!SCM_UNBNDP (o)) \
318 #define POP_CONS_MARK() \
323 while (!SCM_UNBNDP (o)) \
333 * Instruction operation
336 #define FETCH() (*ip++)
337 #define FETCH_LENGTH(len) do { len=*ip++; len<<=8; len+=*ip++; len<<=8; len+=*ip++; } while (0)
341 #define CLOCK(n) vp->clock += n
347 #ifdef HAVE_LABELS_AS_VALUES
348 #define NEXT_JUMP() goto *jump_table[FETCH () & SCM_VM_INSTRUCTION_MASK]
350 #define NEXT_JUMP() goto vm_start
357 CHECK_STACK_LEAK (); \
362 /* See frames.h for the layout of stack frames */
363 /* When this is called, bp points to the new program data,
364 and the arguments are already on the stack */
365 #define DROP_FRAME() \
369 CHECK_UNDERFLOW (); \