Blame gnulib/lib/alloca.c

Packit Service a2ae7a
/* alloca.c -- allocate automatically reclaimed memory
Packit Service a2ae7a
   (Mostly) portable public-domain implementation -- D A Gwyn
Packit Service a2ae7a
Packit Service a2ae7a
   This implementation of the PWB library alloca function,
Packit Service a2ae7a
   which is used to allocate space off the run-time stack so
Packit Service a2ae7a
   that it is automatically reclaimed upon procedure exit,
Packit Service a2ae7a
   was inspired by discussions with J. Q. Johnson of Cornell.
Packit Service a2ae7a
   J.Otto Tennant <jot@cray.com> contributed the Cray support.
Packit Service a2ae7a
Packit Service a2ae7a
   There are some preprocessor constants that can
Packit Service a2ae7a
   be defined when compiling for your specific system, for
Packit Service a2ae7a
   improved efficiency; however, the defaults should be okay.
Packit Service a2ae7a
Packit Service a2ae7a
   The general concept of this implementation is to keep
Packit Service a2ae7a
   track of all alloca-allocated blocks, and reclaim any
Packit Service a2ae7a
   that are found to be deeper in the stack than the current
Packit Service a2ae7a
   invocation.  This heuristic does not reclaim storage as
Packit Service a2ae7a
   soon as it becomes invalid, but it will do so eventually.
Packit Service a2ae7a
Packit Service a2ae7a
   As a special case, alloca(0) reclaims storage without
Packit Service a2ae7a
   allocating any.  It is a good idea to use alloca(0) in
Packit Service a2ae7a
   your main control loop, etc. to force garbage collection.  */
Packit Service a2ae7a
Packit Service a2ae7a
#include <config.h>
Packit Service a2ae7a
Packit Service a2ae7a
#include <alloca.h>
Packit Service a2ae7a
Packit Service a2ae7a
#include <string.h>
Packit Service a2ae7a
#include <stdlib.h>
Packit Service a2ae7a
Packit Service a2ae7a
#ifdef emacs
Packit Service a2ae7a
# include "lisp.h"
Packit Service a2ae7a
# include "blockinput.h"
Packit Service a2ae7a
# ifdef EMACS_FREE
Packit Service a2ae7a
#  undef free
Packit Service a2ae7a
#  define free EMACS_FREE
Packit Service a2ae7a
# endif
Packit Service a2ae7a
#else
Packit Service a2ae7a
# define memory_full() abort ()
Packit Service a2ae7a
#endif
Packit Service a2ae7a
Packit Service a2ae7a
/* If compiling with GCC 2, this file's not needed.  */
Packit Service a2ae7a
#if !defined (__GNUC__) || __GNUC__ < 2
Packit Service a2ae7a
Packit Service a2ae7a
/* If someone has defined alloca as a macro,
Packit Service a2ae7a
   there must be some other way alloca is supposed to work.  */
Packit Service a2ae7a
# ifndef alloca
Packit Service a2ae7a
Packit Service a2ae7a
#  ifdef emacs
Packit Service a2ae7a
#   ifdef static
Packit Service a2ae7a
/* actually, only want this if static is defined as ""
Packit Service a2ae7a
   -- this is for usg, in which emacs must undefine static
Packit Service a2ae7a
   in order to make unexec workable
Packit Service a2ae7a
   */
Packit Service a2ae7a
#    ifndef STACK_DIRECTION
Packit Service a2ae7a
you
Packit Service a2ae7a
lose
Packit Service a2ae7a
-- must know STACK_DIRECTION at compile-time
Packit Service a2ae7a
/* Using #error here is not wise since this file should work for
Packit Service a2ae7a
   old and obscure compilers.  */
Packit Service a2ae7a
#    endif /* STACK_DIRECTION undefined */
Packit Service a2ae7a
#   endif /* static */
Packit Service a2ae7a
#  endif /* emacs */
Packit Service a2ae7a
Packit Service a2ae7a
/* If your stack is a linked list of frames, you have to
Packit Service a2ae7a
   provide an "address metric" ADDRESS_FUNCTION macro.  */
Packit Service a2ae7a
Packit Service a2ae7a
#  if defined (CRAY) && defined (CRAY_STACKSEG_END)
Packit Service a2ae7a
long i00afunc ();
Packit Service a2ae7a
#   define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
Packit Service a2ae7a
#  else
Packit Service a2ae7a
#   define ADDRESS_FUNCTION(arg) &(arg)
Packit Service a2ae7a
#  endif
Packit Service a2ae7a
Packit Service a2ae7a
/* Define STACK_DIRECTION if you know the direction of stack
Packit Service a2ae7a
   growth for your system; otherwise it will be automatically
Packit Service a2ae7a
   deduced at run-time.
Packit Service a2ae7a
Packit Service a2ae7a
   STACK_DIRECTION > 0 => grows toward higher addresses
Packit Service a2ae7a
   STACK_DIRECTION < 0 => grows toward lower addresses
Packit Service a2ae7a
   STACK_DIRECTION = 0 => direction of growth unknown  */
Packit Service a2ae7a
Packit Service a2ae7a
#  ifndef STACK_DIRECTION
Packit Service a2ae7a
#   define STACK_DIRECTION      0       /* Direction unknown.  */
Packit Service a2ae7a
#  endif
Packit Service a2ae7a
Packit Service a2ae7a
#  if STACK_DIRECTION != 0
Packit Service a2ae7a
Packit Service a2ae7a
#   define STACK_DIR    STACK_DIRECTION /* Known at compile-time.  */
Packit Service a2ae7a
Packit Service a2ae7a
#  else /* STACK_DIRECTION == 0; need run-time code.  */
Packit Service a2ae7a
Packit Service a2ae7a
static int stack_dir;           /* 1 or -1 once known.  */
Packit Service a2ae7a
#   define STACK_DIR    stack_dir
Packit Service a2ae7a
Packit Service a2ae7a
static int
Packit Service a2ae7a
find_stack_direction (int *addr, int depth)
Packit Service a2ae7a
{
Packit Service a2ae7a
  int dir, dummy = 0;
Packit Service a2ae7a
  if (! addr)
Packit Service a2ae7a
    addr = &dummy;
Packit Service a2ae7a
  *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1;
Packit Service a2ae7a
  dir = depth ? find_stack_direction (addr, depth - 1) : 0;
Packit Service a2ae7a
  return dir + dummy;
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#  endif /* STACK_DIRECTION == 0 */
Packit Service a2ae7a
Packit Service a2ae7a
/* An "alloca header" is used to:
Packit Service a2ae7a
   (a) chain together all alloca'ed blocks;
Packit Service a2ae7a
   (b) keep track of stack depth.
Packit Service a2ae7a
Packit Service a2ae7a
   It is very important that sizeof(header) agree with malloc
Packit Service a2ae7a
   alignment chunk size.  The following default should work okay.  */
Packit Service a2ae7a
Packit Service a2ae7a
#  ifndef       ALIGN_SIZE
Packit Service a2ae7a
#   define ALIGN_SIZE   sizeof(double)
Packit Service a2ae7a
#  endif
Packit Service a2ae7a
Packit Service a2ae7a
typedef union hdr
Packit Service a2ae7a
{
Packit Service a2ae7a
  char align[ALIGN_SIZE];       /* To force sizeof(header).  */
Packit Service a2ae7a
  struct
Packit Service a2ae7a
    {
Packit Service a2ae7a
      union hdr *next;          /* For chaining headers.  */
Packit Service a2ae7a
      char *deep;               /* For stack depth measure.  */
Packit Service a2ae7a
    } h;
Packit Service a2ae7a
} header;
Packit Service a2ae7a
Packit Service a2ae7a
static header *last_alloca_header = NULL;       /* -> last alloca header.  */
Packit Service a2ae7a
Packit Service a2ae7a
/* Return a pointer to at least SIZE bytes of storage,
Packit Service a2ae7a
   which will be automatically reclaimed upon exit from
Packit Service a2ae7a
   the procedure that called alloca.  Originally, this space
Packit Service a2ae7a
   was supposed to be taken from the current stack frame of the
Packit Service a2ae7a
   caller, but that method cannot be made to work for some
Packit Service a2ae7a
   implementations of C, for example under Gould's UTX/32.  */
Packit Service a2ae7a
Packit Service a2ae7a
void *
Packit Service a2ae7a
alloca (size_t size)
Packit Service a2ae7a
{
Packit Service a2ae7a
  auto char probe;              /* Probes stack depth: */
Packit Service a2ae7a
  register char *depth = ADDRESS_FUNCTION (probe);
Packit Service a2ae7a
Packit Service a2ae7a
#  if STACK_DIRECTION == 0
Packit Service a2ae7a
  if (STACK_DIR == 0)           /* Unknown growth direction.  */
Packit Service a2ae7a
    STACK_DIR = find_stack_direction (NULL, (size & 1) + 20);
Packit Service a2ae7a
#  endif
Packit Service a2ae7a
Packit Service a2ae7a
  /* Reclaim garbage, defined as all alloca'd storage that
Packit Service a2ae7a
     was allocated from deeper in the stack than currently.  */
Packit Service a2ae7a
Packit Service a2ae7a
  {
Packit Service a2ae7a
    register header *hp;        /* Traverses linked list.  */
Packit Service a2ae7a
Packit Service a2ae7a
#  ifdef emacs
Packit Service a2ae7a
    BLOCK_INPUT;
Packit Service a2ae7a
#  endif
Packit Service a2ae7a
Packit Service a2ae7a
    for (hp = last_alloca_header; hp != NULL;)
Packit Service a2ae7a
      if ((STACK_DIR > 0 && hp->h.deep > depth)
Packit Service a2ae7a
          || (STACK_DIR < 0 && hp->h.deep < depth))
Packit Service a2ae7a
        {
Packit Service a2ae7a
          register header *np = hp->h.next;
Packit Service a2ae7a
Packit Service a2ae7a
          free (hp);            /* Collect garbage.  */
Packit Service a2ae7a
Packit Service a2ae7a
          hp = np;              /* -> next header.  */
Packit Service a2ae7a
        }
Packit Service a2ae7a
      else
Packit Service a2ae7a
        break;                  /* Rest are not deeper.  */
Packit Service a2ae7a
Packit Service a2ae7a
    last_alloca_header = hp;    /* -> last valid storage.  */
Packit Service a2ae7a
Packit Service a2ae7a
#  ifdef emacs
Packit Service a2ae7a
    UNBLOCK_INPUT;
Packit Service a2ae7a
#  endif
Packit Service a2ae7a
  }
Packit Service a2ae7a
Packit Service a2ae7a
  if (size == 0)
Packit Service a2ae7a
    return NULL;                /* No allocation required.  */
Packit Service a2ae7a
Packit Service a2ae7a
  /* Allocate combined header + user data storage.  */
Packit Service a2ae7a
Packit Service a2ae7a
  {
Packit Service a2ae7a
    /* Address of header.  */
Packit Service a2ae7a
    register header *new;
Packit Service a2ae7a
Packit Service a2ae7a
    size_t combined_size = sizeof (header) + size;
Packit Service a2ae7a
    if (combined_size < sizeof (header))
Packit Service a2ae7a
      memory_full ();
Packit Service a2ae7a
Packit Service a2ae7a
    new = malloc (combined_size);
Packit Service a2ae7a
Packit Service a2ae7a
    if (! new)
Packit Service a2ae7a
      memory_full ();
Packit Service a2ae7a
Packit Service a2ae7a
    new->h.next = last_alloca_header;
Packit Service a2ae7a
    new->h.deep = depth;
Packit Service a2ae7a
Packit Service a2ae7a
    last_alloca_header = new;
Packit Service a2ae7a
Packit Service a2ae7a
    /* User storage begins just after header.  */
Packit Service a2ae7a
Packit Service a2ae7a
    return (void *) (new + 1);
Packit Service a2ae7a
  }
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#  if defined (CRAY) && defined (CRAY_STACKSEG_END)
Packit Service a2ae7a
Packit Service a2ae7a
#   ifdef DEBUG_I00AFUNC
Packit Service a2ae7a
#    include <stdio.h>
Packit Service a2ae7a
#   endif
Packit Service a2ae7a
Packit Service a2ae7a
#   ifndef CRAY_STACK
Packit Service a2ae7a
#    define CRAY_STACK
Packit Service a2ae7a
#    ifndef CRAY2
Packit Service a2ae7a
/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
Packit Service a2ae7a
struct stack_control_header
Packit Service a2ae7a
  {
Packit Service a2ae7a
    long shgrow:32;             /* Number of times stack has grown.  */
Packit Service a2ae7a
    long shaseg:32;             /* Size of increments to stack.  */
Packit Service a2ae7a
    long shhwm:32;              /* High water mark of stack.  */
Packit Service a2ae7a
    long shsize:32;             /* Current size of stack (all segments).  */
Packit Service a2ae7a
  };
Packit Service a2ae7a
Packit Service a2ae7a
/* The stack segment linkage control information occurs at
Packit Service a2ae7a
   the high-address end of a stack segment.  (The stack
Packit Service a2ae7a
   grows from low addresses to high addresses.)  The initial
Packit Service a2ae7a
   part of the stack segment linkage control information is
Packit Service a2ae7a
   0200 (octal) words.  This provides for register storage
Packit Service a2ae7a
   for the routine which overflows the stack.  */
Packit Service a2ae7a
Packit Service a2ae7a
struct stack_segment_linkage
Packit Service a2ae7a
  {
Packit Service a2ae7a
    long ss[0200];              /* 0200 overflow words.  */
Packit Service a2ae7a
    long sssize:32;             /* Number of words in this segment.  */
Packit Service a2ae7a
    long ssbase:32;             /* Offset to stack base.  */
Packit Service a2ae7a
    long:32;
Packit Service a2ae7a
    long sspseg:32;             /* Offset to linkage control of previous
Packit Service a2ae7a
                                   segment of stack.  */
Packit Service a2ae7a
    long:32;
Packit Service a2ae7a
    long sstcpt:32;             /* Pointer to task common address block.  */
Packit Service a2ae7a
    long sscsnm;                /* Private control structure number for
Packit Service a2ae7a
                                   microtasking.  */
Packit Service a2ae7a
    long ssusr1;                /* Reserved for user.  */
Packit Service a2ae7a
    long ssusr2;                /* Reserved for user.  */
Packit Service a2ae7a
    long sstpid;                /* Process ID for pid based multi-tasking.  */
Packit Service a2ae7a
    long ssgvup;                /* Pointer to multitasking thread giveup.  */
Packit Service a2ae7a
    long sscray[7];             /* Reserved for Cray Research.  */
Packit Service a2ae7a
    long ssa0;
Packit Service a2ae7a
    long ssa1;
Packit Service a2ae7a
    long ssa2;
Packit Service a2ae7a
    long ssa3;
Packit Service a2ae7a
    long ssa4;
Packit Service a2ae7a
    long ssa5;
Packit Service a2ae7a
    long ssa6;
Packit Service a2ae7a
    long ssa7;
Packit Service a2ae7a
    long sss0;
Packit Service a2ae7a
    long sss1;
Packit Service a2ae7a
    long sss2;
Packit Service a2ae7a
    long sss3;
Packit Service a2ae7a
    long sss4;
Packit Service a2ae7a
    long sss5;
Packit Service a2ae7a
    long sss6;
Packit Service a2ae7a
    long sss7;
Packit Service a2ae7a
  };
Packit Service a2ae7a
Packit Service a2ae7a
#    else /* CRAY2 */
Packit Service a2ae7a
/* The following structure defines the vector of words
Packit Service a2ae7a
   returned by the STKSTAT library routine.  */
Packit Service a2ae7a
struct stk_stat
Packit Service a2ae7a
  {
Packit Service a2ae7a
    long now;                   /* Current total stack size.  */
Packit Service a2ae7a
    long maxc;                  /* Amount of contiguous space which would
Packit Service a2ae7a
                                   be required to satisfy the maximum
Packit Service a2ae7a
                                   stack demand to date.  */
Packit Service a2ae7a
    long high_water;            /* Stack high-water mark.  */
Packit Service a2ae7a
    long overflows;             /* Number of stack overflow ($STKOFEN) calls.  */
Packit Service a2ae7a
    long hits;                  /* Number of internal buffer hits.  */
Packit Service a2ae7a
    long extends;               /* Number of block extensions.  */
Packit Service a2ae7a
    long stko_mallocs;          /* Block allocations by $STKOFEN.  */
Packit Service a2ae7a
    long underflows;            /* Number of stack underflow calls ($STKRETN).  */
Packit Service a2ae7a
    long stko_free;             /* Number of deallocations by $STKRETN.  */
Packit Service a2ae7a
    long stkm_free;             /* Number of deallocations by $STKMRET.  */
Packit Service a2ae7a
    long segments;              /* Current number of stack segments.  */
Packit Service a2ae7a
    long maxs;                  /* Maximum number of stack segments so far.  */
Packit Service a2ae7a
    long pad_size;              /* Stack pad size.  */
Packit Service a2ae7a
    long current_address;       /* Current stack segment address.  */
Packit Service a2ae7a
    long current_size;          /* Current stack segment size.  This
Packit Service a2ae7a
                                   number is actually corrupted by STKSTAT to
Packit Service a2ae7a
                                   include the fifteen word trailer area.  */
Packit Service a2ae7a
    long initial_address;       /* Address of initial segment.  */
Packit Service a2ae7a
    long initial_size;          /* Size of initial segment.  */
Packit Service a2ae7a
  };
Packit Service a2ae7a
Packit Service a2ae7a
/* The following structure describes the data structure which trails
Packit Service a2ae7a
   any stack segment.  I think that the description in 'asdef' is
Packit Service a2ae7a
   out of date.  I only describe the parts that I am sure about.  */
Packit Service a2ae7a
Packit Service a2ae7a
struct stk_trailer
Packit Service a2ae7a
  {
Packit Service a2ae7a
    long this_address;          /* Address of this block.  */
Packit Service a2ae7a
    long this_size;             /* Size of this block (does not include
Packit Service a2ae7a
                                   this trailer).  */
Packit Service a2ae7a
    long unknown2;
Packit Service a2ae7a
    long unknown3;
Packit Service a2ae7a
    long link;                  /* Address of trailer block of previous
Packit Service a2ae7a
                                   segment.  */
Packit Service a2ae7a
    long unknown5;
Packit Service a2ae7a
    long unknown6;
Packit Service a2ae7a
    long unknown7;
Packit Service a2ae7a
    long unknown8;
Packit Service a2ae7a
    long unknown9;
Packit Service a2ae7a
    long unknown10;
Packit Service a2ae7a
    long unknown11;
Packit Service a2ae7a
    long unknown12;
Packit Service a2ae7a
    long unknown13;
Packit Service a2ae7a
    long unknown14;
Packit Service a2ae7a
  };
Packit Service a2ae7a
Packit Service a2ae7a
#    endif /* CRAY2 */
Packit Service a2ae7a
#   endif /* not CRAY_STACK */
Packit Service a2ae7a
Packit Service a2ae7a
#   ifdef CRAY2
Packit Service a2ae7a
/* Determine a "stack measure" for an arbitrary ADDRESS.
Packit Service a2ae7a
   I doubt that "lint" will like this much.  */
Packit Service a2ae7a
Packit Service a2ae7a
static long
Packit Service a2ae7a
i00afunc (long *address)
Packit Service a2ae7a
{
Packit Service a2ae7a
  struct stk_stat status;
Packit Service a2ae7a
  struct stk_trailer *trailer;
Packit Service a2ae7a
  long *block, size;
Packit Service a2ae7a
  long result = 0;
Packit Service a2ae7a
Packit Service a2ae7a
  /* We want to iterate through all of the segments.  The first
Packit Service a2ae7a
     step is to get the stack status structure.  We could do this
Packit Service a2ae7a
     more quickly and more directly, perhaps, by referencing the
Packit Service a2ae7a
     $LM00 common block, but I know that this works.  */
Packit Service a2ae7a
Packit Service a2ae7a
  STKSTAT (&status);
Packit Service a2ae7a
Packit Service a2ae7a
  /* Set up the iteration.  */
Packit Service a2ae7a
Packit Service a2ae7a
  trailer = (struct stk_trailer *) (status.current_address
Packit Service a2ae7a
                                    + status.current_size
Packit Service a2ae7a
                                    - 15);
Packit Service a2ae7a
Packit Service a2ae7a
  /* There must be at least one stack segment.  Therefore it is
Packit Service a2ae7a
     a fatal error if "trailer" is null.  */
Packit Service a2ae7a
Packit Service a2ae7a
  if (trailer == NULL)
Packit Service a2ae7a
    abort ();
Packit Service a2ae7a
Packit Service a2ae7a
  /* Discard segments that do not contain our argument address.  */
Packit Service a2ae7a
Packit Service a2ae7a
  while (trailer != NULL)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      block = (long *) trailer->this_address;
Packit Service a2ae7a
      size = trailer->this_size;
Packit Service a2ae7a
      if (block == NULL || size == 0)
Packit Service a2ae7a
        abort ();
Packit Service a2ae7a
      trailer = (struct stk_trailer *) trailer->link;
Packit Service a2ae7a
      if ((block <= address) && (address < (block + size)))
Packit Service a2ae7a
        break;
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
  /* Set the result to the offset in this segment and add the sizes
Packit Service a2ae7a
     of all predecessor segments.  */
Packit Service a2ae7a
Packit Service a2ae7a
  result = address - block;
Packit Service a2ae7a
Packit Service a2ae7a
  if (trailer == NULL)
Packit Service a2ae7a
    {
Packit Service a2ae7a
      return result;
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
  do
Packit Service a2ae7a
    {
Packit Service a2ae7a
      if (trailer->this_size <= 0)
Packit Service a2ae7a
        abort ();
Packit Service a2ae7a
      result += trailer->this_size;
Packit Service a2ae7a
      trailer = (struct stk_trailer *) trailer->link;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  while (trailer != NULL);
Packit Service a2ae7a
Packit Service a2ae7a
  /* We are done.  Note that if you present a bogus address (one
Packit Service a2ae7a
     not in any segment), you will get a different number back, formed
Packit Service a2ae7a
     from subtracting the address of the first block.  This is probably
Packit Service a2ae7a
     not what you want.  */
Packit Service a2ae7a
Packit Service a2ae7a
  return (result);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#   else /* not CRAY2 */
Packit Service a2ae7a
/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
Packit Service a2ae7a
   Determine the number of the cell within the stack,
Packit Service a2ae7a
   given the address of the cell.  The purpose of this
Packit Service a2ae7a
   routine is to linearize, in some sense, stack addresses
Packit Service a2ae7a
   for alloca.  */
Packit Service a2ae7a
Packit Service a2ae7a
static long
Packit Service a2ae7a
i00afunc (long address)
Packit Service a2ae7a
{
Packit Service a2ae7a
  long stkl = 0;
Packit Service a2ae7a
Packit Service a2ae7a
  long size, pseg, this_segment, stack;
Packit Service a2ae7a
  long result = 0;
Packit Service a2ae7a
Packit Service a2ae7a
  struct stack_segment_linkage *ssptr;
Packit Service a2ae7a
Packit Service a2ae7a
  /* Register B67 contains the address of the end of the
Packit Service a2ae7a
     current stack segment.  If you (as a subprogram) store
Packit Service a2ae7a
     your registers on the stack and find that you are past
Packit Service a2ae7a
     the contents of B67, you have overflowed the segment.
Packit Service a2ae7a
Packit Service a2ae7a
     B67 also points to the stack segment linkage control
Packit Service a2ae7a
     area, which is what we are really interested in.  */
Packit Service a2ae7a
Packit Service a2ae7a
  stkl = CRAY_STACKSEG_END ();
Packit Service a2ae7a
  ssptr = (struct stack_segment_linkage *) stkl;
Packit Service a2ae7a
Packit Service a2ae7a
  /* If one subtracts 'size' from the end of the segment,
Packit Service a2ae7a
     one has the address of the first word of the segment.
Packit Service a2ae7a
Packit Service a2ae7a
     If this is not the first segment, 'pseg' will be
Packit Service a2ae7a
     nonzero.  */
Packit Service a2ae7a
Packit Service a2ae7a
  pseg = ssptr->sspseg;
Packit Service a2ae7a
  size = ssptr->sssize;
Packit Service a2ae7a
Packit Service a2ae7a
  this_segment = stkl - size;
Packit Service a2ae7a
Packit Service a2ae7a
  /* It is possible that calling this routine itself caused
Packit Service a2ae7a
     a stack overflow.  Discard stack segments which do not
Packit Service a2ae7a
     contain the target address.  */
Packit Service a2ae7a
Packit Service a2ae7a
  while (!(this_segment <= address && address <= stkl))
Packit Service a2ae7a
    {
Packit Service a2ae7a
#    ifdef DEBUG_I00AFUNC
Packit Service a2ae7a
      fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
Packit Service a2ae7a
#    endif
Packit Service a2ae7a
      if (pseg == 0)
Packit Service a2ae7a
        break;
Packit Service a2ae7a
      stkl = stkl - pseg;
Packit Service a2ae7a
      ssptr = (struct stack_segment_linkage *) stkl;
Packit Service a2ae7a
      size = ssptr->sssize;
Packit Service a2ae7a
      pseg = ssptr->sspseg;
Packit Service a2ae7a
      this_segment = stkl - size;
Packit Service a2ae7a
    }
Packit Service a2ae7a
Packit Service a2ae7a
  result = address - this_segment;
Packit Service a2ae7a
Packit Service a2ae7a
  /* If you subtract pseg from the current end of the stack,
Packit Service a2ae7a
     you get the address of the previous stack segment's end.
Packit Service a2ae7a
     This seems a little convoluted to me, but I'll bet you save
Packit Service a2ae7a
     a cycle somewhere.  */
Packit Service a2ae7a
Packit Service a2ae7a
  while (pseg != 0)
Packit Service a2ae7a
    {
Packit Service a2ae7a
#    ifdef DEBUG_I00AFUNC
Packit Service a2ae7a
      fprintf (stderr, "%011o %011o\n", pseg, size);
Packit Service a2ae7a
#    endif
Packit Service a2ae7a
      stkl = stkl - pseg;
Packit Service a2ae7a
      ssptr = (struct stack_segment_linkage *) stkl;
Packit Service a2ae7a
      size = ssptr->sssize;
Packit Service a2ae7a
      pseg = ssptr->sspseg;
Packit Service a2ae7a
      result += size;
Packit Service a2ae7a
    }
Packit Service a2ae7a
  return (result);
Packit Service a2ae7a
}
Packit Service a2ae7a
Packit Service a2ae7a
#   endif /* not CRAY2 */
Packit Service a2ae7a
#  endif /* CRAY */
Packit Service a2ae7a
Packit Service a2ae7a
# endif /* no alloca */
Packit Service a2ae7a
#endif /* not GCC 2 */