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