| /* alloca.c -- allocate automatically reclaimed memory |
| This file is in the public domain. */ |
| |
| /* (Mostly) portable implementation -- D A Gwyn |
| |
| This implementation of the PWB library alloca function, |
| which is used to allocate space off the run-time stack so |
| that it is automatically reclaimed upon procedure exit, |
| was inspired by discussions with J. Q. Johnson of Cornell. |
| J.Otto Tennant <jot@cray.com> contributed the Cray support. |
| |
| There are some preprocessor constants that can |
| be defined when compiling for your specific system, for |
| improved efficiency; however, the defaults should be okay. |
| |
| The general concept of this implementation is to keep |
| track of all alloca-allocated blocks, and reclaim any |
| that are found to be deeper in the stack than the current |
| invocation. This heuristic does not reclaim storage as |
| soon as it becomes invalid, but it will do so eventually. |
| |
| As a special case, alloca(0) reclaims storage without |
| allocating any. It is a good idea to use alloca(0) in |
| your main control loop, etc. to force garbage collection. */ |
| |
| #include <config.h> |
| |
| #include <alloca.h> |
| |
| #include <string.h> |
| #include <stdlib.h> |
| |
| #ifdef emacs |
| # include "lisp.h" |
| # include "blockinput.h" |
| # ifdef EMACS_FREE |
| # undef free |
| # define free EMACS_FREE |
| # endif |
| #else |
| # define memory_full() abort () |
| #endif |
| |
| /* If compiling with GCC or clang, this file is not needed. */ |
| #if !(defined __GNUC__ || defined __clang__) |
| |
| /* If someone has defined alloca as a macro, |
| there must be some other way alloca is supposed to work. */ |
| # ifndef alloca |
| |
| # ifdef emacs |
| # ifdef static |
| /* actually, only want this if static is defined as "" |
| -- this is for usg, in which emacs must undefine static |
| in order to make unexec workable |
| */ |
| # ifndef STACK_DIRECTION |
| you |
| lose |
| -- must know STACK_DIRECTION at compile-time |
| /* Using #error here is not wise since this file should work for |
| old and obscure compilers. */ |
| # endif /* STACK_DIRECTION undefined */ |
| # endif /* static */ |
| # endif /* emacs */ |
| |
| /* Define STACK_DIRECTION if you know the direction of stack |
| growth for your system; otherwise it will be automatically |
| deduced at run-time. |
| |
| STACK_DIRECTION > 0 => grows toward higher addresses |
| STACK_DIRECTION < 0 => grows toward lower addresses |
| STACK_DIRECTION = 0 => direction of growth unknown */ |
| |
| # ifndef STACK_DIRECTION |
| # define STACK_DIRECTION 0 /* Direction unknown. */ |
| # endif |
| |
| # if STACK_DIRECTION != 0 |
| |
| # define STACK_DIR STACK_DIRECTION /* Known at compile-time. */ |
| |
| # else /* STACK_DIRECTION == 0; need run-time code. */ |
| |
| static int stack_dir; /* 1 or -1 once known. */ |
| # define STACK_DIR stack_dir |
| |
| static int |
| find_stack_direction (int *addr, int depth) |
| { |
| int dir, dummy = 0; |
| if (! addr) |
| addr = &dummy; |
| *addr = addr < &dummy ? 1 : addr == &dummy ? 0 : -1; |
| dir = depth ? find_stack_direction (addr, depth - 1) : 0; |
| return dir + dummy; |
| } |
| |
| # endif /* STACK_DIRECTION == 0 */ |
| |
| /* An "alloca header" is used to: |
| (a) chain together all alloca'ed blocks; |
| (b) keep track of stack depth. |
| |
| It is very important that sizeof(header) agree with malloc |
| alignment chunk size. The following default should work okay. */ |
| |
| # ifndef ALIGN_SIZE |
| # define ALIGN_SIZE sizeof(double) |
| # endif |
| |
| typedef union hdr |
| { |
| char align[ALIGN_SIZE]; /* To force sizeof(header). */ |
| struct |
| { |
| union hdr *next; /* For chaining headers. */ |
| char *deep; /* For stack depth measure. */ |
| } h; |
| } header; |
| |
| static header *last_alloca_header = NULL; /* -> last alloca header. */ |
| |
| /* Return a pointer to at least SIZE bytes of storage, |
| which will be automatically reclaimed upon exit from |
| the procedure that called alloca. Originally, this space |
| was supposed to be taken from the current stack frame of the |
| caller, but that method cannot be made to work for some |
| implementations of C, for example under Gould's UTX/32. */ |
| |
| void * |
| alloca (size_t size) |
| { |
| auto char probe; /* Probes stack depth: */ |
| register char *depth = &probe; |
| |
| # if STACK_DIRECTION == 0 |
| if (STACK_DIR == 0) /* Unknown growth direction. */ |
| STACK_DIR = find_stack_direction (NULL, (size & 1) + 20); |
| # endif |
| |
| /* Reclaim garbage, defined as all alloca'd storage that |
| was allocated from deeper in the stack than currently. */ |
| |
| { |
| register header *hp; /* Traverses linked list. */ |
| |
| # ifdef emacs |
| BLOCK_INPUT; |
| # endif |
| |
| for (hp = last_alloca_header; hp != NULL;) |
| if ((STACK_DIR > 0 && hp->h.deep > depth) |
| || (STACK_DIR < 0 && hp->h.deep < depth)) |
| { |
| register header *np = hp->h.next; |
| |
| free (hp); /* Collect garbage. */ |
| |
| hp = np; /* -> next header. */ |
| } |
| else |
| break; /* Rest are not deeper. */ |
| |
| last_alloca_header = hp; /* -> last valid storage. */ |
| |
| # ifdef emacs |
| UNBLOCK_INPUT; |
| # endif |
| } |
| |
| if (size == 0) |
| return NULL; /* No allocation required. */ |
| |
| /* Allocate combined header + user data storage. */ |
| |
| { |
| /* Address of header. */ |
| register header *new; |
| |
| size_t combined_size = sizeof (header) + size; |
| if (combined_size < sizeof (header)) |
| memory_full (); |
| |
| new = malloc (combined_size); |
| |
| if (! new) |
| memory_full (); |
| |
| new->h.next = last_alloca_header; |
| new->h.deep = depth; |
| |
| last_alloca_header = new; |
| |
| /* User storage begins just after header. */ |
| |
| return (void *) (new + 1); |
| } |
| } |
| |
| # endif /* no alloca */ |
| #endif /* not GCC || clang */ |