pike.git / src / stralloc.c

version» Context lines:

pike.git/src/stralloc.c:11:   #include "pike_macros.h"   #include "pike_memory.h"   #include "pike_error.h"   #include "gc.h"   #include "stuff.h"   #include "bignum.h"   #include "interpret.h"   #include "block_alloc.h"   #include "operators.h"   #include "pike_float.h" + #include "block_allocator.h"   #include "port.h"      #include <errno.h>   #include <float.h>   #include <ctype.h>   #include <math.h>    - /* #define STRALLOC_USE_PRIMES */ -  - #ifdef STRALLOC_USE_PRIMES -  - #define SET_HSIZE(X) htable_size=hashprimes[(X)] - #define HMODULO(X) ((X) % htable_size) -  - #else -  +    #define SET_HSIZE(X) htable_mask=(htable_size=(1<<(X)))-1   #define HMODULO(X) ((X) & (htable_mask))      static unsigned INT32 htable_mask;    - #endif -  +    #if (SIZEOF_LONG == 4) && defined(_LP64)   /* Kludge for gcc and the system header files not using the same model... */   #undef LONG_MIN   #undef LONG_MAX   #undef ULONG_MAX   #define LONG_MIN INT_MIN   #define LONG_MAX INT_MAX   #define ULONG_MAX UINT_MAX   #endif   
pike.git/src/stralloc.c:73:   }while(0)      #define UNLOCK_BUCKET(HVAL) do { \    size_t hval__=(HVAL); \    mt_unlock(BUCKETLOCK(hval__)); \   }while(0)      #else   #define LOCK_BUCKET(HVAL)   #define UNLOCK_BUCKET(HVAL) - #endif + #endif /* PIKE_RUN_UNLOCKED */    - #define BEGIN_HASH_SIZE 997 - #define MAX_AVG_LINK_LENGTH 2 + #define BEGIN_HASH_SIZE 1024      /* Experimental dynamic hash length */   #ifndef HASH_PREFIX   static unsigned int HASH_PREFIX=64;   static unsigned int need_more_hash_prefix_depth=0;   #endif      /* Force a new hashkey to be generated early during init. */   static unsigned int need_new_hashkey_depth=0xffff;   static size_t hashkey = 0xa55aa55a;
pike.git/src/stralloc.c:100:   static struct pike_string **base_table=0;   static unsigned INT32 num_strings=0;   PMOD_EXPORT struct pike_string *empty_pike_string = 0;      /*** Main string hash function ***/      #define StrHash(s,len) low_do_hash(s,len,0)   #define low_do_hash(STR,LEN,SHIFT) low_hashmem( (STR), (LEN)<<(SHIFT), HASH_PREFIX<<(SHIFT), hashkey )   #define do_hash(STR) low_do_hash(STR->str,STR->len,STR->size_shift)    + /* Returns true if str could contain n. */ + PMOD_EXPORT int string_range_contains( struct pike_string *str, int n ) + { +  INT32 min, max; +  check_string_range( str, 1, &min, &max ); +  if( n >= min && n <= max ) +  return 1; +  return 0; + }    -  + /* Returns true if str2 could be in str1. */ + PMOD_EXPORT int string_range_contains_string( struct pike_string *str1, +  struct pike_string *str2 ) + { +  INT32 max1, min1; +  INT32 max2, min2; +  if( !str2->len ) return 1; /* Empty string is part of every string */ +  check_string_range( str1, 1, &min1, &max1 ); +  check_string_range( str2, 1, &min2, &max2 ); +  if( (min2 < min1) || (max2 > max1) ) +  { +  if( (str1->flags & STRING_CONTENT_CHECKED) == +  (str2->flags & STRING_CONTENT_CHECKED) ) +  return 0; +  /* fallback to simple size-shift check. */ +  return str1->size_shift >= str2->size_shift; +  } +  return 1; + } +  + PMOD_EXPORT void check_string_range( struct pike_string *str, +  int loose, +  INT32 *min, INT32 *max ) + { +  INT32 s_min = MAX_INT32; +  INT32 s_max = MIN_INT32; +  ssize_t i; +  +  if( loose || ((str->flags & STRING_CONTENT_CHECKED ) && (!str->size_shift || !max)) ) +  { +  if( str->flags & STRING_CONTENT_CHECKED ) +  { +  s_min = str->min; +  s_max = str->max; +  +  if( str->size_shift ) +  { +  s_min <<= 8 * str->size_shift; +  s_max <<= 8 * str->size_shift; +  if( s_min ) +  s_min -= (1<<(8*str->size_shift))-1; +  s_max += str->size_shift == 1 ? 255 : 65535; +  } +  } +  else +  { +  switch( str->size_shift ) +  { +  case 2: s_min = MIN_INT32; s_max=MAX_INT32; break; +  case 1: s_min = 0; s_max = 65535; break; +  case 0: s_min = 0; s_max = 255; break; +  } +  } +  } +  else +  { +  str->flags |= STRING_CONTENT_CHECKED; +  +  switch( str->size_shift ) +  { +  case 0: +  { +  p_wchar0 *p = (p_wchar0*)str->str; +  int upper = 0, lower = 0; +  for( i=0; i<str->len; i++,p++ ) +  { +  /* For 7-bit strings it's easy to check for +  * lower/uppercase, so do that here as well. +  */ +  if( *p >= 'A' && *p <= 'Z') upper++; +  if( *p >= 'a' && *p <= 'z') lower++; +  +  if( *p > s_max ) s_max = *p; +  if( *p < s_min ) s_min = *p; +  } +  +  if( s_max < 128 ) +  { +  if( upper && !lower ) +  str->flags |= STRING_IS_UPPERCASE; +  if( lower && !upper ) +  str->flags |= STRING_IS_LOWERCASE; +  if( !lower && !upper ) +  str->flags |= STRING_IS_LOWERCASE|STRING_IS_UPPERCASE; +  } +  } +  str->min = s_min; +  str->max = s_max; +  break; +  +  case 1: +  { +  p_wchar1 *p = (p_wchar1*)str->str; +  for( i=0; i<str->len; i++,p++ ) +  { +  if( *p > s_max ) s_max = *p; +  if( *p < s_min ) s_min = *p; +  } +  } +  str->min = (s_min+255) >> 8; +  str->max = (s_max+255) >> 8; +  break; +  +  case 2: +  { +  p_wchar2 *p = (p_wchar2*)str->str; +  for( i=0; i<str->len; i++,p++ ) +  { +  if( *p > s_max ) s_max = *p; +  if( *p < s_min ) s_min = *p; +  } +  } +  str->min = (s_min+65535) >> 16; +  str->max = (s_max+65535) >> 16; +  break; +  } +  } +  if( min ) *min = s_min; +  if( max ) *max = s_max; + } +    static INLINE int find_magnitude1(const p_wchar1 *s, ptrdiff_t len)   {    const p_wchar1 *e=s+len;    while(s<e)    if(*s++>=256)    return 1;    return 0;   }      static INLINE int find_magnitude2(const p_wchar2 *s, ptrdiff_t len)
pike.git/src/stralloc.c:186: Inside #if defined(PIKE_DEBUG)
   pos, s->len-1);    } else {    Pike_fatal("Attempt to index the empty string with %"PRINTPTRDIFFT"d.\n",    pos);    }    }       if(pos == s->len && value)    Pike_fatal("string zero termination foul!\n");   #endif -  switch(s->size_shift) -  { -  case 0: STR0(s)[pos]=value; break; -  case 1: STR1(s)[pos]=value; break; -  case 2: STR2(s)[pos]=value; break; - #ifdef PIKE_DEBUG -  default: -  Pike_fatal("Illegal shift size!\n"); - #endif -  } +     s->flags |= STRING_NOT_HASHED; -  +  +  if(!s->size_shift) +  STR0(s)[pos]=value; +  else if(s->size_shift == 1) +  STR1(s)[pos]=value; +  else +  STR2(s)[pos]=value;   }      #ifdef PIKE_DEBUG   PMOD_EXPORT struct pike_string *debug_check_size_shift(struct pike_string *a,    int shift)   {    if(a->size_shift != shift)    Pike_fatal("Wrong STRX macro used!\n");    return a;   }
pike.git/src/stralloc.c:343:   static int wrong_hash(struct pike_string *s)   {    return s->hval != do_hash(s);   }   static int improper_zero_termination(struct pike_string *s)   {    return index_shared_string(s,s->len);   }   #else   #define locate_problem(X) - #endif + #endif /* PIKE_DEBUG */      /* Find a string in the shared string table.    * This assumes that the string is minimized!!!!    */ - static INLINE struct pike_string *internal_findstring(const char *s, + static struct pike_string *internal_findstring(const char *s,    ptrdiff_t len,    int size_shift,    size_t hval)   { -  struct pike_string *curr,**prev, **base; +  struct pike_string *curr; + //,**prev, **base;    unsigned int depth=0;   #ifndef HASH_PREFIX    unsigned int prefix_depth=0;   #endif    size_t h;    LOCK_BUCKET(hval);    h=HMODULO(hval); -  for(base = prev = base_table + h;( curr=*prev ); prev=&curr->next) +  for(curr = base_table[h]; curr; curr = curr->next)    {   #ifdef PIKE_DEBUG    if(curr->refs<1)    {    debug_dump_pike_string(curr, 70);    locate_problem(has_zero_refs);    Pike_fatal("String with no references.\n");    }   #endif    debug_malloc_touch(curr);    -  if (hval == curr->hval && -  len==curr->len && -  size_shift==curr->size_shift && +  if ( len == curr->len && +  size_shift == curr->size_shift && +  hval == curr->hval &&    ( curr->str == s ||    !MEMCMP(curr->str, s,len<<size_shift))) /* found it */    { -  *prev = curr->next; -  curr->next = *base; -  *base = curr; +  /* *prev = curr->next; */ +  /* curr->next = *base; */ +  /* *base = curr; */    UNLOCK_BUCKET(hval);    return curr; /* pointer to string */    }    depth++;   #ifndef HASH_PREFIX    if (curr->len > (ptrdiff_t)HASH_PREFIX)    prefix_depth++;   #endif    }    if (depth > need_new_hashkey_depth) {
pike.git/src/stralloc.c:530:      /* Allocation of strings */      /* Without the str at the end, to get the size of the header. */   struct pike_string_hdr {    PIKE_STRING_CONTENTS;   };      /* Allocate some fixed string sizes with BLOCK_ALLOC. */    - /* Use the BLOCK_ALLOC() stuff for short strings */ -  - #undef INIT_BLOCK - #ifdef ATOMIC_SVALUE - #define INIT_BLOCK(NEW_STR) do { \ -  (NEW_STR)->ref_type = T_STRING; \ -  (NEW_STR)->refs = 0; \ -  add_ref((NEW_STR)); \ -  (NEW_STR)->flags = \ -  STRING_NOT_HASHED|STRING_NOT_SHARED|STRING_IS_SHORT; \ -  } while(0) - #else /* !ATOMIC_SVALUE */ - #define INIT_BLOCK(NEW_STR) do { \ -  (NEW_STR)->refs = 0; \ -  add_ref((NEW_STR)); \ -  (NEW_STR)->flags = \ -  STRING_NOT_HASHED|STRING_NOT_SHARED|STRING_IS_SHORT; \ -  } while(0) - #endif -  +    #define SHORT_STRING_BLOCK 256 - #define SHORT_STRING_THRESHOLD 15 /* % 4 === -1 */ +     -  + #define SHORT_STRING_THRESHOLD 15 +    struct short_pike_string0 {    PIKE_STRING_CONTENTS;    p_wchar0 str[SHORT_STRING_THRESHOLD+1];   };    - struct short_pike_string1 { -  PIKE_STRING_CONTENTS; -  p_wchar1 str[SHORT_STRING_THRESHOLD+1]; - }; + static struct block_allocator string_allocator = BA_INIT(sizeof(struct short_pike_string0), SHORT_STRING_BLOCK);    - struct short_pike_string2 { -  PIKE_STRING_CONTENTS; -  p_wchar2 str[SHORT_STRING_THRESHOLD+1]; - }; -  - BLOCK_ALLOC(short_pike_string0, SHORT_STRING_BLOCK) - BLOCK_ALLOC(short_pike_string1, SHORT_STRING_BLOCK) - BLOCK_ALLOC(short_pike_string2, SHORT_STRING_BLOCK) -  - #undef INIT_BLOCK - #define INIT_BLOCK(x) -  - #define really_free_short_pike_string(s) do { \ -  if (!s->size_shift) { \ -  really_free_short_pike_string0((struct short_pike_string0 *)s); \ -  } else if (s->size_shift == 1) { \ -  really_free_short_pike_string1((struct short_pike_string1 *)s); \ -  DO_IF_DEBUG( \ -  } else if (s->size_shift != 2) { \ -  Pike_fatal("Unsupported string shift: %d\n", s->size_shift); \ -  ) \ -  } else { \ -  really_free_short_pike_string2((struct short_pike_string2 *)s); \ -  } \ -  } while(0) -  +    #define free_unlinked_pike_string(s) do { \ -  if (s->len <= SHORT_STRING_THRESHOLD) { \ -  really_free_short_pike_string(s); \ +  if (s->flags & STRING_IS_SHORT) { \ +  ba_free(&string_allocator, s); \    } else { \    debug_free((char *)s, DMALLOC_LOCATION(), 1); \    } \    } while(0)      /* note that begin_shared_string expects the _exact_ size of the string,    * not the maximum size    */   PMOD_EXPORT struct pike_string *debug_begin_shared_string(size_t len)   {    struct pike_string *t;   #ifdef PIKE_DEBUG    extern int d_flag;    if(d_flag>10)    verify_shared_strings_tables();   #endif -  if (len <= SHORT_STRING_THRESHOLD) { -  t=(struct pike_string *)alloc_short_pike_string0(); -  } else { +  if (len <= SHORT_STRING_THRESHOLD) +  { +  t=(struct pike_string *)ba_alloc(&string_allocator); +  t->flags = STRING_NOT_HASHED | STRING_NOT_SHARED | STRING_IS_SHORT; +  } else +  {    t=(struct pike_string *)xalloc(len + 1 + sizeof(struct pike_string_hdr));    t->flags = STRING_NOT_HASHED | STRING_NOT_SHARED;    }   #ifdef ATOMIC_SVALUE    t->ref_type = T_STRING;   #endif    t->refs = 0;    add_ref(t); /* For DMALLOC */    t->str[len]=0;    t->len=len; -  + /* t->min = t->max = 0; */    t->size_shift=0;    DO_IF_DEBUG(t->next = NULL);    return t;   }      static void link_pike_string(struct pike_string *s, size_t hval)   {    size_t h;      #ifdef PIKE_DEBUG
pike.git/src/stralloc.c:649:       LOCK_BUCKET(hval);    h=HMODULO(hval);    s->next = base_table[h];    base_table[h] = s;    s->hval=hval;    s->flags &= ~(STRING_NOT_HASHED|STRING_NOT_SHARED);    num_strings++;    UNLOCK_BUCKET(hval);    -  if(num_strings > MAX_AVG_LINK_LENGTH * htable_size) { +  if(num_strings > htable_size) {    stralloc_rehash();    }      #ifndef HASH_PREFIX    /* These heuristics might require tuning! /Hubbe */ -  if((need_more_hash_prefix_depth > MAX_AVG_LINK_LENGTH * 4) || -  (need_new_hashkey_depth > MAX_AVG_LINK_LENGTH * 128)) +  if((need_more_hash_prefix_depth > 4) || +  (need_new_hashkey_depth > 128))    {    /* Changed heuristic 2005-01-17:    *    * Increase HASH_PREFIX if there's some bucket containing -  * more than MAX_AVG_LINK_LENGTH * 4 strings that are longer +  * more than 4 strings that are longer    * than HASH_PREFIX.    * /grubba    *    * Changed heuristic 2011-12-30:    *    * Generate a new hash key if there's some bucket containing -  * more than MAX_AVG_LINK_LENGTH * 16 strings. This ought to +  * more than 16 strings. This ought to    * suffice to alleviate the #hashdos vulnerability.    *    * /grubba    */       /* This could in theory have a pretty ugly complexity    * /Hubbe    */      #ifdef PIKE_RUN_UNLOCKED    mt_lock(bucket_locks); -  if(need_more_hash_prefix_depth <= MAX_AVG_LINK_DEPTH * 4) +  if(need_more_hash_prefix_depth <= 4)    {    /* Someone got here before us */    mt_lock(bucket_locks);    return;    }    for(h=1;h<BUCKET_LOCKS;h++) mt_lock(bucket_locks+h);   #endif       /* A simple mixing function. */    hashkey ^= (hashkey << 5) | (current_time.tv_sec ^ current_time.tv_usec);    -  if (need_more_hash_prefix_depth > MAX_AVG_LINK_LENGTH * 4) { +  if (need_more_hash_prefix_depth > 4) {    HASH_PREFIX=HASH_PREFIX*2;   #if 0    fprintf(stderr, "Doubling HASH_PREFIX to %d and rehashing\n",    HASH_PREFIX);   #endif /* 0 */    }    /* NOTE: No need to update to the correct values, since that will    * be done on demand.    */    need_new_hashkey_depth = 0;
pike.git/src/stralloc.c:726: Inside #if undefined(HASH_PREFIX)
   h2=HMODULO(tmp2->hval);       tmp2->next=base_table[h2]; /* and re-hash */    base_table[h2]=tmp2;    }    }   #ifdef PIKE_RUN_UNLOCKED    for(h=0;h<BUCKET_LOCKS;h++) mt_unlock(bucket_locks + h);   #endif    } - #endif + #endif /* !HASH_PREFIX */   }      PMOD_EXPORT struct pike_string *debug_begin_wide_shared_string(size_t len, int shift)   {    struct pike_string *t = NULL;   #ifdef PIKE_DEBUG    extern int d_flag;    if(d_flag>10)    verify_shared_strings_tables();   #endif -  if (len <= SHORT_STRING_THRESHOLD) { -  if (!shift) { -  t = (struct pike_string *)alloc_short_pike_string0(); -  } else if (shift == 1) { -  t = (struct pike_string *)alloc_short_pike_string1(); +  if ((len<<shift) <= SHORT_STRING_THRESHOLD) {   #ifdef PIKE_DEBUG -  } else if (shift != 2) { +  if (shift > 2)    Pike_fatal("Unsupported string shift: %d\n", shift);   #endif /* PIKE_DEBUG */ -  +  t=(struct pike_string *)ba_alloc(&string_allocator); +  t->flags = STRING_NOT_HASHED|STRING_NOT_SHARED|STRING_IS_SHORT;    } else { -  t = (struct pike_string *)alloc_short_pike_string2(); -  } -  } else { +     t=(struct pike_string *)xalloc(((len + 1)<<shift) +    sizeof(struct pike_string_hdr));    t->flags = STRING_NOT_HASHED|STRING_NOT_SHARED;    }   #ifdef ATOMIC_SVALUE    t->ref_type = T_STRING;   #endif    t->refs = 0;    add_ref(t); /* For DMALLOC */    t->len=len;    t->size_shift=shift;    DO_IF_DEBUG(t->next = NULL);    low_set_index(t,len,0);    return t;   }      PMOD_EXPORT void hash_string(struct pike_string *s)   {    if (!(s->flags & STRING_NOT_HASHED)) return; -  +  /* if( s->len < HASH_PREFIX ) */ +  /* check_string_range( s, 0, 0, 0 ); */    s->hval=do_hash(s);    s->flags &= ~STRING_NOT_HASHED;   }      /*    * This function assumes that the shift size is already the minimum it    * can be.    */   struct pike_string *low_end_shared_string(struct pike_string *s)   {
pike.git/src/stralloc.c:1106: Inside #if defined(PIKE_DEBUG)
   Pike_fatal("Freeing string with %d references.\n", s->refs);    }    if(d_flag > 2 && !(s->flags & STRING_NOT_SHARED))    {    if(s->next == (struct pike_string *)(ptrdiff_t)-1)    Pike_fatal("Freeing shared string again!\n");       if(((ptrdiff_t)s->next) & 1)    Pike_fatal("Freeing shared string again, memory corrupt or other bug!\n");    } -  if ((s->size_shift < 0) || (s->size_shift > 2)) { +  if (s->size_shift > 2) {    Pike_fatal("Freeing string with bad shift (0x%08x); could it be a type?\n",    s->size_shift);    }   #endif    if (!(s->flags & STRING_NOT_SHARED))    unlink_pike_string(s);    if (s->flags & STRING_CLEAR_ON_EXIT) -  MEMSET(s->str, 0, s->len<<s->size_shift); +  guaranteed_memset(s->str, 0, s->len<<s->size_shift);    free_unlinked_pike_string(s);    GC_FREE_SIMPLE_BLOCK(s);   }      void do_really_free_string(struct pike_string *s)   {    if (s)    really_free_string(s);   }   
pike.git/src/stralloc.c:1137:    if(!sub_ref(s))    really_free_string(s);   }         /*    * String table status    */   struct pike_string *add_string_status(int verbose)   { -  dynamic_buffer save_buf; -  char b[200]; +  struct string_builder s; +  init_string_builder(&s, 0);    -  init_buf(&save_buf); -  +     if (verbose)    { -  int allocd_strings=0; -  int allocd_bytes=0; -  int num_distinct_strings=0; -  int bytes_distinct_strings=0; -  ptrdiff_t overhead_bytes = 0; +  long alloced_strings[8] = {0,0,0,0,0,0,0,0}; +  long alloced_bytes[8] = {0,0,0,0,0,0,0,0}; +  long num_distinct_strings[8] = {0,0,0,0,0,0,0,0}; +  long bytes_distinct_strings[8] = {0,0,0,0,0,0,0,0}; +  long overhead_bytes[8] = {0,0,0,0,0,0,0,0};    unsigned INT32 e;    struct pike_string *p;    for(e=0;e<htable_size;e++)    {    LOCK_BUCKET(e);    for(p=base_table[e];p;p=p->next)    { -  num_distinct_strings++; -  bytes_distinct_strings+=DO_ALIGN(p->len,sizeof(void *)); -  allocd_strings+=p->refs; -  allocd_bytes+=p->refs*DO_ALIGN(p->len+3,sizeof(void *)); +  int is_short = (p->len <= SHORT_STRING_THRESHOLD); +  int key = (is_short?0:4) | p->size_shift; +  num_distinct_strings[key]++; +  if (is_short) { +  bytes_distinct_strings[key] += +  DO_ALIGN(SHORT_STRING_THRESHOLD << p->size_shift, sizeof(void *)); +  } else { +  bytes_distinct_strings[key] += +  DO_ALIGN(p->len << p->size_shift, sizeof(void *));    } -  +  alloced_strings[key] += p->refs; +  alloced_bytes[key] += +  p->refs*DO_ALIGN((p->len+3) << p->size_shift,sizeof(void *)); +  }    UNLOCK_BUCKET(e);    } -  overhead_bytes=sizeof(struct pike_string_hdr)*num_distinct_strings; -  my_strcat("\nShared string hash table:\n"); -  my_strcat("-------------------------\t Strings Bytes\n"); +  string_builder_sprintf(&s, +  "\nShared string hash table:\n" +  "-------------------------\n" +  "\n" +  "Type Count Distinct Bytes Actual Overhead %%\n" +  "------------------------------------------------------------\n"); +  for(e = 0; e < 8; e++) { +  int shift = e & 3; +  ptrdiff_t overhead; +  if (!num_distinct_strings[e]) continue; +  if (shift != 3) { +  if (e < 4) { +  string_builder_sprintf(&s, "Short/%-2d ", 8<<shift); +  } else { +  string_builder_sprintf(&s, "Long/%-2d ", 8<<shift); +  }    -  sprintf(b,"Total asked for\t\t\t%8ld %8ld\n", -  (long)allocd_strings, (long)allocd_bytes); -  my_strcat(b); -  sprintf(b,"Strings malloced\t\t%8ld %8ld + %ld overhead\n", -  (long)num_distinct_strings, -  (long)bytes_distinct_strings, -  DO_NOT_WARN((long)overhead_bytes)); -  my_strcat(b); -  sprintf(b, "Space actually required/total string bytes %ld%%\n", -  DO_NOT_WARN((long)((bytes_distinct_strings + overhead_bytes)*100 / -  allocd_bytes))); -  my_strcat(b); +  overhead_bytes[e] = +  DO_NOT_WARN((long)sizeof(struct pike_string_hdr) * +  num_distinct_strings[e]); +  +  alloced_strings[e|3] += alloced_strings[e]; +  alloced_bytes[e|3] += alloced_bytes[e]; +  num_distinct_strings[e|3] += num_distinct_strings[e]; +  bytes_distinct_strings[e|3] += bytes_distinct_strings[e]; +  overhead_bytes[e|3] += overhead_bytes[e]; +  } else { +  if (e < 4) { +  string_builder_sprintf(&s, "Total short"); +  } else { +  string_builder_sprintf(&s, "Total long ");    } -  +  } +  string_builder_sprintf(&s, +  "%8ld %8ld %8ld %8ld %8ld ", +  alloced_strings[e], num_distinct_strings[e], +  alloced_bytes[e], bytes_distinct_strings[e], +  overhead_bytes[e]); +  if (alloced_bytes[e]) { +  string_builder_sprintf(&s, "%4d\n", +  (bytes_distinct_strings[e] + +  overhead_bytes[e]) * 100 / +  alloced_bytes[e]); +  } else { +  string_builder_strcat(&s, " -\n"); +  } +  } +  alloced_strings[7] += alloced_strings[3]; +  alloced_bytes[7] += alloced_bytes[3]; +  num_distinct_strings[7] += num_distinct_strings[3]; +  bytes_distinct_strings[7] += bytes_distinct_strings[3]; +  overhead_bytes[7] += overhead_bytes[3]; +  string_builder_sprintf(&s, +  "------------------------------------------------------------\n" +  "Total %8ld %8ld %8ld %8ld %8ld ", +  alloced_strings[7], num_distinct_strings[7], +  alloced_bytes[7], bytes_distinct_strings[7], +  overhead_bytes[7]); +  if (alloced_bytes[7]) { +  string_builder_sprintf(&s, "%4d\n", +  (bytes_distinct_strings[7] + +  overhead_bytes[7]) * 100 / +  alloced_bytes[7]); +  } else { +  string_builder_strcat(&s, " -\n"); +  } +  }   /*    sprintf(b,"Searches: %ld Average search length: %6.3f\n",    (long)num_str_searches, (double)search_len / num_str_searches);    my_strcat(b);   */ -  return free_buf(&save_buf); +  return finish_string_builder(&s);   }      /*** PIKE_DEBUG ***/   #ifdef PIKE_DEBUG      static long last_stralloc_verify=0;   extern long current_do_debug_cycle;      PMOD_EXPORT void check_string(struct pike_string *s)   {
pike.git/src/stralloc.c:1369: Inside #if defined(PIKE_DEBUG) and #if 0
   for(tmp2=base_table[e];tmp2;tmp2=tmp2->next)    {    if(tmp2 == tmp)    fprintf(stderr,"String found in hashbin %ld (not %ld)\n",    (long)e,    (long)HMODULO(foo->hval));    }    UNLOCK_BUCKET(e);    }    } - #endif + #endif /* 0 */    return tmp;   }      PMOD_EXPORT void debug_dump_pike_string(struct pike_string *s, INT32 max)   {    INT32 e;    fprintf(stderr,"0x%p: %ld refs, len=%ld, size_shift=%d, hval=%lux (%lx)\n",    s,    (long)s->refs,    DO_NOT_WARN((long)s->len),
pike.git/src/stralloc.c:1428: Inside #if defined(PIKE_DEBUG)
   for(p=base_table[e];p;p=p->next) {    debug_dump_pike_string(p, 70);   #ifdef DEBUG_MALLOC    debug_malloc_dump_references (p, 2, 1, 0);   #endif    }    UNLOCK_BUCKET(e);    }   }    - #endif + #endif /* PIKE_DEBUG */         /*** String compare functions ***/      /* does not take locale into account */   int low_quick_binary_strcmp(char *a, ptrdiff_t alen,    char *b, ptrdiff_t blen)   {    int tmp;    if(alen > blen)
pike.git/src/stralloc.c:1627:    return a->len - b->len;    }    }   }      struct pike_string *realloc_unlinked_string(struct pike_string *a,    ptrdiff_t size)   {    struct pike_string *r = NULL;    -  if (a->len <= SHORT_STRING_THRESHOLD) { -  if (size <= SHORT_STRING_THRESHOLD) { +  if (a->flags & STRING_IS_SHORT ) +  { +  if (size <= SHORT_STRING_THRESHOLD/(1<<a->size_shift)) {    /* There's already space enough. */    a->len = size;    low_set_index(a, size, 0);    return a;    } -  } else if (size > SHORT_STRING_THRESHOLD) { +  } else {    r=(struct pike_string *)realloc((char *)a,    sizeof(struct pike_string_hdr)+    ((size+1)<<a->size_shift));    }       if(!r)    {    r=begin_wide_shared_string(size, a->size_shift); -  +  r->flags |= a->flags & ~15; +  r->min = a->min; +  r->max = a->max;    if (a->len <= size) {    MEMCPY(r->str, a->str, a->len<<a->size_shift);    } else {    MEMCPY(r->str, a->str, size<<a->size_shift);    }    free_string(a);    }       r->len=size;    low_set_index(r,size,0);
pike.git/src/stralloc.c:1668:    ptrdiff_t size)   {    struct pike_string *r;    if(a->refs==1)    {    unlink_pike_string(a);    return realloc_unlinked_string(a, size);    }else{    r=begin_wide_shared_string(size,a->size_shift);    MEMCPY(r->str, a->str, a->len<<a->size_shift); +  r->flags |= a->flags & ~15; +  r->min = a->min; +  r->max = a->max;    free_string(a);    return r;    }   }      struct pike_string *new_realloc_shared_string(struct pike_string *a, INT32 size, int shift)   {    struct pike_string *r;    if(shift == a->size_shift) return realloc_shared_string(a,size);       r=begin_wide_shared_string(size,shift);    pike_string_cpy(MKPCHARP_STR(r),a); -  +  r->flags |= (a->flags & ~15); +  r->min = a->min; +  r->max = a->max;    free_string(a);    return r;   }         /* Modify one index in a shared string    * Not suitable for building new strings or changing multiple characters    * within a string!    *    * Phew, this function become complicated when I inserted magic for wide
pike.git/src/stralloc.c:1811:    }          /* We now know that the string has the right character size */    if(a->refs==1)    {    /* One ref - destructive mode */       unlink_pike_string(a);    low_set_index(a, index, c); +  CLEAR_STRING_CHECKED(a);    if((((unsigned int)index) >= HASH_PREFIX) && (index < a->len-8))    {    struct pike_string *old;   #ifdef PIKE_DEBUG    if (wrong_hash(a)) {    Pike_fatal("Broken hash optimization.\n");    }   #endif    /* Doesn't change hash value - sneak it in there */    old = internal_findstring(a->str, a->len, a->size_shift, a->hval);
pike.git/src/stralloc.c:1842:    }else{    struct pike_string *r;    r=begin_wide_shared_string(a->len,a->size_shift);    MEMCPY(r->str, a->str, a->len << a->size_shift);    low_set_index(r,index,c);    free_string(a);    return end_shared_string(r);    }   }    + PMOD_EXPORT void set_flags_for_add( struct pike_string *ret, +  unsigned char aflags, +  unsigned char amin, +  unsigned char amax, +  struct pike_string *b) + { +  if( !b->len ) { +  ret->flags |= aflags & ~15; +  ret->min = amin; +  ret->max = amax; +  return; +  } +  if( aflags & b->flags & STRING_CONTENT_CHECKED ) +  { +  ret->min = MINIMUM( amin, b->min ); +  ret->max = MAXIMUM( amax, b->max ); +  ret->flags |= STRING_CONTENT_CHECKED; +  } +  else +  ret->flags &= ~STRING_CONTENT_CHECKED; +  +  ret->flags &= ~(STRING_IS_LOWERCASE | STRING_IS_UPPERCASE); +  ret->flags |= (aflags & b->flags & (STRING_IS_LOWERCASE | STRING_IS_UPPERCASE)); + } +  + PMOD_EXPORT void update_flags_for_add( struct pike_string *a, struct pike_string *b) + { +  if( !b->len ) return; +  if( a->flags & STRING_CONTENT_CHECKED ) +  { +  if(b->flags & STRING_CONTENT_CHECKED) +  { +  if( b->min < a->min ) a->min = b->min; +  if( b->max > a->max ) a->max = b->max; +  } +  else +  a->flags &= ~STRING_CONTENT_CHECKED; +  } +  +  a->flags &= ~(STRING_IS_LOWERCASE | STRING_IS_UPPERCASE) | b->flags; + } +    /*** Add strings ***/   PMOD_EXPORT struct pike_string *add_shared_strings(struct pike_string *a,    struct pike_string *b)   {    struct pike_string *ret;    PCHARP tmp;    int target_size=MAXIMUM(a->size_shift,b->size_shift);       ret=begin_wide_shared_string(a->len+b->len,target_size);    tmp=MKPCHARP_STR(ret);    pike_string_cpy(tmp,a);    INC_PCHARP(tmp,a->len);    pike_string_cpy(tmp,b); -  +  set_flags_for_add( ret, a->flags, a->min, a->max, b );    return low_end_shared_string(ret);   }      PMOD_EXPORT struct pike_string *add_and_free_shared_strings(struct pike_string *a,    struct pike_string *b)   {    ptrdiff_t alen = a->len;    if(a->size_shift == b->size_shift)    { -  a = realloc_shared_string(a,alen + b->len); +  a = realloc_shared_string(a, alen + b->len); +  update_flags_for_add( a, b );    MEMCPY(a->str+(alen<<a->size_shift),b->str,b->len<<b->size_shift);    free_string(b);    a->flags |= STRING_NOT_HASHED;    return end_shared_string(a);    }else{    struct pike_string *ret=add_shared_strings(a,b);    free_string(a);    free_string(b);    return ret;    }   }         PMOD_EXPORT ptrdiff_t string_search(struct pike_string *haystack,    struct pike_string *needle,    ptrdiff_t start)   {    SearchMojt mojt;    char *r;    -  if(needle->size_shift > haystack->size_shift || -  start + needle->len > haystack->len) +  if( !string_range_contains_string( haystack, needle ) )    return -1;    -  +  if(start + needle->len > haystack->len) +  return -1; +     if(!needle->len) return start;       mojt=compile_memsearcher(MKPCHARP_STR(needle),    needle->len,    haystack->len,    needle);       r = (char *)mojt.vtab->funcN(mojt.data,    ADD_PCHARP(MKPCHARP_STR(haystack), start),    haystack->len - start).ptr;
pike.git/src/stralloc.c:1967:    struct pike_string *to)   {    struct pike_string *ret;    char *s,*tmp,*end;    PCHARP r;    int shift;    SearchMojt mojt;    ONERROR mojt_uwp;    replace_searchfunc f = (replace_searchfunc)0;    -  if(!str->len) +  if(!str->len || !string_range_contains_string(str, del))    { -  add_ref(empty_pike_string); -  return empty_pike_string; +  add_ref(str); +  return str;    }       shift=MAXIMUM(str->size_shift,to->size_shift);       if(!del->len)    {    int e,pos;    ret=begin_wide_shared_string(str->len + to->len * (str->len -1),shift);    low_set_index(ret,0,index_shared_string(str,0));    for(pos=e=1;e<str->len;e++)
pike.git/src/stralloc.c:2068:    }    generic_memcpy(r,MKPCHARP(s,str->size_shift),(end-s)>>str->size_shift);       CALL_AND_UNSET_ONERROR (mojt_uwp);    return end_shared_string(ret);   }      /*** init/exit memory ***/   void init_shared_string_table(void)   { -  init_short_pike_string0_blocks(); -  init_short_pike_string1_blocks(); -  init_short_pike_string2_blocks(); +     for(hashprimes_entry=0;hashprimes[hashprimes_entry]<BEGIN_HASH_SIZE;hashprimes_entry++);    SET_HSIZE(hashprimes_entry);    base_table=(struct pike_string **)xalloc(sizeof(struct pike_string *)*htable_size);    MEMSET((char *)base_table,0,sizeof(struct pike_string *)*htable_size);   #ifdef PIKE_RUN_UNLOCKED    {    int h;    bucket_locks=(PIKE_MUTEX_T *)xalloc(sizeof(PIKE_MUTEX_T)*BUCKET_LOCKS);    for(h=0;h<BUCKET_LOCKS;h++) mt_init(bucket_locks + h);    }   #endif    empty_pike_string = make_shared_string(""); -  +  empty_pike_string->flags |= STRING_CONTENT_CHECKED | STRING_IS_LOWERCASE | STRING_IS_UPPERCASE; +  empty_pike_string->min = empty_pike_string->max = 0;   }      #ifdef DO_PIKE_CLEANUP   PMOD_EXPORT struct shared_string_location *all_shared_string_locations;   #endif         void cleanup_shared_string_table(void)   {    unsigned INT32 e;
pike.git/src/stralloc.c:2144:   #endif    }    base_table[e]=0;    UNLOCK_BUCKET(e);    }    free((char *)base_table);    base_table=0;    num_strings=0;      #ifdef DO_PIKE_CLEANUP -  free_all_short_pike_string0_blocks(); -  free_all_short_pike_string1_blocks(); -  free_all_short_pike_string2_blocks(); +  ba_destroy(&string_allocator);   #endif /* DO_PIKE_CLEANUP */   }      static INLINE size_t memory_in_string (struct pike_string *s)   { -  if (s->len <= SHORT_STRING_THRESHOLD) -  switch (s->size_shift) { -  case 0: return sizeof (struct short_pike_string0); -  case 1: return sizeof (struct short_pike_string1); -  default: return sizeof (struct short_pike_string2); -  } +  if (s->flags & STRING_IS_SHORT ) +  return sizeof (struct short_pike_string0);    else    return sizeof (struct pike_string_hdr) + ((s->len + 1) << s->size_shift);   }      void count_memory_in_short_pike_strings(size_t *num, size_t *size)   { -  size_t num_=0, size_=0; -  count_memory_in_short_pike_string0s(num, size); -  count_memory_in_short_pike_string1s(&num_, &size_); -  *num += num_; -  *size += size_; -  count_memory_in_short_pike_string2s(&num_, &size_); -  *num += num_; -  *size += size_; +  ba_count_all(&string_allocator, num, size);   }      void count_memory_in_strings(size_t *num, size_t *size)   {    unsigned INT32 e;    size_t num_=0, size_=0;    if(!base_table)    {    *num=*size=0;    return;
pike.git/src/stralloc.c:2293:   }      /* str becomes invalid if successful (i.e. nonzero returned),    * otherwise nothing happens. */   PMOD_EXPORT int init_string_builder_with_string (struct string_builder *s,    struct pike_string *str)   {    if (str->refs == 1 && str->len > SHORT_STRING_THRESHOLD) {    /* Unlink the string and use it as buffer directly. */    unlink_pike_string (str); +  str->flags = STRING_NOT_SHARED;    s->s = str;    s->malloced = str->len;    s->known_shift = str->size_shift;    return 1;    }    return 0;   }      PMOD_EXPORT void string_build_mkspace(struct string_builder *s,    ptrdiff_t chars, int mag)
pike.git/src/stralloc.c:2725:    val = -val;    } else if (flags & APPEND_POSITIVE) {    string_builder_putchar(s, '+');    }    if ((flags & APPEND_ZERO_PAD) && (precision < min_width)) {    precision = min_width;    }       tmp = val;    if (base & (base - 1)) { +  size_t cnt;    /* Calculate the output length.    * Use do-while to ensure that zero isn't output as an empty string.    */    len = 0;    do {    len++;    tmp /= base;    } while (tmp);       /* Precision is minimum number of digits. */    if (len < precision) len = precision;       /* Perform padding. */ -  if ((len < min_width) && !(flags & APPEND_LEFT)) { +  if (!(flags & APPEND_LEFT)) { +  if (len < min_width) {    string_builder_fill(s, min_width - len, MKPCHARP(" ", 0),    4, 0); -  +  }    min_width = 0;    }    -  +  cnt = len; +     tmp = val;    switch(s->s->size_shift) {    case 0:    {    p_wchar0 *p = string_builder_allocate(s, len, 0);    do { -  p[--len] = numbers[tmp%base]; +  p[--cnt] = numbers[tmp%base];    tmp /= base; -  } while (len); +  } while (cnt);    }    break;    case 1:    {    p_wchar1 *p = string_builder_allocate(s, len, 0);    do { -  p[--len] = numbers[tmp%base]; +  p[--cnt] = numbers[tmp%base];    tmp /= base; -  } while (len); +  } while (cnt);    }    break;    case 2:    {    p_wchar2 *p = string_builder_allocate(s, len, 0);    do { -  p[--len] = numbers[tmp%base]; +  p[--cnt] = numbers[tmp%base];    tmp /= base; -  } while (len); +  } while (cnt);    }    break;    }    } else {    /* base is a power of two, so we can do without    * the division and modulo operations.    */    int delta;    size_t shift;    unsigned int mask;
pike.git/src/stralloc.c:3414:    if (val > mul_limit || (val == mul_limit && xx > add_limit))    overflow = 1;    else    val = base * val + xx;    }       if(ptr != 0)    *ptr = str;       if (overflow) { - #ifdef AUTO_BIGNUM +     push_string(make_shared_binary_pcharp(str_start,    SUBTRACT_PCHARP(str,str_start)));    /* Note that this can conceivably throw errors()    * in some situations that might not be desirable...    * take care.    * /Hubbe    *    * It could probably also be faster...    */    push_int(base);    convert_stack_top_with_base_to_bignum();    if(neg) o_negate();       *r = *--Pike_sp;    dmalloc_touch_svalue (r); - #else /* !AUTO_BIGNUM */ -  r->u.integer = neg ? MIN_INT_TYPE : MAX_INT_TYPE; - #endif +     }    else {    if (neg)    r->u.integer = val > (unsigned INT_TYPE) MAX_INT_TYPE ?    -(INT_TYPE) (val - (unsigned INT_TYPE) MAX_INT_TYPE) - MAX_INT_TYPE :    -(INT_TYPE) val;    else    r->u.integer = (INT_TYPE) val;    }