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