]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/valgrind/src/valgrind-3.6.0-svn/coregrind/m_sparsewa.c
update
[l4.git] / l4 / pkg / valgrind / src / valgrind-3.6.0-svn / coregrind / m_sparsewa.c
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@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 /*--------------------------------------------------------------------*/