1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-01 20:30:28 +02:00

Optimize make-stack

* libguile/continuations.h:
* libguile/continuations.c (scm_i_continuation_to_frame): Operate on
  low-level C structures instead of heap objects.

* libguile/frames.h:
* libguile/frames.c (frame_offset, frame_stack_base): Const args.
  (scm_c_frame_closure): New helper.
  (scm_frame_procedure): Use the new helper.

* libguile/stacks.c (stack_depth, narrow_stack, scm_make_stack): Rework
  to avoid allocating frames as we traverse the stack, and to avoid an
  n**2 case where there are outer cuts.
This commit is contained in:
Andy Wingo 2014-04-14 16:31:02 +02:00
parent 8de051da47
commit 3b14dd2f27
5 changed files with 103 additions and 80 deletions

View file

@ -168,8 +168,8 @@ scm_i_make_continuation (int *first, struct scm_vm *vp, SCM vm_cont)
} }
#undef FUNC_NAME #undef FUNC_NAME
SCM int
scm_i_continuation_to_frame (SCM continuation) scm_i_continuation_to_frame (SCM continuation, struct scm_frame *frame)
{ {
SCM contregs; SCM contregs;
scm_t_contregs *cont; scm_t_contregs *cont;
@ -179,18 +179,17 @@ scm_i_continuation_to_frame (SCM continuation)
if (scm_is_true (cont->vm_cont)) if (scm_is_true (cont->vm_cont))
{ {
struct scm_frame frame;
struct scm_vm_cont *data = SCM_VM_CONT_DATA (cont->vm_cont); struct scm_vm_cont *data = SCM_VM_CONT_DATA (cont->vm_cont);
frame.stack_holder = data; frame->stack_holder = data;
frame.fp_offset = (data->fp + data->reloc) - data->stack_base; frame->fp_offset = (data->fp + data->reloc) - data->stack_base;
frame.sp_offset = (data->sp + data->reloc) - data->stack_base; frame->sp_offset = (data->sp + data->reloc) - data->stack_base;
frame.ip = data->ra; frame->ip = data->ra;
return scm_c_make_frame (SCM_VM_FRAME_KIND_CONT, &frame); return 1;
} }
else else
return SCM_BOOL_F; return 0;
} }
struct scm_vm * struct scm_vm *

View file

@ -3,7 +3,7 @@
#ifndef SCM_CONTINUATIONS_H #ifndef SCM_CONTINUATIONS_H
#define SCM_CONTINUATIONS_H #define SCM_CONTINUATIONS_H
/* Copyright (C) 1995,1996,2000,2001, 2006, 2008, 2009, 2010, 2012, 2013 Free Software Foundation, Inc. /* Copyright (C) 1995,1996,2000,2001, 2006, 2008, 2009, 2010, 2012, 2013, 2014 Free Software Foundation, Inc.
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License * modify it under the terms of the GNU Lesser General Public License
@ -76,7 +76,10 @@ SCM_INTERNAL SCM scm_i_make_continuation (int *first,
SCM_INTERNAL void scm_i_check_continuation (SCM cont); SCM_INTERNAL void scm_i_check_continuation (SCM cont);
SCM_INTERNAL void scm_i_reinstate_continuation (SCM cont); SCM_INTERNAL void scm_i_reinstate_continuation (SCM cont);
SCM_INTERNAL SCM scm_i_continuation_to_frame (SCM cont); struct scm_frame;
SCM_INTERNAL int scm_i_continuation_to_frame (SCM cont,
struct scm_frame *frame);
SCM_INTERNAL struct scm_vm* scm_i_contregs_vp (SCM contregs); SCM_INTERNAL struct scm_vm* scm_i_contregs_vp (SCM contregs);
SCM_INTERNAL SCM scm_i_contregs_vm_cont (SCM contregs); SCM_INTERNAL SCM scm_i_contregs_vm_cont (SCM contregs);

View file

@ -58,7 +58,7 @@ scm_i_frame_print (SCM frame, SCM port, scm_print_state *pstate)
} }
static SCM* static SCM*
frame_stack_base (enum scm_vm_frame_kind kind, struct scm_frame *frame) frame_stack_base (enum scm_vm_frame_kind kind, const struct scm_frame *frame)
{ {
switch (kind) switch (kind)
{ {
@ -74,7 +74,7 @@ frame_stack_base (enum scm_vm_frame_kind kind, struct scm_frame *frame)
} }
static scm_t_ptrdiff static scm_t_ptrdiff
frame_offset (enum scm_vm_frame_kind kind, struct scm_frame *frame) frame_offset (enum scm_vm_frame_kind kind, const struct scm_frame *frame)
{ {
switch (kind) switch (kind)
{ {
@ -124,13 +124,27 @@ SCM_DEFINE (scm_frame_p, "frame?", 1, 0, 0,
} }
#undef FUNC_NAME #undef FUNC_NAME
/* Retrieve the local in slot 0, which may or may not actually be a
procedure, and may or may not actually be the procedure being
applied. If you want the procedure, look it up from the IP. */
SCM
scm_c_frame_closure (enum scm_vm_frame_kind kind, const struct scm_frame *frame)
{
SCM *fp = frame_stack_base (kind, frame) + frame->fp_offset;
return SCM_FRAME_PROGRAM (fp);
}
SCM_DEFINE (scm_frame_procedure, "frame-procedure", 1, 0, 0, SCM_DEFINE (scm_frame_procedure, "frame-procedure", 1, 0, 0,
(SCM frame), (SCM frame),
"") "")
#define FUNC_NAME s_scm_frame_procedure #define FUNC_NAME s_scm_frame_procedure
{ {
SCM_VALIDATE_VM_FRAME (1, frame); SCM_VALIDATE_VM_FRAME (1, frame);
return SCM_FRAME_PROGRAM (SCM_VM_FRAME_FP (frame));
/* FIXME: Retrieve procedure from address? */
return scm_c_frame_closure (SCM_VM_FRAME_KIND (frame),
SCM_VM_FRAME_DATA (frame));
} }
#undef FUNC_NAME #undef FUNC_NAME

View file

@ -167,6 +167,10 @@ enum scm_vm_frame_kind
SCM_INTERNAL SCM* scm_i_frame_stack_base (SCM frame); SCM_INTERNAL SCM* scm_i_frame_stack_base (SCM frame);
SCM_INTERNAL scm_t_ptrdiff scm_i_frame_offset (SCM frame); SCM_INTERNAL scm_t_ptrdiff scm_i_frame_offset (SCM frame);
/* See notes in frames.c before using this. */
SCM_INTERNAL SCM scm_c_frame_closure (enum scm_vm_frame_kind kind,
const struct scm_frame *frame);
SCM_INTERNAL SCM scm_c_make_frame (enum scm_vm_frame_kind kind, SCM_INTERNAL SCM scm_c_make_frame (enum scm_vm_frame_kind kind,
const struct scm_frame *frame); const struct scm_frame *frame);

View file

@ -65,11 +65,12 @@ static SCM scm_sys_stacks;
/* Count number of debug info frames on a stack, beginning with FRAME. /* Count number of debug info frames on a stack, beginning with FRAME.
*/ */
static long static long
stack_depth (SCM frame) stack_depth (enum scm_vm_frame_kind kind, const struct scm_frame *frame)
{ {
long n = 0; struct scm_frame tmp;
/* count frames, skipping boot frames */ long n = 1;
for (; scm_is_true (frame); frame = scm_frame_previous (frame)) memcpy (&tmp, frame, sizeof tmp);
while (scm_c_frame_previous (kind, &tmp))
++n; ++n;
return n; return n;
} }
@ -108,24 +109,19 @@ find_prompt (SCM key)
return fp_offset; return fp_offset;
} }
static void static long
narrow_stack (SCM stack, SCM inner_cut, SCM outer_cut) narrow_stack (long len, enum scm_vm_frame_kind kind, struct scm_frame *frame,
SCM inner_cut, SCM outer_cut)
{ {
unsigned long int len;
SCM frame;
len = SCM_STACK_LENGTH (stack);
frame = SCM_STACK_FRAME (stack);
/* Cut inner part. */ /* Cut inner part. */
if (scm_is_true (scm_procedure_p (inner_cut))) if (scm_is_true (scm_procedure_p (inner_cut)))
{ {
/* Cut until the given procedure is seen. */ /* Cut until the given procedure is seen. */
for (; len ;) for (; len ;)
{ {
SCM proc = scm_frame_procedure (frame); SCM proc = scm_c_frame_closure (kind, frame);
len--; len--;
frame = scm_frame_previous (frame); scm_c_frame_previous (kind, frame);
if (scm_is_eq (proc, inner_cut)) if (scm_is_eq (proc, inner_cut))
break; break;
} }
@ -138,32 +134,32 @@ narrow_stack (SCM stack, SCM inner_cut, SCM outer_cut)
for (; inner && len; --inner) for (; inner && len; --inner)
{ {
len--; len--;
frame = scm_frame_previous (frame); scm_c_frame_previous (kind, frame);
} }
} }
else else
{ {
/* Cut until the given prompt tag is seen. */ /* Cut until the given prompt tag is seen. */
scm_t_ptrdiff fp_offset = find_prompt (inner_cut); scm_t_ptrdiff fp_offset = find_prompt (inner_cut);
for (; len; len--, frame = scm_frame_previous (frame)) for (; len; len--, scm_c_frame_previous (kind, frame))
if (fp_offset == SCM_VM_FRAME_FP_OFFSET (frame)) if (fp_offset == frame->fp_offset)
break; break;
} }
SCM_SET_STACK_LENGTH (stack, len);
SCM_SET_STACK_FRAME (stack, frame);
/* Cut outer part. */ /* Cut outer part. */
if (scm_is_true (scm_procedure_p (outer_cut))) if (scm_is_true (scm_procedure_p (outer_cut)))
{ {
long i, new_len;
struct scm_frame tmp;
memcpy (&tmp, frame, sizeof tmp);
/* Cut until the given procedure is seen. */ /* Cut until the given procedure is seen. */
for (; len ;) for (new_len = i = 0; i < len; i++, scm_c_frame_previous (kind, &tmp))
{ if (scm_is_eq (scm_c_frame_closure (kind, &tmp), outer_cut))
frame = scm_stack_ref (stack, scm_from_long (len - 1)); new_len = i;
len--;
if (scm_is_eq (scm_frame_procedure (frame), outer_cut)) len = new_len;
break;
}
} }
else if (scm_is_integer (outer_cut)) else if (scm_is_integer (outer_cut))
{ {
@ -178,17 +174,23 @@ narrow_stack (SCM stack, SCM inner_cut, SCM outer_cut)
else else
{ {
/* Cut until the given prompt tag is seen. */ /* Cut until the given prompt tag is seen. */
long i;
struct scm_frame tmp;
scm_t_ptrdiff fp_offset = find_prompt (outer_cut); scm_t_ptrdiff fp_offset = find_prompt (outer_cut);
while (len)
{ memcpy (&tmp, frame, sizeof tmp);
frame = scm_stack_ref (stack, scm_from_long (len - 1));
len--; for (i = 0; i < len; i++, scm_c_frame_previous (kind, &tmp))
if (fp_offset == SCM_VM_FRAME_FP_OFFSET (frame)) if (tmp.fp_offset == fp_offset)
break; break;
}
if (i < len)
len = i;
else
len = 0;
} }
SCM_SET_STACK_LENGTH (stack, len); return len;
} }
@ -244,9 +246,9 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
#define FUNC_NAME s_scm_make_stack #define FUNC_NAME s_scm_make_stack
{ {
long n; long n;
SCM frame;
SCM stack;
SCM inner_cut, outer_cut; SCM inner_cut, outer_cut;
enum scm_vm_frame_kind kind;
struct scm_frame frame;
/* Extract a pointer to the innermost frame of whatever object /* Extract a pointer to the innermost frame of whatever object
scm_make_stack was given. */ scm_make_stack was given. */
@ -254,48 +256,46 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
{ {
SCM cont; SCM cont;
struct scm_vm_cont *c; struct scm_vm_cont *c;
struct scm_frame tmp;
cont = scm_i_capture_current_stack (); cont = scm_i_capture_current_stack ();
c = SCM_VM_CONT_DATA (cont); c = SCM_VM_CONT_DATA (cont);
tmp.stack_holder = c;
tmp.fp_offset = (c->fp + c->reloc) - c->stack_base; kind = SCM_VM_FRAME_KIND_CONT;
tmp.sp_offset = (c->sp + c->reloc) - c->stack_base; frame.stack_holder = c;
tmp.ip = c->ra; frame.fp_offset = (c->fp + c->reloc) - c->stack_base;
frame = scm_c_make_frame (SCM_VM_FRAME_KIND_CONT, &tmp); frame.sp_offset = (c->sp + c->reloc) - c->stack_base;
frame.ip = c->ra;
} }
else if (SCM_VM_FRAME_P (obj)) else if (SCM_VM_FRAME_P (obj))
frame = obj; {
kind = SCM_VM_FRAME_KIND (obj);
memcpy (&frame, SCM_VM_FRAME_DATA (obj), sizeof frame);
}
else if (SCM_CONTINUATIONP (obj)) else if (SCM_CONTINUATIONP (obj))
/* FIXME: Narrowing to prompt tags should narrow with respect to the prompts /* FIXME: Narrowing to prompt tags should narrow with respect to the prompts
that were in place when the continuation was captured. */ that were in place when the continuation was captured. */
frame = scm_i_continuation_to_frame (obj); {
kind = SCM_VM_FRAME_KIND_CONT;
if (!scm_i_continuation_to_frame (obj, &frame))
return SCM_BOOL_F;
}
else else
{ {
SCM_WRONG_TYPE_ARG (SCM_ARG1, obj); SCM_WRONG_TYPE_ARG (SCM_ARG1, obj);
/* not reached */ /* not reached */
} }
/* FIXME: is this even possible? */ /* Skip initial boot frame, if any. This is possible if the frame
if (scm_is_true (frame) originates from a captured continuation. */
&& SCM_PROGRAM_P (scm_frame_procedure (frame)) if (SCM_PROGRAM_P (scm_c_frame_closure (kind, &frame))
&& SCM_PROGRAM_IS_BOOT (scm_frame_procedure (frame))) && SCM_PROGRAM_IS_BOOT (scm_c_frame_closure (kind, &frame))
frame = scm_frame_previous (frame); && !scm_c_frame_previous (kind, &frame))
if (scm_is_false (frame))
return SCM_BOOL_F; return SCM_BOOL_F;
/* Count number of frames. Also get stack id tag and check whether /* Count number of frames. Also get stack id tag and check whether
there are more stackframes than we want to record there are more stackframes than we want to record
(SCM_BACKTRACE_MAXDEPTH). */ (SCM_BACKTRACE_MAXDEPTH). */
n = stack_depth (frame); n = stack_depth (kind, &frame);
/* Make the stack object. */
stack = scm_make_struct (scm_stack_type, SCM_INUM0, SCM_EOL);
SCM_SET_STACK_LENGTH (stack, n);
SCM_SET_STACK_ID (stack, scm_stack_id (obj));
SCM_SET_STACK_FRAME (stack, frame);
/* Narrow the stack according to the arguments given to scm_make_stack. */ /* Narrow the stack according to the arguments given to scm_make_stack. */
SCM_VALIDATE_REST_ARGUMENT (args); SCM_VALIDATE_REST_ARGUMENT (args);
@ -313,15 +313,18 @@ SCM_DEFINE (scm_make_stack, "make-stack", 1, 0, 1,
args = SCM_CDR (args); args = SCM_CDR (args);
} }
narrow_stack (stack, n = narrow_stack (n, kind, &frame, inner_cut, outer_cut);
inner_cut,
outer_cut);
n = SCM_STACK_LENGTH (stack);
} }
if (n > 0) if (n > 0)
{
/* Make the stack object. */
SCM stack = scm_make_struct (scm_stack_type, SCM_INUM0, SCM_EOL);
SCM_SET_STACK_LENGTH (stack, n);
SCM_SET_STACK_ID (stack, scm_stack_id (obj));
SCM_SET_STACK_FRAME (stack, scm_c_make_frame (kind, &frame));
return stack; return stack;
}
else else
return SCM_BOOL_F; return SCM_BOOL_F;
} }