/* alloca.c -- allocate automatically reclaimed memory1(Mostly) portable public-domain implementation -- D A Gwyn23This implementation of the PWB library alloca function,4which is used to allocate space off the run-time stack so5that it is automatically reclaimed upon procedure exit,6was inspired by discussions with J. Q. Johnson of Cornell.7J.Otto Tennant <[email protected]> contributed the Cray support.89There are some preprocessor constants that can10be defined when compiling for your specific system, for11improved efficiency; however, the defaults should be okay.1213The general concept of this implementation is to keep14track of all alloca-allocated blocks, and reclaim any15that are found to be deeper in the stack than the current16invocation. This heuristic does not reclaim storage as17soon as it becomes invalid, but it will do so eventually.1819As a special case, alloca(0) reclaims storage without20allocating any. It is a good idea to use alloca(0) in21your main control loop, etc. to force garbage collection. */2223/* If compiling with GCC 2, this file's not needed. */24#if !defined (__GNUC__) || __GNUC__ < 22526/* If someone has defined alloca as a macro,27there must be some other way alloca is supposed to work. */28#ifndef alloca2930/* If your stack is a linked list of frames, you have to31provide an "address metric" ADDRESS_FUNCTION macro. */3233#if defined (CRAY) && defined (CRAY_STACKSEG_END)34long i00afunc ();35#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))36#else37#define ADDRESS_FUNCTION(arg) &(arg)38#endif3940typedef void *pointer;4142#define NULL 04344/* Different portions of Emacs need to call different versions of45malloc. The Emacs executable needs alloca to call xmalloc, because46ordinary malloc isn't protected from input signals. On the other47hand, the utilities in lib-src need alloca to call malloc; some of48them are very simple, and don't have an xmalloc routine.4950Non-Emacs programs expect this to call use xmalloc.5152Callers below should use malloc. */5354#define malloc xmalloc55extern pointer malloc ();5657/* Define STACK_DIRECTION if you know the direction of stack58growth for your system; otherwise it will be automatically59deduced at run-time.6061STACK_DIRECTION > 0 => grows toward higher addresses62STACK_DIRECTION < 0 => grows toward lower addresses63STACK_DIRECTION = 0 => direction of growth unknown */6465#ifndef STACK_DIRECTION66#define STACK_DIRECTION 0 /* Direction unknown. */67#endif6869#if STACK_DIRECTION != 07071#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */7273#else /* STACK_DIRECTION == 0; need run-time code. */7475static int stack_dir; /* 1 or -1 once known. */76#define STACK_DIR stack_dir7778static void79find_stack_direction ()80{81static char *addr = NULL; /* Address of first `dummy', once known. */82auto char dummy; /* To get stack address. */8384if (addr == NULL)85{ /* Initial entry. */86addr = ADDRESS_FUNCTION (dummy);8788find_stack_direction (); /* Recurse once. */89}90else91{92/* Second entry. */93if (ADDRESS_FUNCTION (dummy) > addr)94stack_dir = 1; /* Stack grew upward. */95else96stack_dir = -1; /* Stack grew downward. */97}98}99100#endif /* STACK_DIRECTION == 0 */101102/* An "alloca header" is used to:103(a) chain together all alloca'ed blocks;104(b) keep track of stack depth.105106It is very important that sizeof(header) agree with malloc107alignment chunk size. The following default should work okay. */108109#ifndef ALIGN_SIZE110#define ALIGN_SIZE sizeof(double)111#endif112113typedef union hdr114{115char align[ALIGN_SIZE]; /* To force sizeof(header). */116struct117{118union hdr *next; /* For chaining headers. */119char *deep; /* For stack depth measure. */120} h;121} header;122123static header *last_alloca_header = NULL; /* -> last alloca header. */124125/* Return a pointer to at least SIZE bytes of storage,126which will be automatically reclaimed upon exit from127the procedure that called alloca. Originally, this space128was supposed to be taken from the current stack frame of the129caller, but that method cannot be made to work for some130implementations of C, for example under Gould's UTX/32. */131132pointer133alloca (size)134unsigned size;135{136auto char probe; /* Probes stack depth: */137register char *depth = ADDRESS_FUNCTION (probe);138139#if STACK_DIRECTION == 0140if (STACK_DIR == 0) /* Unknown growth direction. */141find_stack_direction ();142#endif143144/* Reclaim garbage, defined as all alloca'd storage that145was allocated from deeper in the stack than currently. */146147{148register header *hp; /* Traverses linked list. */149150for (hp = last_alloca_header; hp != NULL;)151if ((STACK_DIR > 0 && hp->h.deep > depth)152|| (STACK_DIR < 0 && hp->h.deep < depth))153{154register header *np = hp->h.next;155156free ((pointer) hp); /* Collect garbage. */157158hp = np; /* -> next header. */159}160else161break; /* Rest are not deeper. */162163last_alloca_header = hp; /* -> last valid storage. */164}165166if (size == 0)167return NULL; /* No allocation required. */168169/* Allocate combined header + user data storage. */170171{172register pointer new = malloc (sizeof (header) + size);173/* Address of header. */174175((header *) new)->h.next = last_alloca_header;176((header *) new)->h.deep = depth;177178last_alloca_header = (header *) new;179180/* User storage begins just after header. */181182return (pointer) ((char *) new + sizeof (header));183}184}185186#if defined (CRAY) && defined (CRAY_STACKSEG_END)187188#ifdef DEBUG_I00AFUNC189#include <stdio.h>190#endif191192#ifndef CRAY_STACK193#define CRAY_STACK194#ifndef CRAY2195/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */196struct stack_control_header197{198long shgrow:32; /* Number of times stack has grown. */199long shaseg:32; /* Size of increments to stack. */200long shhwm:32; /* High water mark of stack. */201long shsize:32; /* Current size of stack (all segments). */202};203204/* The stack segment linkage control information occurs at205the high-address end of a stack segment. (The stack206grows from low addresses to high addresses.) The initial207part of the stack segment linkage control information is2080200 (octal) words. This provides for register storage209for the routine which overflows the stack. */210211struct stack_segment_linkage212{213long ss[0200]; /* 0200 overflow words. */214long sssize:32; /* Number of words in this segment. */215long ssbase:32; /* Offset to stack base. */216long:32;217long sspseg:32; /* Offset to linkage control of previous218segment of stack. */219long:32;220long sstcpt:32; /* Pointer to task common address block. */221long sscsnm; /* Private control structure number for222microtasking. */223long ssusr1; /* Reserved for user. */224long ssusr2; /* Reserved for user. */225long sstpid; /* Process ID for pid based multi-tasking. */226long ssgvup; /* Pointer to multitasking thread giveup. */227long sscray[7]; /* Reserved for Cray Research. */228long ssa0;229long ssa1;230long ssa2;231long ssa3;232long ssa4;233long ssa5;234long ssa6;235long ssa7;236long sss0;237long sss1;238long sss2;239long sss3;240long sss4;241long sss5;242long sss6;243long sss7;244};245246#else /* CRAY2 */247/* The following structure defines the vector of words248returned by the STKSTAT library routine. */249struct stk_stat250{251long now; /* Current total stack size. */252long maxc; /* Amount of contiguous space which would253be required to satisfy the maximum254stack demand to date. */255long high_water; /* Stack high-water mark. */256long overflows; /* Number of stack overflow ($STKOFEN) calls. */257long hits; /* Number of internal buffer hits. */258long extends; /* Number of block extensions. */259long stko_mallocs; /* Block allocations by $STKOFEN. */260long underflows; /* Number of stack underflow calls ($STKRETN). */261long stko_free; /* Number of deallocations by $STKRETN. */262long stkm_free; /* Number of deallocations by $STKMRET. */263long segments; /* Current number of stack segments. */264long maxs; /* Maximum number of stack segments so far. */265long pad_size; /* Stack pad size. */266long current_address; /* Current stack segment address. */267long current_size; /* Current stack segment size. This268number is actually corrupted by STKSTAT to269include the fifteen word trailer area. */270long initial_address; /* Address of initial segment. */271long initial_size; /* Size of initial segment. */272};273274/* The following structure describes the data structure which trails275any stack segment. I think that the description in 'asdef' is276out of date. I only describe the parts that I am sure about. */277278struct stk_trailer279{280long this_address; /* Address of this block. */281long this_size; /* Size of this block (does not include282this trailer). */283long unknown2;284long unknown3;285long link; /* Address of trailer block of previous286segment. */287long unknown5;288long unknown6;289long unknown7;290long unknown8;291long unknown9;292long unknown10;293long unknown11;294long unknown12;295long unknown13;296long unknown14;297};298299#endif /* CRAY2 */300#endif /* not CRAY_STACK */301302#ifdef CRAY2303/* Determine a "stack measure" for an arbitrary ADDRESS.304I doubt that "lint" will like this much. */305306static long307i00afunc (long *address)308{309struct stk_stat status;310struct stk_trailer *trailer;311long *block, size;312long result = 0;313314/* We want to iterate through all of the segments. The first315step is to get the stack status structure. We could do this316more quickly and more directly, perhaps, by referencing the317$LM00 common block, but I know that this works. */318319STKSTAT (&status);320321/* Set up the iteration. */322323trailer = (struct stk_trailer *) (status.current_address324+ status.current_size325- 15);326327/* There must be at least one stack segment. Therefore it is328a fatal error if "trailer" is null. */329330if (trailer == 0)331abort ();332333/* Discard segments that do not contain our argument address. */334335while (trailer != 0)336{337block = (long *) trailer->this_address;338size = trailer->this_size;339if (block == 0 || size == 0)340abort ();341trailer = (struct stk_trailer *) trailer->link;342if ((block <= address) && (address < (block + size)))343break;344}345346/* Set the result to the offset in this segment and add the sizes347of all predecessor segments. */348349result = address - block;350351if (trailer == 0)352{353return result;354}355356do357{358if (trailer->this_size <= 0)359abort ();360result += trailer->this_size;361trailer = (struct stk_trailer *) trailer->link;362}363while (trailer != 0);364365/* We are done. Note that if you present a bogus address (one366not in any segment), you will get a different number back, formed367from subtracting the address of the first block. This is probably368not what you want. */369370return (result);371}372373#else /* not CRAY2 */374/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.375Determine the number of the cell within the stack,376given the address of the cell. The purpose of this377routine is to linearize, in some sense, stack addresses378for alloca. */379380static long381i00afunc (long address)382{383long stkl = 0;384385long size, pseg, this_segment, stack;386long result = 0;387388struct stack_segment_linkage *ssptr;389390/* Register B67 contains the address of the end of the391current stack segment. If you (as a subprogram) store392your registers on the stack and find that you are past393the contents of B67, you have overflowed the segment.394395B67 also points to the stack segment linkage control396area, which is what we are really interested in. */397398stkl = CRAY_STACKSEG_END ();399ssptr = (struct stack_segment_linkage *) stkl;400401/* If one subtracts 'size' from the end of the segment,402one has the address of the first word of the segment.403404If this is not the first segment, 'pseg' will be405nonzero. */406407pseg = ssptr->sspseg;408size = ssptr->sssize;409410this_segment = stkl - size;411412/* It is possible that calling this routine itself caused413a stack overflow. Discard stack segments which do not414contain the target address. */415416while (!(this_segment <= address && address <= stkl))417{418#ifdef DEBUG_I00AFUNC419fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);420#endif421if (pseg == 0)422break;423stkl = stkl - pseg;424ssptr = (struct stack_segment_linkage *) stkl;425size = ssptr->sssize;426pseg = ssptr->sspseg;427this_segment = stkl - size;428}429430result = address - this_segment;431432/* If you subtract pseg from the current end of the stack,433you get the address of the previous stack segment's end.434This seems a little convoluted to me, but I'll bet you save435a cycle somewhere. */436437while (pseg != 0)438{439#ifdef DEBUG_I00AFUNC440fprintf (stderr, "%011o %011o\n", pseg, size);441#endif442stkl = stkl - pseg;443ssptr = (struct stack_segment_linkage *) stkl;444size = ssptr->sssize;445pseg = ssptr->sspseg;446result += size;447}448return (result);449}450451#endif /* not CRAY2 */452#endif /* CRAY */453454#endif /* no alloca */455#endif /* not GCC version 2 */456457458