/* alloca.c -- allocate automatically reclaimed memory (Mostly) portable public-domain implementation -- D A Gwyn This implementation of the PWB library alloca function, which is used to allocate space off the run-time stack so that it is automatically reclaimed upon procedure exit, was inspired by discussions with J. Q. Johnson of Cornell. J.Otto Tennant <jot@cray.com> contributed the Cray support. There are some preprocessor constants that can be defined when compiling for your specific system, for improved efficiency; however, the defaults should be okay. The general concept of this implementation is to keep track of all alloca-allocated blocks, and reclaim any that are found to be deeper in the stack than the current invocation. This heuristic does not reclaim storage as soon as it becomes invalid, but it will do so eventually. As a special case, alloca(0) reclaims storage without allocating any. It is a good idea to use alloca(0) in your main control loop, etc. to force garbage collection. */#ifdef HAVE_CONFIG_H#include <config.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_STDLIB_H#include <stdlib.h>#endif#ifdef emacs#include "blockinput.h"#endif/* If compiling with GCC 2, this file's not needed. */#if !defined (__GNUC__) || __GNUC__ < 2/* If someone has defined alloca as a macro, there must be some other way alloca is supposed to work. */#ifndef alloca#ifdef emacs#ifdef static/* actually, only want this if static is defined as "" -- this is for usg, in which emacs must undefine static in order to make unexec workable */#ifndef STACK_DIRECTIONyoulose--mustknowSTACK_DIRECTIONatcompile-time#endif /* STACK_DIRECTION undefined */#endif /* static */#endif /* emacs *//* If your stack is a linked list of frames, you have to provide an "address metric" ADDRESS_FUNCTION macro. */#if defined (CRAY) && defined (CRAY_STACKSEG_END)longi00afunc();#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))#else#define ADDRESS_FUNCTION(arg) &(arg)#endif#if __STDC__typedefvoid*pointer;#elsetypedefchar*pointer;#endif#ifndef NULL#define NULL 0#endif/* Different portions of Emacs need to call different versions of malloc. The Emacs executable needs alloca to call xmalloc, because ordinary malloc isn't protected from input signals. On the other hand, the utilities in lib-src need alloca to call malloc; some of them are very simple, and don't have an xmalloc routine. Non-Emacs programs expect this to call use xmalloc. Callers below should use malloc. */#ifndef emacs#define malloc xmalloc#endifexternpointermalloc();/* Define STACK_DIRECTION if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */#ifndef STACK_DIRECTION#define STACK_DIRECTION 0 /* Direction unknown. */#endif#if STACK_DIRECTION != 0#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */#else /* STACK_DIRECTION == 0; need run-time code. */staticintstack_dir;/* 1 or -1 once known. */#define STACK_DIR stack_dirstaticvoidfind_stack_direction(){staticchar*addr=NULL;/* Address of first `dummy', once known. */autochardummy;/* To get stack address. */if(addr==NULL){/* Initial entry. */addr=ADDRESS_FUNCTION(dummy);find_stack_direction();/* Recurse once. */}else{/* Second entry. */if(ADDRESS_FUNCTION(dummy)>addr)stack_dir=1;/* Stack grew upward. */elsestack_dir=-1;/* Stack grew downward. */}}#endif /* STACK_DIRECTION == 0 *//* An "alloca header" is used to: (a) chain together all alloca'ed blocks; (b) keep track of stack depth. It is very important that sizeof(header) agree with malloc alignment chunk size. The following default should work okay. */#ifndef ALIGN_SIZE#define ALIGN_SIZE sizeof(double)#endiftypedefunionhdr{charalign[ALIGN_SIZE];/* To force sizeof(header). */struct{unionhdr*next;/* For chaining headers. */char*deep;/* For stack depth measure. */}h;}header;staticheader*last_alloca_header=NULL;/* -> last alloca header. *//* Return a pointer to at least SIZE bytes of storage, which will be automatically reclaimed upon exit from the procedure that called alloca. Originally, this space was supposed to be taken from the current stack frame of the caller, but that method cannot be made to work for some implementations of C, for example under Gould's UTX/32. */pointeralloca(size)unsignedsize;{autocharprobe;/* Probes stack depth: */registerchar*depth=ADDRESS_FUNCTION(probe);#if STACK_DIRECTION == 0if(STACK_DIR==0)/* Unknown growth direction. */find_stack_direction();#endif/* Reclaim garbage, defined as all alloca'd storage that was allocated from deeper in the stack than currently. */{registerheader*hp;/* Traverses linked list. */#ifdef emacsBLOCK_INPUT;#endiffor(hp=last_alloca_header;hp!=NULL;)if((STACK_DIR>0&&hp->h.deep>depth)||(STACK_DIR<0&&hp->h.deep<depth)){registerheader*np=hp->h.next;free((pointer)hp);/* Collect garbage. */hp=np;/* -> next header. */}elsebreak;/* Rest are not deeper. */last_alloca_header=hp;/* -> last valid storage. */#ifdef emacsUNBLOCK_INPUT;#endif}if(size==0)returnNULL;/* No allocation required. *//* Allocate combined header + user data storage. */{registerpointernew=malloc(sizeof(header)+size);/* Address of header. */if(new==0)abort();((header*)new)->h.next=last_alloca_header;((header*)new)->h.deep=depth;last_alloca_header=(header*)new;/* User storage begins just after header. */return(pointer)((char*)new+sizeof(header));}}#if defined (CRAY) && defined (CRAY_STACKSEG_END)#ifdef DEBUG_I00AFUNC#include <stdio.h>#endif#ifndef CRAY_STACK#define CRAY_STACK#ifndef CRAY2/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */structstack_control_header{longshgrow:32;/* Number of times stack has grown. */longshaseg:32;/* Size of increments to stack. */longshhwm:32;/* High water mark of stack. */longshsize:32;/* Current size of stack (all segments). */};/* The stack segment linkage control information occurs at the high-address end of a stack segment. (The stack grows from low addresses to high addresses.) The initial part of the stack segment linkage control information is 0200 (octal) words. This provides for register storage for the routine which overflows the stack. */structstack_segment_linkage{longss[0200];/* 0200 overflow words. */longsssize:32;/* Number of words in this segment. */longssbase:32;/* Offset to stack base. */long:32;longsspseg:32;/* Offset to linkage control of previous segment of stack. */long:32;longsstcpt:32;/* Pointer to task common address block. */longsscsnm;/* Private control structure number for microtasking. */longssusr1;/* Reserved for user. */longssusr2;/* Reserved for user. */longsstpid;/* Process ID for pid based multi-tasking. */longssgvup;/* Pointer to multitasking thread giveup. */longsscray[7];/* Reserved for Cray Research. */longssa0;longssa1;longssa2;longssa3;longssa4;longssa5;longssa6;longssa7;longsss0;longsss1;longsss2;longsss3;longsss4;longsss5;longsss6;longsss7;};#else /* CRAY2 *//* The following structure defines the vector of words returned by the STKSTAT library routine. */structstk_stat{longnow;/* Current total stack size. */longmaxc;/* Amount of contiguous space which would be required to satisfy the maximum stack demand to date. */longhigh_water;/* Stack high-water mark. */longoverflows;/* Number of stack overflow ($STKOFEN) calls. */longhits;/* Number of internal buffer hits. */longextends;/* Number of block extensions. */longstko_mallocs;/* Block allocations by $STKOFEN. */longunderflows;/* Number of stack underflow calls ($STKRETN). */longstko_free;/* Number of deallocations by $STKRETN. */longstkm_free;/* Number of deallocations by $STKMRET. */longsegments;/* Current number of stack segments. */longmaxs;/* Maximum number of stack segments so far. */longpad_size;/* Stack pad size. */longcurrent_address;/* Current stack segment address. */longcurrent_size;/* Current stack segment size. This number is actually corrupted by STKSTAT to include the fifteen word trailer area. */longinitial_address;/* Address of initial segment. */longinitial_size;/* Size of initial segment. */};/* The following structure describes the data structure which trails any stack segment. I think that the description in 'asdef' is out of date. I only describe the parts that I am sure about. */structstk_trailer{longthis_address;/* Address of this block. */longthis_size;/* Size of this block (does not include this trailer). */longunknown2;longunknown3;longlink;/* Address of trailer block of previous segment. */longunknown5;longunknown6;longunknown7;longunknown8;longunknown9;longunknown10;longunknown11;longunknown12;longunknown13;longunknown14;};#endif /* CRAY2 */#endif /* not CRAY_STACK */#ifdef CRAY2/* Determine a "stack measure" for an arbitrary ADDRESS. I doubt that "lint" will like this much. */staticlongi00afunc(long*address){structstk_statstatus;structstk_trailer*trailer;long*block,size;longresult=0;/* We want to iterate through all of the segments. The first step is to get the stack status structure. We could do this more quickly and more directly, perhaps, by referencing the $LM00 common block, but I know that this works. */STKSTAT(&status);/* Set up the iteration. */trailer=(structstk_trailer*)(status.current_address+status.current_size-15);/* There must be at least one stack segment. Therefore it is a fatal error if "trailer" is null. */if(trailer==0)abort();/* Discard segments that do not contain our argument address. */while(trailer!=0){block=(long*)trailer->this_address;size=trailer->this_size;if(block==0||size==0)abort();trailer=(structstk_trailer*)trailer->link;if((block<=address)&&(address<(block+size)))break;}/* Set the result to the offset in this segment and add the sizes of all predecessor segments. */result=address-block;if(trailer==0){returnresult;}do{if(trailer->this_size<=0)abort();result+=trailer->this_size;trailer=(structstk_trailer*)trailer->link;}while(trailer!=0);/* We are done. Note that if you present a bogus address (one not in any segment), you will get a different number back, formed from subtracting the address of the first block. This is probably not what you want. */return(result);}#else /* not CRAY2 *//* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP. Determine the number of the cell within the stack, given the address of the cell. The purpose of this routine is to linearize, in some sense, stack addresses for alloca. */staticlongi00afunc(longaddress){longstkl=0;longsize,pseg,this_segment,stack;longresult=0;structstack_segment_linkage*ssptr;/* Register B67 contains the address of the end of the current stack segment. If you (as a subprogram) store your registers on the stack and find that you are past the contents of B67, you have overflowed the segment. B67 also points to the stack segment linkage control area, which is what we are really interested in. */stkl=CRAY_STACKSEG_END();ssptr=(structstack_segment_linkage*)stkl;/* If one subtracts 'size' from the end of the segment, one has the address of the first word of the segment. If this is not the first segment, 'pseg' will be nonzero. */pseg=ssptr->sspseg;size=ssptr->sssize;this_segment=stkl-size;/* It is possible that calling this routine itself caused a stack overflow. Discard stack segments which do not contain the target address. */while(!(this_segment<=address&&address<=stkl)){#ifdef DEBUG_I00AFUNCfprintf(stderr,"%011o %011o %011o\n",this_segment,address,stkl);#endifif(pseg==0)break;stkl=stkl-pseg;ssptr=(structstack_segment_linkage*)stkl;size=ssptr->sssize;pseg=ssptr->sspseg;this_segment=stkl-size;}result=address-this_segment;/* If you subtract pseg from the current end of the stack, you get the address of the previous stack segment's end. This seems a little convoluted to me, but I'll bet you save a cycle somewhere. */while(pseg!=0){#ifdef DEBUG_I00AFUNCfprintf(stderr,"%011o %011o\n",pseg,size);#endifstkl=stkl-pseg;ssptr=(structstack_segment_linkage*)stkl;size=ssptr->sssize;pseg=ssptr->sspseg;result+=size;}return(result);}#endif /* not CRAY2 */#endif /* CRAY */#endif /* no alloca */#endif /* not GCC version 2 */