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