diff --git a/Zend/Optimizer/dce.c b/Zend/Optimizer/dce.c index 347d71300e324..4aca34c943ca7 100644 --- a/Zend/Optimizer/dce.c +++ b/Zend/Optimizer/dce.c @@ -523,7 +523,7 @@ static inline bool may_throw_dce_exception(const zend_op *opline) { return opline->opcode == ZEND_ADD_ARRAY_ELEMENT && opline->op2_type == IS_UNUSED; } -int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, bool reorder_dtor_effects) { +int dce_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *optimizer_ctx, zend_ssa *ssa, bool reorder_dtor_effects) { int i; zend_ssa_phi *phi; int removed_ops = 0; @@ -536,20 +536,17 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, bool reorder_d ctx.op_array = op_array; ctx.reorder_dtor_effects = reorder_dtor_effects; + void *checkpoint = zend_arena_checkpoint(optimizer_ctx->arena); /* We have no dedicated phi vector, so we use the whole ssa var vector instead */ ctx.instr_worklist_len = zend_bitset_len(op_array->last); - ctx.instr_worklist = alloca(sizeof(zend_ulong) * ctx.instr_worklist_len); - memset(ctx.instr_worklist, 0, sizeof(zend_ulong) * ctx.instr_worklist_len); + ctx.instr_worklist = zend_arena_calloc(&optimizer_ctx->arena, ctx.instr_worklist_len, sizeof(zend_ulong)); ctx.phi_worklist_len = zend_bitset_len(ssa->vars_count); - ctx.phi_worklist = alloca(sizeof(zend_ulong) * ctx.phi_worklist_len); - memset(ctx.phi_worklist, 0, sizeof(zend_ulong) * ctx.phi_worklist_len); - ctx.phi_worklist_no_val = alloca(sizeof(zend_ulong) * ctx.phi_worklist_len); - memset(ctx.phi_worklist_no_val, 0, sizeof(zend_ulong) * ctx.phi_worklist_len); + ctx.phi_worklist = zend_arena_calloc(&optimizer_ctx->arena, ctx.phi_worklist_len, sizeof(zend_ulong)); + ctx.phi_worklist_no_val = zend_arena_calloc(&optimizer_ctx->arena, ctx.phi_worklist_len, sizeof(zend_ulong)); /* Optimistically assume all instructions and phis to be dead */ - ctx.instr_dead = alloca(sizeof(zend_ulong) * ctx.instr_worklist_len); - memset(ctx.instr_dead, 0, sizeof(zend_ulong) * ctx.instr_worklist_len); - ctx.phi_dead = alloca(sizeof(zend_ulong) * ctx.phi_worklist_len); + ctx.instr_dead = zend_arena_calloc(&optimizer_ctx->arena, ctx.instr_worklist_len, sizeof(zend_ulong)); + ctx.phi_dead = zend_arena_alloc(&optimizer_ctx->arena, ctx.phi_worklist_len * sizeof(zend_ulong)); memset(ctx.phi_dead, 0xff, sizeof(zend_ulong) * ctx.phi_worklist_len); /* Mark non-CV phis as live. Even if the result is unused, we generally cannot remove one @@ -664,5 +661,7 @@ int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, bool reorder_d } } FOREACH_PHI_END(); + zend_arena_release(&optimizer_ctx->arena, checkpoint); + return removed_ops; } diff --git a/Zend/Optimizer/dfa_pass.c b/Zend/Optimizer/dfa_pass.c index 66c001746d799..a103527613137 100644 --- a/Zend/Optimizer/dfa_pass.c +++ b/Zend/Optimizer/dfa_pass.c @@ -1076,7 +1076,7 @@ void zend_dfa_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *ctx } if (ZEND_OPTIMIZER_PASS_14 & ctx->optimization_level) { - if (dce_optimize_op_array(op_array, ssa, 0)) { + if (dce_optimize_op_array(op_array, ctx, ssa, 0)) { remove_nops = 1; } if (zend_dfa_optimize_jmps(op_array, ssa)) { diff --git a/Zend/Optimizer/zend_optimizer_internal.h b/Zend/Optimizer/zend_optimizer_internal.h index 9e295bad73dcb..92410c18bf86b 100644 --- a/Zend/Optimizer/zend_optimizer_internal.h +++ b/Zend/Optimizer/zend_optimizer_internal.h @@ -121,7 +121,7 @@ uint32_t zend_optimizer_classify_function(zend_string *name, uint32_t num_args); void zend_optimizer_migrate_jump(zend_op_array *op_array, zend_op *new_opline, zend_op *opline); void zend_optimizer_shift_jump(zend_op_array *op_array, zend_op *opline, uint32_t *shiftlist); int sccp_optimize_op_array(zend_optimizer_ctx *ctx, zend_op_array *op_array, zend_ssa *ssa, zend_call_info **call_map); -int dce_optimize_op_array(zend_op_array *op_array, zend_ssa *ssa, bool reorder_dtor_effects); +int dce_optimize_op_array(zend_op_array *op_array, zend_optimizer_ctx *optimizer_ctx, zend_ssa *ssa, bool reorder_dtor_effects); zend_result zend_ssa_escape_analysis(const zend_script *script, zend_op_array *op_array, zend_ssa *ssa); typedef void (*zend_op_array_func_t)(zend_op_array *, void *context); diff --git a/Zend/zend_portability.h b/Zend/zend_portability.h index 6ad9f1b1db2f9..d36d4a663ab8b 100644 --- a/Zend/zend_portability.h +++ b/Zend/zend_portability.h @@ -63,10 +63,6 @@ #include -#if HAVE_ALLOCA_H && !defined(_ALLOCA_H) -# include -#endif - #if defined(ZEND_WIN32) && !defined(__clang__) #include #endif @@ -181,6 +177,9 @@ # define ZEND_EXTENSIONS_SUPPORT 0 #endif +#if defined(HAVE_ALLOCA_H) && !defined(_ALLOCA_H) +# include +#endif /* AIX requires this to be the first thing in the file. */ #ifndef __GNUC__ # ifndef HAVE_ALLOCA_H @@ -194,6 +193,25 @@ char *alloca(); # endif #endif +#if !ZEND_DEBUG && (defined(HAVE_ALLOCA) || (defined (__GNUC__) && __GNUC__ >= 2)) && !(defined(ZTS) && defined(HPUX)) && !defined(DARWIN) +# define ZEND_ALLOCA_MAX_SIZE (32 * 1024) +# define ALLOCA_FLAG(name) \ + bool name; +# define SET_ALLOCA_FLAG(name) \ + name = true +# define do_alloca_ex(size, limit, use_heap) \ + ((use_heap = (UNEXPECTED((size) > (limit)))) ? emalloc(size) : alloca(size)) +# define do_alloca(size, use_heap) \ + do_alloca_ex(size, ZEND_ALLOCA_MAX_SIZE, use_heap) +# define free_alloca(p, use_heap) \ + do { if (UNEXPECTED(use_heap)) efree(p); } while (0) +#else +# define ALLOCA_FLAG(name) +# define SET_ALLOCA_FLAG(name) +# define do_alloca(p, use_heap) emalloc(p) +# define free_alloca(p, use_heap) efree(p) +#endif + #if ZEND_GCC_VERSION >= 2096 || __has_attribute(__malloc__) # define ZEND_ATTRIBUTE_MALLOC __attribute__ ((__malloc__)) #else @@ -345,25 +363,6 @@ char *alloca(); # define XtOffsetOf(s_type, field) offsetof(s_type, field) #endif -#if (defined(HAVE_ALLOCA) || (defined (__GNUC__) && __GNUC__ >= 2)) && !(defined(ZTS) && defined(HPUX)) && !defined(DARWIN) -# define ZEND_ALLOCA_MAX_SIZE (32 * 1024) -# define ALLOCA_FLAG(name) \ - bool name; -# define SET_ALLOCA_FLAG(name) \ - name = 1 -# define do_alloca_ex(size, limit, use_heap) \ - ((use_heap = (UNEXPECTED((size) > (limit)))) ? emalloc(size) : alloca(size)) -# define do_alloca(size, use_heap) \ - do_alloca_ex(size, ZEND_ALLOCA_MAX_SIZE, use_heap) -# define free_alloca(p, use_heap) \ - do { if (UNEXPECTED(use_heap)) efree(p); } while (0) -#else -# define ALLOCA_FLAG(name) -# define SET_ALLOCA_FLAG(name) -# define do_alloca(p, use_heap) emalloc(p) -# define free_alloca(p, use_heap) efree(p) -#endif - #ifdef HAVE_SIGSETJMP # define SETJMP(a) sigsetjmp(a, 0) # define LONGJMP(a,b) siglongjmp(a, b) diff --git a/configure.ac b/configure.ac index 63513b7d800ea..5a24b52800047 100644 --- a/configure.ac +++ b/configure.ac @@ -1610,7 +1610,7 @@ PHP_INSTALL_HEADERS([Zend/Optimizer], [ \ PHP_ADD_SOURCES(TSRM, TSRM.c, -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) PHP_ADD_SOURCES(main, main.c snprintf.c spprintf.c \ - fopen_wrappers.c alloca.c php_scandir.c \ + fopen_wrappers.c php_scandir.c \ php_ini_builder.c \ php_ini.c SAPI.c rfc1867.c php_content_types.c strlcpy.c \ strlcat.c explicit_bzero.c reentrancy.c php_variables.c php_ticks.c \ diff --git a/ext/standard/crypt_sha256.c b/ext/standard/crypt_sha256.c index 4ba4f6c3dd831..5083ee4fc92f0 100644 --- a/ext/standard/crypt_sha256.c +++ b/ext/standard/crypt_sha256.c @@ -10,7 +10,6 @@ #ifdef PHP_WIN32 # define __alignof__ __alignof -# define alloca _alloca #else # ifndef HAVE_ALIGNOF # include @@ -370,16 +369,23 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX); key_len = strlen(key); + char *tmp_key = NULL; + ALLOCA_FLAG(use_heap_key); + char *tmp_salt = NULL; + ALLOCA_FLAG(use_heap_salt); + + SET_ALLOCA_FLAG(use_heap_key); + SET_ALLOCA_FLAG(use_heap_salt); if ((key - (char *) 0) % __alignof__ (uint32_t) != 0) { - char *tmp = (char *) alloca(key_len + __alignof__(uint32_t)); - key = copied_key = memcpy(tmp + __alignof__(uint32_t) - (tmp - (char *) 0) % __alignof__(uint32_t), key, key_len); + tmp_key = (char *) do_alloca(key_len + __alignof__(uint32_t), use_heap_key); + key = copied_key = memcpy(tmp_key + __alignof__(uint32_t) - (tmp_key - (char *) 0) % __alignof__(uint32_t), key, key_len); } if ((salt - (char *) 0) % __alignof__(uint32_t) != 0) { - char *tmp = (char *) alloca(salt_len + 1 + __alignof__(uint32_t)); + tmp_salt = (char *) do_alloca(salt_len + 1 + __alignof__(uint32_t), use_heap_salt); salt = copied_salt = - memcpy(tmp + __alignof__(uint32_t) - (tmp - (char *) 0) % __alignof__ (uint32_t), salt, salt_len); + memcpy(tmp_salt + __alignof__(uint32_t) - (tmp_salt - (char *) 0) % __alignof__ (uint32_t), salt, salt_len); copied_salt[salt_len] = 0; } @@ -443,7 +449,8 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b sha256_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence P. */ - cp = p_bytes = alloca(key_len); + ALLOCA_FLAG(use_heap_p_bytes); + cp = p_bytes = do_alloca(key_len, use_heap_p_bytes); for (cnt = key_len; cnt >= 32; cnt -= 32) { cp = __php_mempcpy((void *)cp, (const void *)temp_result, 32); } @@ -461,7 +468,8 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b sha256_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence S. */ - cp = s_bytes = alloca(salt_len); + ALLOCA_FLAG(use_heap_s_bytes); + cp = s_bytes = do_alloca(salt_len, use_heap_s_bytes); for (cnt = salt_len; cnt >= 32; cnt -= 32) { cp = __php_mempcpy(cp, temp_result, 32); } @@ -571,6 +579,14 @@ char * php_sha256_crypt_r(const char *key, const char *salt, char *buffer, int b if (copied_salt != NULL) { ZEND_SECURE_ZERO(copied_salt, salt_len); } + if (tmp_key != NULL) { + free_alloca(tmp_key, use_heap_key); + } + if (tmp_salt != NULL) { + free_alloca(tmp_salt, use_heap_salt); + } + free_alloca(p_bytes, use_heap_p_bytes); + free_alloca(s_bytes, use_heap_s_bytes); return buffer; } diff --git a/ext/standard/crypt_sha512.c b/ext/standard/crypt_sha512.c index a7696d63f7e84..caeeff750f6ce 100644 --- a/ext/standard/crypt_sha512.c +++ b/ext/standard/crypt_sha512.c @@ -9,7 +9,6 @@ #include #ifdef PHP_WIN32 # define __alignof__ __alignof -# define alloca _alloca #else # ifndef HAVE_ALIGNOF # include @@ -404,16 +403,23 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX); key_len = strlen(key); + char *tmp_key = NULL; + ALLOCA_FLAG(use_heap_key); + char *tmp_salt = NULL; + ALLOCA_FLAG(use_heap_salt); + + SET_ALLOCA_FLAG(use_heap_key); + SET_ALLOCA_FLAG(use_heap_salt); if ((key - (char *) 0) % __alignof__ (uint64_t) != 0) { - char *tmp = (char *) alloca (key_len + __alignof__ (uint64_t)); + tmp_key = (char *) do_alloca(key_len + __alignof__ (uint64_t), use_heap_key); key = copied_key = - memcpy(tmp + __alignof__(uint64_t) - (tmp - (char *) 0) % __alignof__(uint64_t), key, key_len); + memcpy(tmp_key + __alignof__(uint64_t) - (tmp_key - (char *) 0) % __alignof__(uint64_t), key, key_len); } if ((salt - (char *) 0) % __alignof__ (uint64_t) != 0) { - char *tmp = (char *) alloca(salt_len + 1 + __alignof__(uint64_t)); - salt = copied_salt = memcpy(tmp + __alignof__(uint64_t) - (tmp - (char *) 0) % __alignof__(uint64_t), salt, salt_len); + tmp_salt = (char *) do_alloca(salt_len + 1 + __alignof__(uint64_t), use_heap_salt); + salt = copied_salt = memcpy(tmp_salt + __alignof__(uint64_t) - (tmp_salt - (char *) 0) % __alignof__(uint64_t), salt, salt_len); copied_salt[salt_len] = 0; } @@ -477,7 +483,8 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) sha512_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence P. */ - cp = p_bytes = alloca(key_len); + ALLOCA_FLAG(use_heap_p_bytes); + cp = p_bytes = do_alloca(key_len, use_heap_p_bytes); for (cnt = key_len; cnt >= 64; cnt -= 64) { cp = __php_mempcpy((void *) cp, (const void *)temp_result, 64); } @@ -496,7 +503,8 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) sha512_finish_ctx(&alt_ctx, temp_result); /* Create byte sequence S. */ - cp = s_bytes = alloca(salt_len); + ALLOCA_FLAG(use_heap_s_bytes); + cp = s_bytes = do_alloca(salt_len, use_heap_s_bytes); for (cnt = salt_len; cnt >= 64; cnt -= 64) { cp = __php_mempcpy(cp, temp_result, 64); } @@ -618,6 +626,14 @@ php_sha512_crypt_r(const char *key, const char *salt, char *buffer, int buflen) if (copied_salt != NULL) { ZEND_SECURE_ZERO(copied_salt, salt_len); } + if (tmp_key != NULL) { + free_alloca(tmp_key, use_heap_key); + } + if (tmp_salt != NULL) { + free_alloca(tmp_salt, use_heap_salt); + } + free_alloca(p_bytes, use_heap_p_bytes); + free_alloca(s_bytes, use_heap_s_bytes); return buffer; } diff --git a/main/alloca.c b/main/alloca.c deleted file mode 100644 index 9c8d458189abe..0000000000000 --- a/main/alloca.c +++ /dev/null @@ -1,486 +0,0 @@ -/* 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 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. */ - -#include - -#if !HAVE_ALLOCA - -#include -#include - -#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_DIRECTION -you -lose --- must know STACK_DIRECTION at compile-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) -long i00afunc (); -#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg)) -#else -#define ADDRESS_FUNCTION(arg) &(arg) -#endif - -#if __STDC__ -typedef void *pointer; -#else -typedef char *pointer; -#endif - -#ifndef NULL -#define NULL 0 -#endif - -/* 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. */ - -static int stack_dir; /* 1 or -1 once known. */ -#define STACK_DIR stack_dir - -static void -find_stack_direction () -{ - static char *addr = NULL; /* Address of first `dummy', once known. */ - auto char dummy; /* 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. */ - else - stack_dir = -1; /* Stack grew downward. */ - } -} - -#endif /* STACK_DIRECTION == 0 */ - -/* An "alloca header" is used to: - (a) chain together all alloca'd 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) -#endif - -typedef union hdr -{ - char align[ALIGN_SIZE]; /* To force sizeof(header). */ - struct - { - union hdr *next; /* For chaining headers. */ - char *deep; /* For stack depth measure. */ - } h; -} header; - -static header *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. */ - -pointer -alloca (size) - size_t size; -{ - auto char probe; /* Probes stack depth: */ - register char *depth = ADDRESS_FUNCTION (probe); - -#if STACK_DIRECTION == 0 - if (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. */ - - { - register header *hp; /* Traverses linked list. */ - -#ifdef emacs - BLOCK_INPUT; -#endif - - for (hp = last_alloca_header; hp != NULL;) - if ((STACK_DIR > 0 && hp->h.deep > depth) - || (STACK_DIR < 0 && hp->h.deep < depth)) - { - register header *np = hp->h.next; - - free ((pointer) hp); /* Collect garbage. */ - - hp = np; /* -> next header. */ - } - else - break; /* Rest are not deeper. */ - - last_alloca_header = hp; /* -> last valid storage. */ - -#ifdef emacs - UNBLOCK_INPUT; -#endif - } - - if (size == 0) - return NULL; /* No allocation required. */ - - /* Allocate combined header + user data storage. */ - - { - register pointer new = 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 -#endif - -#ifndef CRAY_STACK -#define CRAY_STACK -#ifndef CRAY2 -/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */ -struct stack_control_header - { - long shgrow:32; /* Number of times stack has grown. */ - long shaseg:32; /* Size of increments to stack. */ - long shhwm:32; /* High water mark of stack. */ - long shsize: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. */ - -struct stack_segment_linkage - { - long ss[0200]; /* 0200 overflow words. */ - long sssize:32; /* Number of words in this segment. */ - long ssbase:32; /* Offset to stack base. */ - long:32; - long sspseg:32; /* Offset to linkage control of previous - segment of stack. */ - long:32; - long sstcpt:32; /* Pointer to task common address block. */ - long sscsnm; /* Private control structure number for - microtasking. */ - long ssusr1; /* Reserved for user. */ - long ssusr2; /* Reserved for user. */ - long sstpid; /* Process ID for pid based multi-tasking. */ - long ssgvup; /* Pointer to multitasking thread give up. */ - long sscray[7]; /* Reserved for Cray Research. */ - long ssa0; - long ssa1; - long ssa2; - long ssa3; - long ssa4; - long ssa5; - long ssa6; - long ssa7; - long sss0; - long sss1; - long sss2; - long sss3; - long sss4; - long sss5; - long sss6; - long sss7; - }; - -#else /* CRAY2 */ -/* The following structure defines the vector of words - returned by the STKSTAT library routine. */ -struct stk_stat - { - long now; /* Current total stack size. */ - long maxc; /* Amount of contiguous space which would - be required to satisfy the maximum - stack demand to date. */ - long high_water; /* Stack high-water mark. */ - long overflows; /* Number of stack overflow ($STKOFEN) calls. */ - long hits; /* Number of internal buffer hits. */ - long extends; /* Number of block extensions. */ - long stko_mallocs; /* Block allocations by $STKOFEN. */ - long underflows; /* Number of stack underflow calls ($STKRETN). */ - long stko_free; /* Number of deallocations by $STKRETN. */ - long stkm_free; /* Number of deallocations by $STKMRET. */ - long segments; /* Current number of stack segments. */ - long maxs; /* Maximum number of stack segments so far. */ - long pad_size; /* Stack pad size. */ - long current_address; /* Current stack segment address. */ - long current_size; /* Current stack segment size. This - number is actually corrupted by STKSTAT to - include the fifteen word trailer area. */ - long initial_address; /* Address of initial segment. */ - long initial_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. */ - -struct stk_trailer - { - long this_address; /* Address of this block. */ - long this_size; /* Size of this block (does not include - this trailer). */ - long unknown2; - long unknown3; - long link; /* Address of trailer block of previous - segment. */ - long unknown5; - long unknown6; - long unknown7; - long unknown8; - long unknown9; - long unknown10; - long unknown11; - long unknown12; - long unknown13; - long unknown14; - }; - -#endif /* CRAY2 */ -#endif /* not CRAY_STACK */ - -#ifdef CRAY2 -/* Determine a "stack measure" for an arbitrary ADDRESS. - I doubt that "lint" will like this much. */ - -static long -i00afunc (long *address) -{ - struct stk_stat status; - struct stk_trailer *trailer; - long *block, size; - long result = 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 = (struct stk_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 = (struct stk_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) - { - return result; - } - - do - { - if (trailer->this_size <= 0) - abort (); - result += trailer->this_size; - trailer = (struct stk_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. */ - -static long -i00afunc (long address) -{ - long stkl = 0; - - long size, pseg, this_segment, stack; - long result = 0; - - struct stack_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 = (struct stack_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_I00AFUNC - fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl); -#endif - if (pseg == 0) - break; - stkl = stkl - pseg; - ssptr = (struct stack_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_I00AFUNC - fprintf (stderr, "%011o %011o\n", pseg, size); -#endif - stkl = stkl - pseg; - ssptr = (struct stack_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 */ -#endif /* HAVE_ALLOCA */