* continuations.c, continuations.h, debug.c, gc.c, init.c, root.c,
[bpt/guile.git] / libguile / stacks.c
CommitLineData
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 */
125static int stack_depth SCM_P ((scm_debug_frame *dframe, long offset, int *maxp));
126static int
127stack_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 */
162static void read_frame SCM_P ((scm_debug_frame *dframe, long offset, scm_info_frame *iframe));
163static void
164read_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 */
205static void read_frames SCM_P ((scm_debug_frame *dframe, long offset, int skip, int n, scm_info_frame *iframes));
206static void
207read_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
302SCM_PROC (s_make_stack, "make-stack", 0, 3, 0, scm_make_stack);
303SCM
304scm_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
363SCM_PROC(s_stack_ref, "stack-ref", 2, 0, 0, scm_stack_ref);
364SCM
365scm_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
383SCM_PROC(s_stack_length, "stack-length", 1, 0, 0, scm_stack_length);
384SCM
385scm_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
399SCM_PROC(s_last_stack_frame, "last-stack-frame", 1, 0, 0, scm_last_stack_frame);
400SCM
401scm_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
440SCM_PROC(s_frame_number, "frame-number", 1, 0, 0, scm_frame_number);
441SCM
442scm_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
452SCM_PROC(s_frame_source, "frame-source", 1, 0, 0, scm_frame_source);
453SCM
454scm_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
464SCM_PROC(s_frame_procedure, "frame-procedure", 1, 0, 0, scm_frame_procedure);
465SCM
466scm_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
478SCM_PROC(s_frame_arguments, "frame-arguments", 1, 0, 0, scm_frame_arguments);
479SCM
480scm_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
490SCM_PROC(s_frame_previous, "frame-previous", 1, 0, 0, scm_frame_previous);
491SCM
492scm_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
507SCM_PROC(s_frame_next, "frame-next", 1, 0, 0, scm_frame_next);
508SCM
509scm_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
524SCM_PROC(s_frame_real_p, "frame-real?", 1, 0, 0, scm_frame_real_p);
525SCM
526scm_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
536SCM_PROC(s_frame_procedure_p, "frame-procedure?", 1, 0, 0, scm_frame_procedure_p);
537SCM
538scm_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
548SCM_PROC(s_frame_evaluating_args_p, "frame-evaluating-args?", 1, 0, 0, scm_frame_evaluating_args_p);
549SCM
550scm_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
560SCM_PROC(s_frame_overflow_p, "frame-overflow?", 1, 0, 0, scm_frame_overflow_p);
561SCM
562scm_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
574void
575scm_init_stacks ()
576{
577#include "stacks.x"
578}