Commit | Line | Data |
---|---|---|
27c7c630 | 1 | /* Copyright (C) 2001, 2009, 2010, 2011, 2012, 2013 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 | 18 | |
6d14383e AW |
19 | /* This file is included in vm.c multiple times */ |
20 | ||
21 | #if (VM_ENGINE == SCM_VM_REGULAR_ENGINE) | |
ff3968c2 | 22 | # define VM_USE_HOOKS 0 /* Various hooks */ |
6d14383e | 23 | #elif (VM_ENGINE == SCM_VM_DEBUG_ENGINE) |
ff3968c2 | 24 | # define VM_USE_HOOKS 1 |
6d14383e | 25 | #else |
ff3968c2 | 26 | # error unknown debug engine VM_ENGINE |
6d14383e | 27 | #endif |
a98cef7e | 28 | |
a98cef7e | 29 | |
eac12024 AW |
30 | /* Register optimization. [ stolen from librep/src/lispmach.h,v 1.3 ] |
31 | ||
32 | Some compilers underestimate the use of the local variables representing | |
33 | the abstract machine registers, and don't put them in hardware registers, | |
34 | which slows down the interpreter considerably. | |
35 | For GCC, I have hand-assigned hardware registers for several architectures. | |
36 | */ | |
37 | ||
38 | #ifdef __GNUC__ | |
39 | #ifdef __mips__ | |
40 | #define IP_REG asm("$16") | |
41 | #define SP_REG asm("$17") | |
42 | #define FP_REG asm("$18") | |
43 | #endif | |
44 | #ifdef __sparc__ | |
45 | #define IP_REG asm("%l0") | |
46 | #define SP_REG asm("%l1") | |
47 | #define FP_REG asm("%l2") | |
48 | #endif | |
49 | #ifdef __alpha__ | |
50 | #ifdef __CRAY__ | |
51 | #define IP_REG asm("r9") | |
52 | #define SP_REG asm("r10") | |
53 | #define FP_REG asm("r11") | |
54 | #else | |
55 | #define IP_REG asm("$9") | |
56 | #define SP_REG asm("$10") | |
57 | #define FP_REG asm("$11") | |
58 | #endif | |
59 | #endif | |
60 | #ifdef __i386__ | |
61 | /* too few registers! because of register allocation errors with various gcs, | |
62 | just punt on explicit assignments on i386, hoping that the "register" | |
63 | declaration will be sufficient. */ | |
64 | #elif defined __x86_64__ | |
65 | /* GCC 4.6 chooses %rbp for IP_REG and %rbx for SP_REG, which works | |
66 | well. Tell it to keep the jump table in a r12, which is | |
67 | callee-saved. */ | |
68 | #define JT_REG asm ("r12") | |
69 | #endif | |
70 | #if defined(PPC) || defined(_POWER) || defined(_IBMR2) | |
71 | #define IP_REG asm("26") | |
72 | #define SP_REG asm("27") | |
73 | #define FP_REG asm("28") | |
74 | #endif | |
75 | #ifdef __hppa__ | |
76 | #define IP_REG asm("%r18") | |
77 | #define SP_REG asm("%r17") | |
78 | #define FP_REG asm("%r16") | |
79 | #endif | |
80 | #ifdef __mc68000__ | |
81 | #define IP_REG asm("a5") | |
82 | #define SP_REG asm("a4") | |
83 | #define FP_REG | |
84 | #endif | |
85 | #ifdef __arm__ | |
86 | #define IP_REG asm("r9") | |
87 | #define SP_REG asm("r8") | |
88 | #define FP_REG asm("r7") | |
89 | #endif | |
90 | #endif | |
91 | ||
92 | #ifndef IP_REG | |
93 | #define IP_REG | |
94 | #endif | |
95 | #ifndef SP_REG | |
96 | #define SP_REG | |
97 | #endif | |
98 | #ifndef FP_REG | |
99 | #define FP_REG | |
100 | #endif | |
101 | #ifndef JT_REG | |
102 | #define JT_REG | |
103 | #endif | |
104 | ||
27c7c630 AW |
105 | #define VM_ASSERT(condition, handler) \ |
106 | do { \ | |
107 | if (SCM_UNLIKELY (!(condition))) \ | |
108 | { \ | |
109 | SYNC_ALL(); \ | |
110 | handler; \ | |
111 | } \ | |
112 | } while (0) | |
eac12024 AW |
113 | |
114 | #ifdef VM_ENABLE_ASSERTIONS | |
115 | # define ASSERT(condition) VM_ASSERT (condition, abort()) | |
116 | #else | |
117 | # define ASSERT(condition) | |
118 | #endif | |
119 | ||
120 | ||
121 | /* Cache the VM's instruction, stack, and frame pointer in local variables. */ | |
122 | #define CACHE_REGISTER() \ | |
123 | { \ | |
124 | ip = vp->ip; \ | |
125 | sp = vp->sp; \ | |
126 | fp = vp->fp; \ | |
127 | } | |
128 | ||
129 | /* Update the registers in VP, a pointer to the current VM. This must be done | |
130 | at least before any GC invocation so that `vp->sp' is up-to-date and the | |
131 | whole stack gets marked. */ | |
132 | #define SYNC_REGISTER() \ | |
133 | { \ | |
134 | vp->ip = ip; \ | |
135 | vp->sp = sp; \ | |
136 | vp->fp = fp; \ | |
137 | } | |
138 | ||
139 | /* FIXME */ | |
140 | #define ASSERT_VARIABLE(x) \ | |
27c7c630 | 141 | VM_ASSERT (SCM_VARIABLEP (x), abort()) |
eac12024 | 142 | #define ASSERT_BOUND_VARIABLE(x) \ |
27c7c630 AW |
143 | VM_ASSERT (SCM_VARIABLEP (x) \ |
144 | && !scm_is_eq (SCM_VARIABLE_REF (x), SCM_UNDEFINED), \ | |
145 | abort()) | |
eac12024 AW |
146 | |
147 | #ifdef VM_ENABLE_PARANOID_ASSERTIONS | |
148 | #define CHECK_IP() \ | |
149 | do { if (ip < bp->base || ip - bp->base > bp->len) abort (); } while (0) | |
150 | #define ASSERT_ALIGNED_PROCEDURE() \ | |
151 | do { if ((scm_t_bits)bp % 8) abort (); } while (0) | |
152 | #define ASSERT_BOUND(x) \ | |
27c7c630 | 153 | VM_ASSERT (!scm_is_eq ((x), SCM_UNDEFINED), abort()) |
eac12024 AW |
154 | #else |
155 | #define CHECK_IP() | |
156 | #define ASSERT_ALIGNED_PROCEDURE() | |
157 | #define ASSERT_BOUND(x) | |
158 | #endif | |
159 | ||
eac12024 AW |
160 | /* Cache the object table and free variables. */ |
161 | #define CACHE_PROGRAM() \ | |
162 | { \ | |
163 | if (bp != SCM_PROGRAM_DATA (program)) { \ | |
164 | bp = SCM_PROGRAM_DATA (program); \ | |
165 | ASSERT_ALIGNED_PROCEDURE (); \ | |
166 | if (SCM_I_IS_VECTOR (SCM_PROGRAM_OBJTABLE (program))) { \ | |
167 | objects = SCM_I_VECTOR_WELTS (SCM_PROGRAM_OBJTABLE (program)); \ | |
eac12024 AW |
168 | } else { \ |
169 | objects = NULL; \ | |
eac12024 AW |
170 | } \ |
171 | } \ | |
172 | } | |
173 | ||
174 | #define SYNC_BEFORE_GC() \ | |
175 | { \ | |
176 | SYNC_REGISTER (); \ | |
177 | } | |
178 | ||
179 | #define SYNC_ALL() \ | |
180 | { \ | |
181 | SYNC_REGISTER (); \ | |
182 | } | |
183 | ||
184 | \f | |
185 | /* | |
186 | * Error check | |
187 | */ | |
188 | ||
189 | /* Accesses to a program's object table. */ | |
eac12024 | 190 | #define CHECK_OBJECT(_num) |
eac12024 | 191 | #define CHECK_FREE_VARIABLE(_num) |
eac12024 AW |
192 | |
193 | \f | |
194 | /* | |
195 | * Hooks | |
196 | */ | |
197 | ||
eac12024 AW |
198 | #if VM_USE_HOOKS |
199 | #define RUN_HOOK(h) \ | |
200 | { \ | |
201 | if (SCM_UNLIKELY (vp->trace_level > 0)) \ | |
202 | { \ | |
203 | SYNC_REGISTER (); \ | |
204 | vm_dispatch_hook (vm, h); \ | |
205 | } \ | |
206 | } | |
207 | #define RUN_HOOK1(h, x) \ | |
208 | { \ | |
209 | if (SCM_UNLIKELY (vp->trace_level > 0)) \ | |
210 | { \ | |
211 | PUSH (x); \ | |
212 | SYNC_REGISTER (); \ | |
213 | vm_dispatch_hook (vm, h); \ | |
214 | DROP(); \ | |
215 | } \ | |
216 | } | |
217 | #else | |
218 | #define RUN_HOOK(h) | |
219 | #define RUN_HOOK1(h, x) | |
220 | #endif | |
221 | ||
222 | #define APPLY_HOOK() \ | |
223 | RUN_HOOK (SCM_VM_APPLY_HOOK) | |
224 | #define PUSH_CONTINUATION_HOOK() \ | |
225 | RUN_HOOK (SCM_VM_PUSH_CONTINUATION_HOOK) | |
226 | #define POP_CONTINUATION_HOOK(n) \ | |
227 | RUN_HOOK1 (SCM_VM_POP_CONTINUATION_HOOK, SCM_I_MAKINUM (n)) | |
228 | #define NEXT_HOOK() \ | |
229 | RUN_HOOK (SCM_VM_NEXT_HOOK) | |
230 | #define ABORT_CONTINUATION_HOOK() \ | |
231 | RUN_HOOK (SCM_VM_ABORT_CONTINUATION_HOOK) | |
232 | #define RESTORE_CONTINUATION_HOOK() \ | |
233 | RUN_HOOK (SCM_VM_RESTORE_CONTINUATION_HOOK) | |
234 | ||
235 | #define VM_HANDLE_INTERRUPTS \ | |
236 | SCM_ASYNC_TICK_WITH_CODE (current_thread, SYNC_REGISTER ()) | |
237 | ||
238 | \f | |
239 | /* | |
240 | * Stack operation | |
241 | */ | |
242 | ||
243 | #ifdef VM_ENABLE_STACK_NULLING | |
244 | # define CHECK_STACK_LEAKN(_n) ASSERT (!sp[_n]); | |
245 | # define CHECK_STACK_LEAK() CHECK_STACK_LEAKN(1) | |
246 | # define NULLSTACK(_n) { int __x = _n; CHECK_STACK_LEAKN (_n+1); while (__x > 0) sp[__x--] = NULL; } | |
247 | /* If you have a nonlocal exit in a pre-wind proc while invoking a continuation | |
248 | inside a dynwind (phew!), the stack is fully rewound but vm_reset_stack for | |
249 | that continuation doesn't have a chance to run. It's not important on a | |
250 | semantic level, but it does mess up our stack nulling -- so this macro is to | |
251 | fix that. */ | |
252 | # define NULLSTACK_FOR_NONLOCAL_EXIT() if (vp->sp > sp) NULLSTACK (vp->sp - sp); | |
253 | #else | |
254 | # define CHECK_STACK_LEAKN(_n) | |
255 | # define CHECK_STACK_LEAK() | |
256 | # define NULLSTACK(_n) | |
257 | # define NULLSTACK_FOR_NONLOCAL_EXIT() | |
258 | #endif | |
259 | ||
260 | /* For this check, we don't use VM_ASSERT, because that leads to a | |
261 | per-site SYNC_ALL, which is too much code growth. The real problem | |
262 | of course is having to check for overflow all the time... */ | |
263 | #define CHECK_OVERFLOW() \ | |
264 | do { if (SCM_UNLIKELY (sp >= stack_limit)) goto handle_overflow; } while (0) | |
265 | ||
266 | #ifdef VM_CHECK_UNDERFLOW | |
267 | #define PRE_CHECK_UNDERFLOW(N) \ | |
268 | VM_ASSERT (sp - (N) > SCM_FRAME_UPPER_ADDRESS (fp), vm_error_stack_underflow ()) | |
269 | #define CHECK_UNDERFLOW() PRE_CHECK_UNDERFLOW (0) | |
270 | #else | |
271 | #define PRE_CHECK_UNDERFLOW(N) /* nop */ | |
272 | #define CHECK_UNDERFLOW() /* nop */ | |
273 | #endif | |
274 | ||
275 | ||
276 | #define PUSH(x) do { sp++; CHECK_OVERFLOW (); *sp = x; } while (0) | |
277 | #define DROP() do { sp--; CHECK_UNDERFLOW (); NULLSTACK (1); } while (0) | |
278 | #define DROPN(_n) do { sp -= (_n); CHECK_UNDERFLOW (); NULLSTACK (_n); } while (0) | |
279 | #define POP(x) do { PRE_CHECK_UNDERFLOW (1); x = *sp--; NULLSTACK (1); } while (0) | |
280 | #define POP2(x,y) do { PRE_CHECK_UNDERFLOW (2); x = *sp--; y = *sp--; NULLSTACK (2); } while (0) | |
281 | #define POP3(x,y,z) do { PRE_CHECK_UNDERFLOW (3); x = *sp--; y = *sp--; z = *sp--; NULLSTACK (3); } while (0) | |
282 | ||
eac12024 AW |
283 | /* Pop the N objects on top of the stack and push a list that contains |
284 | them. */ | |
285 | #define POP_LIST(n) \ | |
286 | do \ | |
287 | { \ | |
288 | int i; \ | |
289 | SCM l = SCM_EOL, x; \ | |
52182d52 | 290 | SYNC_BEFORE_GC (); \ |
eac12024 AW |
291 | for (i = n; i; i--) \ |
292 | { \ | |
293 | POP (x); \ | |
52182d52 | 294 | l = scm_cons (x, l); \ |
eac12024 AW |
295 | } \ |
296 | PUSH (l); \ | |
297 | } while (0) | |
298 | ||
299 | /* The opposite: push all of the elements in L onto the list. */ | |
300 | #define PUSH_LIST(l, NILP) \ | |
301 | do \ | |
302 | { \ | |
303 | for (; scm_is_pair (l); l = SCM_CDR (l)) \ | |
304 | PUSH (SCM_CAR (l)); \ | |
305 | VM_ASSERT (NILP (l), vm_error_improper_list (l)); \ | |
306 | } while (0) | |
307 | ||
308 | \f | |
eac12024 AW |
309 | /* |
310 | * Instruction operation | |
311 | */ | |
312 | ||
313 | #define FETCH() (*ip++) | |
314 | #define FETCH_LENGTH(len) do { len=*ip++; len<<=8; len+=*ip++; len<<=8; len+=*ip++; } while (0) | |
315 | ||
316 | #undef NEXT_JUMP | |
317 | #ifdef HAVE_LABELS_AS_VALUES | |
27c7c630 | 318 | # define NEXT_JUMP() goto *jump_table[FETCH () & SCM_VM_INSTRUCTION_MASK] |
eac12024 | 319 | #else |
27c7c630 | 320 | # define NEXT_JUMP() goto vm_start |
eac12024 AW |
321 | #endif |
322 | ||
323 | #define NEXT \ | |
324 | { \ | |
325 | NEXT_HOOK (); \ | |
326 | CHECK_STACK_LEAK (); \ | |
327 | NEXT_JUMP (); \ | |
328 | } | |
329 | ||
330 | \f | |
331 | /* See frames.h for the layout of stack frames */ | |
332 | /* When this is called, bp points to the new program data, | |
333 | and the arguments are already on the stack */ | |
334 | #define DROP_FRAME() \ | |
335 | { \ | |
336 | sp -= 3; \ | |
337 | NULLSTACK (3); \ | |
338 | CHECK_UNDERFLOW (); \ | |
339 | } | |
340 | ||
238e7a11 | 341 | |
a98cef7e | 342 | static SCM |
7656f194 | 343 | VM_NAME (SCM vm, SCM program, SCM *argv, int nargs) |
a98cef7e | 344 | { |
17e90c5e | 345 | /* VM registers */ |
2fb924f6 | 346 | register scm_t_uint8 *ip IP_REG; /* instruction pointer */ |
17e90c5e KN |
347 | register SCM *sp SP_REG; /* stack pointer */ |
348 | register SCM *fp FP_REG; /* frame pointer */ | |
7656f194 | 349 | struct scm_vm *vp = SCM_VM_DATA (vm); |
a98cef7e | 350 | |
d608d68d | 351 | /* Cache variables */ |
53e28ed9 | 352 | struct scm_objcode *bp = NULL; /* program base pointer */ |
17e90c5e | 353 | SCM *objects = NULL; /* constant objects */ |
3d5ee0cd | 354 | SCM *stack_limit = vp->stack_limit; /* stack limit address */ |
2d026f04 | 355 | |
a2a6c0e3 | 356 | scm_i_thread *current_thread = SCM_I_CURRENT_THREAD; |
a98cef7e | 357 | |
d608d68d | 358 | /* Internal variables */ |
ef24c01b | 359 | int nvalues = 0; |
9d381ba4 AW |
360 | scm_i_jmp_buf registers; /* used for prompts */ |
361 | ||
53e28ed9 | 362 | #ifdef HAVE_LABELS_AS_VALUES |
37a5970c | 363 | static const void **jump_table_pointer = NULL; |
e06e857c | 364 | #endif |
37a5970c | 365 | |
e06e857c | 366 | #ifdef HAVE_LABELS_AS_VALUES |
37a5970c LC |
367 | register const void **jump_table JT_REG; |
368 | ||
369 | if (SCM_UNLIKELY (!jump_table_pointer)) | |
53e28ed9 AW |
370 | { |
371 | int i; | |
37a5970c | 372 | jump_table_pointer = malloc (SCM_VM_NUM_INSTRUCTIONS * sizeof (void*)); |
53e28ed9 | 373 | for (i = 0; i < SCM_VM_NUM_INSTRUCTIONS; i++) |
37a5970c | 374 | jump_table_pointer[i] = &&vm_error_bad_instruction; |
53e28ed9 | 375 | #define VM_INSTRUCTION_TO_LABEL 1 |
37a5970c | 376 | #define jump_table jump_table_pointer |
aeeff258 AW |
377 | #include <libguile/vm-expand.h> |
378 | #include <libguile/vm-i-system.i> | |
379 | #include <libguile/vm-i-scheme.i> | |
380 | #include <libguile/vm-i-loader.i> | |
37a5970c | 381 | #undef jump_table |
53e28ed9 AW |
382 | #undef VM_INSTRUCTION_TO_LABEL |
383 | } | |
37a5970c LC |
384 | |
385 | /* Attempt to keep JUMP_TABLE_POINTER in a register. This saves one | |
386 | load instruction at each instruction dispatch. */ | |
387 | jump_table = jump_table_pointer; | |
53e28ed9 | 388 | #endif |
9d381ba4 AW |
389 | |
390 | if (SCM_I_SETJMP (registers)) | |
391 | { | |
392 | /* Non-local return. Cache the VM registers back from the vp, and | |
393 | go to the handler. | |
394 | ||
395 | Note, at this point, we must assume that any variable local to | |
396 | vm_engine that can be assigned *has* been assigned. So we need to pull | |
397 | all our state back from the ip/fp/sp. | |
398 | */ | |
399 | CACHE_REGISTER (); | |
400 | program = SCM_FRAME_PROGRAM (fp); | |
401 | CACHE_PROGRAM (); | |
402 | /* The stack contains the values returned to this continuation, | |
403 | along with a number-of-values marker -- like an MV return. */ | |
404 | ABORT_CONTINUATION_HOOK (); | |
405 | NEXT; | |
406 | } | |
53e28ed9 | 407 | |
67b699cc AW |
408 | /* Initial frame */ |
409 | CACHE_REGISTER (); | |
410 | PUSH (SCM_PACK (fp)); /* dynamic link */ | |
411 | PUSH (SCM_PACK (0)); /* mvra */ | |
412 | PUSH (SCM_PACK (ip)); /* ra */ | |
413 | PUSH (boot_continuation); | |
414 | fp = sp + 1; | |
415 | ip = SCM_C_OBJCODE_BASE (SCM_PROGRAM_DATA (boot_continuation)); | |
416 | ||
417 | /* MV-call frame, function & arguments */ | |
418 | PUSH (SCM_PACK (fp)); /* dynamic link */ | |
419 | PUSH (SCM_PACK (ip + 1)); /* mvra */ | |
420 | PUSH (SCM_PACK (ip)); /* ra */ | |
421 | PUSH (program); | |
422 | fp = sp + 1; | |
423 | VM_ASSERT (sp + nargs < stack_limit, vm_error_too_many_args (nargs)); | |
424 | while (nargs--) | |
425 | PUSH (*argv++); | |
426 | ||
427 | PUSH_CONTINUATION_HOOK (); | |
428 | ||
429 | apply: | |
430 | program = fp[-1]; | |
431 | if (!SCM_PROGRAM_P (program)) | |
432 | { | |
433 | if (SCM_STRUCTP (program) && SCM_STRUCT_APPLICABLE_P (program)) | |
434 | fp[-1] = SCM_STRUCT_PROCEDURE (program); | |
968a9add | 435 | else if (SCM_HAS_TYP7 (program, scm_tc7_smob) |
67b699cc AW |
436 | && SCM_SMOB_APPLICABLE_P (program)) |
437 | { | |
438 | /* (smob arg0 ... argN) => (apply-smob smob arg0 ... argN) */ | |
439 | int i; | |
440 | PUSH (SCM_BOOL_F); | |
441 | for (i = sp - fp; i >= 0; i--) | |
442 | fp[i] = fp[i - 1]; | |
968a9add | 443 | fp[-1] = SCM_SMOB_DESCRIPTOR (program).apply_trampoline; |
67b699cc AW |
444 | } |
445 | else | |
446 | { | |
447 | SYNC_ALL(); | |
448 | vm_error_wrong_type_apply (program); | |
449 | } | |
450 | goto apply; | |
451 | } | |
452 | ||
453 | CACHE_PROGRAM (); | |
454 | ip = SCM_C_OBJCODE_BASE (bp); | |
455 | ||
456 | APPLY_HOOK (); | |
a98cef7e KN |
457 | |
458 | /* Let's go! */ | |
53e28ed9 | 459 | NEXT; |
a98cef7e KN |
460 | |
461 | #ifndef HAVE_LABELS_AS_VALUES | |
17e90c5e | 462 | vm_start: |
53e28ed9 | 463 | switch ((*ip++) & SCM_VM_INSTRUCTION_MASK) { |
a98cef7e KN |
464 | #endif |
465 | ||
83495480 AW |
466 | #include "vm-expand.h" |
467 | #include "vm-i-system.c" | |
468 | #include "vm-i-scheme.c" | |
469 | #include "vm-i-loader.c" | |
a98cef7e KN |
470 | |
471 | #ifndef HAVE_LABELS_AS_VALUES | |
53e28ed9 AW |
472 | default: |
473 | goto vm_error_bad_instruction; | |
a98cef7e KN |
474 | } |
475 | #endif | |
476 | ||
53bdfcf0 | 477 | abort (); /* never reached */ |
a52b2d3d | 478 | |
53bdfcf0 AW |
479 | vm_error_bad_instruction: |
480 | vm_error_bad_instruction (ip[-1]); | |
481 | abort (); /* never reached */ | |
17e90c5e | 482 | |
53bdfcf0 AW |
483 | handle_overflow: |
484 | SYNC_ALL (); | |
485 | vm_error_stack_overflow (vp); | |
a98cef7e KN |
486 | abort (); /* never reached */ |
487 | } | |
6d14383e | 488 | |
27c7c630 AW |
489 | #undef RUN_HOOK |
490 | #undef RUN_HOOK1 | |
6d14383e | 491 | #undef VM_USE_HOOKS |
17e90c5e KN |
492 | |
493 | /* | |
494 | Local Variables: | |
495 | c-file-style: "gnu" | |
496 | End: | |
497 | */ |