Blame gl/alloca.c

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