Home | History | Annotate | Download | only in coregrind
      1 
      2 /*--------------------------------------------------------------------*/
      3 /*--- An sparse array (of words) implementation.                   ---*/
      4 /*---                                                 m_sparsewa.c ---*/
      5 /*--------------------------------------------------------------------*/
      6 
      7 /*
      8    This file is part of Valgrind, a dynamic binary instrumentation
      9    framework.
     10 
     11    Copyright (C) 2008-2010 OpenWorks Ltd
     12       info (at) open-works.co.uk
     13 
     14    This program is free software; you can redistribute it and/or
     15    modify it under the terms of the GNU General Public License as
     16    published by the Free Software Foundation; either version 2 of the
     17    License, or (at your option) any later version.
     18 
     19    This program is distributed in the hope that it will be useful, but
     20    WITHOUT ANY WARRANTY; without even the implied warranty of
     21    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     22    General Public License for more details.
     23 
     24    You should have received a copy of the GNU General Public License
     25    along with this program; if not, write to the Free Software
     26    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
     27    02111-1307, USA.
     28 
     29    The GNU General Public License is contained in the file COPYING.
     30 */
     31 
     32 #include "pub_core_basics.h"
     33 #include "pub_core_libcassert.h"
     34 #include "pub_core_libcbase.h"
     35 #include "pub_core_sparsewa.h"      /* self */
     36 
     37 /////////////////////////////////////////////////////////
     38 //                                                     //
     39 // SparseWA: Implementation                            //
     40 //                                                     //
     41 /////////////////////////////////////////////////////////
     42 
     43 //////// SWA data structures
     44 
     45 // (UInt) `echo "Level Zero Byte Map" | md5sum`
     46 #define Level0_MAGIC 0x458ec222
     47 
     48 // (UInt) `echo "Level N Byte Map" | md5sum`
     49 #define LevelN_MAGIC 0x0a280a1a
     50 
     51 /* It's important that the .magic field appears at offset zero in both
     52    structs, so that we can reliably distinguish between them. */
     53 
     54 typedef
     55    struct {
     56       UWord magic;
     57       UWord words[256];
     58       Int   nInUse;
     59       UChar inUse[256/8];
     60    }
     61    Level0;
     62 
     63 typedef
     64    struct {
     65       UWord magic;
     66       void* child[256]; /* either LevelN* or Level0* */
     67       Int   nInUse;
     68       Int   level; /* 3 .. 1 on 32-bit, 7 .. 1 on 64-bit */
     69    }
     70    LevelN;
     71 
     72 typedef
     73    struct {
     74       UWord partial_key;
     75       Int   curr_ix;
     76       void* curr_nd; /* LevelN* or Level0* */
     77       Int   resume_point; /* 1, 2 or 3 */
     78    }
     79    SWAStackElem;
     80 
     81 struct _SparseWA {
     82    void*        (*alloc_nofail)(HChar*,SizeT);
     83    HChar*       cc;
     84    void         (*dealloc)(void*);
     85    LevelN*      root;
     86    SWAStackElem iterStack[8];
     87    Int          isUsed;
     88 };
     89 
     90 //////// SWA helper functions (bitarray)
     91 
     92 static inline UWord swa_bitarray_read ( UChar* arr, UWord ix ) {
     93    UWord bix = ix >> 3;
     94    UWord off = ix & 7;
     95    return (arr[bix] >> off) & 1;
     96 }
     97 
     98 static inline UWord swa_bitarray_read_then_set ( UChar* arr, UWord ix ) {
     99    UWord bix = ix >> 3;
    100    UWord off = ix & 7;
    101    UChar old = arr[bix];
    102    UChar nyu = old | (1 << off);
    103    arr[bix] = nyu;
    104    return (old >> off) & 1;
    105 }
    106 
    107 static inline UWord swa_bitarray_read_then_clear ( UChar* arr, UWord ix ) {
    108    UWord bix = ix >> 3;
    109    UWord off = ix & 7;
    110    UChar old = arr[bix];
    111    UChar nyu = old & ~(1 << off);
    112    arr[bix] = nyu;
    113    return (old >> off) & 1;
    114 }
    115 
    116 //////// SWA helper functions (iteration)
    117 
    118 static void swa_PUSH ( SparseWA* swa, UWord partial_key, Int curr_ix,
    119                                       void* curr_nd, Int resume_point )
    120 {
    121    Int sp = swa->isUsed;
    122    const Int _3_or_7 = sizeof(void*) - 1;
    123    // if (0) VG_(printf)("PUSH, old sp = %d\n", sp);
    124    vg_assert(sp >= 0 && sp <= _3_or_7);
    125    swa->iterStack[sp].partial_key  = partial_key;
    126    swa->iterStack[sp].curr_ix      = curr_ix;
    127    swa->iterStack[sp].curr_nd      = curr_nd;
    128    swa->iterStack[sp].resume_point = resume_point;
    129    swa->isUsed = sp+1;
    130 }
    131 
    132 static void swa_POP ( SparseWA* swa,
    133                       UWord* partial_key, Int* curr_ix,
    134                       void** curr_nd, Int* resume_point )
    135 {
    136    Int sp = swa->isUsed - 1;
    137    const Int _3_or_7 = sizeof(void*) - 1;
    138    // if (0) VG_(printf)("POP,  old sp = %d\n", sp+1);
    139    vg_assert(sp >= 0 && sp <= _3_or_7);
    140    *partial_key  = swa->iterStack[sp].partial_key;
    141    *curr_ix      = swa->iterStack[sp].curr_ix;
    142    *curr_nd      = swa->iterStack[sp].curr_nd;
    143    *resume_point = swa->iterStack[sp].resume_point;
    144    swa->isUsed = sp;
    145 }
    146 
    147 //////// SWA helper functions (allocation)
    148 
    149 static LevelN* swa_new_LevelN ( SparseWA* swa, Int level )
    150 {
    151    LevelN* levelN = swa->alloc_nofail( swa->cc, sizeof(LevelN) );
    152    VG_(memset)(levelN, 0, sizeof(*levelN));
    153    levelN->magic = LevelN_MAGIC;
    154    levelN->level = level;
    155    return levelN;
    156 }
    157 
    158 static Level0* swa_new_Level0 ( SparseWA* swa )
    159 {
    160    Level0* level0 = swa->alloc_nofail( swa->cc, sizeof(Level0) );
    161    VG_(memset)(level0, 0, sizeof(*level0));
    162    level0->magic = Level0_MAGIC;
    163    return level0;
    164 }
    165 
    166 
    167 //////// SWA public interface
    168 
    169 void VG_(initIterSWA) ( SparseWA* swa )
    170 {
    171    swa->isUsed = 0;
    172    if (swa->root) swa_PUSH(swa, 0, 0, swa->root, 1/*start_new_node*/);
    173 }
    174 
    175 
    176 Bool VG_(nextIterSWA)( SparseWA* swa,
    177                        /*OUT*/UWord* keyP, /*OUT*/UWord* valP )
    178 {
    179    UWord p_key;
    180    Int   curr_ix;
    181    void* curr_nd;
    182    Int   resume_point;
    183 
    184    /* dispatch whatever's on top of the stack; what that actually
    185       means is to return to some previously-saved context. */
    186    dispatch:
    187 
    188    if (swa->isUsed == 0)
    189       return False;
    190 
    191    swa_POP(swa, &p_key, &curr_ix, &curr_nd, &resume_point);
    192    switch (resume_point) {
    193       case 1:  goto start_new_node;
    194       case 2:  goto resume_leaf_node;
    195       case 3:  goto resume_nonleaf_node;
    196       default: vg_assert(0);
    197    }
    198 
    199    start_new_node:
    200    if (*(UWord*)curr_nd == Level0_MAGIC) {
    201       /* curr_nd is a leaf node */
    202       Level0* level0 = (Level0*)curr_nd;
    203       for (curr_ix = 0; curr_ix < 256; curr_ix++) {
    204          if (swa_bitarray_read(level0->inUse, curr_ix) == 1) {
    205             swa_PUSH(swa, p_key, curr_ix, curr_nd, 2/*resume_leaf_node*/);
    206             *keyP = (p_key << 8) + (UWord)curr_ix;
    207             *valP = level0->words[curr_ix];
    208             return True;
    209             resume_leaf_node:
    210             level0 = (Level0*)curr_nd;
    211          }
    212       }
    213    } else {
    214       /* curr_nd is a non-leaf node */
    215       LevelN* levelN;
    216       vg_assert(*(UWord*)curr_nd == LevelN_MAGIC);
    217       levelN = (LevelN*)curr_nd;
    218       for (curr_ix = 0; curr_ix < 256; curr_ix++) {
    219          if (levelN->child[curr_ix]) {
    220             swa_PUSH(swa, p_key, curr_ix, curr_nd, 3/*resume_nonleaf_node*/);
    221             p_key = (p_key << 8) + (UWord)curr_ix;
    222             curr_nd = levelN->child[curr_ix];
    223             goto start_new_node;
    224             resume_nonleaf_node:
    225             levelN = (LevelN*)curr_nd;
    226          }
    227       }
    228    }
    229 
    230    goto dispatch;
    231 }
    232 
    233 
    234 SparseWA* VG_(newSWA) ( void*(*alloc_nofail)(HChar* cc, SizeT),
    235                         HChar* cc,
    236                         void(*dealloc)(void*) )
    237 {
    238    SparseWA* swa;
    239    vg_assert(alloc_nofail);
    240    vg_assert(cc);
    241    vg_assert(dealloc);
    242    swa = alloc_nofail( cc, sizeof(SparseWA) );
    243    VG_(memset)(swa, 0, sizeof(*swa));
    244    swa->alloc_nofail = alloc_nofail;
    245    swa->cc = cc;
    246    swa->dealloc = dealloc;
    247    swa->root = NULL;
    248    return swa;
    249 }
    250 
    251 
    252 static void swa_deleteSWA_wrk ( void(*dealloc)(void*), void* nd )
    253 {
    254    Int i;
    255    vg_assert(nd);
    256    if (*(UWord*)nd == LevelN_MAGIC) {
    257       LevelN* levelN = (LevelN*)nd;
    258       for (i = 0; i < 256; i++) {
    259          if (levelN->child[i]) {
    260             swa_deleteSWA_wrk( dealloc, levelN->child[i] );
    261          }
    262       }
    263    } else {
    264       vg_assert(*(UWord*)nd == Level0_MAGIC);
    265    }
    266    dealloc(nd);
    267 }
    268 void VG_(deleteSWA) ( SparseWA* swa )
    269 {
    270    if (swa->root)
    271       swa_deleteSWA_wrk( swa->dealloc, swa->root );
    272    swa->dealloc(swa);
    273 }
    274 
    275 
    276 Bool VG_(lookupSWA) ( SparseWA* swa,
    277                       /*OUT*/UWord* keyP, /*OUT*/UWord* valP,
    278                       UWord key )
    279 {
    280    Int     i;
    281    UWord   ix;
    282    Level0* level0;
    283    LevelN* levelN;
    284    const Int _3_or_7 = sizeof(void*) - 1;
    285 
    286    vg_assert(swa);
    287    levelN = swa->root;
    288 
    289    /* levels 3/7 .. 1 */
    290    for (i = _3_or_7; i >= 1; i--) {
    291       if (!levelN) return False;
    292       vg_assert(levelN->level == i);
    293       vg_assert(levelN->nInUse > 0);
    294       ix = (key >> (i*8)) & 0xFF;
    295       levelN = levelN->child[ix];
    296    }
    297 
    298    /* level0 */
    299    level0 = (Level0*)levelN;
    300    if (!level0) return False;
    301    vg_assert(level0->magic == Level0_MAGIC);
    302    vg_assert(level0->nInUse > 0);
    303    ix = key & 0xFF;
    304    if (swa_bitarray_read(level0->inUse, ix) == 0) return False;
    305    *keyP = key; /* this is stupid.  only here to make it look like WordFM */
    306    *valP = level0->words[ix];
    307    return True;
    308 }
    309 
    310 
    311 Bool VG_(addToSWA) ( SparseWA* swa, UWord key, UWord val )
    312 {
    313    Int     i;
    314    UWord   ix;
    315    Level0* level0;
    316    LevelN* levelN;
    317    Bool    already_present;
    318    const Int _3_or_7 = sizeof(void*) - 1;
    319 
    320    vg_assert(swa);
    321 
    322    if (!swa->root)
    323       swa->root = swa_new_LevelN(swa, _3_or_7);
    324    levelN = swa->root;
    325 
    326    /* levels 3/7 .. 2 */
    327    for (i = _3_or_7; i >= 2; i--) {
    328       /* levelN is the level-i map */
    329       vg_assert(levelN);
    330       vg_assert(levelN->level == i);
    331       ix = (key >> (i*8)) & 0xFF;
    332       if (levelN->child[ix] == NULL) {
    333          levelN->child[ix] = swa_new_LevelN(swa, i-1);
    334          levelN->nInUse++;
    335       }
    336       vg_assert(levelN->nInUse >= 1 && levelN->nInUse <= 256);
    337       levelN = levelN->child[ix];
    338    }
    339 
    340    /* levelN is the level-1 map */
    341    vg_assert(levelN);
    342    vg_assert(levelN->level == 1);
    343    ix = (key >> (1*8)) & 0xFF;
    344    if (levelN->child[ix] == NULL) {
    345       levelN->child[ix] = swa_new_Level0(swa);
    346       levelN->nInUse++;
    347    }
    348    vg_assert(levelN->nInUse >= 1 && levelN->nInUse <= 256);
    349    level0 = levelN->child[ix];
    350 
    351    /* level0 is the level-0 map */
    352    vg_assert(level0);
    353    vg_assert(level0->magic == Level0_MAGIC);
    354    ix = key & 0xFF;
    355    if (swa_bitarray_read_then_set(level0->inUse, ix) == 0) {
    356       level0->nInUse++;
    357       already_present = False;
    358    } else {
    359       already_present = True;
    360    }
    361    vg_assert(level0->nInUse >= 1 && level0->nInUse <= 256);
    362    level0->words[ix] = val;
    363 
    364    return already_present;
    365 }
    366 
    367 
    368 Bool VG_(delFromSWA) ( SparseWA* swa,
    369                        /*OUT*/UWord* oldK, /*OUT*/UWord* oldV, UWord key )
    370 {
    371    Int     i;
    372    UWord   ix;
    373    Level0* level0;
    374    LevelN* levelN;
    375    const Int _3_or_7 = sizeof(void*) - 1;
    376 
    377    LevelN* visited[_3_or_7];
    378    UWord   visitedIx[_3_or_7];
    379    Int     nVisited = 0;
    380 
    381    vg_assert(swa);
    382    levelN = swa->root;
    383 
    384    /* levels 3/7 .. 1 */
    385    for (i = _3_or_7; i >= 1; i--) {
    386       /* level i */
    387       if (!levelN) return False;
    388       vg_assert(levelN->level == i);
    389       vg_assert(levelN->nInUse > 0);
    390       ix = (key >> (i*8)) & 0xFF;
    391       visited[nVisited]     = levelN;
    392       visitedIx[nVisited++] = ix;
    393       levelN = levelN->child[ix];
    394    }
    395 
    396    /* level 0 */
    397    level0 = (Level0*)levelN;
    398    if (!level0) return False;
    399    vg_assert(level0->magic == Level0_MAGIC);
    400    vg_assert(level0->nInUse > 0);
    401    ix = key & 0xFF;
    402 
    403    if (swa_bitarray_read_then_clear(level0->inUse, ix) == 0)
    404       return False;
    405 
    406    *oldK = key; /* this is silly */
    407    *oldV = level0->words[ix];
    408 
    409    level0->nInUse--;
    410    if (level0->nInUse > 0)
    411       return True;
    412 
    413    vg_assert(nVisited == _3_or_7);
    414    swa->dealloc( level0 );
    415 
    416    /* levels 1 .. 3/7 */
    417    for (i = 1; i <= _3_or_7; i++) {
    418       /* level i */
    419       nVisited--;
    420       vg_assert(visited[nVisited]->child[ visitedIx[nVisited] ]);
    421       visited[nVisited]->child[ visitedIx[nVisited] ] = NULL;
    422       visited[nVisited]->nInUse--;
    423       vg_assert(visited[nVisited]->nInUse >= 0);
    424       if (visited[nVisited]->nInUse > 0)
    425          return True;
    426       swa->dealloc(visited[nVisited]);
    427    }
    428 
    429    vg_assert(nVisited == 0);
    430    swa->root = NULL;
    431    return True;
    432 }
    433 
    434 
    435 static UWord swa_sizeSWA_wrk ( void* nd )
    436 {
    437    Int   i;
    438    UWord sum = 0;
    439    if (*(UWord*)nd == LevelN_MAGIC) {
    440       LevelN* levelN = (LevelN*)nd;
    441       for (i = 0; i < 256; i++) {
    442          if (levelN->child[i]) {
    443             sum += swa_sizeSWA_wrk( levelN->child[i] );
    444          }
    445       }
    446    } else {
    447       Level0* level0;
    448       vg_assert(*(UWord*)nd == Level0_MAGIC);
    449       level0 = (Level0*)nd;
    450       for (i = 0; i < 256/8; i += 2) {
    451          UWord x = level0->inUse[i+0]; /* assume zero-extend */
    452          UWord y = level0->inUse[i+1]; /* assume zero-extend */
    453          /* do 'sum += popcount(x) + popcount(y)' for byte-sized x, y */
    454          /* unroll the loop twice so as to expose more ILP */
    455          x = (x & 0x55) + ((x >> 1) & 0x55);
    456          y = (y & 0x55) + ((y >> 1) & 0x55);
    457          x = (x & 0x33) + ((x >> 2) & 0x33);
    458          y = (y & 0x33) + ((y >> 2) & 0x33);
    459          x = (x & 0x0F) + ((x >> 4) & 0x0F);
    460          y = (y & 0x0F) + ((y >> 4) & 0x0F);
    461          sum += x + y;
    462       }
    463    }
    464    return sum;
    465 }
    466 UWord VG_(sizeSWA) ( SparseWA* swa )
    467 {
    468    if (swa->root)
    469       return swa_sizeSWA_wrk ( swa->root );
    470    else
    471       return 0;
    472 }
    473 
    474 
    475 
    476 /*--------------------------------------------------------------------*/
    477 /*--- end                                             m_sparsewa.c ---*/
    478 /*--------------------------------------------------------------------*/
    479