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