1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-19 18:20:22 +02:00

remove debug frames

* libguile/debug.h (scm_t_debug_frame): Remove this type, as it was
  internal to the old evaluator.
  (SCM_EVALFRAME, SCM_APPLYFRAME, SCM_VOIDFRAME, SCM_MACROEXPF)
  (SCM_TAILREC, SCM_TRACED_FRAME, SCM_ARGS_READY, SCM_DOVERFLOW)
  (SCM_MAX_FRAME_SIZE, SCM_FRAMETYPE)
  (SCM_EVALFRAMEP, SCM_APPLYFRAMEP, SCM_VOIDFRAMEP, SCM_MACROEXPFP)
  (SCM_TAILRECP, SCM_TRACED_FRAME_P, SCM_ARGS_READY_P, SCM_OVERFLOWP)
  (SCM_SET_MACROEXP, SCM_SET_TAILREC, SCM_SET_TRACED_FRAME)
  (SCM_SET_ARGSREADY, SCM_SET_OVERFLOW)
  (SCM_CLEAR_MACROEXP, SCM_CLEAR_TRACED_FRAME, SCM_CLEAR_ARGSREADY):
  Remove macro accessors to scm_t_debug_frame.
  (SCM_DEBUGOBJP, SCM_DEBUGOBJ_FRAME, SCM_SET_DEBUGOBJ_FRAME):
  (scm_debug_object_p, scm_make_debugobj): Remove debugobj accessors.
  (scm_i_unmemoize_expr): Remove unused declaration.

* libguile/debug.c (scm_debug_options): No more max limit on frame
  sizes.
  (scm_start_stack): Just call out to scm_vm_call_with_new_stack.
  (scm_debug_object_p, scm_make_debugobj, scm_init_debug): No more
  debugobj smob type.

* libguile/deprecated.h:
* libguile/deprecated.c (scm_i_deprecated_last_debug_frame)
  (scm_last_debug_frame): Remove deprecated debug-frame bits.

* libguile/stacks.c (scm_make_stack): Rework this function and its
  dependents to only walk VM frames.
  (scm_stack_id): Call out to the holder of the VM frame in question,
  which should be a VM or a VM continuation, for the stack ID. Currently
  this bit is stubbed out.
  (scm_last_stack_frame): Removed. It seems this is mainly useful for a
  debugger, and we need to rewrite the debugger to work on the Scheme
  level.

* test-suite/tests/continuations.test ("continuations"): Remove test for
  last-stack-frame.

* libguile/continuations.h (struct scm_t_contregs):
* libguile/continuations.c (scm_make_continuation):
  (copy_stack_and_call, scm_i_with_continuation_barrier): No need to
  save and restore debug frames.

* libguile/threads.h (scm_i_thread): Don't track debug frames.
  (scm_i_last_debug_frame, scm_i_set_last_debug_frame): Remove macro
  accessors.

* libguile/threads.c (guilify_self_1): Don't track debug frames.

* libguile/throw.c: No need to track debug frames in a jmpbuf.

* libguile/vm-engine.c (vm_engine, VM_PUSH_DEBUG_FRAMES): Don't push
  debug frames.

* libguile/vm.h:
* libguile/vm.c (scm_vm_call_with_new_stack): New function. Currently
  stubbed out though.
This commit is contained in:
Andy Wingo 2009-12-03 11:03:39 +01:00
parent b2b554efd3
commit 14aa25e410
14 changed files with 88 additions and 500 deletions

View file

@ -43,32 +43,6 @@
/* {Frames and stacks}
*
* The debugging evaluator creates debug frames on the stack. These
* are linked from the innermost frame and outwards. The last frame
* created can always be accessed as SCM_LAST_DEBUG_FRAME.
* Continuations contain a pointer to the innermost debug frame on the
* continuation stack.
*
* Each debug frame contains a set of flags and information about one
* or more stack frames. The case of multiple frames occurs due to
* tail recursion. The maximal number of stack frames which can be
* recorded in one debug frame can be set dynamically with the debug
* option FRAMES.
*
* Stack frame information is of two types: eval information (the
* expression being evaluated and its environment) and apply
* information (the procedure being applied and its arguments). A
* stack frame normally corresponds to an eval/apply pair, but macros
* and special forms (which are implemented as macros in Guile) only
* have eval information and apply calls leads to apply only frames.
*
* Since we want to record the total stack information and later
* manipulate this data at the scheme level in the debugger, we need
* to transform it into a new representation. In the following code
* section you'll find the functions implementing this data type.
*
* Representation:
*
* The stack is represented as a struct with an id slot and a tail
* array of scm_t_info_frame structs.
@ -104,248 +78,48 @@
/* Some auxiliary functions for reading debug frames off the stack.
*/
static SCM stack_id_with_fp (SCM vmframe, SCM **fp);
/* Stacks often contain pointers to other items on the stack; for
example, each scm_t_debug_frame structure contains a pointer to the
next frame out. When we capture a continuation, we copy the stack
into the heap, and just leave all the pointers unchanged. This
makes it simple to restore the continuation --- just copy the stack
back! However, if we retrieve a pointer from the heap copy to
another item that was originally on the stack, we have to add an
offset to the pointer to discover the new referent.
If PTR is a pointer retrieved from a continuation, whose original
target was on the stack, and OFFSET is the appropriate offset from
the original stack to the continuation, then RELOC_MUMBLE (PTR,
OFFSET) is a pointer to the copy in the continuation of the
original referent, cast to an scm_debug_MUMBLE *. */
#define RELOC_INFO(ptr, offset) \
((scm_t_debug_info *) ((SCM_STACKITEM *) (ptr) + (offset)))
#define RELOC_FRAME(ptr, offset) \
((scm_t_debug_frame *) ((SCM_STACKITEM *) (ptr) + (offset)))
/* Count number of debug info frames on a stack, beginning with
* DFRAME. OFFSET is used for relocation of pointers when the stack
* is read from a continuation.
/* Count number of debug info frames on a stack, beginning with VMFRAME.
*/
static long
stack_depth (scm_t_debug_frame *dframe, scm_t_ptrdiff offset, SCM vmframe,
SCM *id)
stack_depth (SCM vmframe, SCM *fp)
{
long n;
for (n = 0;
dframe && !SCM_VOIDFRAMEP (*dframe);
dframe = RELOC_FRAME (dframe->prev, offset))
{
if (SCM_EVALFRAMEP (*dframe))
{
scm_t_debug_info *info = RELOC_INFO (dframe->info, offset);
scm_t_debug_info *vect = RELOC_INFO (dframe->vect, offset);
/* If current frame is a macro during expansion, we should
skip the previously recorded macro transformer
application frame. */
if (SCM_MACROEXPP (*dframe) && n > 0)
--n;
n += (info - vect) / 2 + 1;
/* Data in the apply part of an eval info frame comes from previous
stack frame if the scm_t_debug_info vector is overflowed. */
if ((((info - vect) & 1) == 0)
&& SCM_OVERFLOWP (*dframe)
&& !SCM_UNBNDP (info[1].a.proc))
++n;
}
else
{
scm_t_debug_info *vect = RELOC_INFO (dframe->vect, offset);
if (SCM_PROGRAM_P (vect[0].a.proc))
{
if (!SCM_PROGRAM_IS_BOOT (vect[0].a.proc))
/* Programs can end up in the debug stack via deval; but we just
ignore those, because we know that the debugging VM engine
pushes one dframe per invocation, with the boot program as
the proc, so we only count those. */
continue;
/* count vmframe back to previous boot frame */
for (; scm_is_true (vmframe); vmframe = scm_c_vm_frame_prev (vmframe))
{
if (!SCM_PROGRAM_IS_BOOT (scm_vm_frame_program (vmframe)))
++n;
else
{ /* skip boot frame, cut out of the vm backtrace */
vmframe = scm_c_vm_frame_prev (vmframe);
break;
}
}
}
else
++n; /* increment for non-program apply frame */
}
}
if (dframe && SCM_VOIDFRAMEP (*dframe))
*id = RELOC_INFO(dframe->vect, offset)[0].id;
/* count vmframes, skipping boot frames */
for (; scm_is_true (vmframe) && SCM_VM_FRAME_FP (vmframe) > fp;
vmframe = scm_c_vm_frame_prev (vmframe))
if (!SCM_PROGRAM_IS_BOOT (scm_vm_frame_program (vmframe)))
++n;
return n;
}
/* Read debug info from DFRAME into IFRAME.
*/
static void
read_frame (scm_t_debug_frame *dframe, scm_t_ptrdiff offset,
scm_t_info_frame *iframe)
{
scm_t_bits flags = SCM_UNPACK (SCM_INUM0); /* UGh. */
if (SCM_EVALFRAMEP (*dframe))
{
scm_t_debug_info *info = RELOC_INFO (dframe->info, offset);
scm_t_debug_info *vect = RELOC_INFO (dframe->vect, offset);
if ((info - vect) & 1)
{
/* Debug.vect ends with apply info. */
--info;
if (!SCM_UNBNDP (info[1].a.proc))
{
flags |= SCM_FRAMEF_PROC;
iframe->proc = info[1].a.proc;
iframe->args = info[1].a.args;
if (!SCM_ARGS_READY_P (*dframe))
flags |= SCM_FRAMEF_EVAL_ARGS;
}
}
}
else
{
scm_t_debug_info *vect = RELOC_INFO (dframe->vect, offset);
flags |= SCM_FRAMEF_PROC;
iframe->proc = vect[0].a.proc;
iframe->args = vect[0].a.args;
}
iframe->flags = flags;
}
/* Look up the first body form of the apply closure. We'll use this
below to prevent it from being displayed.
*/
static SCM
get_applybody ()
{
SCM var = scm_sym2var (scm_sym_apply, SCM_BOOL_F, SCM_BOOL_F);
if (SCM_VARIABLEP (var) && SCM_CLOSUREP (SCM_VARIABLE_REF (var)))
return SCM_CAR (SCM_CLOSURE_BODY (SCM_VARIABLE_REF (var)));
else
return SCM_UNDEFINED;
}
#define NEXT_FRAME(iframe, n, quit) \
do { \
++iframe; \
if (--n == 0) \
goto quit; \
} while (0)
/* Fill the scm_t_info_frame vector IFRAME with data from N stack frames
* starting with the first stack frame represented by debug frame
* DFRAME.
* starting with the first stack frame represented by VMFRAME.
*/
static scm_t_bits
read_frames (scm_t_debug_frame *dframe, scm_t_ptrdiff offset,
SCM vmframe, long n, scm_t_info_frame *iframes)
read_frames (SCM vmframe, long n, scm_t_info_frame *iframes)
{
scm_t_info_frame *iframe = iframes;
scm_t_debug_info *info, *vect;
static SCM applybody = SCM_UNDEFINED;
/* The value of applybody has to be setup after r4rs.scm has executed. */
if (SCM_UNBNDP (applybody))
applybody = get_applybody ();
for (;
dframe && !SCM_VOIDFRAMEP (*dframe) && n > 0;
dframe = RELOC_FRAME (dframe->prev, offset))
for (; scm_is_true (vmframe);
vmframe = scm_c_vm_frame_prev (vmframe))
{
read_frame (dframe, offset, iframe);
if (SCM_EVALFRAMEP (*dframe))
{
/* If current frame is a macro during expansion, we should
skip the previously recorded macro transformer
application frame. */
if (SCM_MACROEXPP (*dframe) && iframe > iframes)
{
*(iframe - 1) = *iframe;
--iframe;
++n;
}
info = RELOC_INFO (dframe->info, offset);
vect = RELOC_INFO (dframe->vect, offset);
if ((info - vect) & 1)
--info;
/* Data in the apply part of an eval info frame comes from
previous stack frame if the scm_t_debug_info vector is
overflowed. */
else if (SCM_OVERFLOWP (*dframe)
&& !SCM_UNBNDP (info[1].a.proc))
{
NEXT_FRAME (iframe, n, quit);
iframe->flags = SCM_UNPACK(SCM_INUM0) | SCM_FRAMEF_PROC;
iframe->proc = info[1].a.proc;
iframe->args = info[1].a.args;
}
if (SCM_OVERFLOWP (*dframe))
iframe->flags |= SCM_FRAMEF_OVERFLOW;
info -= 2;
NEXT_FRAME (iframe, n, quit);
while (info >= vect)
{
if (!SCM_UNBNDP (info[1].a.proc))
{
iframe->flags = SCM_UNPACK(SCM_INUM0) | SCM_FRAMEF_PROC;
iframe->proc = info[1].a.proc;
iframe->args = info[1].a.args;
}
else
iframe->flags = SCM_UNPACK (SCM_INUM0);
iframe->source = SCM_BOOL_F;
info -= 2;
NEXT_FRAME (iframe, n, quit);
}
}
else if (SCM_PROGRAM_P (iframe->proc))
if (SCM_PROGRAM_IS_BOOT (scm_vm_frame_program (vmframe)))
/* skip boot frame */
continue;
else
{
if (!SCM_PROGRAM_IS_BOOT (iframe->proc))
/* Programs can end up in the debug stack via deval; but we just
ignore those, because we know that the debugging VM engine
pushes one dframe per invocation, with the boot program as
the proc, so we only count those. */
continue;
for (; scm_is_true (vmframe);
vmframe = scm_c_vm_frame_prev (vmframe))
{
if (SCM_PROGRAM_IS_BOOT (scm_vm_frame_program (vmframe)))
{ /* skip boot frame, back to interpreted frames */
vmframe = scm_c_vm_frame_prev (vmframe);
break;
}
else
{
/* Oh dear, oh dear, oh dear. */
iframe->flags = SCM_UNPACK (SCM_INUM0) | SCM_FRAMEF_PROC;
iframe->source = scm_vm_frame_source (vmframe);
iframe->proc = scm_vm_frame_program (vmframe);
iframe->args = scm_vm_frame_arguments (vmframe);
++iframe;
if (--n == 0)
goto quit;
}
}
/* Oh dear, oh dear, oh dear. */
iframe->flags = SCM_UNPACK (SCM_INUM0) | SCM_FRAMEF_PROC;
iframe->source = scm_vm_frame_source (vmframe);
iframe->proc = scm_vm_frame_program (vmframe);
iframe->args = scm_vm_frame_arguments (vmframe);
++iframe;
if (--n == 0)
break;
}
else
{
NEXT_FRAME (iframe, n, quit);
}
quit:
if (iframe > iframes)
(iframe - 1) -> flags |= SCM_FRAMEF_REAL;
}
return iframe - iframes; /* Number of frames actually read */
}
@ -448,11 +222,10 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
{
long n, size;
int maxp;
scm_t_debug_frame *dframe;
scm_t_info_frame *iframe;
SCM vmframe;
long offset = 0;
SCM stack, id;
SCM stack;
SCM id, *id_fp;
SCM inner_cut, outer_cut;
/* Extract a pointer to the innermost frame of whatever object
@ -460,24 +233,13 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
if (scm_is_eq (obj, SCM_BOOL_T))
{
struct scm_vm *vp = SCM_VM_DATA (scm_the_vm ());
dframe = scm_i_last_debug_frame ();
vmframe = scm_c_make_vm_frame (scm_the_vm (), vp->fp, vp->sp, vp->ip, 0);
}
else if (SCM_DEBUGOBJP (obj))
{
dframe = SCM_DEBUGOBJ_FRAME (obj);
vmframe = SCM_BOOL_F;
}
else if (SCM_VM_FRAME_P (obj))
{
dframe = NULL;
vmframe = obj;
}
vmframe = obj;
else if (SCM_CONTINUATIONP (obj))
{
scm_t_contregs *cont = SCM_CONTREGS (obj);
offset = cont->offset;
dframe = RELOC_FRAME (cont->dframe, offset);
if (!scm_is_null (cont->vm_conts))
{ SCM vm_cont;
struct scm_vm_cont *data;
@ -497,12 +259,18 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
/* not reached */
}
if (scm_is_false (vmframe))
return SCM_BOOL_F;
/* Get ID of the stack corresponding to the given frame. */
id = stack_id_with_fp (vmframe, &id_fp);
/* Count number of frames. Also get stack id tag and check whether
there are more stackframes than we want to record
(SCM_BACKTRACE_MAXDEPTH). */
id = SCM_BOOL_F;
maxp = 0;
n = stack_depth (dframe, offset, vmframe, &id);
n = stack_depth (vmframe, id_fp);
/* FIXME: redo maxp? */
size = n * SCM_FRAME_N_SLOTS;
@ -514,7 +282,7 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
SCM_STACK (stack) -> length = n;
/* Translate the current chain of stack frames into debugging information. */
n = read_frames (dframe, offset, vmframe, n, iframe);
n = read_frames (vmframe, n, iframe);
if (n != SCM_STACK (stack)->length)
{
scm_puts ("warning: stack count incorrect!\n", scm_current_error_port ());
@ -561,39 +329,58 @@ SCM_DEFINE (scm_stack_id, "stack-id", 1, 0, 0,
"Return the identifier given to @var{stack} by @code{start-stack}.")
#define FUNC_NAME s_scm_stack_id
{
scm_t_debug_frame *dframe;
long offset = 0;
SCM vmframe, *id_fp;
if (scm_is_eq (stack, SCM_BOOL_T))
{
dframe = scm_i_last_debug_frame ();
}
else if (SCM_DEBUGOBJP (stack))
{
dframe = SCM_DEBUGOBJ_FRAME (stack);
struct scm_vm *vp = SCM_VM_DATA (scm_the_vm ());
vmframe = scm_c_make_vm_frame (scm_the_vm (), vp->fp, vp->sp, vp->ip, 0);
}
else if (SCM_VM_FRAME_P (stack))
vmframe = stack;
else if (SCM_CONTINUATIONP (stack))
{
scm_t_contregs *cont = SCM_CONTREGS (stack);
offset = cont->offset;
dframe = RELOC_FRAME (cont->dframe, offset);
}
else if (SCM_STACKP (stack))
{
return SCM_STACK (stack) -> id;
if (!scm_is_null (cont->vm_conts))
{ SCM vm_cont;
struct scm_vm_cont *data;
vm_cont = scm_cdr (scm_car (cont->vm_conts));
data = SCM_VM_CONT_DATA (vm_cont);
vmframe = scm_c_make_vm_frame (vm_cont,
data->fp + data->reloc,
data->sp + data->reloc,
data->ip,
data->reloc);
} else
vmframe = SCM_BOOL_F;
}
else
{
SCM_WRONG_TYPE_ARG (1, stack);
SCM_WRONG_TYPE_ARG (SCM_ARG1, stack);
/* not reached */
}
while (dframe && !SCM_VOIDFRAMEP (*dframe))
dframe = RELOC_FRAME (dframe->prev, offset);
if (dframe && SCM_VOIDFRAMEP (*dframe))
return RELOC_INFO (dframe->vect, offset)[0].id;
return SCM_BOOL_F;
return stack_id_with_fp (vmframe, &id_fp);
}
#undef FUNC_NAME
static SCM
stack_id_with_fp (SCM vmframe, SCM **fp)
{
SCM holder = SCM_VM_FRAME_STACK_HOLDER (vmframe);
if (SCM_VM_CONT_P (holder))
{
*fp = NULL;
return SCM_BOOL_F;
}
else
{
*fp = NULL;
return SCM_BOOL_F;
}
}
SCM_DEFINE (scm_stack_ref, "stack-ref", 2, 0, 0,
(SCM stack, SCM index),
"Return the @var{index}'th frame from @var{stack}.")
@ -629,46 +416,6 @@ SCM_DEFINE (scm_frame_p, "frame?", 1, 0, 0,
}
#undef FUNC_NAME
SCM_DEFINE (scm_last_stack_frame, "last-stack-frame", 1, 0, 0,
(SCM obj),
"Return the last (innermost) frame of @var{obj}, which must be\n"
"either a debug object or a continuation.")
#define FUNC_NAME s_scm_last_stack_frame
{
scm_t_debug_frame *dframe;
long offset = 0;
SCM stack;
if (SCM_DEBUGOBJP (obj))
{
dframe = SCM_DEBUGOBJ_FRAME (obj);
}
else if (SCM_CONTINUATIONP (obj))
{
scm_t_contregs *cont = SCM_CONTREGS (obj);
offset = cont->offset;
dframe = RELOC_FRAME (cont->dframe, offset);
}
else
{
SCM_WRONG_TYPE_ARG (1, obj);
/* not reached */
}
if (!dframe || SCM_VOIDFRAMEP (*dframe))
return SCM_BOOL_F;
stack = scm_make_struct (scm_stack_type, scm_from_int (SCM_FRAME_N_SLOTS),
SCM_EOL);
SCM_STACK (stack) -> length = 1;
SCM_STACK (stack) -> frames = &SCM_STACK (stack) -> tail[0];
read_frame (dframe, offset,
(scm_t_info_frame *) &SCM_STACK (stack) -> frames[0]);
return scm_cons (stack, SCM_INUM0);
}
#undef FUNC_NAME
SCM_DEFINE (scm_frame_number, "frame-number", 1, 0, 0,
(SCM frame),
"Return the frame number of @var{frame}.")