void freeInternedStrings() { int unmarked = 0; hashIterateP(hash_table); if(unmarked) { int size; /* Update count to remaining number of strings */ hash_table.hash_count -= unmarked; /* Calculate nearest multiple of 2 larger than count */ for(size = 1; size < hash_table.hash_count; size <<= 1); /* Ensure new table is less than 2/3 full */ size = hash_table.hash_count*3 > size*2 ? size<< 1 : size; resizeHash(&hash_table, size); } }
//The following function is converted from the macro with the same name,since it may lead compiling error under //Microsoft Visual Studio. static void _findHashEntry(HashTable* table,Object* ptr,Monitor* ptr2,int add_if_absent,int scavenge,int locked) { int hash; int i; Thread *self; hash = HASH(ptr); if(locked) { self = threadSelf(); lockHashTable0(table, self); } i = hash & (table->hash_size - 1); for(;;) { ptr2 = table->hash_table[i].data; if((ptr2 == NULL) || (COMPARE(ptr, ptr2, hash, table->hash_table[i].hash))) break; i = (i+1) & (table->hash_size - 1); } if(ptr2) { ptr2 = FOUND(ptr, ptr2); } else if(add_if_absent) { table->hash_table[i].hash = hash; ptr2 = table->hash_table[i].data = PREPARE(ptr); if(ptr2) { table->hash_count++; if((table->hash_count * 4) > (table->hash_size * 3)) { int new_size; if(scavenge) { HashEntry *entry = table->hash_table; int cnt = table->hash_count; for(; cnt; entry++) { void *data = entry->data; if(data) { if(SCAVENGE(data)) { entry->data = NULL; table->hash_count--; } cnt--; } } if((table->hash_count * 3) > (table->hash_size * 2)) new_size = table->hash_size*2; else new_size = table->hash_size; } else new_size = table->hash_size*2; resizeHash(table, new_size); } } } if(locked) unlockHashTable0(table, self); }
/* * Look up an entry. * * We probe on collisions, wrapping around the table. */ void* dvmHashTableLookup(HashTable* pHashTable, u4 itemHash, void* item, HashCompareFunc cmpFunc, bool doAdd) { HashEntry* pEntry; HashEntry* pEnd; void* result = NULL; assert(pHashTable->tableSize > 0); assert(item != HASH_TOMBSTONE); assert(item != NULL); /* jump to the first entry and probe for a match */ pEntry = &pHashTable->pEntries[itemHash & (pHashTable->tableSize-1)]; pEnd = &pHashTable->pEntries[pHashTable->tableSize]; while (pEntry->data != NULL) { if (pEntry->data != HASH_TOMBSTONE && pEntry->hashValue == itemHash && (*cmpFunc)(pEntry->data, item) == 0) { /* match */ //LOGD("+++ match on entry %d\n", pEntry - pHashTable->pEntries); break; } pEntry++; if (pEntry == pEnd) { /* wrap around to start */ if (pHashTable->tableSize == 1) break; /* edge case - single-entry table */ pEntry = pHashTable->pEntries; } //LOGI("+++ look probing %d...\n", pEntry - pHashTable->pEntries); } if (pEntry->data == NULL) { if (doAdd) { pEntry->hashValue = itemHash; pEntry->data = item; pHashTable->numEntries++; /* * We've added an entry. See if this brings us too close to full. */ if ((pHashTable->numEntries+pHashTable->numDeadEntries) * LOAD_DENOM > pHashTable->tableSize * LOAD_NUMER) { if (!resizeHash(pHashTable, pHashTable->tableSize * 2)) { /* don't really have a way to indicate failure */ LOGE("Dalvik hash resize failure\n"); dvmAbort(); } /* note "pEntry" is now invalid */ } else { //LOGW("okay %d/%d/%d\n", // pHashTable->numEntries, pHashTable->tableSize, // (pHashTable->tableSize * LOAD_NUMER) / LOAD_DENOM); } /* full table is bad -- search for nonexistent never halts */ assert(pHashTable->numEntries < pHashTable->tableSize); result = item; } else { assert(result == NULL); } } else { result = pEntry->data; } return result; }