pike.git / src / mapping.c

version» Context lines:

pike.git/src/mapping.c:13:   #include "pike_macros.h"   #include "pike_error.h"   #include "pike_memory.h"   #include "pike_types.h"   #include "dynamic_buffer.h"   #include "interpret.h"   #include "las.h"   #include "gc.h"   #include "stralloc.h"   #include "pike_security.h" - #include "block_alloc.h" + #include "block_allocator.h"   #include "opcodes.h"   #include "stuff.h"      #define AVG_LINK_LENGTH 4   #define MIN_LINK_LENGTH 1   #define MAP_SLOTS(X) ((X)?((X)+((X)>>4)+8):0)      struct mapping *first_mapping;      struct mapping *gc_internal_mapping = 0;
pike.git/src/mapping.c:35:      #define unlink_mapping_data(M) do{ \    struct mapping_data *md_=(M); \    if(md_->hardlinks) { md_->hardlinks--; md_->valrefs--; } \    free_mapping_data(M); \   }while(0)      #define MAPPING_DATA_SIZE(HSIZE, KEYPAIRS) \    PTR_TO_INT(MD_KEYPAIRS(0, HSIZE) + KEYPAIRS)    - #undef EXIT_BLOCK - #define EXIT_BLOCK(m) do{ \ - DO_IF_DEBUG( \ -  if(m->refs) { \ -  DO_IF_DMALLOC(describe_something(m, T_MAPPING, 0,2,0, NULL)); \ -  Pike_fatal("really free mapping on mapping with %d refs.\n", m->refs); \ -  } \ - ) \ -  \ -  FREE_PROT(m); \ -  \ -  unlink_mapping_data(m->data); \ -  \ -  DOUBLEUNLINK(first_mapping, m); \ -  \ -  GC_FREE(m); \ - }while(0) + static struct block_allocator mapping_allocator = BA_INIT_PAGES(sizeof(struct mapping), 2); + void count_memory_in_mappings(size_t * num, size_t * size) { +  struct mapping *m; +  double datasize = 0.0; +  ba_count_all(&mapping_allocator, num, size); +  for(m=first_mapping;m;m=m->next) { +  datasize+=MAPPING_DATA_SIZE(m->data->hashsize, m->data->num_keypairs) / (double) m->data->refs; +  } +  *size += (size_t) datasize; + }    -  + void really_free_mapping(struct mapping * m) { + #ifdef PIKE_DEBUG +  if (m->refs) { + # ifdef DEBUG_MALLOC +  describe_something(m, T_MAPPING, 0,2,0, NULL); + # endif +  Pike_fatal("really free mapping on mapping with %d refs.\n", m->refs); +  } + #endif +  FREE_PROT(m); +  unlink_mapping_data(m->data); +  DOUBLEUNLINK(first_mapping, m); +  GC_FREE(m); +  ba_free(&mapping_allocator, m); + }    - #undef COUNT_OTHER + ATTRIBUTE((malloc)) + static struct mapping * alloc_mapping() { +  return ba_alloc(&mapping_allocator); + }    - #define COUNT_OTHER() do{ \ -  struct mapping *m; \ -  double datasize = 0.0; \ -  for(m=first_mapping;m;m=m->next) \ -  { \ -  datasize+=MAPPING_DATA_SIZE(m->data->hashsize, m->data->num_keypairs) / \ -  (double) m->data->refs; \ -  } \ -  size += (size_t) datasize; \ - }while(0) + void free_all_mapping_blocks() { +  ba_destroy(&mapping_allocator); + }    - BLOCK_ALLOC_FILL_PAGES(mapping, 2) -  +    #ifndef PIKE_MAPPING_KEYPAIR_LOOP   #define IF_ELSE_KEYPAIR_LOOP(X, Y) Y   #define FREE_KEYPAIR(md, k) do { \    k->next = md->free_list; \    md->free_list = k; \    } while(0)   #else /* PIKE_MAPPING_KEYPAIR_LOOP */   #define IF_ELSE_KEYPAIR_LOOP(X, Y) X   #define FREE_KEYPAIR(md, k) do { \    md->free_list--; \
pike.git/src/mapping.c:115:   void mapping_free_keypair(struct mapping_data *md, struct keypair *k)   {    FREE_KEYPAIR(md, k);   }      static INLINE int check_type_contains(TYPE_FIELD types, const struct svalue * s) {    return (TYPEOF(*s) == PIKE_T_OBJECT || types & (BIT_OBJECT|(1 << TYPEOF(*s))));   }      static INLINE int check_type_overlaps(TYPE_FIELD t1, TYPE_FIELD t2) { -  return t1 & t2 || (t1|t2) & BIT_OBJECT; +  return (!t1 && !t2) || t1 & t2 || (t1|t2) & BIT_OBJECT;   }      #ifdef PIKE_DEBUG      /** This function checks that the type field isn't lacking any bits.    * It is used for debugging purposes only.    */   static void check_mapping_type_fields(const struct mapping *m)   {    INT32 e;
pike.git/src/mapping.c:299:   PMOD_EXPORT void do_free_mapping(struct mapping *m)   {    if (m)    inl_free_mapping(m);   }      /* This function is used to rehash a mapping without losing the internal    * order in each hash chain. This is to prevent mappings from becoming    * inefficient just after being rehashed.    */ + /* Evil: Steal the svalues from the old md. */   static void mapping_rehash_backwards_evil(struct mapping_data *md,    struct keypair *from)   {    unsigned INT32 h;    struct keypair *k, *prev = NULL, *next;       if(!(k = from)) return;       /* Reverse the hash chain. */    while ((next = k->next)) {    k->next = prev;    prev = k;    k = next;    }    k->next = prev;    -  from = k; +  prev = k;       /* Rehash and reverse the hash chain. */ -  while (from) { +  while ((from = prev)) { +  /* Reverse */ +  prev = from->next; +  from->next = next; +  next = from; +  +  if (md->flags & MAPPING_WEAK) { +  +  switch(md->flags & MAPPING_WEAK) { +  default: +  Pike_fatal("Instable mapping data flags.\n"); +  case MAPPING_WEAK_INDICES: +  if (REFCOUNTED_TYPE(TYPEOF(from->ind)) && +  (*from->ind.u.refs > 1)) { +  goto keep_keypair; +  } +  break; +  case MAPPING_WEAK_VALUES: +  if (REFCOUNTED_TYPE(TYPEOF(from->val)) && +  (*from->val.u.refs > 1)) { +  goto keep_keypair; +  } +  break; +  case MAPPING_WEAK: +  /* NB: Compat: Unreference counted values are counted +  * as multi-referenced here. +  */ +  if ((!REFCOUNTED_TYPE(TYPEOF(from->ind)) || +  (*from->ind.u.refs > 1)) && +  (!REFCOUNTED_TYPE(TYPEOF(from->val)) || +  (*from->val.u.refs > 1))) { +  goto keep_keypair; +  } +  break; +  } +  +  /* Free. +  * Note that we don't need to free or unlink the keypair, +  * since that will be done by the caller anyway. */ +  free_svalue(&from->ind); +  free_svalue(&from->val); +  +  continue; +  } +  keep_keypair: +     /* unlink */    k=md->free_list;   #ifndef PIKE_MAPPING_KEYPAIR_LOOP   #ifdef PIKE_DEBUG    if(!k) Pike_fatal("Error in rehash: not enough keypairs.\n");   #endif    md->free_list=k->next;   #else /* PIKE_MAPPING_KEYPAIR_LOOP */    md->free_list++;   #endif /* !PIKE_MAPPING_KEYPAIR_LOOP */
pike.git/src/mapping.c:343:    /* link */    h=k->hval;    h&=md->hashsize - 1;    k->next=md->hash[h];    md->hash[h]=k;       /* update */    md->ind_types |= 1<< (TYPEOF(k->ind));    md->val_types |= 1<< (TYPEOF(k->val));    md->size++; -  -  /* Reverse */ -  prev = from->next; -  from->next = next; -  next = from; -  from = prev; +     }   }    -  + /* Good: Copy the svalues from the old md. */   static void mapping_rehash_backwards_good(struct mapping_data *md,    struct keypair *from)   {    unsigned INT32 h;    struct keypair *k, *prev = NULL, *next;       if(!(k = from)) return;       /* Reverse the hash chain. */    while ((next = k->next)) {    k->next = prev;    prev = k;    k = next;    }    k->next = prev;    -  from = k; +  prev = k;       /* Rehash and reverse the hash chain. */ -  while (from) { +  while ((from = prev)) { +  /* Reverse */ +  prev = from->next; +  from->next = next; +  next = from; +  +  if (md->flags & MAPPING_WEAK) { +  +  switch(md->flags & MAPPING_WEAK) { +  default: +  Pike_fatal("Instable mapping data flags.\n"); +  case MAPPING_WEAK_INDICES: +  if (REFCOUNTED_TYPE(TYPEOF(from->ind)) && +  (*from->ind.u.refs > 1)) { +  goto keep_keypair; +  } +  break; +  case MAPPING_WEAK_VALUES: +  if (REFCOUNTED_TYPE(TYPEOF(from->val)) && +  (*from->val.u.refs > 1)) { +  goto keep_keypair; +  } +  break; +  case MAPPING_WEAK: +  /* NB: Compat: Unreference counted values are counted +  * as multi-referenced here. +  */ +  if ((!REFCOUNTED_TYPE(TYPEOF(from->ind)) || +  (*from->ind.u.refs > 1)) && +  (!REFCOUNTED_TYPE(TYPEOF(from->val)) || +  (*from->val.u.refs > 1))) { +  goto keep_keypair; +  } +  break; +  } +  +  /* Skip copying of this keypair. +  * +  * NB: We can't mess with the original md here, +  * since it might be in use by an iterator +  * or similar. +  */ +  +  continue; +  } +  keep_keypair: +     /* unlink */    k=md->free_list;   #ifndef PIKE_MAPPING_KEYPAIR_LOOP   #ifdef PIKE_DEBUG    if(!k) Pike_fatal("Error in rehash: not enough keypairs.\n");   #endif    md->free_list=k->next;   #else /* PIKE_MAPPING_KEYPAIR_LOOP */    md->free_list++;   #endif /* !PIKE_MAPPING_KEYPAIR_LOOP */
pike.git/src/mapping.c:398:    /* link */    h=k->hval;    h&=md->hashsize - 1;    k->next=md->hash[h];    md->hash[h]=k;       /* update */    md->ind_types |= 1<< (TYPEOF(k->ind));    md->val_types |= 1<< (TYPEOF(k->val));    md->size++; -  -  /* Reverse */ -  prev = from->next; -  from->next = next; -  next = from; -  from = prev; +     }   }      /** This function re-allocates a mapping. It adjusts the max no. of    * values can be fitted into the mapping. It takes a bit of time to    * run, but is used seldom enough not to degrade preformance significantly.    *    * @param m the mapping to be rehashed    * @param new_size new mappingsize    * @return the rehashed mapping
pike.git/src/mapping.c:445:    if ((md->hashsize == new_size) && (md->refs == 1)) return m;       init_mapping(m, new_size, md->flags);    debug_malloc_touch(m);    new_md=m->data;       /* This operation is now 100% atomic - no locking required */    if(md->refs>1)    {    /* good */ +  /* More than one reference to the md ==> We need to +  * keep it afterwards. +  */    for(e=0;e<md->hashsize;e++)    mapping_rehash_backwards_good(new_md, md->hash[e]);       unlink_mapping_data(md);    }else{    /* evil */ -  +  /* We have the only reference to the md, +  * so we can just copy the svalues without +  * bothering about type checking. +  */    for(e=0;e<md->hashsize;e++)    mapping_rehash_backwards_evil(new_md, md->hash[e]);       free((char *)md);    GC_FREE_BLOCK(md);    }      #ifdef PIKE_DEBUG -  if(m->data->size != tmp) -  Pike_fatal("Rehash failed, size not same any more.\n"); +  if((m->data->size != tmp) && +  ((m->data->size > tmp) || !(m->data->flags & MAPPING_WEAK))) +  Pike_fatal("Rehash failed, size not same any more (%ld != %ld).\n", +  (long)m->data->size, (long)tmp);   #endif   #ifdef MAPPING_SIZE_DEBUG    m->debug_size = m->data->size;   #endif      #ifdef PIKE_DEBUG    if(d_flag>1) check_mapping(m);   #endif       return m;
pike.git/src/mapping.c:2396: Inside #if defined(PIKE_DEBUG)
     void check_all_mappings(void)   {    struct mapping *m;    for(m=first_mapping;m;m=m->next)    check_mapping(m);   }   #endif      static void visit_mapping_data (struct mapping_data *md, int action, -  struct mapping *m) +  struct mapping *UNUSED(m))   {    switch (action) {   #ifdef PIKE_DEBUG    default:    Pike_fatal ("Unknown visit action %d.\n", action);    case VISIT_NORMAL:    case VISIT_COMPLEX_ONLY:    break;   #endif    case VISIT_COUNT_BYTES: