missing/alloca.c

Go to the documentation of this file.
00001 /* alloca -- (mostly) portable public-domain implementation -- D A Gwyn
00002 
00003    last edit:   86/05/30        rms
00004    include config.h, since on VMS it renames some symbols.
00005    Use xmalloc instead of malloc.
00006 
00007    This implementation of the PWB library alloca() function,
00008    which is used to allocate space off the run-time stack so
00009    that it is automatically reclaimed upon procedure exit, 
00010    was inspired by discussions with J. Q. Johnson of Cornell.
00011 
00012    It should work under any C implementation that uses an
00013    actual procedure stack (as opposed to a linked list of
00014    frames).  There are some preprocessor constants that can
00015    be defined when compiling for your specific system, for
00016    improved efficiency; however, the defaults should be okay.
00017 
00018    The general concept of this implementation is to keep
00019    track of all alloca()-allocated blocks, and reclaim any
00020    that are found to be deeper in the stack than the current
00021    invocation.  This heuristic does not reclaim storage as
00022    soon as it becomes invalid, but it will do so eventually.
00023 
00024    As a special case, alloca(0) reclaims storage without
00025    allocating any.  It is a good idea to use alloca(0) in
00026    your main control loop, etc. to force garbage collection.
00027 */
00028 #ifndef lint
00029 static char     SCCSid[] = "@(#)alloca.c        1.1";   /* for the "what" utility */
00030 #endif
00031 
00032 #include "ruby/config.h"
00033 #ifdef C_ALLOCA
00034 
00035 #ifdef emacs
00036 #ifdef static
00037 /* actually, only want this if static is defined as ""
00038    -- this is for usg, in which emacs must undefine static
00039    in order to make unexec workable
00040    */
00041 #ifndef STACK_DIRECTION
00042 you
00043 lose
00044 -- must know STACK_DIRECTION at compile-time
00045 #endif /* STACK_DIRECTION undefined */
00046 #endif /* static */
00047 #endif /* emacs */
00048 
00049 #ifdef X3J11
00050 typedef void    *pointer;               /* generic pointer type */
00051 #else
00052 typedef char    *pointer;               /* generic pointer type */
00053 #endif /* X3J11 */
00054 
00055 #define NULL    0                       /* null pointer constant */
00056 
00057 #ifdef RUBY_LIB_PREFIX
00058 #define xmalloc ruby_xmalloc
00059 #define xfree ruby_xfree
00060 #endif
00061 
00062 extern void     xfree();
00063 extern pointer  xmalloc();
00064 
00065 /*
00066         Define STACK_DIRECTION if you know the direction of stack
00067         growth for your system; otherwise it will be automatically
00068         deduced at run-time.
00069 
00070         STACK_DIRECTION > 0 => grows toward higher addresses
00071         STACK_DIRECTION < 0 => grows toward lower addresses
00072         STACK_DIRECTION = 0 => direction of growth unknown
00073 */
00074 
00075 #ifndef STACK_DIRECTION
00076 #define STACK_DIRECTION 0               /* direction unknown */
00077 #endif
00078 
00079 #if STACK_DIRECTION != 0
00080 
00081 #define STACK_DIR       STACK_DIRECTION /* known at compile-time */
00082 
00083 #else   /* STACK_DIRECTION == 0; need run-time code */
00084 
00085 static int      stack_dir;              /* 1 or -1 once known */
00086 #define STACK_DIR       stack_dir
00087 
00088 static void
00089 find_stack_direction (/* void */)
00090 {
00091   static char   *addr = NULL;   /* address of first
00092                                    `dummy', once known */
00093   auto char     dummy;          /* to get stack address */
00094 
00095   if (addr == NULL)
00096     {                           /* initial entry */
00097       addr = &dummy;
00098 
00099       find_stack_direction ();  /* recurse once */
00100     }
00101   else                          /* second entry */
00102     if (&dummy > addr)
00103       stack_dir = 1;            /* stack grew upward */
00104     else
00105       stack_dir = -1;           /* stack grew downward */
00106 }
00107 
00108 #endif  /* STACK_DIRECTION == 0 */
00109 
00110 /*
00111         An "alloca header" is used to:
00112         (a) chain together all alloca()ed blocks;
00113         (b) keep track of stack depth.
00114 
00115         It is very important that sizeof(header) agree with malloc()
00116         alignment chunk size.  The following default should work okay.
00117 */
00118 
00119 #ifndef ALIGN_SIZE
00120 #define ALIGN_SIZE      sizeof(double)
00121 #endif
00122 
00123 typedef union hdr
00124 {
00125   char  align[ALIGN_SIZE];      /* to force sizeof(header) */
00126   struct
00127     {
00128       union hdr *next;          /* for chaining headers */
00129       char *deep;               /* for stack depth measure */
00130     } h;
00131 } header;
00132 
00133 /*
00134         alloca( size ) returns a pointer to at least `size' bytes of
00135         storage which will be automatically reclaimed upon exit from
00136         the procedure that called alloca().  Originally, this space
00137         was supposed to be taken from the current stack frame of the
00138         caller, but that method cannot be made to work for some
00139         implementations of C, for example under Gould's UTX/32.
00140 */
00141 
00142 static header *last_alloca_header = NULL; /* -> last alloca header */
00143 
00144 pointer
00145 alloca (size)                   /* returns pointer to storage */
00146      unsigned   size;           /* # bytes to allocate */
00147 {
00148   auto char     probe;          /* probes stack depth: */
00149   register char *depth = &probe;
00150 
00151 #if STACK_DIRECTION == 0
00152   if (STACK_DIR == 0)           /* unknown growth direction */
00153     find_stack_direction ();
00154 #endif
00155 
00156   /* Reclaim garbage, defined as all alloca()ed storage that
00157      was allocated from deeper in the stack than currently. */
00158   {
00159     register header     *hp;    /* traverses linked list */
00160 
00161     for (hp = last_alloca_header; hp != NULL;)
00162       if (STACK_DIR > 0 && hp->h.deep > depth
00163           || STACK_DIR < 0 && hp->h.deep < depth)
00164         {
00165           register header       *np = hp->h.next;
00166 
00167           xfree ((pointer) hp); /* collect garbage */
00168 
00169           hp = np;              /* -> next header */
00170         }
00171       else
00172         break;                  /* rest are not deeper */
00173 
00174     last_alloca_header = hp;    /* -> last valid storage */
00175   }
00176 
00177   if (size == 0)
00178     return NULL;                /* no allocation required */
00179 
00180   /* Allocate combined header + user data storage. */
00181 
00182   {
00183     register pointer    new = xmalloc (sizeof (header) + size);
00184     /* address of header */
00185 
00186     ((header *)new)->h.next = last_alloca_header;
00187     ((header *)new)->h.deep = depth;
00188 
00189     last_alloca_header = (header *)new;
00190 
00191     /* User storage begins just after header. */
00192 
00193     return (pointer)((char *)new + sizeof(header));
00194   }
00195 }
00196 
00197 #endif
00198 

Generated on Wed Aug 10 09:17:08 2011 for Ruby by  doxygen 1.4.7