xref: /netbsd-src/external/gpl2/xcvs/dist/lib/alloca.c (revision 5a6c14c844c4c665da5632061aebde7bb2cb5766)
1a7c91847Schristos /* alloca.c -- allocate automatically reclaimed memory
2a7c91847Schristos    (Mostly) portable public-domain implementation -- D A Gwyn
3a7c91847Schristos 
4a7c91847Schristos    This implementation of the PWB library alloca function,
5a7c91847Schristos    which is used to allocate space off the run-time stack so
6a7c91847Schristos    that it is automatically reclaimed upon procedure exit,
7a7c91847Schristos    was inspired by discussions with J. Q. Johnson of Cornell.
8a7c91847Schristos    J.Otto Tennant <jot@cray.com> contributed the Cray support.
9a7c91847Schristos 
10a7c91847Schristos    There are some preprocessor constants that can
11a7c91847Schristos    be defined when compiling for your specific system, for
12a7c91847Schristos    improved efficiency; however, the defaults should be okay.
13a7c91847Schristos 
14a7c91847Schristos    The general concept of this implementation is to keep
15a7c91847Schristos    track of all alloca-allocated blocks, and reclaim any
16a7c91847Schristos    that are found to be deeper in the stack than the current
17a7c91847Schristos    invocation.  This heuristic does not reclaim storage as
18a7c91847Schristos    soon as it becomes invalid, but it will do so eventually.
19a7c91847Schristos 
20a7c91847Schristos    As a special case, alloca(0) reclaims storage without
21a7c91847Schristos    allocating any.  It is a good idea to use alloca(0) in
22a7c91847Schristos    your main control loop, etc. to force garbage collection.  */
23*5a6c14c8Schristos #include <sys/cdefs.h>
24*5a6c14c8Schristos __RCSID("$NetBSD: alloca.c,v 1.2 2016/05/17 14:00:09 christos Exp $");
25a7c91847Schristos 
26a7c91847Schristos #ifdef HAVE_CONFIG_H
27a7c91847Schristos # include <config.h>
28a7c91847Schristos #endif
29a7c91847Schristos 
30a7c91847Schristos #include <alloca.h>
31a7c91847Schristos 
32a7c91847Schristos #include <string.h>
33a7c91847Schristos #include <stdlib.h>
34a7c91847Schristos 
35a7c91847Schristos #ifdef emacs
36a7c91847Schristos # include "lisp.h"
37a7c91847Schristos # include "blockinput.h"
38a7c91847Schristos # ifdef EMACS_FREE
39a7c91847Schristos #  undef free
40a7c91847Schristos #  define free EMACS_FREE
41a7c91847Schristos # endif
42a7c91847Schristos #else
43a7c91847Schristos # define memory_full() abort ()
44a7c91847Schristos #endif
45a7c91847Schristos 
46a7c91847Schristos /* If compiling with GCC 2, this file's not needed.  */
47a7c91847Schristos #if !defined (__GNUC__) || __GNUC__ < 2
48a7c91847Schristos 
49a7c91847Schristos /* If someone has defined alloca as a macro,
50a7c91847Schristos    there must be some other way alloca is supposed to work.  */
51a7c91847Schristos # ifndef alloca
52a7c91847Schristos 
53a7c91847Schristos #  ifdef emacs
54a7c91847Schristos #   ifdef static
55a7c91847Schristos /* actually, only want this if static is defined as ""
56a7c91847Schristos    -- this is for usg, in which emacs must undefine static
57a7c91847Schristos    in order to make unexec workable
58a7c91847Schristos    */
59a7c91847Schristos #    ifndef STACK_DIRECTION
60a7c91847Schristos you
61a7c91847Schristos lose
62a7c91847Schristos -- must know STACK_DIRECTION at compile-time
63a7c91847Schristos /* Using #error here is not wise since this file should work for
64a7c91847Schristos    old and obscure compilers.  */
65a7c91847Schristos #    endif /* STACK_DIRECTION undefined */
66a7c91847Schristos #   endif /* static */
67a7c91847Schristos #  endif /* emacs */
68a7c91847Schristos 
69a7c91847Schristos /* If your stack is a linked list of frames, you have to
70a7c91847Schristos    provide an "address metric" ADDRESS_FUNCTION macro.  */
71a7c91847Schristos 
72a7c91847Schristos #  if defined (CRAY) && defined (CRAY_STACKSEG_END)
73a7c91847Schristos long i00afunc ();
74a7c91847Schristos #   define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
75a7c91847Schristos #  else
76a7c91847Schristos #   define ADDRESS_FUNCTION(arg) &(arg)
77a7c91847Schristos #  endif
78a7c91847Schristos 
79a7c91847Schristos /* Define STACK_DIRECTION if you know the direction of stack
80a7c91847Schristos    growth for your system; otherwise it will be automatically
81a7c91847Schristos    deduced at run-time.
82a7c91847Schristos 
83a7c91847Schristos    STACK_DIRECTION > 0 => grows toward higher addresses
84a7c91847Schristos    STACK_DIRECTION < 0 => grows toward lower addresses
85a7c91847Schristos    STACK_DIRECTION = 0 => direction of growth unknown  */
86a7c91847Schristos 
87a7c91847Schristos #  ifndef STACK_DIRECTION
88a7c91847Schristos #   define STACK_DIRECTION	0	/* Direction unknown.  */
89a7c91847Schristos #  endif
90a7c91847Schristos 
91a7c91847Schristos #  if STACK_DIRECTION != 0
92a7c91847Schristos 
93a7c91847Schristos #   define STACK_DIR	STACK_DIRECTION	/* Known at compile-time.  */
94a7c91847Schristos 
95a7c91847Schristos #  else /* STACK_DIRECTION == 0; need run-time code.  */
96a7c91847Schristos 
97a7c91847Schristos static int stack_dir;		/* 1 or -1 once known.  */
98a7c91847Schristos #   define STACK_DIR	stack_dir
99a7c91847Schristos 
100a7c91847Schristos static void
find_stack_direction(void)101a7c91847Schristos find_stack_direction (void)
102a7c91847Schristos {
103a7c91847Schristos   static char *addr = NULL;	/* Address of first `dummy', once known.  */
104a7c91847Schristos   auto char dummy;		/* To get stack address.  */
105a7c91847Schristos 
106a7c91847Schristos   if (addr == NULL)
107a7c91847Schristos     {				/* Initial entry.  */
108a7c91847Schristos       addr = ADDRESS_FUNCTION (dummy);
109a7c91847Schristos 
110a7c91847Schristos       find_stack_direction ();	/* Recurse once.  */
111a7c91847Schristos     }
112a7c91847Schristos   else
113a7c91847Schristos     {
114a7c91847Schristos       /* Second entry.  */
115a7c91847Schristos       if (ADDRESS_FUNCTION (dummy) > addr)
116a7c91847Schristos 	stack_dir = 1;		/* Stack grew upward.  */
117a7c91847Schristos       else
118a7c91847Schristos 	stack_dir = -1;		/* Stack grew downward.  */
119a7c91847Schristos     }
120a7c91847Schristos }
121a7c91847Schristos 
122a7c91847Schristos #  endif /* STACK_DIRECTION == 0 */
123a7c91847Schristos 
124a7c91847Schristos /* An "alloca header" is used to:
125a7c91847Schristos    (a) chain together all alloca'ed blocks;
126a7c91847Schristos    (b) keep track of stack depth.
127a7c91847Schristos 
128a7c91847Schristos    It is very important that sizeof(header) agree with malloc
129a7c91847Schristos    alignment chunk size.  The following default should work okay.  */
130a7c91847Schristos 
131a7c91847Schristos #  ifndef	ALIGN_SIZE
132a7c91847Schristos #   define ALIGN_SIZE	sizeof(double)
133a7c91847Schristos #  endif
134a7c91847Schristos 
135a7c91847Schristos typedef union hdr
136a7c91847Schristos {
137a7c91847Schristos   char align[ALIGN_SIZE];	/* To force sizeof(header).  */
138a7c91847Schristos   struct
139a7c91847Schristos     {
140a7c91847Schristos       union hdr *next;		/* For chaining headers.  */
141a7c91847Schristos       char *deep;		/* For stack depth measure.  */
142a7c91847Schristos     } h;
143a7c91847Schristos } header;
144a7c91847Schristos 
145a7c91847Schristos static header *last_alloca_header = NULL;	/* -> last alloca header.  */
146a7c91847Schristos 
147a7c91847Schristos /* Return a pointer to at least SIZE bytes of storage,
148a7c91847Schristos    which will be automatically reclaimed upon exit from
149a7c91847Schristos    the procedure that called alloca.  Originally, this space
150a7c91847Schristos    was supposed to be taken from the current stack frame of the
151a7c91847Schristos    caller, but that method cannot be made to work for some
152a7c91847Schristos    implementations of C, for example under Gould's UTX/32.  */
153a7c91847Schristos 
154a7c91847Schristos void *
alloca(size_t size)155a7c91847Schristos alloca (size_t size)
156a7c91847Schristos {
157a7c91847Schristos   auto char probe;		/* Probes stack depth: */
158a7c91847Schristos   register char *depth = ADDRESS_FUNCTION (probe);
159a7c91847Schristos 
160a7c91847Schristos #  if STACK_DIRECTION == 0
161a7c91847Schristos   if (STACK_DIR == 0)		/* Unknown growth direction.  */
162a7c91847Schristos     find_stack_direction ();
163a7c91847Schristos #  endif
164a7c91847Schristos 
165a7c91847Schristos   /* Reclaim garbage, defined as all alloca'd storage that
166a7c91847Schristos      was allocated from deeper in the stack than currently.  */
167a7c91847Schristos 
168a7c91847Schristos   {
169a7c91847Schristos     register header *hp;	/* Traverses linked list.  */
170a7c91847Schristos 
171a7c91847Schristos #  ifdef emacs
172a7c91847Schristos     BLOCK_INPUT;
173a7c91847Schristos #  endif
174a7c91847Schristos 
175a7c91847Schristos     for (hp = last_alloca_header; hp != NULL;)
176a7c91847Schristos       if ((STACK_DIR > 0 && hp->h.deep > depth)
177a7c91847Schristos 	  || (STACK_DIR < 0 && hp->h.deep < depth))
178a7c91847Schristos 	{
179a7c91847Schristos 	  register header *np = hp->h.next;
180a7c91847Schristos 
181a7c91847Schristos 	  free (hp);		/* Collect garbage.  */
182a7c91847Schristos 
183a7c91847Schristos 	  hp = np;		/* -> next header.  */
184a7c91847Schristos 	}
185a7c91847Schristos       else
186a7c91847Schristos 	break;			/* Rest are not deeper.  */
187a7c91847Schristos 
188a7c91847Schristos     last_alloca_header = hp;	/* -> last valid storage.  */
189a7c91847Schristos 
190a7c91847Schristos #  ifdef emacs
191a7c91847Schristos     UNBLOCK_INPUT;
192a7c91847Schristos #  endif
193a7c91847Schristos   }
194a7c91847Schristos 
195a7c91847Schristos   if (size == 0)
196a7c91847Schristos     return NULL;		/* No allocation required.  */
197a7c91847Schristos 
198a7c91847Schristos   /* Allocate combined header + user data storage.  */
199a7c91847Schristos 
200a7c91847Schristos   {
201a7c91847Schristos     /* Address of header.  */
202a7c91847Schristos     register header *new;
203a7c91847Schristos 
204a7c91847Schristos     size_t combined_size = sizeof (header) + size;
205a7c91847Schristos     if (combined_size < sizeof (header))
206a7c91847Schristos       memory_full ();
207a7c91847Schristos 
208a7c91847Schristos     new = malloc (combined_size);
209a7c91847Schristos 
210a7c91847Schristos     if (! new)
211a7c91847Schristos       memory_full ();
212a7c91847Schristos 
213a7c91847Schristos     new->h.next = last_alloca_header;
214a7c91847Schristos     new->h.deep = depth;
215a7c91847Schristos 
216a7c91847Schristos     last_alloca_header = new;
217a7c91847Schristos 
218a7c91847Schristos     /* User storage begins just after header.  */
219a7c91847Schristos 
220a7c91847Schristos     return (void *) (new + 1);
221a7c91847Schristos   }
222a7c91847Schristos }
223a7c91847Schristos 
224a7c91847Schristos #  if defined (CRAY) && defined (CRAY_STACKSEG_END)
225a7c91847Schristos 
226a7c91847Schristos #   ifdef DEBUG_I00AFUNC
227a7c91847Schristos #    include <stdio.h>
228a7c91847Schristos #   endif
229a7c91847Schristos 
230a7c91847Schristos #   ifndef CRAY_STACK
231a7c91847Schristos #    define CRAY_STACK
232a7c91847Schristos #    ifndef CRAY2
233a7c91847Schristos /* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
234a7c91847Schristos struct stack_control_header
235a7c91847Schristos   {
236a7c91847Schristos     long shgrow:32;		/* Number of times stack has grown.  */
237a7c91847Schristos     long shaseg:32;		/* Size of increments to stack.  */
238a7c91847Schristos     long shhwm:32;		/* High water mark of stack.  */
239a7c91847Schristos     long shsize:32;		/* Current size of stack (all segments).  */
240a7c91847Schristos   };
241a7c91847Schristos 
242a7c91847Schristos /* The stack segment linkage control information occurs at
243a7c91847Schristos    the high-address end of a stack segment.  (The stack
244a7c91847Schristos    grows from low addresses to high addresses.)  The initial
245a7c91847Schristos    part of the stack segment linkage control information is
246a7c91847Schristos    0200 (octal) words.  This provides for register storage
247a7c91847Schristos    for the routine which overflows the stack.  */
248a7c91847Schristos 
249a7c91847Schristos struct stack_segment_linkage
250a7c91847Schristos   {
251a7c91847Schristos     long ss[0200];		/* 0200 overflow words.  */
252a7c91847Schristos     long sssize:32;		/* Number of words in this segment.  */
253a7c91847Schristos     long ssbase:32;		/* Offset to stack base.  */
254a7c91847Schristos     long:32;
255a7c91847Schristos     long sspseg:32;		/* Offset to linkage control of previous
256a7c91847Schristos 				   segment of stack.  */
257a7c91847Schristos     long:32;
258a7c91847Schristos     long sstcpt:32;		/* Pointer to task common address block.  */
259a7c91847Schristos     long sscsnm;		/* Private control structure number for
260a7c91847Schristos 				   microtasking.  */
261a7c91847Schristos     long ssusr1;		/* Reserved for user.  */
262a7c91847Schristos     long ssusr2;		/* Reserved for user.  */
263a7c91847Schristos     long sstpid;		/* Process ID for pid based multi-tasking.  */
264a7c91847Schristos     long ssgvup;		/* Pointer to multitasking thread giveup.  */
265a7c91847Schristos     long sscray[7];		/* Reserved for Cray Research.  */
266a7c91847Schristos     long ssa0;
267a7c91847Schristos     long ssa1;
268a7c91847Schristos     long ssa2;
269a7c91847Schristos     long ssa3;
270a7c91847Schristos     long ssa4;
271a7c91847Schristos     long ssa5;
272a7c91847Schristos     long ssa6;
273a7c91847Schristos     long ssa7;
274a7c91847Schristos     long sss0;
275a7c91847Schristos     long sss1;
276a7c91847Schristos     long sss2;
277a7c91847Schristos     long sss3;
278a7c91847Schristos     long sss4;
279a7c91847Schristos     long sss5;
280a7c91847Schristos     long sss6;
281a7c91847Schristos     long sss7;
282a7c91847Schristos   };
283a7c91847Schristos 
284a7c91847Schristos #    else /* CRAY2 */
285a7c91847Schristos /* The following structure defines the vector of words
286a7c91847Schristos    returned by the STKSTAT library routine.  */
287a7c91847Schristos struct stk_stat
288a7c91847Schristos   {
289a7c91847Schristos     long now;			/* Current total stack size.  */
290a7c91847Schristos     long maxc;			/* Amount of contiguous space which would
291a7c91847Schristos 				   be required to satisfy the maximum
292a7c91847Schristos 				   stack demand to date.  */
293a7c91847Schristos     long high_water;		/* Stack high-water mark.  */
294a7c91847Schristos     long overflows;		/* Number of stack overflow ($STKOFEN) calls.  */
295a7c91847Schristos     long hits;			/* Number of internal buffer hits.  */
296a7c91847Schristos     long extends;		/* Number of block extensions.  */
297a7c91847Schristos     long stko_mallocs;		/* Block allocations by $STKOFEN.  */
298a7c91847Schristos     long underflows;		/* Number of stack underflow calls ($STKRETN).  */
299a7c91847Schristos     long stko_free;		/* Number of deallocations by $STKRETN.  */
300a7c91847Schristos     long stkm_free;		/* Number of deallocations by $STKMRET.  */
301a7c91847Schristos     long segments;		/* Current number of stack segments.  */
302a7c91847Schristos     long maxs;			/* Maximum number of stack segments so far.  */
303a7c91847Schristos     long pad_size;		/* Stack pad size.  */
304a7c91847Schristos     long current_address;	/* Current stack segment address.  */
305a7c91847Schristos     long current_size;		/* Current stack segment size.  This
306a7c91847Schristos 				   number is actually corrupted by STKSTAT to
307a7c91847Schristos 				   include the fifteen word trailer area.  */
308a7c91847Schristos     long initial_address;	/* Address of initial segment.  */
309a7c91847Schristos     long initial_size;		/* Size of initial segment.  */
310a7c91847Schristos   };
311a7c91847Schristos 
312a7c91847Schristos /* The following structure describes the data structure which trails
313a7c91847Schristos    any stack segment.  I think that the description in 'asdef' is
314a7c91847Schristos    out of date.  I only describe the parts that I am sure about.  */
315a7c91847Schristos 
316a7c91847Schristos struct stk_trailer
317a7c91847Schristos   {
318a7c91847Schristos     long this_address;		/* Address of this block.  */
319a7c91847Schristos     long this_size;		/* Size of this block (does not include
320a7c91847Schristos 				   this trailer).  */
321a7c91847Schristos     long unknown2;
322a7c91847Schristos     long unknown3;
323a7c91847Schristos     long link;			/* Address of trailer block of previous
324a7c91847Schristos 				   segment.  */
325a7c91847Schristos     long unknown5;
326a7c91847Schristos     long unknown6;
327a7c91847Schristos     long unknown7;
328a7c91847Schristos     long unknown8;
329a7c91847Schristos     long unknown9;
330a7c91847Schristos     long unknown10;
331a7c91847Schristos     long unknown11;
332a7c91847Schristos     long unknown12;
333a7c91847Schristos     long unknown13;
334a7c91847Schristos     long unknown14;
335a7c91847Schristos   };
336a7c91847Schristos 
337a7c91847Schristos #    endif /* CRAY2 */
338a7c91847Schristos #   endif /* not CRAY_STACK */
339a7c91847Schristos 
340a7c91847Schristos #   ifdef CRAY2
341a7c91847Schristos /* Determine a "stack measure" for an arbitrary ADDRESS.
342a7c91847Schristos    I doubt that "lint" will like this much.  */
343a7c91847Schristos 
344a7c91847Schristos static long
i00afunc(long * address)345a7c91847Schristos i00afunc (long *address)
346a7c91847Schristos {
347a7c91847Schristos   struct stk_stat status;
348a7c91847Schristos   struct stk_trailer *trailer;
349a7c91847Schristos   long *block, size;
350a7c91847Schristos   long result = 0;
351a7c91847Schristos 
352a7c91847Schristos   /* We want to iterate through all of the segments.  The first
353a7c91847Schristos      step is to get the stack status structure.  We could do this
354a7c91847Schristos      more quickly and more directly, perhaps, by referencing the
355a7c91847Schristos      $LM00 common block, but I know that this works.  */
356a7c91847Schristos 
357a7c91847Schristos   STKSTAT (&status);
358a7c91847Schristos 
359a7c91847Schristos   /* Set up the iteration.  */
360a7c91847Schristos 
361a7c91847Schristos   trailer = (struct stk_trailer *) (status.current_address
362a7c91847Schristos 				    + status.current_size
363a7c91847Schristos 				    - 15);
364a7c91847Schristos 
365a7c91847Schristos   /* There must be at least one stack segment.  Therefore it is
366a7c91847Schristos      a fatal error if "trailer" is null.  */
367a7c91847Schristos 
368a7c91847Schristos   if (trailer == 0)
369a7c91847Schristos     abort ();
370a7c91847Schristos 
371a7c91847Schristos   /* Discard segments that do not contain our argument address.  */
372a7c91847Schristos 
373a7c91847Schristos   while (trailer != 0)
374a7c91847Schristos     {
375a7c91847Schristos       block = (long *) trailer->this_address;
376a7c91847Schristos       size = trailer->this_size;
377a7c91847Schristos       if (block == 0 || size == 0)
378a7c91847Schristos 	abort ();
379a7c91847Schristos       trailer = (struct stk_trailer *) trailer->link;
380a7c91847Schristos       if ((block <= address) && (address < (block + size)))
381a7c91847Schristos 	break;
382a7c91847Schristos     }
383a7c91847Schristos 
384a7c91847Schristos   /* Set the result to the offset in this segment and add the sizes
385a7c91847Schristos      of all predecessor segments.  */
386a7c91847Schristos 
387a7c91847Schristos   result = address - block;
388a7c91847Schristos 
389a7c91847Schristos   if (trailer == 0)
390a7c91847Schristos     {
391a7c91847Schristos       return result;
392a7c91847Schristos     }
393a7c91847Schristos 
394a7c91847Schristos   do
395a7c91847Schristos     {
396a7c91847Schristos       if (trailer->this_size <= 0)
397a7c91847Schristos 	abort ();
398a7c91847Schristos       result += trailer->this_size;
399a7c91847Schristos       trailer = (struct stk_trailer *) trailer->link;
400a7c91847Schristos     }
401a7c91847Schristos   while (trailer != 0);
402a7c91847Schristos 
403a7c91847Schristos   /* We are done.  Note that if you present a bogus address (one
404a7c91847Schristos      not in any segment), you will get a different number back, formed
405a7c91847Schristos      from subtracting the address of the first block.  This is probably
406a7c91847Schristos      not what you want.  */
407a7c91847Schristos 
408a7c91847Schristos   return (result);
409a7c91847Schristos }
410a7c91847Schristos 
411a7c91847Schristos #   else /* not CRAY2 */
412a7c91847Schristos /* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
413a7c91847Schristos    Determine the number of the cell within the stack,
414a7c91847Schristos    given the address of the cell.  The purpose of this
415a7c91847Schristos    routine is to linearize, in some sense, stack addresses
416a7c91847Schristos    for alloca.  */
417a7c91847Schristos 
418a7c91847Schristos static long
i00afunc(long address)419a7c91847Schristos i00afunc (long address)
420a7c91847Schristos {
421a7c91847Schristos   long stkl = 0;
422a7c91847Schristos 
423a7c91847Schristos   long size, pseg, this_segment, stack;
424a7c91847Schristos   long result = 0;
425a7c91847Schristos 
426a7c91847Schristos   struct stack_segment_linkage *ssptr;
427a7c91847Schristos 
428a7c91847Schristos   /* Register B67 contains the address of the end of the
429a7c91847Schristos      current stack segment.  If you (as a subprogram) store
430a7c91847Schristos      your registers on the stack and find that you are past
431a7c91847Schristos      the contents of B67, you have overflowed the segment.
432a7c91847Schristos 
433a7c91847Schristos      B67 also points to the stack segment linkage control
434a7c91847Schristos      area, which is what we are really interested in.  */
435a7c91847Schristos 
436a7c91847Schristos   stkl = CRAY_STACKSEG_END ();
437a7c91847Schristos   ssptr = (struct stack_segment_linkage *) stkl;
438a7c91847Schristos 
439a7c91847Schristos   /* If one subtracts 'size' from the end of the segment,
440a7c91847Schristos      one has the address of the first word of the segment.
441a7c91847Schristos 
442a7c91847Schristos      If this is not the first segment, 'pseg' will be
443a7c91847Schristos      nonzero.  */
444a7c91847Schristos 
445a7c91847Schristos   pseg = ssptr->sspseg;
446a7c91847Schristos   size = ssptr->sssize;
447a7c91847Schristos 
448a7c91847Schristos   this_segment = stkl - size;
449a7c91847Schristos 
450a7c91847Schristos   /* It is possible that calling this routine itself caused
451a7c91847Schristos      a stack overflow.  Discard stack segments which do not
452a7c91847Schristos      contain the target address.  */
453a7c91847Schristos 
454a7c91847Schristos   while (!(this_segment <= address && address <= stkl))
455a7c91847Schristos     {
456a7c91847Schristos #    ifdef DEBUG_I00AFUNC
457a7c91847Schristos       fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
458a7c91847Schristos #    endif
459a7c91847Schristos       if (pseg == 0)
460a7c91847Schristos 	break;
461a7c91847Schristos       stkl = stkl - pseg;
462a7c91847Schristos       ssptr = (struct stack_segment_linkage *) stkl;
463a7c91847Schristos       size = ssptr->sssize;
464a7c91847Schristos       pseg = ssptr->sspseg;
465a7c91847Schristos       this_segment = stkl - size;
466a7c91847Schristos     }
467a7c91847Schristos 
468a7c91847Schristos   result = address - this_segment;
469a7c91847Schristos 
470a7c91847Schristos   /* If you subtract pseg from the current end of the stack,
471a7c91847Schristos      you get the address of the previous stack segment's end.
472a7c91847Schristos      This seems a little convoluted to me, but I'll bet you save
473a7c91847Schristos      a cycle somewhere.  */
474a7c91847Schristos 
475a7c91847Schristos   while (pseg != 0)
476a7c91847Schristos     {
477a7c91847Schristos #    ifdef DEBUG_I00AFUNC
478a7c91847Schristos       fprintf (stderr, "%011o %011o\n", pseg, size);
479a7c91847Schristos #    endif
480a7c91847Schristos       stkl = stkl - pseg;
481a7c91847Schristos       ssptr = (struct stack_segment_linkage *) stkl;
482a7c91847Schristos       size = ssptr->sssize;
483a7c91847Schristos       pseg = ssptr->sspseg;
484a7c91847Schristos       result += size;
485a7c91847Schristos     }
486a7c91847Schristos   return (result);
487a7c91847Schristos }
488a7c91847Schristos 
489a7c91847Schristos #   endif /* not CRAY2 */
490a7c91847Schristos #  endif /* CRAY */
491a7c91847Schristos 
492a7c91847Schristos # endif /* no alloca */
493a7c91847Schristos #endif /* not GCC version 2 */
494