Commit | Line | Data |
---|---|---|
782d171c MD |
1 | /* Representation of stack frame debug information |
2 | * Copyright (C) 1996 Mikael Djurfeldt | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2, or (at your option) | |
7 | * any later version. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this software; see the file COPYING. If not, write to | |
16 | * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, 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 | * The author can be reached at djurfeldt@nada.kth.se | |
43 | * Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN | |
44 | */ | |
45 | \f | |
46 | ||
47 | #include <stdio.h> | |
48 | #include "_scm.h" | |
49 | #include "debug.h" | |
50 | #include "continuations.h" | |
51 | ||
52 | #include "stacks.h" | |
53 | ||
54 | \f | |
55 | /* {Frames and stacks} | |
56 | * | |
57 | * The debugging evaluator creates debug frames on the stack. These | |
58 | * are linked from the innermost frame and outwards. The last frame | |
59 | * created can always be accessed as SCM_LAST_DEBUG_FRAME. | |
60 | * Continuations contain a pointer to the innermost debug frame on the | |
61 | * continuation stack. | |
62 | * | |
63 | * Each debug frame contains a set of flags and information about one | |
64 | * or more stack frames. The case of multiple frames occurs due to | |
65 | * tail recursion. The maximal number of stack frames which can be | |
66 | * recorded in one debug frame can be set dynamically with the debug | |
67 | * option FRAMES. | |
68 | * | |
69 | * Stack frame information is of two types: eval information (the | |
70 | * expression being evaluated and its environment) and apply | |
71 | * information (the procedure being applied and its arguments). A | |
72 | * stack frame normally corresponds to an eval/apply pair, but macros | |
73 | * and special forms (which are implemented as macros in Guile) only | |
74 | * have eval information and apply calls leads to apply only frames. | |
75 | * | |
76 | * Since we want to record the total stack information and later | |
77 | * manipulate this data at the scheme level in the debugger, we need | |
78 | * to transform it into a new representation. In the following code | |
79 | * section you'll find the functions implementing this data type. | |
80 | * | |
81 | * Representation: | |
82 | * | |
83 | * The stack is represented as an ordinary scheme vector. It is | |
84 | * logically divided into sections of SCM values. Each section is an | |
85 | * scm_info_frame struct. | |
86 | * | |
87 | * A frame is represented as a pair where the car contains a stack and | |
88 | * the cdr an inum. The inum is an index to the first SCM value of | |
89 | * the scm_info_frame struct. | |
90 | * | |
91 | * Stacks | |
92 | * Constructor | |
93 | * make-stack | |
94 | * Selector | |
95 | * stack-ref | |
96 | * Inspector | |
97 | * stack-length | |
98 | * | |
99 | * Frames | |
100 | * Constructor | |
101 | * last-stack-frame | |
102 | * Selectors | |
103 | * frame-number | |
104 | * frame-source | |
105 | * frame-procedure | |
106 | * frame-arguments | |
107 | * frame-previous | |
108 | * frame-next | |
109 | * Predicates | |
110 | * frame-real? | |
111 | * frame-procedure? | |
112 | * frame-evaluating-args? | |
113 | * frame-overflow? | |
114 | */ | |
115 | ||
116 | \f | |
117 | ||
118 | /* Some auxiliary functions for reading debug frames off the stack. | |
119 | */ | |
120 | ||
121 | /* Count number of debug info frames on a stack, beginning with | |
122 | * DFRAME. OFFSET is used for relocation of pointers when the stack | |
123 | * is read from a continuation. | |
124 | */ | |
125 | static int stack_depth SCM_P ((scm_debug_frame *dframe, long offset, int *maxp)); | |
126 | static int | |
127 | stack_depth (dframe, offset, maxp) | |
128 | scm_debug_frame *dframe; | |
129 | long offset; | |
130 | int *maxp; | |
131 | { | |
132 | int n, size; | |
133 | int max_depth = SCM_BACKTRACE_MAXDEPTH; | |
134 | scm_debug_info *info; | |
135 | for (n = 0; | |
136 | dframe && n < max_depth; | |
137 | dframe = (scm_debug_frame *) ((SCM_STACKITEM *) dframe->prev + offset)) | |
138 | { | |
139 | if (SCM_EVALFRAMEP (*dframe)) | |
140 | { | |
141 | size = dframe->status & SCM_MAX_FRAME_SIZE; | |
142 | info = (scm_debug_info *) (*((SCM_STACKITEM **) &dframe->vect[size]) | |
143 | + offset); | |
144 | n += (info - dframe->vect) / 2 + 1; | |
145 | /* Data in the apply part of an eval info frame comes from previous | |
146 | stack frame if the scm_debug_info vector is overflowed. */ | |
147 | if ((((info - dframe->vect) & 1) == 0) | |
148 | && SCM_OVERFLOWP (*dframe) | |
149 | && !SCM_UNBNDP (info[1].a.proc)) | |
150 | ++n; | |
151 | } | |
152 | else | |
153 | ++n; | |
154 | } | |
155 | if (dframe) | |
156 | *maxp = 1; | |
157 | return n; | |
158 | } | |
159 | ||
160 | /* Read debug info from DFRAME into IFRAME. | |
161 | */ | |
162 | static void read_frame SCM_P ((scm_debug_frame *dframe, long offset, scm_info_frame *iframe)); | |
163 | static void | |
164 | read_frame (dframe, offset, iframe) | |
165 | scm_debug_frame *dframe; | |
166 | long offset; | |
167 | scm_info_frame *iframe; | |
168 | { | |
169 | SCM flags = SCM_INUM0; | |
170 | int size; | |
171 | scm_debug_info *info; | |
172 | if (SCM_EVALFRAMEP (*dframe)) | |
173 | { | |
174 | size = dframe->status & SCM_MAX_FRAME_SIZE; | |
175 | info = (scm_debug_info *) (*((SCM_STACKITEM **) &dframe->vect[size]) | |
176 | + offset); | |
177 | if ((info - dframe->vect) & 1) | |
178 | { | |
179 | /* Debug.vect ends with apply info. */ | |
180 | --info; | |
181 | if (info[1].a.proc != SCM_UNDEFINED) | |
182 | { | |
183 | flags |= SCM_FRAMEF_PROC; | |
184 | iframe->proc = info[1].a.proc; | |
185 | iframe->args = info[1].a.args; | |
186 | if (!SCM_ARGS_READY_P (*dframe)) | |
187 | flags |= SCM_FRAMEF_EVAL_ARGS; | |
188 | } | |
189 | } | |
190 | iframe->source = scm_make_memoized (info[0].e.exp, info[0].e.env); | |
191 | } | |
192 | else | |
193 | { | |
194 | flags |= SCM_FRAMEF_PROC; | |
195 | iframe->proc = dframe->vect[0].a.proc; | |
196 | iframe->args = dframe->vect[0].a.args; | |
197 | } | |
198 | iframe->flags = flags; | |
199 | } | |
200 | ||
201 | /* Fill the scm_info_frame vector IFRAME with data from N stack frames | |
202 | * starting with the first stack frame represented by debug frame | |
203 | * DFRAME. | |
204 | */ | |
205 | static void read_frames SCM_P ((scm_debug_frame *dframe, long offset, int skip, int n, scm_info_frame *iframes)); | |
206 | static void | |
207 | read_frames (dframe, offset, skip, n, iframes) | |
208 | scm_debug_frame *dframe; | |
209 | long offset; | |
210 | int skip; | |
211 | int n; | |
212 | scm_info_frame *iframes; | |
213 | { | |
214 | int size; | |
215 | scm_info_frame *iframe = iframes; | |
216 | scm_debug_info *info; | |
217 | ||
218 | for (; | |
219 | dframe && n > 0; | |
220 | dframe = (scm_debug_frame *) ((SCM_STACKITEM *) dframe->prev + offset)) | |
221 | { | |
222 | read_frame (dframe, offset, iframe); | |
223 | if (SCM_EVALFRAMEP (*dframe)) | |
224 | { | |
225 | size = dframe->status & SCM_MAX_FRAME_SIZE; | |
226 | info = (scm_debug_info *) (*((SCM_STACKITEM **) &dframe->vect[size]) | |
227 | + offset); | |
228 | if ((info - dframe->vect) & 1) | |
229 | --info; | |
230 | /* Data in the apply part of an eval info frame comes from | |
231 | previous stack frame if the scm_debug_info vector is overflowed. */ | |
232 | else if (SCM_OVERFLOWP (*dframe) | |
233 | && !SCM_UNBNDP (info[1].a.proc)) | |
234 | { | |
235 | if (skip) | |
236 | --skip; | |
237 | else | |
238 | { | |
239 | ++iframe; | |
240 | if (--n == 0) | |
241 | goto quit; | |
242 | } | |
243 | iframe->flags = SCM_INUM0 | SCM_FRAMEF_PROC; | |
244 | iframe->proc = info[1].a.proc; | |
245 | iframe->args = info[1].a.args; | |
246 | } | |
247 | if (SCM_OVERFLOWP (*dframe)) | |
248 | iframe->flags |= SCM_FRAMEF_OVERFLOW; | |
249 | info -= 2; | |
250 | if (skip) | |
251 | --skip; | |
252 | else | |
253 | { | |
254 | ++iframe; | |
255 | if (--n == 0) | |
256 | goto quit; | |
257 | } | |
258 | while (info >= dframe->vect) | |
259 | { | |
260 | if (!SCM_UNBNDP (info[1].a.proc)) | |
261 | { | |
262 | iframe->flags = SCM_INUM0 | SCM_FRAMEF_PROC; | |
263 | iframe->proc = info[1].a.proc; | |
264 | iframe->args = info[1].a.args; | |
265 | } | |
266 | else | |
267 | iframe->flags = SCM_INUM0; | |
268 | iframe->source = scm_make_memoized (info[0].e.exp, | |
269 | info[0].e.env); | |
270 | info -= 2; | |
271 | if (skip) | |
272 | --skip; | |
273 | else | |
274 | { | |
275 | ++iframe; | |
276 | if (--n == 0) | |
277 | goto quit; | |
278 | } | |
279 | } | |
280 | } | |
281 | else | |
282 | { | |
283 | if (skip) | |
284 | --skip; | |
285 | else | |
286 | { | |
287 | ++iframe; | |
288 | --n; | |
289 | } | |
290 | } | |
291 | quit: | |
292 | if (iframe > iframes) | |
293 | (iframe - 1) -> flags |= SCM_FRAMEF_REAL; | |
294 | } | |
295 | } | |
296 | ||
297 | \f | |
298 | ||
299 | /* Stacks | |
300 | */ | |
301 | ||
302 | SCM_PROC (s_make_stack, "make-stack", 0, 3, 0, scm_make_stack); | |
303 | SCM | |
304 | scm_make_stack (obj, inner_cut, outer_cut) | |
305 | SCM obj; | |
306 | SCM inner_cut; | |
307 | SCM outer_cut; | |
308 | { | |
309 | int i, n, maxp = 0, size; | |
310 | scm_debug_frame *dframe; | |
311 | scm_info_frame *iframe; | |
312 | long offset = 0; | |
313 | SCM stack; | |
314 | ||
315 | if (SCM_UNBNDP (inner_cut)) | |
316 | inner_cut = SCM_INUM0; | |
317 | if (SCM_UNBNDP (outer_cut)) | |
318 | outer_cut = SCM_INUM0; | |
319 | SCM_ASSERT (SCM_INUMP (inner_cut), inner_cut, SCM_ARG2, s_make_stack); | |
320 | SCM_ASSERT (SCM_INUMP (outer_cut), outer_cut, SCM_ARG3, s_make_stack); | |
321 | ||
322 | if (SCM_IMP (obj) | |
323 | || (!SCM_DEBUGOBJP (obj) && (scm_tc7_contin != SCM_TYP7 (obj)))) | |
324 | dframe = scm_last_debug_frame; | |
325 | else | |
326 | { | |
327 | SCM_ASSERT (SCM_NIMP (obj), obj, SCM_ARG1, s_make_stack); | |
328 | if (SCM_DEBUGOBJP (obj)) | |
329 | dframe = (scm_debug_frame *) SCM_DEBUGOBJ_FRAME (obj); | |
330 | else if (scm_tc7_contin == SCM_TYP7 (obj)) | |
331 | { | |
332 | offset = ((SCM_STACKITEM *) (SCM_CHARS (obj) + sizeof (scm_contregs)) | |
333 | - SCM_BASE (obj)); | |
334 | #ifndef STACK_GROWS_UP | |
335 | offset += SCM_LENGTH (obj); | |
336 | #endif | |
337 | dframe = (scm_debug_frame *) ((SCM_STACKITEM *) SCM_DFRAME (obj) | |
338 | + offset); | |
339 | } | |
340 | else scm_wta (obj, (char *) SCM_ARG1, s_make_stack); | |
341 | } | |
342 | ||
343 | i = SCM_INUM (inner_cut); | |
344 | n = stack_depth (dframe, offset, &maxp) - i - SCM_INUM (outer_cut); | |
345 | if (n < 0) | |
346 | n = 0; | |
347 | size = n * SCM_FRAME_N_SLOTS; | |
348 | ||
349 | stack = scm_make_vector (SCM_MAKINUM (size), SCM_BOOL_F, SCM_UNDEFINED); | |
350 | iframe = (scm_info_frame *) SCM_VELTS (stack); | |
351 | read_frames ((scm_debug_frame *) ((SCM_STACKITEM *) dframe + offset), | |
352 | offset, | |
353 | i, | |
354 | n, | |
355 | iframe); | |
356 | ||
357 | if (n > 0 && maxp) | |
358 | iframe[n - 1].flags |= SCM_FRAMEF_OVERFLOW; | |
359 | ||
360 | return stack; | |
361 | } | |
362 | ||
363 | SCM_PROC(s_stack_ref, "stack-ref", 2, 0, 0, scm_stack_ref); | |
364 | SCM | |
365 | scm_stack_ref (stack, i) | |
366 | SCM stack; | |
367 | SCM i; | |
368 | { | |
369 | SCM_ASSERT (SCM_NIMP (stack) | |
370 | && SCM_STACKP (stack), | |
371 | stack, | |
372 | SCM_ARG1, | |
373 | s_stack_ref); | |
374 | SCM_ASSERT (SCM_INUMP (i), i, SCM_ARG2, s_stack_ref); | |
375 | SCM_ASSERT (SCM_INUM (i) >= 0 | |
376 | && SCM_INUM (i) < SCM_STACK_LENGTH (stack), | |
377 | i, | |
378 | SCM_OUTOFRANGE, | |
379 | s_stack_ref); | |
380 | return scm_cons (stack, i); | |
381 | } | |
382 | ||
383 | SCM_PROC(s_stack_length, "stack-length", 1, 0, 0, scm_stack_length); | |
384 | SCM | |
385 | scm_stack_length (stack) | |
386 | SCM stack; | |
387 | { | |
388 | SCM_ASSERT (SCM_NIMP (stack) | |
389 | && SCM_STACKP (stack), | |
390 | stack, | |
391 | SCM_ARG1, | |
392 | s_stack_length); | |
393 | return SCM_MAKINUM (SCM_STACK_LENGTH (stack)); | |
394 | } | |
395 | ||
396 | /* Frames | |
397 | */ | |
398 | ||
399 | SCM_PROC(s_last_stack_frame, "last-stack-frame", 1, 0, 0, scm_last_stack_frame); | |
400 | SCM | |
401 | scm_last_stack_frame (obj) | |
402 | SCM obj; | |
403 | { | |
404 | scm_debug_frame *dframe; | |
405 | long offset = 0; | |
406 | SCM fobj, v; | |
407 | ||
408 | SCM_ASSERT (SCM_NIMP (obj), obj, SCM_ARG1, s_last_stack_frame); | |
409 | if (SCM_DEBUGOBJP (obj)) | |
410 | dframe = (scm_debug_frame *) SCM_DEBUGOBJ_FRAME (obj); | |
411 | else if (scm_tc7_contin == SCM_TYP7 (obj)) | |
412 | { | |
413 | offset = ((SCM_STACKITEM *) (SCM_CHARS (obj) + sizeof (scm_contregs)) | |
414 | - SCM_BASE (obj)); | |
415 | #ifndef STACK_GROWS_UP | |
416 | offset += SCM_LENGTH (obj); | |
417 | #endif | |
418 | dframe = (scm_debug_frame *) ((SCM_STACKITEM *) SCM_DFRAME (obj) + offset); | |
419 | } | |
420 | else scm_wta (obj, (char *) SCM_ARG1, s_last_stack_frame); | |
421 | ||
422 | if (!dframe) | |
423 | return SCM_BOOL_F; | |
424 | ||
425 | v = scm_make_vector (SCM_MAKINUM (SCM_FRAME_N_SLOTS), | |
426 | SCM_BOOL_F, | |
427 | SCM_UNDEFINED); | |
428 | ||
429 | SCM_NEWCELL (fobj); | |
430 | SCM_DEFER_INTS; | |
431 | SCM_SETCAR (fobj, v); | |
432 | SCM_SETCDR (fobj, SCM_INUM0); | |
433 | SCM_ALLOW_INTS; | |
434 | ||
435 | read_frame (dframe, offset, (scm_info_frame *) SCM_VELTS (v)); | |
436 | ||
437 | return fobj; | |
438 | } | |
439 | ||
440 | SCM_PROC(s_frame_number, "frame-number", 1, 0, 0, scm_frame_number); | |
441 | SCM | |
442 | scm_frame_number (frame) | |
443 | SCM frame; | |
444 | { | |
445 | SCM_ASSERT (SCM_NIMP (frame) && SCM_FRAMEP (frame), | |
446 | frame, | |
447 | SCM_ARG1, | |
448 | s_frame_number); | |
449 | return SCM_MAKINUM (SCM_FRAME_NUMBER (frame)); | |
450 | } | |
451 | ||
452 | SCM_PROC(s_frame_source, "frame-source", 1, 0, 0, scm_frame_source); | |
453 | SCM | |
454 | scm_frame_source (frame) | |
455 | SCM frame; | |
456 | { | |
457 | SCM_ASSERT (SCM_NIMP (frame) && SCM_FRAMEP (frame), | |
458 | frame, | |
459 | SCM_ARG1, | |
460 | s_frame_source); | |
461 | return SCM_FRAME_SOURCE (frame); | |
462 | } | |
463 | ||
464 | SCM_PROC(s_frame_procedure, "frame-procedure", 1, 0, 0, scm_frame_procedure); | |
465 | SCM | |
466 | scm_frame_procedure (frame) | |
467 | SCM frame; | |
468 | { | |
469 | SCM_ASSERT (SCM_NIMP (frame) && SCM_FRAMEP (frame), | |
470 | frame, | |
471 | SCM_ARG1, | |
472 | s_frame_procedure); | |
473 | return (SCM_FRAME_PROC_P (frame) | |
474 | ? SCM_BOOL_F | |
475 | : SCM_FRAME_PROC (frame)); | |
476 | } | |
477 | ||
478 | SCM_PROC(s_frame_arguments, "frame-arguments", 1, 0, 0, scm_frame_arguments); | |
479 | SCM | |
480 | scm_frame_arguments (frame) | |
481 | SCM frame; | |
482 | { | |
483 | SCM_ASSERT (SCM_NIMP (frame) && SCM_FRAMEP (frame), | |
484 | frame, | |
485 | SCM_ARG1, | |
486 | s_frame_arguments); | |
487 | return SCM_FRAME_ARGS (frame); | |
488 | } | |
489 | ||
490 | SCM_PROC(s_frame_previous, "frame-previous", 1, 0, 0, scm_frame_previous); | |
491 | SCM | |
492 | scm_frame_previous (frame) | |
493 | SCM frame; | |
494 | { | |
495 | int n; | |
496 | SCM_ASSERT (SCM_NIMP (frame) && SCM_FRAMEP (frame), | |
497 | frame, | |
498 | SCM_ARG1, | |
499 | s_frame_previous); | |
500 | n = SCM_INUM (SCM_CDR (frame)) + 1; | |
501 | if (n >= SCM_STACK_LENGTH (SCM_CAR (frame))) | |
502 | return SCM_BOOL_F; | |
503 | else | |
504 | return scm_cons (SCM_CAR (frame), SCM_MAKINUM (n)); | |
505 | } | |
506 | ||
507 | SCM_PROC(s_frame_next, "frame-next", 1, 0, 0, scm_frame_next); | |
508 | SCM | |
509 | scm_frame_next (frame) | |
510 | SCM frame; | |
511 | { | |
512 | int n; | |
513 | SCM_ASSERT (SCM_NIMP (frame) && SCM_FRAMEP (frame), | |
514 | frame, | |
515 | SCM_ARG1, | |
516 | s_frame_next); | |
517 | n = SCM_INUM (SCM_CDR (frame)) - 1; | |
518 | if (n < 0) | |
519 | return SCM_BOOL_F; | |
520 | else | |
521 | return scm_cons (SCM_CAR (frame), SCM_MAKINUM (n)); | |
522 | } | |
523 | ||
524 | SCM_PROC(s_frame_real_p, "frame-real?", 1, 0, 0, scm_frame_real_p); | |
525 | SCM | |
526 | scm_frame_real_p (frame) | |
527 | SCM frame; | |
528 | { | |
529 | SCM_ASSERT (SCM_NIMP (frame) && SCM_FRAMEP (frame), | |
530 | frame, | |
531 | SCM_ARG1, | |
532 | s_frame_real_p); | |
533 | return SCM_FRAME_REAL_P (frame) ? SCM_BOOL_T : SCM_BOOL_F; | |
534 | } | |
535 | ||
536 | SCM_PROC(s_frame_procedure_p, "frame-procedure?", 1, 0, 0, scm_frame_procedure_p); | |
537 | SCM | |
538 | scm_frame_procedure_p (frame) | |
539 | SCM frame; | |
540 | { | |
541 | SCM_ASSERT (SCM_NIMP (frame) && SCM_FRAMEP (frame), | |
542 | frame, | |
543 | SCM_ARG1, | |
544 | s_frame_procedure_p); | |
545 | return SCM_FRAME_PROC_P (frame) ? SCM_BOOL_T : SCM_BOOL_F; | |
546 | } | |
547 | ||
548 | SCM_PROC(s_frame_evaluating_args_p, "frame-evaluating-args?", 1, 0, 0, scm_frame_evaluating_args_p); | |
549 | SCM | |
550 | scm_frame_evaluating_args_p (frame) | |
551 | SCM frame; | |
552 | { | |
553 | SCM_ASSERT (SCM_NIMP (frame) && SCM_FRAMEP (frame), | |
554 | frame, | |
555 | SCM_ARG1, | |
556 | s_frame_evaluating_args_p); | |
557 | return SCM_FRAME_EVAL_ARGS_P (frame) ? SCM_BOOL_T : SCM_BOOL_F; | |
558 | } | |
559 | ||
560 | SCM_PROC(s_frame_overflow_p, "frame-overflow?", 1, 0, 0, scm_frame_overflow_p); | |
561 | SCM | |
562 | scm_frame_overflow_p (frame) | |
563 | SCM frame; | |
564 | { | |
565 | SCM_ASSERT (SCM_NIMP (frame) && SCM_FRAMEP (frame), | |
566 | frame, | |
567 | SCM_ARG1, | |
568 | s_frame_overflow_p); | |
569 | return SCM_FRAME_OVERFLOW_P (frame) ? SCM_BOOL_T : SCM_BOOL_F; | |
570 | } | |
571 | ||
572 | \f | |
573 | ||
574 | void | |
575 | scm_init_stacks () | |
576 | { | |
577 | #include "stacks.x" | |
578 | } |