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