]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: optionally check all allocations in hashmap.c
authorJan Ziak <0xe2.0x9a.0x9b@gmail.com>
Mon, 25 Mar 2013 20:35:46 +0000 (21:35 +0100)
committerJan Ziak <0xe2.0x9a.0x9b@gmail.com>
Mon, 25 Mar 2013 20:35:46 +0000 (21:35 +0100)
Adds the new debugging constant 'checkgc'. If its value is non-zero
all calls to mallocgc() from hashmap.c will start a garbage collection.

Fixes #5074.

R=golang-dev, khr
CC=golang-dev, rsc
https://golang.org/cl/7663051

src/pkg/runtime/hashmap.c

index 0f92becab266381e8e1a40c17222cf9eb8d7712b..036af5a249c18f398141216293d2f0851f678c5a 100644 (file)
@@ -126,6 +126,7 @@ enum
 {
        docheck = 0,  // check invariants before and after every op.  Slow!!!
        debug = 0,    // print every operation
+       checkgc = 0 || docheck,  // check interaction of mallocgc() with the garbage collector
 };
 static void
 check(MapType *t, Hmap *h)
@@ -253,6 +254,7 @@ hash_init(MapType *t, Hmap *h, uint32 hint)
 
        // allocate initial hash table
        // If hint is large zeroing this memory could take a while.
+       if(checkgc) mstats.next_gc = mstats.heap_alloc;
        buckets = runtime·mallocgc(bucketsize << B, 0, 1, 0);
        for(i = 0; i < (uintptr)1 << B; i++) {
                b = (Bucket*)(buckets + i * bucketsize);
@@ -322,6 +324,7 @@ evacuate(MapType *t, Hmap *h, uintptr oldbucket)
                                // the B'th bit of the hash in this case.
                                if((hash & newbit) == 0) {
                                        if(xi == BUCKETSIZE) {
+                                               if(checkgc) mstats.next_gc = mstats.heap_alloc;
                                                newx = runtime·mallocgc(h->bucketsize, 0, 1, 0);
                                                clearbucket(newx);
                                                x->overflow = newx;
@@ -346,6 +349,7 @@ evacuate(MapType *t, Hmap *h, uintptr oldbucket)
                                        xv += h->valuesize;
                                } else {
                                        if(yi == BUCKETSIZE) {
+                                               if(checkgc) mstats.next_gc = mstats.heap_alloc;
                                                newy = runtime·mallocgc(h->bucketsize, 0, 1, 0);
                                                clearbucket(newy);
                                                y->overflow = newy;
@@ -441,6 +445,7 @@ hash_grow(MapType *t, Hmap *h)
                runtime·throw("evacuation not done in time");
        old_buckets = h->buckets;
        // NOTE: this could be a big malloc, but since we don't need zeroing it is probably fast.
+       if(checkgc) mstats.next_gc = mstats.heap_alloc;
        new_buckets = runtime·mallocgc(h->bucketsize << (h->B + 1), 0, 1, 0);
        flags = (h->flags & ~(Iterator | OldIterator));
        if((h->flags & Iterator) != 0) {
@@ -611,6 +616,7 @@ hash_insert(MapType *t, Hmap *h, void *key, void *value)
 
        if(inserti == nil) {
                // all current buckets are full, allocate a new one.
+               if(checkgc) mstats.next_gc = mstats.heap_alloc;
                newb = runtime·mallocgc(h->bucketsize, 0, 1, 0);
                clearbucket(newb);
                b->overflow = newb;
@@ -621,11 +627,13 @@ hash_insert(MapType *t, Hmap *h, void *key, void *value)
 
        // store new key/value at insert position
        if((h->flags & IndirectKey) != 0) {
+               if(checkgc) mstats.next_gc = mstats.heap_alloc;
                kmem = runtime·mallocgc(t->key->size, 0, 1, 0);
                *(byte**)insertk = kmem;
                insertk = kmem;
        }
        if((h->flags & IndirectValue) != 0) {
+               if(checkgc) mstats.next_gc = mstats.heap_alloc;
                vmem = runtime·mallocgc(t->elem->size, 0, 1, 0);
                *(byte**)insertv = vmem;
                insertv = vmem;