Merge commit 'e20d7001c3f7150400169fecb0bf0eefdf122fe2' into vm-check
[bpt/guile.git] / libguile / stacks.c
CommitLineData
782d171c 1/* Representation of stack frame debug information
e20d7001 2 * Copyright (C) 1996,1997,2000,2001, 2006, 2007, 2008, 2009 Free Software Foundation
782d171c 3 *
73be1d9e
MV
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
782d171c 8 *
73be1d9e 9 * This library is distributed in the hope that it will be useful,
782d171c 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
782d171c 13 *
73be1d9e
MV
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
92205699 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 17 */
1bbd0b84 18
1bbd0b84 19
782d171c 20\f
dbb605f5
LC
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
782d171c 24
a0599745
MD
25#include "libguile/_scm.h"
26#include "libguile/eval.h"
27#include "libguile/debug.h"
28#include "libguile/continuations.h"
29#include "libguile/struct.h"
30#include "libguile/macros.h"
31#include "libguile/procprop.h"
32#include "libguile/modules.h"
33#include "libguile/root.h"
34#include "libguile/strings.h"
b1b942b7
AW
35#include "libguile/vm.h" /* to capture vm stacks */
36#include "libguile/frames.h" /* vm frames */
37#include "libguile/instructions.h" /* scm_op_halt */
a0599745
MD
38
39#include "libguile/validate.h"
40#include "libguile/stacks.h"
22fc179a
HWN
41#include "libguile/private-options.h"
42
782d171c
MD
43
44\f
45/* {Frames and stacks}
46 *
47 * The debugging evaluator creates debug frames on the stack. These
48 * are linked from the innermost frame and outwards. The last frame
49 * created can always be accessed as SCM_LAST_DEBUG_FRAME.
50 * Continuations contain a pointer to the innermost debug frame on the
51 * continuation stack.
52 *
53 * Each debug frame contains a set of flags and information about one
54 * or more stack frames. The case of multiple frames occurs due to
55 * tail recursion. The maximal number of stack frames which can be
56 * recorded in one debug frame can be set dynamically with the debug
57 * option FRAMES.
58 *
59 * Stack frame information is of two types: eval information (the
60 * expression being evaluated and its environment) and apply
61 * information (the procedure being applied and its arguments). A
62 * stack frame normally corresponds to an eval/apply pair, but macros
63 * and special forms (which are implemented as macros in Guile) only
64 * have eval information and apply calls leads to apply only frames.
65 *
66 * Since we want to record the total stack information and later
67 * manipulate this data at the scheme level in the debugger, we need
68 * to transform it into a new representation. In the following code
69 * section you'll find the functions implementing this data type.
70 *
71 * Representation:
72 *
7115d1e4 73 * The stack is represented as a struct with an id slot and a tail
92c2555f 74 * array of scm_t_info_frame structs.
782d171c
MD
75 *
76 * A frame is represented as a pair where the car contains a stack and
77 * the cdr an inum. The inum is an index to the first SCM value of
92c2555f 78 * the scm_t_info_frame struct.
782d171c
MD
79 *
80 * Stacks
81 * Constructor
82 * make-stack
7115d1e4
MD
83 * Selectors
84 * stack-id
782d171c
MD
85 * stack-ref
86 * Inspector
87 * stack-length
88 *
89 * Frames
90 * Constructor
91 * last-stack-frame
92 * Selectors
93 * frame-number
94 * frame-source
95 * frame-procedure
96 * frame-arguments
97 * frame-previous
98 * frame-next
99 * Predicates
100 * frame-real?
101 * frame-procedure?
102 * frame-evaluating-args?
7115d1e4 103 * frame-overflow? */
782d171c
MD
104
105\f
106
107/* Some auxiliary functions for reading debug frames off the stack.
108 */
109
c0ab1b8d 110/* Stacks often contain pointers to other items on the stack; for
92c2555f 111 example, each scm_t_debug_frame structure contains a pointer to the
c0ab1b8d
JB
112 next frame out. When we capture a continuation, we copy the stack
113 into the heap, and just leave all the pointers unchanged. This
114 makes it simple to restore the continuation --- just copy the stack
115 back! However, if we retrieve a pointer from the heap copy to
116 another item that was originally on the stack, we have to add an
117 offset to the pointer to discover the new referent.
118
119 If PTR is a pointer retrieved from a continuation, whose original
120 target was on the stack, and OFFSET is the appropriate offset from
121 the original stack to the continuation, then RELOC_MUMBLE (PTR,
122 OFFSET) is a pointer to the copy in the continuation of the
123 original referent, cast to an scm_debug_MUMBLE *. */
124#define RELOC_INFO(ptr, offset) \
92c2555f 125 ((scm_t_debug_info *) ((SCM_STACKITEM *) (ptr) + (offset)))
c0ab1b8d 126#define RELOC_FRAME(ptr, offset) \
92c2555f 127 ((scm_t_debug_frame *) ((SCM_STACKITEM *) (ptr) + (offset)))
c0ab1b8d 128
782d171c
MD
129/* Count number of debug info frames on a stack, beginning with
130 * DFRAME. OFFSET is used for relocation of pointers when the stack
131 * is read from a continuation.
132 */
b1b942b7
AW
133static long
134stack_depth (scm_t_debug_frame *dframe, scm_t_ptrdiff offset, SCM vmframe,
135 SCM *id)
782d171c 136{
c014a02e 137 long n;
782d171c 138 for (n = 0;
b1b942b7 139 dframe && !SCM_VOIDFRAMEP (*dframe);
c0ab1b8d 140 dframe = RELOC_FRAME (dframe->prev, offset))
782d171c
MD
141 {
142 if (SCM_EVALFRAMEP (*dframe))
143 {
7f12a943
MV
144 scm_t_debug_info *info = RELOC_INFO (dframe->info, offset);
145 scm_t_debug_info *vect = RELOC_INFO (dframe->vect, offset);
146 n += (info - vect) / 2 + 1;
782d171c 147 /* Data in the apply part of an eval info frame comes from previous
92c2555f 148 stack frame if the scm_t_debug_info vector is overflowed. */
7f12a943 149 if ((((info - vect) & 1) == 0)
782d171c
MD
150 && SCM_OVERFLOWP (*dframe)
151 && !SCM_UNBNDP (info[1].a.proc))
b1b942b7 152 ++n;
782d171c 153 }
b1b942b7
AW
154 else if (SCM_APPLYFRAMEP (*dframe))
155 {
156 scm_t_debug_info *vect = RELOC_INFO (dframe->vect, offset);
157 if (SCM_PROGRAM_P (vect[0].a.proc))
158 {
2f9769b6
AW
159 if (!SCM_PROGRAM_IS_BOOT (vect[0].a.proc))
160 /* Programs can end up in the debug stack via deval; but we just
161 ignore those, because we know that the debugging VM engine
162 pushes one dframe per invocation, with the boot program as
163 the proc, so we only count those. */
164 continue;
3b9e095b 165 /* count vmframe back to previous boot frame */
b1b942b7
AW
166 for (; scm_is_true (vmframe); vmframe = scm_c_vm_frame_prev (vmframe))
167 {
2f9769b6
AW
168 if (!SCM_PROGRAM_IS_BOOT (scm_vm_frame_program (vmframe)))
169 ++n;
170 else
3b9e095b 171 { /* skip boot frame, cut out of the vm backtrace */
b1b942b7
AW
172 vmframe = scm_c_vm_frame_prev (vmframe);
173 break;
174 }
b1b942b7
AW
175 }
176 }
3b9e095b
AW
177 else
178 ++n; /* increment for non-program apply frame */
b1b942b7 179 }
782d171c
MD
180 else
181 ++n;
182 }
66f45472 183 if (dframe && SCM_VOIDFRAMEP (*dframe))
7f12a943 184 *id = RELOC_INFO(dframe->vect, offset)[0].id;
782d171c
MD
185 return n;
186}
187
188/* Read debug info from DFRAME into IFRAME.
189 */
782d171c 190static void
7f12a943
MV
191read_frame (scm_t_debug_frame *dframe, scm_t_ptrdiff offset,
192 scm_t_info_frame *iframe)
782d171c 193{
92c2555f 194 scm_t_bits flags = SCM_UNPACK (SCM_INUM0); /* UGh. */
782d171c
MD
195 if (SCM_EVALFRAMEP (*dframe))
196 {
7f12a943
MV
197 scm_t_debug_info *info = RELOC_INFO (dframe->info, offset);
198 scm_t_debug_info *vect = RELOC_INFO (dframe->vect, offset);
199 if ((info - vect) & 1)
782d171c
MD
200 {
201 /* Debug.vect ends with apply info. */
202 --info;
54778cd3 203 if (!SCM_UNBNDP (info[1].a.proc))
782d171c
MD
204 {
205 flags |= SCM_FRAMEF_PROC;
206 iframe->proc = info[1].a.proc;
207 iframe->args = info[1].a.args;
208 if (!SCM_ARGS_READY_P (*dframe))
209 flags |= SCM_FRAMEF_EVAL_ARGS;
210 }
211 }
6629eb1c 212 iframe->source = scm_make_memoized (info[0].e.exp, info[0].e.env);
782d171c
MD
213 }
214 else
215 {
7f12a943 216 scm_t_debug_info *vect = RELOC_INFO (dframe->vect, offset);
782d171c 217 flags |= SCM_FRAMEF_PROC;
7f12a943
MV
218 iframe->proc = vect[0].a.proc;
219 iframe->args = vect[0].a.args;
782d171c
MD
220 }
221 iframe->flags = flags;
222}
223
7a13c3ae
MD
224/* Look up the first body form of the apply closure. We'll use this
225 below to prevent it from being displayed.
226*/
227static SCM
228get_applybody ()
229{
86d31dfe
MV
230 SCM var = scm_sym2var (scm_sym_apply, SCM_BOOL_F, SCM_BOOL_F);
231 if (SCM_VARIABLEP (var) && SCM_CLOSUREP (SCM_VARIABLE_REF (var)))
f9450cdb 232 return SCM_CAR (SCM_CLOSURE_BODY (SCM_VARIABLE_REF (var)));
7a13c3ae
MD
233 else
234 return SCM_UNDEFINED;
235}
7115d1e4
MD
236
237#define NEXT_FRAME(iframe, n, quit) \
d3a6bc94 238do { \
13dcb666 239 if (SCM_MEMOIZEDP (iframe->source) \
bc36d050 240 && scm_is_eq (SCM_MEMOIZED_EXP (iframe->source), applybody)) \
7a13c3ae
MD
241 { \
242 iframe->source = SCM_BOOL_F; \
7888309b 243 if (scm_is_false (iframe->proc)) \
7a13c3ae
MD
244 { \
245 --iframe; \
246 ++n; \
247 } \
248 } \
7115d1e4
MD
249 ++iframe; \
250 if (--n == 0) \
251 goto quit; \
d3a6bc94 252} while (0)
7115d1e4
MD
253
254
92c2555f 255/* Fill the scm_t_info_frame vector IFRAME with data from N stack frames
7a13c3ae
MD
256 * starting with the first stack frame represented by debug frame
257 * DFRAME.
258 */
259
92c2555f 260static scm_t_bits
7f12a943 261read_frames (scm_t_debug_frame *dframe, scm_t_ptrdiff offset,
b1b942b7 262 SCM vmframe, long n, scm_t_info_frame *iframes)
782d171c 263{
92c2555f 264 scm_t_info_frame *iframe = iframes;
7f12a943 265 scm_t_debug_info *info, *vect;
7a13c3ae 266 static SCM applybody = SCM_UNDEFINED;
782d171c 267
7a13c3ae
MD
268 /* The value of applybody has to be setup after r4rs.scm has executed. */
269 if (SCM_UNBNDP (applybody))
270 applybody = get_applybody ();
782d171c 271 for (;
66f45472 272 dframe && !SCM_VOIDFRAMEP (*dframe) && n > 0;
c0ab1b8d 273 dframe = RELOC_FRAME (dframe->prev, offset))
782d171c
MD
274 {
275 read_frame (dframe, offset, iframe);
276 if (SCM_EVALFRAMEP (*dframe))
277 {
6629eb1c
MD
278 /* If current frame is a macro during expansion, we should
279 skip the previously recorded macro transformer
280 application frame. */
281 if (SCM_MACROEXPP (*dframe) && iframe > iframes)
7c939801
MD
282 {
283 *(iframe - 1) = *iframe;
284 --iframe;
285 }
c0ab1b8d 286 info = RELOC_INFO (dframe->info, offset);
7f12a943
MV
287 vect = RELOC_INFO (dframe->vect, offset);
288 if ((info - vect) & 1)
782d171c
MD
289 --info;
290 /* Data in the apply part of an eval info frame comes from
13dcb666
DH
291 previous stack frame if the scm_t_debug_info vector is
292 overflowed. */
782d171c
MD
293 else if (SCM_OVERFLOWP (*dframe)
294 && !SCM_UNBNDP (info[1].a.proc))
295 {
7115d1e4 296 NEXT_FRAME (iframe, n, quit);
f1267706 297 iframe->flags = SCM_UNPACK(SCM_INUM0) | SCM_FRAMEF_PROC;
782d171c
MD
298 iframe->proc = info[1].a.proc;
299 iframe->args = info[1].a.args;
300 }
301 if (SCM_OVERFLOWP (*dframe))
302 iframe->flags |= SCM_FRAMEF_OVERFLOW;
303 info -= 2;
7115d1e4 304 NEXT_FRAME (iframe, n, quit);
7f12a943 305 while (info >= vect)
782d171c
MD
306 {
307 if (!SCM_UNBNDP (info[1].a.proc))
308 {
f1267706 309 iframe->flags = SCM_UNPACK(SCM_INUM0) | SCM_FRAMEF_PROC;
782d171c
MD
310 iframe->proc = info[1].a.proc;
311 iframe->args = info[1].a.args;
312 }
313 else
f1267706 314 iframe->flags = SCM_UNPACK (SCM_INUM0);
782d171c
MD
315 iframe->source = scm_make_memoized (info[0].e.exp,
316 info[0].e.env);
317 info -= 2;
7115d1e4 318 NEXT_FRAME (iframe, n, quit);
782d171c
MD
319 }
320 }
3b9e095b
AW
321 else if (SCM_PROGRAM_P (iframe->proc))
322 {
2f9769b6
AW
323 if (!SCM_PROGRAM_IS_BOOT (iframe->proc))
324 /* Programs can end up in the debug stack via deval; but we just
325 ignore those, because we know that the debugging VM engine
326 pushes one dframe per invocation, with the boot program as
327 the proc, so we only count those. */
328 continue;
3b9e095b
AW
329 for (; scm_is_true (vmframe);
330 vmframe = scm_c_vm_frame_prev (vmframe))
b1b942b7 331 {
3b9e095b
AW
332 if (SCM_PROGRAM_IS_BOOT (scm_vm_frame_program (vmframe)))
333 { /* skip boot frame, back to interpreted frames */
334 vmframe = scm_c_vm_frame_prev (vmframe);
335 break;
336 }
337 else
b1b942b7 338 {
3b9e095b
AW
339 /* Oh dear, oh dear, oh dear. */
340 iframe->flags = SCM_UNPACK (SCM_INUM0) | SCM_FRAMEF_PROC;
341 iframe->source = scm_vm_frame_source (vmframe);
342 iframe->proc = scm_vm_frame_program (vmframe);
343 iframe->args = scm_vm_frame_arguments (vmframe);
344 ++iframe;
345 if (--n == 0)
346 goto quit;
b1b942b7 347 }
3b9e095b 348 }
3b9e095b
AW
349 }
350 else
351 {
352 NEXT_FRAME (iframe, n, quit);
353 }
782d171c
MD
354 quit:
355 if (iframe > iframes)
356 (iframe - 1) -> flags |= SCM_FRAMEF_REAL;
357 }
7c939801 358 return iframe - iframes; /* Number of frames actually read */
782d171c
MD
359}
360
c3a6c6f9
MD
361/* Narrow STACK by cutting away stackframes (mutatingly).
362 *
363 * Inner frames (most recent) are cut by advancing the frames pointer.
364 * Outer frames are cut by decreasing the recorded length.
365 *
366 * Cut maximally INNER inner frames and OUTER outer frames using
367 * the keys INNER_KEY and OUTER_KEY.
368 *
369 * Frames are cut away starting at the end points and moving towards
370 * the center of the stack. The key is normally compared to the
371 * operator in application frames. Frames up to and including the key
372 * are cut.
373 *
374 * If INNER_KEY is #t a different scheme is used for inner frames:
375 *
376 * Frames up to but excluding the first source frame originating from
377 * a user module are cut, except for possible application frames
378 * between the user frame and the last system frame previously
379 * encountered.
380 */
381
7115d1e4 382static void
34d19ef6 383narrow_stack (SCM stack, long inner, SCM inner_key, long outer, SCM outer_key)
7115d1e4 384{
92c2555f 385 scm_t_stack *s = SCM_STACK (stack);
13dcb666 386 unsigned long int i;
c014a02e 387 long n = s->length;
7115d1e4
MD
388
389 /* Cut inner part. */
bc36d050 390 if (scm_is_eq (inner_key, SCM_BOOL_T))
c3a6c6f9 391 {
13dcb666 392 /* Cut all frames up to user module code */
c3a6c6f9
MD
393 for (i = 0; inner; ++i, --inner)
394 {
395 SCM m = s->frames[i].source;
13dcb666
DH
396 if (SCM_MEMOIZEDP (m)
397 && !SCM_IMP (SCM_MEMOIZED_ENV (m))
7888309b 398 && scm_is_false (scm_system_module_env_p (SCM_MEMOIZED_ENV (m))))
c3a6c6f9
MD
399 {
400 /* Back up in order to include any non-source frames */
13dcb666 401 while (i > 0)
c3a6c6f9 402 {
13dcb666
DH
403 m = s->frames[i - 1].source;
404 if (SCM_MEMOIZEDP (m))
405 break;
406
407 m = s->frames[i - 1].proc;
7888309b
MV
408 if (scm_is_true (scm_procedure_p (m))
409 && scm_is_true (scm_procedure_property
13dcb666
DH
410 (m, scm_sym_system_procedure)))
411 break;
412
c3a6c6f9
MD
413 --i;
414 ++inner;
415 }
416 break;
417 }
418 }
419 }
420 else
421 /* Use standard cutting procedure. */
422 {
423 for (i = 0; inner; --inner)
bc36d050 424 if (scm_is_eq (s->frames[i++].proc, inner_key))
c3a6c6f9
MD
425 break;
426 }
7115d1e4
MD
427 s->frames = &s->frames[i];
428 n -= i;
429
430 /* Cut outer part. */
431 for (; n && outer; --outer)
bc36d050 432 if (scm_is_eq (s->frames[--n].proc, outer_key))
7115d1e4
MD
433 break;
434
435 s->length = n;
436}
437
782d171c
MD
438\f
439
440/* Stacks
441 */
442
762e289a 443SCM scm_stack_type;
66f45472 444
a1ec6916 445SCM_DEFINE (scm_stack_p, "stack?", 1, 0, 0,
1bbd0b84 446 (SCM obj),
b380b885 447 "Return @code{#t} if @var{obj} is a calling stack.")
1bbd0b84 448#define FUNC_NAME s_scm_stack_p
66f45472 449{
7888309b 450 return scm_from_bool(SCM_STACKP (obj));
66f45472 451}
1bbd0b84 452#undef FUNC_NAME
66f45472 453
af45e3b0
DH
454SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
455 (SCM obj, SCM args),
67941e3c
MG
456 "Create a new stack. If @var{obj} is @code{#t}, the current\n"
457 "evaluation stack is used for creating the stack frames,\n"
458 "otherwise the frames are taken from @var{obj} (which must be\n"
baffb19f
NJ
459 "either a debug object or a continuation).\n\n"
460 "@var{args} should be a list containing any combination of\n"
461 "integer, procedure and @code{#t} values.\n\n"
462 "These values specify various ways of cutting away uninteresting\n"
463 "stack frames from the top and bottom of the stack that\n"
464 "@code{make-stack} returns. They come in pairs like this:\n"
465 "@code{(@var{inner_cut_1} @var{outer_cut_1} @var{inner_cut_2}\n"
466 "@var{outer_cut_2} @dots{})}.\n\n"
467 "Each @var{inner_cut_N} can be @code{#t}, an integer, or a\n"
468 "procedure. @code{#t} means to cut away all frames up to but\n"
469 "excluding the first user module frame. An integer means to cut\n"
470 "away exactly that number of frames. A procedure means to cut\n"
471 "away all frames up to but excluding the application frame whose\n"
472 "procedure matches the specified one.\n\n"
473 "Each @var{outer_cut_N} can be an integer or a procedure. An\n"
474 "integer means to cut away that number of frames. A procedure\n"
475 "means to cut away frames down to but excluding the application\n"
476 "frame whose procedure matches the specified one.\n\n"
477 "If the @var{outer_cut_N} of the last pair is missing, it is\n"
478 "taken as 0.")
1bbd0b84 479#define FUNC_NAME s_scm_make_stack
782d171c 480{
c014a02e 481 long n, size;
1be6b49c 482 int maxp;
13dcb666 483 scm_t_debug_frame *dframe;
92c2555f 484 scm_t_info_frame *iframe;
b1b942b7 485 SCM vmframe;
c014a02e 486 long offset = 0;
66f45472 487 SCM stack, id;
af45e3b0 488 SCM inner_cut, outer_cut;
f6f88e0d
MD
489
490 /* Extract a pointer to the innermost frame of whatever object
491 scm_make_stack was given. */
bc36d050 492 if (scm_is_eq (obj, SCM_BOOL_T))
782d171c 493 {
b1b942b7 494 struct scm_vm *vp = SCM_VM_DATA (scm_the_vm ());
9de87eea 495 dframe = scm_i_last_debug_frame ();
b1b942b7 496 vmframe = scm_c_make_vm_frame (scm_the_vm (), vp->fp, vp->sp, vp->ip, 0);
13dcb666
DH
497 }
498 else if (SCM_DEBUGOBJP (obj))
499 {
500 dframe = SCM_DEBUGOBJ_FRAME (obj);
b1b942b7
AW
501 vmframe = SCM_BOOL_F;
502 }
503 else if (SCM_VM_FRAME_P (obj))
504 {
505 dframe = NULL;
506 vmframe = obj;
13dcb666
DH
507 }
508 else if (SCM_CONTINUATIONP (obj))
509 {
7f12a943
MV
510 scm_t_contregs *cont = SCM_CONTREGS (obj);
511 offset = cont->offset;
512 dframe = RELOC_FRAME (cont->dframe, offset);
b1b942b7
AW
513 if (!scm_is_null (cont->vm_conts))
514 { SCM vm_cont;
515 struct scm_vm_cont *data;
516 vm_cont = scm_cdr (scm_car (cont->vm_conts));
517 data = SCM_VM_CONT_DATA (vm_cont);
518 vmframe = scm_c_make_vm_frame (vm_cont,
7aa6f86b
AW
519 data->fp + data->reloc,
520 data->sp + data->reloc,
b1b942b7
AW
521 data->ip,
522 data->reloc);
523 } else
524 vmframe = SCM_BOOL_F;
13dcb666
DH
525 }
526 else
527 {
528 SCM_WRONG_TYPE_ARG (SCM_ARG1, obj);
529 /* not reached */
782d171c
MD
530 }
531
f6f88e0d
MD
532 /* Count number of frames. Also get stack id tag and check whether
533 there are more stackframes than we want to record
534 (SCM_BACKTRACE_MAXDEPTH). */
66f45472
MD
535 id = SCM_BOOL_F;
536 maxp = 0;
b1b942b7
AW
537 n = stack_depth (dframe, offset, vmframe, &id);
538 /* FIXME: redo maxp? */
782d171c
MD
539 size = n * SCM_FRAME_N_SLOTS;
540
f6f88e0d 541 /* Make the stack object. */
e11e83f3 542 stack = scm_make_struct (scm_stack_type, scm_from_long (size), SCM_EOL);
66f45472 543 SCM_STACK (stack) -> id = id;
7115d1e4
MD
544 iframe = &SCM_STACK (stack) -> tail[0];
545 SCM_STACK (stack) -> frames = iframe;
3b9e095b 546 SCM_STACK (stack) -> length = n;
7115d1e4 547
f6f88e0d 548 /* Translate the current chain of stack frames into debugging information. */
98922879
AW
549 n = read_frames (dframe, offset, vmframe, n, iframe);
550 if (n != SCM_STACK (stack)->length)
551 {
552 scm_puts ("warning: stack count incorrect!\n", scm_current_error_port ());
553 SCM_STACK (stack)->length = n;
554 }
7115d1e4 555
f6f88e0d 556 /* Narrow the stack according to the arguments given to scm_make_stack. */
af45e3b0 557 SCM_VALIDATE_REST_ARGUMENT (args);
d2e53ed6 558 while (n > 0 && !scm_is_null (args))
f6f88e0d
MD
559 {
560 inner_cut = SCM_CAR (args);
561 args = SCM_CDR (args);
d2e53ed6 562 if (scm_is_null (args))
af45e3b0 563 {
13dcb666 564 outer_cut = SCM_INUM0;
af45e3b0
DH
565 }
566 else
f6f88e0d
MD
567 {
568 outer_cut = SCM_CAR (args);
569 args = SCM_CDR (args);
570 }
f6f88e0d
MD
571
572 narrow_stack (stack,
e11e83f3
MV
573 scm_is_integer (inner_cut) ? scm_to_int (inner_cut) : n,
574 scm_is_integer (inner_cut) ? 0 : inner_cut,
575 scm_is_integer (outer_cut) ? scm_to_int (outer_cut) : n,
576 scm_is_integer (outer_cut) ? 0 : outer_cut);
f6f88e0d
MD
577
578 n = SCM_STACK (stack) -> length;
579 }
580
b1b942b7
AW
581 if (n > 0 && maxp)
582 iframe[n - 1].flags |= SCM_FRAMEF_OVERFLOW;
583
7115d1e4 584 if (n > 0)
b1b942b7 585 return stack;
7115d1e4
MD
586 else
587 return SCM_BOOL_F;
782d171c 588}
1bbd0b84 589#undef FUNC_NAME
782d171c 590
a1ec6916 591SCM_DEFINE (scm_stack_id, "stack-id", 1, 0, 0,
1bbd0b84 592 (SCM stack),
b380b885 593 "Return the identifier given to @var{stack} by @code{start-stack}.")
1bbd0b84 594#define FUNC_NAME s_scm_stack_id
66f45472 595{
92c2555f 596 scm_t_debug_frame *dframe;
c014a02e 597 long offset = 0;
bc36d050 598 if (scm_is_eq (stack, SCM_BOOL_T))
7115d1e4 599 {
9de87eea 600 dframe = scm_i_last_debug_frame ();
13dcb666
DH
601 }
602 else if (SCM_DEBUGOBJP (stack))
603 {
604 dframe = SCM_DEBUGOBJ_FRAME (stack);
605 }
606 else if (SCM_CONTINUATIONP (stack))
607 {
7f12a943
MV
608 scm_t_contregs *cont = SCM_CONTREGS (stack);
609 offset = cont->offset;
610 dframe = RELOC_FRAME (cont->dframe, offset);
13dcb666
DH
611 }
612 else if (SCM_STACKP (stack))
613 {
614 return SCM_STACK (stack) -> id;
7115d1e4 615 }
13dcb666
DH
616 else
617 {
618 SCM_WRONG_TYPE_ARG (1, stack);
619 }
620
7115d1e4 621 while (dframe && !SCM_VOIDFRAMEP (*dframe))
c0ab1b8d 622 dframe = RELOC_FRAME (dframe->prev, offset);
7115d1e4 623 if (dframe && SCM_VOIDFRAMEP (*dframe))
7f12a943 624 return RELOC_INFO (dframe->vect, offset)[0].id;
7115d1e4 625 return SCM_BOOL_F;
66f45472 626}
1bbd0b84 627#undef FUNC_NAME
66f45472 628
a1ec6916 629SCM_DEFINE (scm_stack_ref, "stack-ref", 2, 0, 0,
13dcb666
DH
630 (SCM stack, SCM index),
631 "Return the @var{index}'th frame from @var{stack}.")
1bbd0b84 632#define FUNC_NAME s_scm_stack_ref
782d171c 633{
13dcb666
DH
634 unsigned long int c_index;
635
636 SCM_VALIDATE_STACK (1, stack);
a55c2b68 637 c_index = scm_to_unsigned_integer (index, 0, SCM_STACK_LENGTH(stack)-1);
13dcb666 638 return scm_cons (stack, index);
782d171c 639}
1bbd0b84 640#undef FUNC_NAME
782d171c 641
3b3b36dd 642SCM_DEFINE (scm_stack_length, "stack-length", 1, 0, 0,
67941e3c
MG
643 (SCM stack),
644 "Return the length of @var{stack}.")
1bbd0b84 645#define FUNC_NAME s_scm_stack_length
782d171c 646{
34d19ef6 647 SCM_VALIDATE_STACK (1, stack);
e11e83f3 648 return scm_from_int (SCM_STACK_LENGTH (stack));
782d171c 649}
1bbd0b84 650#undef FUNC_NAME
782d171c
MD
651
652/* Frames
653 */
654
a1ec6916 655SCM_DEFINE (scm_frame_p, "frame?", 1, 0, 0,
1bbd0b84 656 (SCM obj),
67941e3c 657 "Return @code{#t} if @var{obj} is a stack frame.")
1bbd0b84 658#define FUNC_NAME s_scm_frame_p
66f45472 659{
7888309b 660 return scm_from_bool(SCM_FRAMEP (obj));
66f45472 661}
1bbd0b84 662#undef FUNC_NAME
66f45472 663
3b3b36dd 664SCM_DEFINE (scm_last_stack_frame, "last-stack-frame", 1, 0, 0,
67941e3c 665 (SCM obj),
b0b0deff
NJ
666 "Return the last (innermost) frame of @var{obj}, which must be\n"
667 "either a debug object or a continuation.")
1bbd0b84 668#define FUNC_NAME s_scm_last_stack_frame
782d171c 669{
92c2555f 670 scm_t_debug_frame *dframe;
c014a02e 671 long offset = 0;
7115d1e4 672 SCM stack;
782d171c 673
782d171c 674 if (SCM_DEBUGOBJP (obj))
13dcb666
DH
675 {
676 dframe = SCM_DEBUGOBJ_FRAME (obj);
677 }
5f144b10 678 else if (SCM_CONTINUATIONP (obj))
782d171c 679 {
7f12a943
MV
680 scm_t_contregs *cont = SCM_CONTREGS (obj);
681 offset = cont->offset;
682 dframe = RELOC_FRAME (cont->dframe, offset);
782d171c 683 }
3323ad08
JB
684 else
685 {
276dd677
DH
686 SCM_WRONG_TYPE_ARG (1, obj);
687 /* not reached */
3323ad08 688 }
782d171c 689
66f45472 690 if (!dframe || SCM_VOIDFRAMEP (*dframe))
782d171c
MD
691 return SCM_BOOL_F;
692
e11e83f3 693 stack = scm_make_struct (scm_stack_type, scm_from_int (SCM_FRAME_N_SLOTS),
c0ab1b8d 694 SCM_EOL);
7115d1e4
MD
695 SCM_STACK (stack) -> length = 1;
696 SCM_STACK (stack) -> frames = &SCM_STACK (stack) -> tail[0];
c0ab1b8d 697 read_frame (dframe, offset,
92c2555f 698 (scm_t_info_frame *) &SCM_STACK (stack) -> frames[0]);
782d171c 699
13dcb666 700 return scm_cons (stack, SCM_INUM0);
782d171c 701}
1bbd0b84 702#undef FUNC_NAME
782d171c 703
3b3b36dd 704SCM_DEFINE (scm_frame_number, "frame-number", 1, 0, 0,
67941e3c
MG
705 (SCM frame),
706 "Return the frame number of @var{frame}.")
1bbd0b84 707#define FUNC_NAME s_scm_frame_number
782d171c 708{
34d19ef6 709 SCM_VALIDATE_FRAME (1, frame);
e11e83f3 710 return scm_from_int (SCM_FRAME_NUMBER (frame));
782d171c 711}
1bbd0b84 712#undef FUNC_NAME
782d171c 713
3b3b36dd 714SCM_DEFINE (scm_frame_source, "frame-source", 1, 0, 0,
67941e3c
MG
715 (SCM frame),
716 "Return the source of @var{frame}.")
1bbd0b84 717#define FUNC_NAME s_scm_frame_source
782d171c 718{
34d19ef6 719 SCM_VALIDATE_FRAME (1, frame);
782d171c
MD
720 return SCM_FRAME_SOURCE (frame);
721}
1bbd0b84 722#undef FUNC_NAME
782d171c 723
3b3b36dd 724SCM_DEFINE (scm_frame_procedure, "frame-procedure", 1, 0, 0,
67941e3c
MG
725 (SCM frame),
726 "Return the procedure for @var{frame}, or @code{#f} if no\n"
727 "procedure is associated with @var{frame}.")
1bbd0b84 728#define FUNC_NAME s_scm_frame_procedure
782d171c 729{
34d19ef6 730 SCM_VALIDATE_FRAME (1, frame);
782d171c 731 return (SCM_FRAME_PROC_P (frame)
afa92d19
TP
732 ? SCM_FRAME_PROC (frame)
733 : SCM_BOOL_F);
782d171c 734}
1bbd0b84 735#undef FUNC_NAME
782d171c 736
3b3b36dd 737SCM_DEFINE (scm_frame_arguments, "frame-arguments", 1, 0, 0,
67941e3c
MG
738 (SCM frame),
739 "Return the arguments of @var{frame}.")
1bbd0b84 740#define FUNC_NAME s_scm_frame_arguments
782d171c 741{
34d19ef6 742 SCM_VALIDATE_FRAME (1, frame);
782d171c
MD
743 return SCM_FRAME_ARGS (frame);
744}
1bbd0b84 745#undef FUNC_NAME
782d171c 746
3b3b36dd 747SCM_DEFINE (scm_frame_previous, "frame-previous", 1, 0, 0,
67941e3c
MG
748 (SCM frame),
749 "Return the previous frame of @var{frame}, or @code{#f} if\n"
750 "@var{frame} is the first frame in its stack.")
1bbd0b84 751#define FUNC_NAME s_scm_frame_previous
782d171c 752{
13dcb666
DH
753 unsigned long int n;
754 SCM_VALIDATE_FRAME (1, frame);
e11e83f3 755 n = scm_to_ulong (SCM_CDR (frame)) + 1;
782d171c
MD
756 if (n >= SCM_STACK_LENGTH (SCM_CAR (frame)))
757 return SCM_BOOL_F;
758 else
e11e83f3 759 return scm_cons (SCM_CAR (frame), scm_from_ulong (n));
782d171c 760}
1bbd0b84 761#undef FUNC_NAME
782d171c 762
3b3b36dd 763SCM_DEFINE (scm_frame_next, "frame-next", 1, 0, 0,
1bbd0b84 764 (SCM frame),
67941e3c
MG
765 "Return the next frame of @var{frame}, or @code{#f} if\n"
766 "@var{frame} is the last frame in its stack.")
1bbd0b84 767#define FUNC_NAME s_scm_frame_next
782d171c 768{
13dcb666
DH
769 unsigned long int n;
770 SCM_VALIDATE_FRAME (1, frame);
e11e83f3 771 n = scm_to_ulong (SCM_CDR (frame));
13dcb666 772 if (n == 0)
782d171c
MD
773 return SCM_BOOL_F;
774 else
e11e83f3 775 return scm_cons (SCM_CAR (frame), scm_from_ulong (n - 1));
782d171c 776}
1bbd0b84 777#undef FUNC_NAME
782d171c 778
3b3b36dd 779SCM_DEFINE (scm_frame_real_p, "frame-real?", 1, 0, 0,
67941e3c
MG
780 (SCM frame),
781 "Return @code{#t} if @var{frame} is a real frame.")
1bbd0b84 782#define FUNC_NAME s_scm_frame_real_p
782d171c 783{
34d19ef6 784 SCM_VALIDATE_FRAME (1, frame);
7888309b 785 return scm_from_bool(SCM_FRAME_REAL_P (frame));
782d171c 786}
1bbd0b84 787#undef FUNC_NAME
782d171c 788
3b3b36dd 789SCM_DEFINE (scm_frame_procedure_p, "frame-procedure?", 1, 0, 0,
67941e3c
MG
790 (SCM frame),
791 "Return @code{#t} if a procedure is associated with @var{frame}.")
1bbd0b84 792#define FUNC_NAME s_scm_frame_procedure_p
782d171c 793{
34d19ef6 794 SCM_VALIDATE_FRAME (1, frame);
7888309b 795 return scm_from_bool(SCM_FRAME_PROC_P (frame));
782d171c 796}
1bbd0b84 797#undef FUNC_NAME
782d171c 798
3b3b36dd 799SCM_DEFINE (scm_frame_evaluating_args_p, "frame-evaluating-args?", 1, 0, 0,
67941e3c
MG
800 (SCM frame),
801 "Return @code{#t} if @var{frame} contains evaluated arguments.")
1bbd0b84 802#define FUNC_NAME s_scm_frame_evaluating_args_p
782d171c 803{
34d19ef6 804 SCM_VALIDATE_FRAME (1, frame);
7888309b 805 return scm_from_bool(SCM_FRAME_EVAL_ARGS_P (frame));
782d171c 806}
1bbd0b84 807#undef FUNC_NAME
782d171c 808
3b3b36dd 809SCM_DEFINE (scm_frame_overflow_p, "frame-overflow?", 1, 0, 0,
67941e3c
MG
810 (SCM frame),
811 "Return @code{#t} if @var{frame} is an overflow frame.")
1bbd0b84 812#define FUNC_NAME s_scm_frame_overflow_p
782d171c 813{
34d19ef6 814 SCM_VALIDATE_FRAME (1, frame);
7888309b 815 return scm_from_bool(SCM_FRAME_OVERFLOW_P (frame));
782d171c 816}
1bbd0b84 817#undef FUNC_NAME
782d171c
MD
818
819\f
820
821void
822scm_init_stacks ()
823{
b3aa4626
KR
824 scm_stack_type =
825 scm_permanent_object
826 (scm_make_vtable (scm_from_locale_string (SCM_STACK_LAYOUT),
827 SCM_UNDEFINED));
cc95e00a
MV
828 scm_set_struct_vtable_name_x (scm_stack_type,
829 scm_from_locale_symbol ("stack"));
a0599745 830#include "libguile/stacks.x"
782d171c 831}
89e00824
ML
832
833/*
834 Local Variables:
835 c-file-style: "gnu"
836 End:
837*/