17293d2530f8c60c1060f9f003e214cc341d35266philippe/*--------------------------------------------------------------------*/
27293d2530f8c60c1060f9f003e214cc341d35266philippe/*--- A pool (memory) allocator that avoids duplicated copies.     ---*/
37293d2530f8c60c1060f9f003e214cc341d35266philippe/*---                                           m_deduppoolalloc.c ---*/
47293d2530f8c60c1060f9f003e214cc341d35266philippe/*--------------------------------------------------------------------*/
57293d2530f8c60c1060f9f003e214cc341d35266philippe/*
67293d2530f8c60c1060f9f003e214cc341d35266philippe   This file is part of Valgrind, a dynamic binary instrumentation
77293d2530f8c60c1060f9f003e214cc341d35266philippe   framework.
87293d2530f8c60c1060f9f003e214cc341d35266philippe
9ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   Copyright (C) 2014-2017 Philippe Waroquiers philippe.waroquiers@skynet.be
107293d2530f8c60c1060f9f003e214cc341d35266philippe
117293d2530f8c60c1060f9f003e214cc341d35266philippe   This program is free software; you can redistribute it and/or
127293d2530f8c60c1060f9f003e214cc341d35266philippe   modify it under the terms of the GNU General Public License as
137293d2530f8c60c1060f9f003e214cc341d35266philippe   published by the Free Software Foundation; either version 2 of the
147293d2530f8c60c1060f9f003e214cc341d35266philippe   License, or (at your option) any later version.
157293d2530f8c60c1060f9f003e214cc341d35266philippe
167293d2530f8c60c1060f9f003e214cc341d35266philippe   This program is distributed in the hope that it will be useful, but
177293d2530f8c60c1060f9f003e214cc341d35266philippe   WITHOUT ANY WARRANTY; without even the implied warranty of
187293d2530f8c60c1060f9f003e214cc341d35266philippe   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
197293d2530f8c60c1060f9f003e214cc341d35266philippe   General Public License for more details.
207293d2530f8c60c1060f9f003e214cc341d35266philippe
217293d2530f8c60c1060f9f003e214cc341d35266philippe   You should have received a copy of the GNU General Public License
227293d2530f8c60c1060f9f003e214cc341d35266philippe   along with this program; if not, write to the Free Software
237293d2530f8c60c1060f9f003e214cc341d35266philippe   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
247293d2530f8c60c1060f9f003e214cc341d35266philippe   02111-1307, USA.
257293d2530f8c60c1060f9f003e214cc341d35266philippe
267293d2530f8c60c1060f9f003e214cc341d35266philippe   The GNU General Public License is contained in the file COPYING.
277293d2530f8c60c1060f9f003e214cc341d35266philippe*/
287293d2530f8c60c1060f9f003e214cc341d35266philippe
297293d2530f8c60c1060f9f003e214cc341d35266philippe#include "pub_core_basics.h"
307293d2530f8c60c1060f9f003e214cc341d35266philippe#include "pub_core_libcbase.h"
317293d2530f8c60c1060f9f003e214cc341d35266philippe#include "pub_core_libcprint.h"
327293d2530f8c60c1060f9f003e214cc341d35266philippe#include "pub_core_libcassert.h"
337293d2530f8c60c1060f9f003e214cc341d35266philippe#include "pub_core_xarray.h"
347293d2530f8c60c1060f9f003e214cc341d35266philippe#include "pub_core_deduppoolalloc.h" /* self */
357293d2530f8c60c1060f9f003e214cc341d35266philippe#include "pub_core_hashtable.h"
367293d2530f8c60c1060f9f003e214cc341d35266philippe#include "pub_core_poolalloc.h"
377293d2530f8c60c1060f9f003e214cc341d35266philippe#include "pub_core_options.h"
387293d2530f8c60c1060f9f003e214cc341d35266philippe#include "pub_core_mallocfree.h"
397293d2530f8c60c1060f9f003e214cc341d35266philippe#include "pub_core_debuglog.h"
407293d2530f8c60c1060f9f003e214cc341d35266philippe
417293d2530f8c60c1060f9f003e214cc341d35266philippestruct _DedupPoolAlloc {
427293d2530f8c60c1060f9f003e214cc341d35266philippe   SizeT  poolSzB; /* Minimum size of a pool. */
431554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   SizeT  fixedSzb; /* If using VG_(allocFixedEltDedupPA), size of elements */
44ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   Bool   strPA;    /* True if this is a string dedup pool */
457293d2530f8c60c1060f9f003e214cc341d35266philippe   SizeT  eltAlign;
46ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   Alloc_Fn_t alloc_fn; /* pool allocator */
475e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian   const HChar*  cc; /* pool allocator's cost centre */
48ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   Free_Fn_t free_fn; /* pool allocator's deallocation function */
497293d2530f8c60c1060f9f003e214cc341d35266philippe   /* XArray of void* (pointers to pools).  The pools themselves.
501554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      Each element is a pointer to a block of size at least PoolSzB bytes.
511554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      The last block might be smaller due to a call to shrink_block. */
527293d2530f8c60c1060f9f003e214cc341d35266philippe   XArray *pools;
537293d2530f8c60c1060f9f003e214cc341d35266philippe
547293d2530f8c60c1060f9f003e214cc341d35266philippe   /* hash table of pool elements, used to dedup.
557293d2530f8c60c1060f9f003e214cc341d35266philippe      If NULL, it means the DedupPoolAlloc is frozen. */
5609a4c794458cdb9dea743fa40e450150a2725257florian   VgHashTable *ht_elements;
577293d2530f8c60c1060f9f003e214cc341d35266philippe
587293d2530f8c60c1060f9f003e214cc341d35266philippe   /* Hash table nodes of pool_elements are allocated with a pool, to
597293d2530f8c60c1060f9f003e214cc341d35266philippe      decrease memory overhead during insertion in the DedupPoolAlloc. */
607293d2530f8c60c1060f9f003e214cc341d35266philippe   PoolAlloc *ht_node_pa;
617293d2530f8c60c1060f9f003e214cc341d35266philippe
621554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   UChar *curpool;       /* last allocated pool. */
631554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   UChar *curpool_free;  /* Pos in current pool to allocate next elt.
641554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe                            always aligned on eltAlign. */
657293d2530f8c60c1060f9f003e214cc341d35266philippe   UChar *curpool_limit; /* Last pos in current pool. */
661554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   /* Note that for a fixed size pool, we only have a single pool to allow
671554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      simple/fast indexing. This single pool is grown, which might change
681554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      the address of the already allocated elements. */
697293d2530f8c60c1060f9f003e214cc341d35266philippe
707293d2530f8c60c1060f9f003e214cc341d35266philippe   /* Total nr of alloc calls, resulting in (we hope) a lot less
717293d2530f8c60c1060f9f003e214cc341d35266philippe      real (dedup) elements. */
721554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   ULong nr_alloc_calls;
737293d2530f8c60c1060f9f003e214cc341d35266philippe};
747293d2530f8c60c1060f9f003e214cc341d35266philippe
757293d2530f8c60c1060f9f003e214cc341d35266philippetypedef
767293d2530f8c60c1060f9f003e214cc341d35266philippe   struct _ht_node {
777293d2530f8c60c1060f9f003e214cc341d35266philippe      struct _ht_node *next; // Read/Write by hashtable (pub_tool_hashtable.h)
787293d2530f8c60c1060f9f003e214cc341d35266philippe      UWord   key;           // Read by hashtable (pub_tool_hashtable.h)
79ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      SizeT   eltSzBorStrNr; // for a normal pool, elt size
80ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                             // for a string pool, the unique str number
811ef70c6f00ab1b50d1936f77037e9923d8ed8c59florian      const void *elt;
827293d2530f8c60c1060f9f003e214cc341d35266philippe   }
837293d2530f8c60c1060f9f003e214cc341d35266philippe   ht_node;
847293d2530f8c60c1060f9f003e214cc341d35266philippe
855e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorianDedupPoolAlloc* VG_(newDedupPA) ( SizeT  poolSzB,
865e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian                                  SizeT  eltAlign,
87ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                                  Alloc_Fn_t alloc_fn,
885e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian                                  const  HChar* cc,
89ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                                  Free_Fn_t free_fn )
907293d2530f8c60c1060f9f003e214cc341d35266philippe{
917293d2530f8c60c1060f9f003e214cc341d35266philippe   DedupPoolAlloc* ddpa;
927293d2530f8c60c1060f9f003e214cc341d35266philippe   vg_assert(poolSzB >= eltAlign);
937293d2530f8c60c1060f9f003e214cc341d35266philippe   vg_assert(poolSzB >= 100); /* let's say */
947293d2530f8c60c1060f9f003e214cc341d35266philippe   vg_assert(poolSzB >= 10*eltAlign); /* let's say */
955e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian   vg_assert(alloc_fn);
967293d2530f8c60c1060f9f003e214cc341d35266philippe   vg_assert(cc);
977293d2530f8c60c1060f9f003e214cc341d35266philippe   vg_assert(free_fn);
985e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian   ddpa = alloc_fn(cc, sizeof(*ddpa));
997293d2530f8c60c1060f9f003e214cc341d35266philippe   VG_(memset)(ddpa, 0, sizeof(*ddpa));
1007293d2530f8c60c1060f9f003e214cc341d35266philippe   ddpa->poolSzB  = poolSzB;
1011554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   ddpa->fixedSzb = 0;
102ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   ddpa->strPA = False;
1037293d2530f8c60c1060f9f003e214cc341d35266philippe   ddpa->eltAlign = eltAlign;
1045e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian   ddpa->alloc_fn = alloc_fn;
1057293d2530f8c60c1060f9f003e214cc341d35266philippe   ddpa->cc       = cc;
1065e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian   ddpa->free_fn  = free_fn;
1075e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian   ddpa->pools    = VG_(newXA)( alloc_fn, cc, free_fn, sizeof(void*) );
1087293d2530f8c60c1060f9f003e214cc341d35266philippe
1097293d2530f8c60c1060f9f003e214cc341d35266philippe   ddpa->ht_elements = VG_(HT_construct) (cc);
1107293d2530f8c60c1060f9f003e214cc341d35266philippe   ddpa->ht_node_pa = VG_(newPA) ( sizeof(ht_node),
1117293d2530f8c60c1060f9f003e214cc341d35266philippe                                   1000,
1125e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian                                   alloc_fn,
1137293d2530f8c60c1060f9f003e214cc341d35266philippe                                   cc,
1147293d2530f8c60c1060f9f003e214cc341d35266philippe                                   free_fn);
1151554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   ddpa->curpool = NULL;
1167293d2530f8c60c1060f9f003e214cc341d35266philippe   ddpa->curpool_limit = NULL;
117a75b56e924f4679686572b2c4ac5345882d65c6bphilippe   ddpa->curpool_free = NULL;
11891ed8ccd3dae8a6abfaa45cc0d250df47b45187fflorian
1197293d2530f8c60c1060f9f003e214cc341d35266philippe   return ddpa;
1207293d2530f8c60c1060f9f003e214cc341d35266philippe}
1217293d2530f8c60c1060f9f003e214cc341d35266philippe
1227293d2530f8c60c1060f9f003e214cc341d35266philippevoid VG_(deleteDedupPA) ( DedupPoolAlloc* ddpa)
1237293d2530f8c60c1060f9f003e214cc341d35266philippe{
1247293d2530f8c60c1060f9f003e214cc341d35266philippe   Word i;
1257293d2530f8c60c1060f9f003e214cc341d35266philippe   if (ddpa->ht_elements)
1261554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      // Free data structures used for insertion.
1271554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      VG_(freezeDedupPA) (ddpa, NULL);
1287293d2530f8c60c1060f9f003e214cc341d35266philippe   for (i = 0; i < VG_(sizeXA) (ddpa->pools); i++)
1295e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian      ddpa->free_fn (*(UWord **)VG_(indexXA) ( ddpa->pools, i ));
1307293d2530f8c60c1060f9f003e214cc341d35266philippe   VG_(deleteXA) (ddpa->pools);
1315e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian   ddpa->free_fn (ddpa);
1327293d2530f8c60c1060f9f003e214cc341d35266philippe}
1337293d2530f8c60c1060f9f003e214cc341d35266philippe
1347293d2530f8c60c1060f9f003e214cc341d35266philippestatic __inline__
1351554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippeUChar* ddpa_align ( DedupPoolAlloc* ddpa, UChar *c )
1367293d2530f8c60c1060f9f003e214cc341d35266philippe{
1371554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   return (UChar*)VG_ROUNDUP(c, ddpa->eltAlign);
1387293d2530f8c60c1060f9f003e214cc341d35266philippe}
1397293d2530f8c60c1060f9f003e214cc341d35266philippe
1401554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe/* Allocate a new pool or grow the (only) pool for a fixed size ddpa. */
1417293d2530f8c60c1060f9f003e214cc341d35266philippe__attribute__((noinline))
142e3e515b85bce2fdfadabac0a566bbc4a3a2178fephilippestatic void ddpa_add_new_pool_or_grow ( DedupPoolAlloc* ddpa )
1437293d2530f8c60c1060f9f003e214cc341d35266philippe{
1447293d2530f8c60c1060f9f003e214cc341d35266philippe   vg_assert(ddpa);
1451554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe
1461554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   if (ddpa->fixedSzb > 0 && ddpa->curpool != NULL) {
1471554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      // Grow (* 2) the current (fixed elt) pool
1481554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      UChar *curpool_align = ddpa_align(ddpa, ddpa->curpool);
1491554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      SizeT curpool_used = ddpa->curpool_free - curpool_align;
1501554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      SizeT curpool_size = ddpa->curpool_limit - ddpa->curpool + 1;
1515e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian      UChar *newpool = ddpa->alloc_fn (ddpa->cc, 2 * curpool_size);
1521554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      UChar *newpool_free = ddpa_align (ddpa, newpool);
1531554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      UChar *newpool_limit = newpool + 2 * curpool_size - 1;
154e3e515b85bce2fdfadabac0a566bbc4a3a2178fephilippe      Word reloc_offset = (Addr)newpool_free - (Addr)curpool_align;
155e3e515b85bce2fdfadabac0a566bbc4a3a2178fephilippe      ht_node *n;
1561554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe
1571554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      VG_(memcpy) (newpool_free, curpool_align, curpool_used);
158e3e515b85bce2fdfadabac0a566bbc4a3a2178fephilippe      /* We have reallocated the (only) pool. We need to relocate the pointers
159e3e515b85bce2fdfadabac0a566bbc4a3a2178fephilippe         in the hash table nodes. */
160e3e515b85bce2fdfadabac0a566bbc4a3a2178fephilippe      VG_(HT_ResetIter) (ddpa->ht_elements);
161e3e515b85bce2fdfadabac0a566bbc4a3a2178fephilippe      while ((n = VG_(HT_Next) (ddpa->ht_elements))) {
162e3e515b85bce2fdfadabac0a566bbc4a3a2178fephilippe        n->elt = (void*)((Addr)n->elt + reloc_offset);
163e3e515b85bce2fdfadabac0a566bbc4a3a2178fephilippe      }
1641554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      newpool_free += curpool_used;
1651554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe
1661554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      VG_(dropHeadXA) (ddpa->pools, 1);
1675e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian      ddpa->free_fn (ddpa->curpool);
1681554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      ddpa->curpool = newpool;
1691554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      ddpa->curpool_free = newpool_free;
1701554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      ddpa->curpool_limit = newpool_limit;
1711554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      VG_(addToXA)( ddpa->pools, &ddpa->curpool);
1721554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   } else {
1731554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      /* Allocate a new pool, or allocate the first/only pool for a
1741554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe         fixed size ddpa. */
1755e1e9234daf0d106770fe34ee26bfd8c87cc0bdbflorian      ddpa->curpool = ddpa->alloc_fn( ddpa->cc, ddpa->poolSzB);
1761554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      ddpa->curpool_limit = ddpa->curpool + ddpa->poolSzB - 1;
1771554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      ddpa->curpool_free = ddpa_align (ddpa, ddpa->curpool);
1781554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      /* add to our collection of pools */
1791554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      VG_(addToXA)( ddpa->pools, &ddpa->curpool );
1801554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   }
1817293d2530f8c60c1060f9f003e214cc341d35266philippe}
1827293d2530f8c60c1060f9f003e214cc341d35266philippe
183e437427c93a605ac907137b3307f1f63a1462524philippe/* Compare function for 'gen' hash table. No need to compare the key
184e437427c93a605ac907137b3307f1f63a1462524philippe   in this function, as the hash table already does it for us,
185e437427c93a605ac907137b3307f1f63a1462524philippe   and that in any case, if the data is equal, the keys must also be
186e437427c93a605ac907137b3307f1f63a1462524philippe   equal. */
1877293d2530f8c60c1060f9f003e214cc341d35266philippestatic Word cmp_pool_elt (const void* node1, const void* node2 )
1887293d2530f8c60c1060f9f003e214cc341d35266philippe{
1897293d2530f8c60c1060f9f003e214cc341d35266philippe   const ht_node* hnode1 = node1;
1907293d2530f8c60c1060f9f003e214cc341d35266philippe   const ht_node* hnode2 = node2;
1917293d2530f8c60c1060f9f003e214cc341d35266philippe
192e437427c93a605ac907137b3307f1f63a1462524philippe   /* As this function is called by hashtable, that has already checked
193e437427c93a605ac907137b3307f1f63a1462524philippe      for key equality, it is likely that it is the 'good' element.
194e437427c93a605ac907137b3307f1f63a1462524philippe      So, we handle the equal case first. */
195ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   if (hnode1->eltSzBorStrNr == hnode2->eltSzBorStrNr)
196ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      return VG_(memcmp) (hnode1->elt, hnode2->elt, hnode1->eltSzBorStrNr);
197ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   else if (hnode1->eltSzBorStrNr < hnode2->eltSzBorStrNr)
1987293d2530f8c60c1060f9f003e214cc341d35266philippe      return -1;
1997293d2530f8c60c1060f9f003e214cc341d35266philippe   else
2007293d2530f8c60c1060f9f003e214cc341d35266philippe      return 1;
2017293d2530f8c60c1060f9f003e214cc341d35266philippe}
2027293d2530f8c60c1060f9f003e214cc341d35266philippe
203ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes/* String compare function for 'gen' hash table.
204ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   Similarly to cmp_pool_elt, no need to compare the key. */
205ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughesstatic Word cmp_pool_str (const void* node1, const void* node2 )
206ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes{
207ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   const ht_node* hnode1 = node1;
208ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   const ht_node* hnode2 = node2;
209ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes
210ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   return VG_(strcmp)(hnode1->elt, hnode2->elt);
211ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes}
212ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes
2137293d2530f8c60c1060f9f003e214cc341d35266philippe/* Print some stats. */
2147293d2530f8c60c1060f9f003e214cc341d35266philippestatic void print_stats (DedupPoolAlloc *ddpa)
2157293d2530f8c60c1060f9f003e214cc341d35266philippe{
2167293d2530f8c60c1060f9f003e214cc341d35266philippe   VG_(message)(Vg_DebugMsg,
217a6a6d9247ac4b1ba7f8dc28000cfcadb8feee85bflorian                "dedupPA:%s %ld allocs (%u uniq)"
2187293d2530f8c60c1060f9f003e214cc341d35266philippe                " %ld pools (%ld bytes free in last pool)\n",
2197293d2530f8c60c1060f9f003e214cc341d35266philippe                ddpa->cc,
2207293d2530f8c60c1060f9f003e214cc341d35266philippe                (long int) ddpa->nr_alloc_calls,
2217293d2530f8c60c1060f9f003e214cc341d35266philippe                VG_(HT_count_nodes)(ddpa->ht_elements),
2227293d2530f8c60c1060f9f003e214cc341d35266philippe                VG_(sizeXA)(ddpa->pools),
223a75b56e924f4679686572b2c4ac5345882d65c6bphilippe                ddpa->curpool ?
224a75b56e924f4679686572b2c4ac5345882d65c6bphilippe                (long int) (ddpa->curpool_limit - ddpa->curpool_free + 1) : 0);
225ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   if (ddpa->strPA)
226ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      VG_(HT_print_stats) (ddpa->ht_elements, cmp_pool_str);
227ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   else
228ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      VG_(HT_print_stats) (ddpa->ht_elements, cmp_pool_elt);
2297293d2530f8c60c1060f9f003e214cc341d35266philippe}
2307293d2530f8c60c1060f9f003e214cc341d35266philippe
2317293d2530f8c60c1060f9f003e214cc341d35266philippe/* Dummy free, as the ht elements are allocated in a pool, and
2327293d2530f8c60c1060f9f003e214cc341d35266philippe   we will destroy the pool in one single operation. */
2337293d2530f8c60c1060f9f003e214cc341d35266philippestatic void htelem_dummyfree(void* ht_elem)
2347293d2530f8c60c1060f9f003e214cc341d35266philippe{
2357293d2530f8c60c1060f9f003e214cc341d35266philippe}
2367293d2530f8c60c1060f9f003e214cc341d35266philippe
2370b9d0646949bd382758763664d3bf2d6115993aephilippevoid VG_(freezeDedupPA) (DedupPoolAlloc *ddpa,
2380b9d0646949bd382758763664d3bf2d6115993aephilippe                         void (*shrink_block)(void*, SizeT))
2397293d2530f8c60c1060f9f003e214cc341d35266philippe{
240e3e515b85bce2fdfadabac0a566bbc4a3a2178fephilippe   if (VG_(clo_stats)
2417293d2530f8c60c1060f9f003e214cc341d35266philippe       && (VG_(clo_verbosity) > 2 || VG_(debugLog_getLevel) () >= 2)) {
2427293d2530f8c60c1060f9f003e214cc341d35266philippe      print_stats(ddpa);
2437293d2530f8c60c1060f9f003e214cc341d35266philippe   }
2441554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   vg_assert (!ddpa->fixedSzb || VG_(sizeXA) (ddpa->pools) == 1);
2451554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   if (shrink_block && ddpa->curpool_limit > ddpa->curpool_free)
2461554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      (*shrink_block)(ddpa->curpool, ddpa->curpool_free - ddpa->curpool);
2477293d2530f8c60c1060f9f003e214cc341d35266philippe   VG_(HT_destruct) ( ddpa->ht_elements, htelem_dummyfree);
2487293d2530f8c60c1060f9f003e214cc341d35266philippe   ddpa->ht_elements = NULL;
2497293d2530f8c60c1060f9f003e214cc341d35266philippe   VG_(deletePA) (ddpa->ht_node_pa);
2507293d2530f8c60c1060f9f003e214cc341d35266philippe   ddpa->ht_node_pa = NULL;
2517293d2530f8c60c1060f9f003e214cc341d35266philippe}
2527293d2530f8c60c1060f9f003e214cc341d35266philippe
253883315ac4b9308db4506078fd6768bd69dbcc821philippe
254883315ac4b9308db4506078fd6768bd69dbcc821philippe// hash function used by gawk and SDBM.
255883315ac4b9308db4506078fd6768bd69dbcc821philippestatic UInt sdbm_hash (const UChar* buf, UInt len )
256883315ac4b9308db4506078fd6768bd69dbcc821philippe{
257883315ac4b9308db4506078fd6768bd69dbcc821philippe  UInt h;
258883315ac4b9308db4506078fd6768bd69dbcc821philippe  UInt i;
259883315ac4b9308db4506078fd6768bd69dbcc821philippe
260883315ac4b9308db4506078fd6768bd69dbcc821philippe  h = 0;
261883315ac4b9308db4506078fd6768bd69dbcc821philippe  for (i = 0; i < len; i++)
262883315ac4b9308db4506078fd6768bd69dbcc821philippe    h = *buf++ + (h<<6) + (h<<16) - h;
263883315ac4b9308db4506078fd6768bd69dbcc821philippe  return h;
264883315ac4b9308db4506078fd6768bd69dbcc821philippe}
265883315ac4b9308db4506078fd6768bd69dbcc821philippe
266ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughesstatic ht_node* allocEltDedupPA (DedupPoolAlloc *ddpa, SizeT eltSzB,
267ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                                 const void *elt)
2687293d2530f8c60c1060f9f003e214cc341d35266philippe{
2697293d2530f8c60c1060f9f003e214cc341d35266philippe   ht_node ht_elt;
2707293d2530f8c60c1060f9f003e214cc341d35266philippe   void* elt_ins;
2717293d2530f8c60c1060f9f003e214cc341d35266philippe   ht_node *ht_ins;
2727293d2530f8c60c1060f9f003e214cc341d35266philippe   vg_assert(ddpa);
2737293d2530f8c60c1060f9f003e214cc341d35266philippe   vg_assert(ddpa->ht_elements);
2747293d2530f8c60c1060f9f003e214cc341d35266philippe
2757293d2530f8c60c1060f9f003e214cc341d35266philippe   ddpa->nr_alloc_calls++;
2767293d2530f8c60c1060f9f003e214cc341d35266philippe
277883315ac4b9308db4506078fd6768bd69dbcc821philippe   ht_elt.key = sdbm_hash (elt, eltSzB);
2787293d2530f8c60c1060f9f003e214cc341d35266philippe
2791ef70c6f00ab1b50d1936f77037e9923d8ed8c59florian   ht_elt.elt = elt;
2807293d2530f8c60c1060f9f003e214cc341d35266philippe
281ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   if (ddpa->strPA)
282ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      ht_ins = VG_(HT_gen_lookup) (ddpa->ht_elements, &ht_elt, cmp_pool_str);
283ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   else {
284ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      ht_elt.eltSzBorStrNr = eltSzB;
285ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      ht_ins = VG_(HT_gen_lookup) (ddpa->ht_elements, &ht_elt, cmp_pool_elt);
286ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   }
2877293d2530f8c60c1060f9f003e214cc341d35266philippe   if (ht_ins)
288ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      return ht_ins;
2897293d2530f8c60c1060f9f003e214cc341d35266philippe
2907293d2530f8c60c1060f9f003e214cc341d35266philippe   /* Not found -> we need to allocate a new element from the pool
2917293d2530f8c60c1060f9f003e214cc341d35266philippe      and insert it in the hash table of inserted elements. */
2927293d2530f8c60c1060f9f003e214cc341d35266philippe
2931554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   // Add a new pool or grow pool if not enough space in the current pool
294a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   if (eltSzB + ddpa->eltAlign > ddpa->poolSzB) {
295a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      // Element (+eltAlign for worst case) bigger than the pool size
296a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      // => allocate a specific pool just for this element
297a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      UChar *newpool = ddpa->alloc_fn (ddpa->cc, eltSzB + ddpa->eltAlign);
298a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      /* add to our collection of pools */
299a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      VG_(addToXA)( ddpa->pools, &newpool );
300a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      elt_ins = ddpa_align (ddpa, newpool);
301a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   } else {
302a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      if (UNLIKELY(ddpa->curpool_free == NULL
303a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes                   || ddpa->curpool_free + eltSzB - 1 > ddpa->curpool_limit)) {
304a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes         ddpa_add_new_pool_or_grow (ddpa);
305a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      }
306a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      elt_ins = ddpa->curpool_free;
307a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes      ddpa->curpool_free = ddpa_align(ddpa, ddpa->curpool_free + eltSzB);
3087293d2530f8c60c1060f9f003e214cc341d35266philippe   }
3097293d2530f8c60c1060f9f003e214cc341d35266philippe
3107293d2530f8c60c1060f9f003e214cc341d35266philippe
311a0664b9ca67b594bd6f570a61d3301167a24750cElliott Hughes   VG_(memcpy)(elt_ins, elt, eltSzB);
3127293d2530f8c60c1060f9f003e214cc341d35266philippe   ht_ins = VG_(allocEltPA) (ddpa->ht_node_pa);
3137293d2530f8c60c1060f9f003e214cc341d35266philippe   ht_ins->key = ht_elt.key;
314ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   if (ddpa->strPA)
315ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      ht_ins->eltSzBorStrNr = VG_(HT_count_nodes)(ddpa->ht_elements) + 1;
316ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   else
317ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      ht_ins->eltSzBorStrNr = eltSzB;
3187293d2530f8c60c1060f9f003e214cc341d35266philippe   ht_ins->elt = elt_ins;
3197293d2530f8c60c1060f9f003e214cc341d35266philippe   VG_(HT_add_node)(ddpa->ht_elements, ht_ins);
320ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   return ht_ins;
321ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes}
322ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes
323ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughesconst void* VG_(allocEltDedupPA) (DedupPoolAlloc *ddpa, SizeT eltSzB,
324ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                                  const void *elt)
325ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes{
326ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   return allocEltDedupPA(ddpa, eltSzB, elt)->elt;
327ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes}
328ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes
329ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott HughesUInt VG_(allocStrDedupPA) (DedupPoolAlloc *ddpa,
330ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                           const HChar* str,
331ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes                           Bool* newStr)
332ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes{
333ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   if (!ddpa->strPA) {
334ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      // First insertion in this ddpa
335ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      vg_assert (ddpa->nr_alloc_calls == 0);
336ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      vg_assert (ddpa->fixedSzb == 0);
337ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      ddpa->strPA = True;
338ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   }
339ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes
340ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   const UInt nr_str = VG_(HT_count_nodes)(ddpa->ht_elements);
341ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   const ht_node* ht_ins = allocEltDedupPA(ddpa, VG_(strlen)(str)+1, str);
342ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes
343ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   *newStr = nr_str < VG_(HT_count_nodes)(ddpa->ht_elements);
344ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes   return ht_ins->eltSzBorStrNr;
3457293d2530f8c60c1060f9f003e214cc341d35266philippe}
3461554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe
3471554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippestatic __inline__
3481554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippeUInt elt2nr (DedupPoolAlloc *ddpa, const void *dedup_elt)
3491554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe{
3508eebf23c35d97489c0d3c8b41dd542e00ae6acbdflorian   vg_assert (dedup_elt >= (const void *)ddpa->curpool
3518eebf23c35d97489c0d3c8b41dd542e00ae6acbdflorian              && dedup_elt < (const void *)ddpa->curpool_free);
3528eebf23c35d97489c0d3c8b41dd542e00ae6acbdflorian   return 1 + ((const UChar*)dedup_elt - (const UChar *)ddpa->curpool)
3531554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      / VG_ROUNDUP(ddpa->fixedSzb, ddpa->eltAlign);
3541554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe}
3551554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe
3561554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippeUInt VG_(allocFixedEltDedupPA) (DedupPoolAlloc *ddpa,
3571554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe                                SizeT eltSzB, const void *elt)
3581554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe{
3591554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   if (ddpa->fixedSzb == 0) {
3601554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      // First insertion in this ddpa
361ed39800a83baf5bffbe391f3974eb2af0f415f80Elliott Hughes      vg_assert (!ddpa->strPA);
3621554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      vg_assert (ddpa->nr_alloc_calls == 0);
3631554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      vg_assert (eltSzB > 0);
3641554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      ddpa->fixedSzb = eltSzB;
3651554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   }
3661554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   vg_assert (ddpa->fixedSzb == eltSzB);
3671ef70c6f00ab1b50d1936f77037e9923d8ed8c59florian   const void *dedup_elt = VG_(allocEltDedupPA) (ddpa, eltSzB, elt);
3681554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   return elt2nr (ddpa, dedup_elt);
3691554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe}
3701554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe
3711554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippevoid* VG_(indexEltNumber) (DedupPoolAlloc *ddpa,
3721554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe                           UInt eltNr)
3731554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe{
3741554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   void *dedup_elt;
3751554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe
376e3e515b85bce2fdfadabac0a566bbc4a3a2178fephilippe   dedup_elt = ddpa->curpool
3771554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      + (eltNr - 1) * VG_ROUNDUP(ddpa->fixedSzb, ddpa->eltAlign);
3781554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe
379e3e515b85bce2fdfadabac0a566bbc4a3a2178fephilippe   vg_assert ((UChar*)dedup_elt >= ddpa->curpool
3801554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe              && (UChar*)dedup_elt < ddpa->curpool_free);
3811554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe
3821554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   return dedup_elt;
3831554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe}
3841554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe
3851554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippeUInt VG_(sizeDedupPA) (DedupPoolAlloc *ddpa)
3861554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe{
3871554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   if (ddpa->curpool == NULL)
3881554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      return 0;
3891554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe
3901554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   vg_assert (ddpa->fixedSzb);
3911554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe   return (ddpa->curpool_free - ddpa_align(ddpa, ddpa->curpool))
3921554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe      / VG_ROUNDUP(ddpa->fixedSzb, ddpa->eltAlign);
3931554fa55be1fb1a7c6633d11ea8ff95be78a9dc6philippe}
394