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