From 639817de90dafbc8cc98a63ff05a7a5ade5dffc1 Mon Sep 17 00:00:00 2001 From: luben Date: Mon, 16 Aug 2010 18:34:46 +0300 Subject: [PATCH 9/9] Important fixes * make hash again work with N_BUCKETS(X) != X * fix memory allocation problems catched by more strict allocators. libhoard catched some use-after-free bugs. * realocate pointers in linear scan - it's faster --- src/hash.c | 88 ++++++++++++++++++++++++++++++++++-------------------------- 1 files changed, 50 insertions(+), 38 deletions(-) diff --git a/src/hash.c b/src/hash.c index 07a9b18..145cea5 100644 --- a/src/hash.c +++ b/src/hash.c @@ -781,15 +781,17 @@ static void expand_hash(PARROT_INTERP, ARGMOD(Hash *hash)) { ASSERT_ARGS(expand_hash) - HashBucket **old_index, **new_index; - HashBucket *old_buckets,*new_buckets, *bucket; - HashBucket * const old_offset = (HashBucket *)((char *)hash + sizeof (Hash)); + + HashBucket **new_index, **index; + HashBucket *new_buckets, *bucket; + + HashBucket * const initial_offset = (HashBucket *)((char *)hash + sizeof (Hash)); void * new_mem; void * const old_mem = hash->buckets; const UINTVAL old_size = hash->mask + 1; - const UINTVAL new_size = old_size << 1; /* Double. Right-shift is 2x */ - const UINTVAL new_mask = new_size - 1 ; + const UINTVAL new_size = old_size << 1; /* Double. Right-shift is 2x */ + const UINTVAL new_mask = new_size - 1; size_t offset, i; /* @@ -804,46 +806,57 @@ expand_hash(PARROT_INTERP, ARGMOD(Hash *hash)) */ /* resize mem */ - if (old_offset != old_mem) { + if (initial_offset != old_mem) { /* This buffer has been reallocated at least once before. */ - new_mem = Parrot_gc_reallocate_memory_chunk_with_interior_pointers( - interp, old_mem, HASH_ALLOC_SIZE(new_size), HASH_ALLOC_SIZE(old_size)); - } + new_mem = Parrot_gc_reallocate_memory_chunk_with_interior_pointers( + interp, old_mem, + HASH_ALLOC_SIZE(new_size), + HASH_ALLOC_SIZE(old_size)); + + new_buckets = (HashBucket *) new_mem; + new_index = (HashBucket **)(new_buckets + N_BUCKETS(new_size)); + + offset = (char *)new_mem - (char *)old_mem; + + /* old index is here */ + index = (HashBucket **)(new_buckets + N_BUCKETS(old_size)); + /* reallocate index */ + mem_sys_memcopy(new_index, index, sizeof(HashBucket *) * old_size); + + /* clear second half of the buckets, freed by old the index */ + memset(new_buckets + N_BUCKETS(old_size), 0, + sizeof (HashBucket *) * old_size); + } else { /* Allocate a new buffer. */ new_mem = Parrot_gc_allocate_memory_chunk_with_interior_pointers( interp, HASH_ALLOC_SIZE(new_size)); - memcpy(new_mem, old_mem, HASH_ALLOC_SIZE(old_size)); + + new_buckets = (HashBucket *) new_mem; + new_index = (HashBucket **)(new_buckets + N_BUCKETS(new_size)); + + offset = (char *)new_buckets - (char *)hash->buckets; + + mem_sys_memcopy(new_buckets, hash->buckets , + N_BUCKETS(old_size) * sizeof (HashBucket)); + mem_sys_memcopy(new_index, hash->index, + sizeof(HashBucket *) * old_size); } /* +---+---+---+---+---+---+-+-+-+-+-+-+-+-+ - | buckets | old_index | new_index | + | buckets | old_index | new_index | +---+---+---+---+---+---+-+-+-+-+-+-+-+-+ ^ ^ | new_mem | hash->index */ - old_buckets = hash->buckets; - old_index = hash->index; - - new_buckets = (HashBucket *) new_mem; - new_index = (HashBucket **)(new_buckets + N_BUCKETS(new_size)); - - /* things can have moved by this offset */ - offset = (char *)new_buckets - (char *)old_buckets; - - /* relocate the bucket index */ - mem_sys_memmove(new_index, old_index, old_size * sizeof (HashBucket *)); /* update hash data */ hash->index = new_index; hash->buckets = new_buckets; hash->mask = new_mask; - /* clear freshly allocated bucket index */ - memset(new_index + old_size, 0, sizeof (HashBucket *) * old_size); - /* * reloc pointers - this part would be also needed, if we * allocate hash memory from GC movable memory, and then @@ -851,33 +864,32 @@ expand_hash(PARROT_INTERP, ARGMOD(Hash *hash)) * as expand_hash is only called for that case). */ if (offset) { - size_t j; - for (j = 0; j < old_size; ++j) { - HashBucket **next_p = new_index + j; - while (*next_p) { - *next_p = (HashBucket *)((char *)*next_p + offset); - bucket = *next_p; - next_p = &bucket->next; + for (i = 0; i < old_size; ++i) { + index = new_index + i; + while (*index) { + *index = (HashBucket *)((char *)*index + offset); + bucket = *index; + index = &bucket->next; } } } /* recalc bucket index */ for (i = 0; i < old_size; ++i) { - HashBucket **next_p = new_index + i; + index = new_index + i; - while ((bucket = *next_p) != NULL) { + while ((bucket = *index) != NULL) { /* rehash the bucket */ const size_t new_loc = get_hash_val(interp, hash, bucket->key) & new_mask; if (i != new_loc) { - *next_p = bucket->next; - bucket->next = new_index[new_loc]; - new_index[new_loc] = bucket; + *index = bucket->next; + bucket->next = new_index[new_loc]; + new_index[new_loc] = bucket; } else - next_p = &bucket->next; + index = &bucket->next; } } -- 1.7.1