1 /* Representation of stack frame debug information
2 * Copyright (C) 1996,1997 Free Software Foundation
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)
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.
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, Inc., 59 Temple Place, Suite 330,
17 * Boston, MA 02111-1307 USA
19 * As a special exception, the Free Software Foundation gives permission
20 * for additional uses of the text contained in its release of GUILE.
22 * The exception is that, if you link the GUILE library with other files
23 * to produce an executable, this does not by itself cause the
24 * resulting executable to be covered by the GNU General Public License.
25 * Your use of that executable is in no way restricted on account of
26 * linking the GUILE library code into it.
28 * This exception does not however invalidate any other reasons why
29 * the executable file might be covered by the GNU General Public License.
31 * This exception applies only to the code released by the
32 * Free Software Foundation under the name GUILE. If you copy
33 * code from other Free Software Foundation releases into a copy of
34 * GUILE, as the General Public License permits, the exception does
35 * not apply to the code that you add in this way. To avoid misleading
36 * anyone as to the status of such modified files, you must delete
37 * this exception notice from them.
39 * If you write modifications of your own for GUILE, it is your choice
40 * whether to permit this exception to apply to your modifications.
41 * If you do not wish that, delete this exception notice.
43 * The author can be reached at djurfeldt@nada.kth.se
44 * Mikael Djurfeldt, SANS/NADA KTH, 10044 STOCKHOLM, SWEDEN */
51 #include "continuations.h"
60 /* {Frames and stacks}
62 * The debugging evaluator creates debug frames on the stack. These
63 * are linked from the innermost frame and outwards. The last frame
64 * created can always be accessed as SCM_LAST_DEBUG_FRAME.
65 * Continuations contain a pointer to the innermost debug frame on the
68 * Each debug frame contains a set of flags and information about one
69 * or more stack frames. The case of multiple frames occurs due to
70 * tail recursion. The maximal number of stack frames which can be
71 * recorded in one debug frame can be set dynamically with the debug
74 * Stack frame information is of two types: eval information (the
75 * expression being evaluated and its environment) and apply
76 * information (the procedure being applied and its arguments). A
77 * stack frame normally corresponds to an eval/apply pair, but macros
78 * and special forms (which are implemented as macros in Guile) only
79 * have eval information and apply calls leads to apply only frames.
81 * Since we want to record the total stack information and later
82 * manipulate this data at the scheme level in the debugger, we need
83 * to transform it into a new representation. In the following code
84 * section you'll find the functions implementing this data type.
88 * The stack is represented as a struct with an id slot and a tail
89 * array of scm_info_frame structs.
91 * A frame is represented as a pair where the car contains a stack and
92 * the cdr an inum. The inum is an index to the first SCM value of
93 * the scm_info_frame struct.
117 * frame-evaluating-args?
122 /* Some auxiliary functions for reading debug frames off the stack.
125 /* Stacks often contain pointers to other items on the stack; for
126 example, each scm_debug_frame structure contains a pointer to the
127 next frame out. When we capture a continuation, we copy the stack
128 into the heap, and just leave all the pointers unchanged. This
129 makes it simple to restore the continuation --- just copy the stack
130 back! However, if we retrieve a pointer from the heap copy to
131 another item that was originally on the stack, we have to add an
132 offset to the pointer to discover the new referent.
134 If PTR is a pointer retrieved from a continuation, whose original
135 target was on the stack, and OFFSET is the appropriate offset from
136 the original stack to the continuation, then RELOC_MUMBLE (PTR,
137 OFFSET) is a pointer to the copy in the continuation of the
138 original referent, cast to an scm_debug_MUMBLE *. */
139 #define RELOC_INFO(ptr, offset) \
140 ((scm_debug_info *) ((SCM_STACKITEM *) (ptr) + (offset)))
141 #define RELOC_FRAME(ptr, offset) \
142 ((scm_debug_frame *) ((SCM_STACKITEM *) (ptr) + (offset)))
145 /* Count number of debug info frames on a stack, beginning with
146 * DFRAME. OFFSET is used for relocation of pointers when the stack
147 * is read from a continuation.
149 static int stack_depth
SCM_P ((scm_debug_frame
*dframe
, long offset
, SCM
*id
, int *maxp
));
151 stack_depth (dframe
, offset
, id
, maxp
)
152 scm_debug_frame
*dframe
;
158 int max_depth
= SCM_BACKTRACE_MAXDEPTH
;
159 scm_debug_info
*info
;
161 dframe
&& !SCM_VOIDFRAMEP (*dframe
) && n
< max_depth
;
162 dframe
= RELOC_FRAME (dframe
->prev
, offset
))
164 if (SCM_EVALFRAMEP (*dframe
))
166 size
= dframe
->status
& SCM_MAX_FRAME_SIZE
;
167 info
= RELOC_INFO (dframe
->info
, offset
);
168 n
+= (info
- dframe
->vect
) / 2 + 1;
169 /* Data in the apply part of an eval info frame comes from previous
170 stack frame if the scm_debug_info vector is overflowed. */
171 if ((((info
- dframe
->vect
) & 1) == 0)
172 && SCM_OVERFLOWP (*dframe
)
173 && !SCM_UNBNDP (info
[1].a
.proc
))
179 if (dframe
&& SCM_VOIDFRAMEP (*dframe
))
180 *id
= dframe
->vect
[0].id
;
186 /* Read debug info from DFRAME into IFRAME.
188 static void read_frame
SCM_P ((scm_debug_frame
*dframe
, long offset
, scm_info_frame
*iframe
));
190 read_frame (dframe
, offset
, iframe
)
191 scm_debug_frame
*dframe
;
193 scm_info_frame
*iframe
;
195 SCM flags
= SCM_INUM0
;
197 scm_debug_info
*info
;
198 if (SCM_EVALFRAMEP (*dframe
))
200 size
= dframe
->status
& SCM_MAX_FRAME_SIZE
;
201 info
= RELOC_INFO (dframe
->info
, offset
);
202 if ((info
- dframe
->vect
) & 1)
204 /* Debug.vect ends with apply info. */
206 if (info
[1].a
.proc
!= SCM_UNDEFINED
)
208 flags
|= SCM_FRAMEF_PROC
;
209 iframe
->proc
= info
[1].a
.proc
;
210 iframe
->args
= info
[1].a
.args
;
211 if (!SCM_ARGS_READY_P (*dframe
))
212 flags
|= SCM_FRAMEF_EVAL_ARGS
;
215 iframe
->source
= scm_make_memoized (info
[0].e
.exp
, info
[0].e
.env
);
219 flags
|= SCM_FRAMEF_PROC
;
220 iframe
->proc
= dframe
->vect
[0].a
.proc
;
221 iframe
->args
= dframe
->vect
[0].a
.args
;
223 iframe
->flags
= flags
;
226 SCM_SYMBOL (scm_sym_apply
, "apply");
228 /* Look up the first body form of the apply closure. We'll use this
229 below to prevent it from being displayed.
234 SCM proc
= SCM_CDR (scm_sym2vcell (scm_sym_apply
, SCM_BOOL_F
, SCM_BOOL_F
));
235 if (SCM_NIMP (proc
) && SCM_CLOSUREP (proc
))
236 return SCM_CADR (SCM_CODE (proc
));
238 return SCM_UNDEFINED
;
241 #define NEXT_FRAME(iframe, n, quit) \
243 if (SCM_NIMP (iframe->source) \
244 && SCM_MEMOIZED_EXP (iframe->source) == applybody) \
246 iframe->source = SCM_BOOL_F; \
247 if (SCM_FALSEP (iframe->proc)) \
259 /* Fill the scm_info_frame vector IFRAME with data from N stack frames
260 * starting with the first stack frame represented by debug frame
264 static int read_frames
SCM_P ((scm_debug_frame
*dframe
, long offset
, int nframes
, scm_info_frame
*iframes
));
266 read_frames (dframe
, offset
, n
, iframes
)
267 scm_debug_frame
*dframe
;
270 scm_info_frame
*iframes
;
273 scm_info_frame
*iframe
= iframes
;
274 scm_debug_info
*info
;
275 static SCM applybody
= SCM_UNDEFINED
;
277 /* The value of applybody has to be setup after r4rs.scm has executed. */
278 if (SCM_UNBNDP (applybody
))
279 applybody
= get_applybody ();
281 dframe
&& !SCM_VOIDFRAMEP (*dframe
) && n
> 0;
282 dframe
= RELOC_FRAME (dframe
->prev
, offset
))
284 read_frame (dframe
, offset
, iframe
);
285 if (SCM_EVALFRAMEP (*dframe
))
287 /* If current frame is a macro during expansion, we should
288 skip the previously recorded macro transformer
289 application frame. */
290 if (SCM_MACROEXPP (*dframe
) && iframe
> iframes
)
292 *(iframe
- 1) = *iframe
;
295 size
= dframe
->status
& SCM_MAX_FRAME_SIZE
;
296 info
= RELOC_INFO (dframe
->info
, offset
);
297 if ((info
- dframe
->vect
) & 1)
299 /* Data in the apply part of an eval info frame comes from
300 previous stack frame if the scm_debug_info vector is overflowed. */
301 else if (SCM_OVERFLOWP (*dframe
)
302 && !SCM_UNBNDP (info
[1].a
.proc
))
304 NEXT_FRAME (iframe
, n
, quit
);
305 iframe
->flags
= SCM_INUM0
| SCM_FRAMEF_PROC
;
306 iframe
->proc
= info
[1].a
.proc
;
307 iframe
->args
= info
[1].a
.args
;
309 if (SCM_OVERFLOWP (*dframe
))
310 iframe
->flags
|= SCM_FRAMEF_OVERFLOW
;
312 NEXT_FRAME (iframe
, n
, quit
);
313 while (info
>= dframe
->vect
)
315 if (!SCM_UNBNDP (info
[1].a
.proc
))
317 iframe
->flags
= SCM_INUM0
| SCM_FRAMEF_PROC
;
318 iframe
->proc
= info
[1].a
.proc
;
319 iframe
->args
= info
[1].a
.args
;
322 iframe
->flags
= SCM_INUM0
;
323 iframe
->source
= scm_make_memoized (info
[0].e
.exp
,
326 NEXT_FRAME (iframe
, n
, quit
);
329 else if (iframe
->proc
== scm_f_gsubr_apply
)
330 /* Skip gsubr apply frames. */
334 NEXT_FRAME (iframe
, n
, quit
);
337 if (iframe
> iframes
)
338 (iframe
- 1) -> flags
|= SCM_FRAMEF_REAL
;
340 return iframe
- iframes
; /* Number of frames actually read */
343 static void narrow_stack
SCM_P ((SCM stack
, int inner
, SCM inner_key
, int outer
, SCM outer_key
));
345 /* Narrow STACK by cutting away stackframes (mutatingly).
347 * Inner frames (most recent) are cut by advancing the frames pointer.
348 * Outer frames are cut by decreasing the recorded length.
350 * Cut maximally INNER inner frames and OUTER outer frames using
351 * the keys INNER_KEY and OUTER_KEY.
353 * Frames are cut away starting at the end points and moving towards
354 * the center of the stack. The key is normally compared to the
355 * operator in application frames. Frames up to and including the key
358 * If INNER_KEY is #t a different scheme is used for inner frames:
360 * Frames up to but excluding the first source frame originating from
361 * a user module are cut, except for possible application frames
362 * between the user frame and the last system frame previously
367 narrow_stack (stack
, inner
, inner_key
, outer
, outer_key
)
374 scm_stack
*s
= SCM_STACK (stack
);
378 /* Cut inner part. */
379 if (inner_key
== SCM_BOOL_T
)
380 /* Cut all frames up to user module code */
382 for (i
= 0; inner
; ++i
, --inner
)
384 SCM m
= s
->frames
[i
].source
;
387 && SCM_NIMP (SCM_MEMOIZED_ENV (m
))
388 && SCM_FALSEP (scm_system_module_env_p (SCM_MEMOIZED_ENV (m
))))
390 /* Back up in order to include any non-source frames */
392 && !((SCM_NIMP (m
= s
->frames
[i
- 1].source
)
393 && SCM_MEMOIZEDP (m
))
394 || (SCM_NIMP (m
= s
->frames
[i
- 1].proc
)
395 && SCM_NFALSEP (scm_procedure_p (m
))
396 && SCM_NFALSEP (scm_procedure_property
397 (m
, scm_sym_system_procedure
)))))
407 /* Use standard cutting procedure. */
409 for (i
= 0; inner
; --inner
)
410 if (s
->frames
[i
++].proc
== inner_key
)
413 s
->frames
= &s
->frames
[i
];
416 /* Cut outer part. */
417 for (; n
&& outer
; --outer
)
418 if (s
->frames
[--n
].proc
== outer_key
)
431 SCM_PROC (s_stack_p
, "stack?", 1, 0, 0, scm_stack_p
);
436 return SCM_NIMP (obj
) && SCM_STACKP (obj
) ? SCM_BOOL_T
: SCM_BOOL_F
;
439 SCM_PROC (s_make_stack
, "make-stack", 0, 0, 1, scm_make_stack
);
441 scm_make_stack (args
)
445 scm_debug_frame
*dframe
;
446 scm_info_frame
*iframe
;
449 SCM obj
, inner_cut
, outer_cut
;
451 SCM_ASSERT (SCM_NIMP (args
) && SCM_CONSP (args
),
452 scm_makfrom0str (s_make_stack
),
455 obj
= SCM_CAR (args
);
456 args
= SCM_CDR (args
);
458 /* Extract a pointer to the innermost frame of whatever object
459 scm_make_stack was given. */
460 if (obj
== SCM_BOOL_T
)
461 dframe
= scm_last_debug_frame
;
464 SCM_ASSERT (SCM_NIMP (obj
), obj
, SCM_ARG1
, s_make_stack
);
465 if (SCM_DEBUGOBJP (obj
))
466 dframe
= (scm_debug_frame
*) SCM_DEBUGOBJ_FRAME (obj
);
467 else if (scm_tc7_contin
== SCM_TYP7 (obj
))
469 offset
= ((SCM_STACKITEM
*) (SCM_CHARS (obj
) + sizeof (scm_contregs
))
471 #ifndef STACK_GROWS_UP
472 offset
+= SCM_LENGTH (obj
);
474 dframe
= RELOC_FRAME (SCM_DFRAME (obj
), offset
);
478 scm_wta (obj
, (char *) SCM_ARG1
, s_make_stack
);
483 /* Count number of frames. Also get stack id tag and check whether
484 there are more stackframes than we want to record
485 (SCM_BACKTRACE_MAXDEPTH). */
488 n
= stack_depth (dframe
, offset
, &id
, &maxp
);
489 size
= n
* SCM_FRAME_N_SLOTS
;
491 /* Make the stack object. */
492 stack
= scm_make_struct (scm_stack_type
, SCM_MAKINUM (size
), SCM_EOL
);
493 SCM_STACK (stack
) -> id
= id
;
494 iframe
= &SCM_STACK (stack
) -> tail
[0];
495 SCM_STACK (stack
) -> frames
= iframe
;
497 /* Translate the current chain of stack frames into debugging information. */
498 n
= read_frames (RELOC_FRAME (dframe
, offset
), offset
, n
, iframe
);
499 SCM_STACK (stack
) -> length
= n
;
501 /* Narrow the stack according to the arguments given to scm_make_stack. */
502 while (n
> 0 && SCM_NIMP (args
) && SCM_CONSP (args
))
504 inner_cut
= SCM_CAR (args
);
505 args
= SCM_CDR (args
);
506 if (SCM_NIMP (args
) && SCM_CONSP (args
))
508 outer_cut
= SCM_CAR (args
);
509 args
= SCM_CDR (args
);
512 outer_cut
= SCM_INUM0
;
515 SCM_INUMP (inner_cut
) ? SCM_INUM (inner_cut
) : n
,
516 SCM_INUMP (inner_cut
) ? 0 : inner_cut
,
517 SCM_INUMP (outer_cut
) ? SCM_INUM (outer_cut
) : n
,
518 SCM_INUMP (outer_cut
) ? 0 : outer_cut
);
520 n
= SCM_STACK (stack
) -> length
;
526 iframe
[n
- 1].flags
|= SCM_FRAMEF_OVERFLOW
;
533 SCM_PROC (s_stack_id
, "stack-id", 1, 0, 0, scm_stack_id
);
538 scm_debug_frame
*dframe
;
540 if (stack
== SCM_BOOL_T
)
541 dframe
= scm_last_debug_frame
;
544 SCM_ASSERT (SCM_NIMP (stack
), stack
, SCM_ARG1
, s_make_stack
);
545 if (SCM_DEBUGOBJP (stack
))
546 dframe
= (scm_debug_frame
*) SCM_DEBUGOBJ_FRAME (stack
);
547 else if (scm_tc7_contin
== SCM_TYP7 (stack
))
549 offset
= ((SCM_STACKITEM
*) (SCM_CHARS (stack
) + sizeof (scm_contregs
))
551 #ifndef STACK_GROWS_UP
552 offset
+= SCM_LENGTH (stack
);
554 dframe
= RELOC_FRAME (SCM_DFRAME (stack
), offset
);
556 else if (SCM_STACKP (stack
))
557 return SCM_STACK (stack
) -> id
;
559 scm_wrong_type_arg (s_stack_id
, SCM_ARG1
, stack
);
561 while (dframe
&& !SCM_VOIDFRAMEP (*dframe
))
562 dframe
= RELOC_FRAME (dframe
->prev
, offset
);
563 if (dframe
&& SCM_VOIDFRAMEP (*dframe
))
564 return dframe
->vect
[0].id
;
568 SCM_PROC (s_stack_ref
, "stack-ref", 2, 0, 0, scm_stack_ref
);
570 scm_stack_ref (stack
, i
)
574 SCM_ASSERT (SCM_NIMP (stack
)
575 && SCM_STACKP (stack
),
579 SCM_ASSERT (SCM_INUMP (i
), i
, SCM_ARG2
, s_stack_ref
);
580 SCM_ASSERT (SCM_INUM (i
) >= 0
581 && SCM_INUM (i
) < SCM_STACK_LENGTH (stack
),
585 return scm_cons (stack
, i
);
588 SCM_PROC(s_stack_length
, "stack-length", 1, 0, 0, scm_stack_length
);
590 scm_stack_length (stack
)
593 SCM_ASSERT (SCM_NIMP (stack
)
594 && SCM_STACKP (stack
),
598 return SCM_MAKINUM (SCM_STACK_LENGTH (stack
));
604 SCM_PROC (s_frame_p
, "frame?", 1, 0, 0, scm_frame_p
);
609 return SCM_NIMP (obj
) && SCM_FRAMEP (obj
);
612 SCM_PROC(s_last_stack_frame
, "last-stack-frame", 1, 0, 0, scm_last_stack_frame
);
614 scm_last_stack_frame (obj
)
617 scm_debug_frame
*dframe
;
621 SCM_ASSERT (SCM_NIMP (obj
), obj
, SCM_ARG1
, s_last_stack_frame
);
622 if (SCM_DEBUGOBJP (obj
))
623 dframe
= (scm_debug_frame
*) SCM_DEBUGOBJ_FRAME (obj
);
624 else if (scm_tc7_contin
== SCM_TYP7 (obj
))
626 offset
= ((SCM_STACKITEM
*) (SCM_CHARS (obj
) + sizeof (scm_contregs
))
628 #ifndef STACK_GROWS_UP
629 offset
+= SCM_LENGTH (obj
);
631 dframe
= RELOC_FRAME (SCM_DFRAME (obj
), offset
);
635 scm_wta (obj
, (char *) SCM_ARG1
, s_last_stack_frame
);
639 if (!dframe
|| SCM_VOIDFRAMEP (*dframe
))
642 stack
= scm_make_struct (scm_stack_type
, SCM_MAKINUM (SCM_FRAME_N_SLOTS
),
644 SCM_STACK (stack
) -> length
= 1;
645 SCM_STACK (stack
) -> frames
= &SCM_STACK (stack
) -> tail
[0];
646 read_frame (dframe
, offset
,
647 (scm_info_frame
*) &SCM_STACK (stack
) -> frames
[0]);
649 return scm_cons (stack
, SCM_INUM0
);;
652 SCM_PROC(s_frame_number
, "frame-number", 1, 0, 0, scm_frame_number
);
654 scm_frame_number (frame
)
657 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
661 return SCM_MAKINUM (SCM_FRAME_NUMBER (frame
));
664 SCM_PROC(s_frame_source
, "frame-source", 1, 0, 0, scm_frame_source
);
666 scm_frame_source (frame
)
669 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
673 return SCM_FRAME_SOURCE (frame
);
676 SCM_PROC(s_frame_procedure
, "frame-procedure", 1, 0, 0, scm_frame_procedure
);
678 scm_frame_procedure (frame
)
681 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
685 return (SCM_FRAME_PROC_P (frame
)
686 ? SCM_FRAME_PROC (frame
)
690 SCM_PROC(s_frame_arguments
, "frame-arguments", 1, 0, 0, scm_frame_arguments
);
692 scm_frame_arguments (frame
)
695 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
699 return SCM_FRAME_ARGS (frame
);
702 SCM_PROC(s_frame_previous
, "frame-previous", 1, 0, 0, scm_frame_previous
);
704 scm_frame_previous (frame
)
708 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
712 n
= SCM_INUM (SCM_CDR (frame
)) + 1;
713 if (n
>= SCM_STACK_LENGTH (SCM_CAR (frame
)))
716 return scm_cons (SCM_CAR (frame
), SCM_MAKINUM (n
));
719 SCM_PROC(s_frame_next
, "frame-next", 1, 0, 0, scm_frame_next
);
721 scm_frame_next (frame
)
725 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
729 n
= SCM_INUM (SCM_CDR (frame
)) - 1;
733 return scm_cons (SCM_CAR (frame
), SCM_MAKINUM (n
));
736 SCM_PROC(s_frame_real_p
, "frame-real?", 1, 0, 0, scm_frame_real_p
);
738 scm_frame_real_p (frame
)
741 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
745 return SCM_FRAME_REAL_P (frame
) ? SCM_BOOL_T
: SCM_BOOL_F
;
748 SCM_PROC(s_frame_procedure_p
, "frame-procedure?", 1, 0, 0, scm_frame_procedure_p
);
750 scm_frame_procedure_p (frame
)
753 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
756 s_frame_procedure_p
);
757 return SCM_FRAME_PROC_P (frame
) ? SCM_BOOL_T
: SCM_BOOL_F
;
760 SCM_PROC(s_frame_evaluating_args_p
, "frame-evaluating-args?", 1, 0, 0, scm_frame_evaluating_args_p
);
762 scm_frame_evaluating_args_p (frame
)
765 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
768 s_frame_evaluating_args_p
);
769 return SCM_FRAME_EVAL_ARGS_P (frame
) ? SCM_BOOL_T
: SCM_BOOL_F
;
772 SCM_PROC(s_frame_overflow_p
, "frame-overflow?", 1, 0, 0, scm_frame_overflow_p
);
774 scm_frame_overflow_p (frame
)
777 SCM_ASSERT (SCM_NIMP (frame
) && SCM_FRAMEP (frame
),
781 return SCM_FRAME_OVERFLOW_P (frame
) ? SCM_BOOL_T
: SCM_BOOL_F
;
790 SCM vtable_layout
= scm_make_struct_layout (scm_nullstr
);
792 = scm_make_struct_layout (scm_makfrom0str (SCM_STACK_LAYOUT
));
793 vtable
= scm_make_vtable_vtable (vtable_layout
, SCM_INUM0
, SCM_EOL
);
795 = scm_permanent_object (scm_make_struct (vtable
, SCM_INUM0
,
796 scm_cons (stack_layout
,