source: vendor/bash/3.1/lib/malloc/alloca.c

Last change on this file was 3228, checked in by bird, 19 years ago

bash 3.1

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