Home | History | Annotate | Line # | Download | only in import
      1      1.1  christos /* alloca.c -- allocate automatically reclaimed memory
      2  1.1.1.2  christos    This file is in the public domain.  */
      3  1.1.1.2  christos 
      4  1.1.1.2  christos /* (Mostly) portable implementation -- D A Gwyn
      5      1.1  christos 
      6      1.1  christos    This implementation of the PWB library alloca function,
      7      1.1  christos    which is used to allocate space off the run-time stack so
      8      1.1  christos    that it is automatically reclaimed upon procedure exit,
      9      1.1  christos    was inspired by discussions with J. Q. Johnson of Cornell.
     10      1.1  christos    J.Otto Tennant <jot (at) cray.com> contributed the Cray support.
     11      1.1  christos 
     12      1.1  christos    There are some preprocessor constants that can
     13      1.1  christos    be defined when compiling for your specific system, for
     14      1.1  christos    improved efficiency; however, the defaults should be okay.
     15      1.1  christos 
     16      1.1  christos    The general concept of this implementation is to keep
     17      1.1  christos    track of all alloca-allocated blocks, and reclaim any
     18      1.1  christos    that are found to be deeper in the stack than the current
     19      1.1  christos    invocation.  This heuristic does not reclaim storage as
     20      1.1  christos    soon as it becomes invalid, but it will do so eventually.
     21      1.1  christos 
     22      1.1  christos    As a special case, alloca(0) reclaims storage without
     23      1.1  christos    allocating any.  It is a good idea to use alloca(0) in
     24      1.1  christos    your main control loop, etc. to force garbage collection.  */
     25      1.1  christos 
     26      1.1  christos #include <config.h>
     27      1.1  christos 
     28      1.1  christos #include <alloca.h>
     29      1.1  christos 
     30      1.1  christos #include <string.h>
     31      1.1  christos #include <stdlib.h>
     32      1.1  christos 
     33      1.1  christos #ifdef emacs
     34      1.1  christos # include "lisp.h"
     35      1.1  christos # include "blockinput.h"
     36      1.1  christos # ifdef EMACS_FREE
     37      1.1  christos #  undef free
     38      1.1  christos #  define free EMACS_FREE
     39      1.1  christos # endif
     40      1.1  christos #else
     41      1.1  christos # define memory_full() abort ()
     42      1.1  christos #endif
     43      1.1  christos 
     44  1.1.1.2  christos /* If compiling with GCC or clang, this file is not needed.  */
     45  1.1.1.2  christos #if !(defined __GNUC__ || defined __clang__)
     46      1.1  christos 
     47      1.1  christos /* If someone has defined alloca as a macro,
     48      1.1  christos    there must be some other way alloca is supposed to work.  */
     49      1.1  christos # ifndef alloca
     50      1.1  christos 
     51      1.1  christos #  ifdef emacs
     52      1.1  christos #   ifdef static
     53      1.1  christos /* actually, only want this if static is defined as ""
     54      1.1  christos    -- this is for usg, in which emacs must undefine static
     55      1.1  christos    in order to make unexec workable
     56      1.1  christos    */
     57      1.1  christos #    ifndef STACK_DIRECTION
     58      1.1  christos you
     59      1.1  christos lose
     60      1.1  christos -- must know STACK_DIRECTION at compile-time
     61      1.1  christos /* Using #error here is not wise since this file should work for
     62      1.1  christos    old and obscure compilers.  */
     63      1.1  christos #    endif /* STACK_DIRECTION undefined */
     64      1.1  christos #   endif /* static */
     65      1.1  christos #  endif /* emacs */
     66      1.1  christos 
     67      1.1  christos /* Define STACK_DIRECTION if you know the direction of stack
     68      1.1  christos    growth for your system; otherwise it will be automatically
     69      1.1  christos    deduced at run-time.
     70      1.1  christos 
     71      1.1  christos    STACK_DIRECTION > 0 => grows toward higher addresses
     72      1.1  christos    STACK_DIRECTION < 0 => grows toward lower addresses
     73      1.1  christos    STACK_DIRECTION = 0 => direction of growth unknown  */
     74      1.1  christos 
     75      1.1  christos #  ifndef STACK_DIRECTION
     76      1.1  christos #   define STACK_DIRECTION      0       /* Direction unknown.  */
     77      1.1  christos #  endif
     78      1.1  christos 
     79      1.1  christos #  if STACK_DIRECTION != 0
     80      1.1  christos 
     81      1.1  christos #   define STACK_DIR    STACK_DIRECTION /* Known at compile-time.  */
     82      1.1  christos 
     83      1.1  christos #  else /* STACK_DIRECTION == 0; need run-time code.  */
     84      1.1  christos 
     85      1.1  christos static int stack_dir;           /* 1 or -1 once known.  */
     86      1.1  christos #   define STACK_DIR    stack_dir
     87      1.1  christos 
     88      1.1  christos static int
     89      1.1  christos find_stack_direction (int *addr, int depth)
     90      1.1  christos {
     91      1.1  christos   int dir, dummy = 0;
     92      1.1  christos   if (! addr)
     93      1.1  christos     addr = &dummy;
     94      1.1  christos   *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1;
     95      1.1  christos   dir = depth ? find_stack_direction (addr, depth - 1) : 0;
     96      1.1  christos   return dir + dummy;
     97      1.1  christos }
     98      1.1  christos 
     99      1.1  christos #  endif /* STACK_DIRECTION == 0 */
    100      1.1  christos 
    101      1.1  christos /* An "alloca header" is used to:
    102      1.1  christos    (a) chain together all alloca'ed blocks;
    103      1.1  christos    (b) keep track of stack depth.
    104      1.1  christos 
    105      1.1  christos    It is very important that sizeof(header) agree with malloc
    106      1.1  christos    alignment chunk size.  The following default should work okay.  */
    107      1.1  christos 
    108      1.1  christos #  ifndef       ALIGN_SIZE
    109      1.1  christos #   define ALIGN_SIZE   sizeof(double)
    110      1.1  christos #  endif
    111      1.1  christos 
    112      1.1  christos typedef union hdr
    113      1.1  christos {
    114      1.1  christos   char align[ALIGN_SIZE];       /* To force sizeof(header).  */
    115      1.1  christos   struct
    116      1.1  christos     {
    117      1.1  christos       union hdr *next;          /* For chaining headers.  */
    118      1.1  christos       char *deep;               /* For stack depth measure.  */
    119      1.1  christos     } h;
    120      1.1  christos } header;
    121      1.1  christos 
    122      1.1  christos static header *last_alloca_header = NULL;       /* -> last alloca header.  */
    123      1.1  christos 
    124      1.1  christos /* Return a pointer to at least SIZE bytes of storage,
    125      1.1  christos    which will be automatically reclaimed upon exit from
    126      1.1  christos    the procedure that called alloca.  Originally, this space
    127      1.1  christos    was supposed to be taken from the current stack frame of the
    128      1.1  christos    caller, but that method cannot be made to work for some
    129      1.1  christos    implementations of C, for example under Gould's UTX/32.  */
    130      1.1  christos 
    131      1.1  christos void *
    132      1.1  christos alloca (size_t size)
    133      1.1  christos {
    134      1.1  christos   auto char probe;              /* Probes stack depth: */
    135  1.1.1.2  christos   register char *depth = &probe;
    136      1.1  christos 
    137      1.1  christos #  if STACK_DIRECTION == 0
    138      1.1  christos   if (STACK_DIR == 0)           /* Unknown growth direction.  */
    139      1.1  christos     STACK_DIR = find_stack_direction (NULL, (size & 1) + 20);
    140      1.1  christos #  endif
    141      1.1  christos 
    142      1.1  christos   /* Reclaim garbage, defined as all alloca'd storage that
    143      1.1  christos      was allocated from deeper in the stack than currently.  */
    144      1.1  christos 
    145      1.1  christos   {
    146      1.1  christos     register header *hp;        /* Traverses linked list.  */
    147      1.1  christos 
    148      1.1  christos #  ifdef emacs
    149      1.1  christos     BLOCK_INPUT;
    150      1.1  christos #  endif
    151      1.1  christos 
    152      1.1  christos     for (hp = last_alloca_header; hp != NULL;)
    153      1.1  christos       if ((STACK_DIR > 0 && hp->h.deep > depth)
    154      1.1  christos           || (STACK_DIR < 0 && hp->h.deep < depth))
    155      1.1  christos         {
    156      1.1  christos           register header *np = hp->h.next;
    157      1.1  christos 
    158      1.1  christos           free (hp);            /* Collect garbage.  */
    159      1.1  christos 
    160      1.1  christos           hp = np;              /* -> next header.  */
    161      1.1  christos         }
    162      1.1  christos       else
    163      1.1  christos         break;                  /* Rest are not deeper.  */
    164      1.1  christos 
    165      1.1  christos     last_alloca_header = hp;    /* -> last valid storage.  */
    166      1.1  christos 
    167      1.1  christos #  ifdef emacs
    168      1.1  christos     UNBLOCK_INPUT;
    169      1.1  christos #  endif
    170      1.1  christos   }
    171      1.1  christos 
    172      1.1  christos   if (size == 0)
    173      1.1  christos     return NULL;                /* No allocation required.  */
    174      1.1  christos 
    175      1.1  christos   /* Allocate combined header + user data storage.  */
    176      1.1  christos 
    177      1.1  christos   {
    178      1.1  christos     /* Address of header.  */
    179      1.1  christos     register header *new;
    180      1.1  christos 
    181      1.1  christos     size_t combined_size = sizeof (header) + size;
    182      1.1  christos     if (combined_size < sizeof (header))
    183      1.1  christos       memory_full ();
    184      1.1  christos 
    185      1.1  christos     new = malloc (combined_size);
    186      1.1  christos 
    187      1.1  christos     if (! new)
    188      1.1  christos       memory_full ();
    189      1.1  christos 
    190      1.1  christos     new->h.next = last_alloca_header;
    191      1.1  christos     new->h.deep = depth;
    192      1.1  christos 
    193      1.1  christos     last_alloca_header = new;
    194      1.1  christos 
    195      1.1  christos     /* User storage begins just after header.  */
    196      1.1  christos 
    197      1.1  christos     return (void *) (new + 1);
    198      1.1  christos   }
    199      1.1  christos }
    200      1.1  christos 
    201      1.1  christos # endif /* no alloca */
    202  1.1.1.2  christos #endif /* not GCC || clang */
    203