Path: blob/master/runtime/compiler/ras/HashTable.cpp
6000 views
/*******************************************************************************1* Copyright (c) 2000, 2019 IBM Corp. and others2*3* This program and the accompanying materials are made available under4* the terms of the Eclipse Public License 2.0 which accompanies this5* distribution and is available at https://www.eclipse.org/legal/epl-2.0/6* or the Apache License, Version 2.0 which accompanies this distribution and7* is available at https://www.apache.org/licenses/LICENSE-2.0.8*9* This Source Code may also be made available under the following10* Secondary Licenses when the conditions for such availability set11* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU12* General Public License, version 2 with the GNU Classpath13* Exception [1] and GNU General Public License, version 2 with the14* OpenJDK Assembly Exception [2].15*16* [1] https://www.gnu.org/software/classpath/license.html17* [2] http://openjdk.java.net/legal/assembly-exception.html18*19* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 OR LicenseRef-GPL-2.0 WITH Assembly-exception20*******************************************************************************/2122#include "ras/HashTable.hpp"2324#include <stddef.h>25#include <stdint.h>26#include <string.h>27#include "env/TRMemory.hpp"28#include "infra/Assert.hpp"2930void *31TR_HashTableEntry::operator new[] (size_t s, TR_Memory *mem)32{33return mem->allocateMemory(s, heapAlloc, TR_MemoryBase::HashTableEntry);34}3536void *37TR_HashTable::operator new (size_t s, TR_Memory *mem)38{39return mem->allocateMemory(s, heapAlloc, TR_MemoryBase::HashTable);40}4142TR_HashTable::TR_HashTable(TR_Memory *mem, TR_HashIndex numElements)43:_mem(mem)44{45uint32_t closedAreaSize = 2, openAreaSize;4647if (numElements > MINIMUM_HASHTABLE_SIZE)48while (closedAreaSize < numElements)49closedAreaSize <<= 1;50else51closedAreaSize = MINIMUM_HASHTABLE_SIZE;5253openAreaSize = closedAreaSize >> 2;5455_mask = closedAreaSize - 1;56_nextFree = closedAreaSize + 1;57_tableSize = closedAreaSize + openAreaSize;58_highestIndex = 0;5960_table = new (_mem) TR_HashTableEntry[_tableSize];6162// Invalidate all hash table entries.63TR_HashIndex i;64for (i = 0; i < _nextFree; i++)65_table[i].invalidate();6667// Initialize the rehash area to link up the free chain.68for (i = _nextFree; i < _tableSize - 1; i++)69{70_table[i].invalidate();71_table[i].setCollisionChain(i + 1);72}7374_table[_tableSize - 1].invalidate();75_table[_tableSize - 1].setCollisionChain(0);76}7778TR_HashTable::TR_HashTable(const TR_HashTable &table, TR_Memory *mem)79: _mem(mem),80_mask(table._mask),81_nextFree(table._nextFree),82_tableSize(table._tableSize),83_highestIndex(table._highestIndex)84{85_table = new (_mem) TR_HashTableEntry[_tableSize];8687for (TR_HashIndex i = 0; i < _tableSize; i++)88{89TR_HashTableEntry &entry = table._table[i];90if (entry.isValid())91{92new ((void *)(_table + i)) TR_HashTableEntry(entry);93}94else95{96_table[i].invalidate();97_table[i].setCollisionChain(entry.getCollisionChain());98}99}100}101102bool103TR_HashTable::locate(void *key, TR_HashIndex &index, TR_HashCode hashCode)104{105if (hashCode == 0)106{107hashCode = calculateHashCode(key);108TR_ASSERT( hashCode != 0, "invalid hash code\n");109}110111index = (hashCode & _mask) + 1;112TR_ASSERT( index != 0, "invalid index\n");113114if (!_table[index].isValid())115return false;116117#ifdef DEBUG118uint32_t collisions = 0;119TR_HashIndex collisionIndex = index;120#endif121while ((_table[index].getHashCode() != hashCode) ||122!isEqual(key, _table[index].getKey()))123{124#ifdef DEBUG125++collisions;126#endif127if (_table[index].getCollisionChain() != 0)128index = _table[index].getCollisionChain();129else130return false;131}132133return true;134}135136bool137TR_HashTable::add(void *key, void *data, TR_HashCode hashCode)138{139TR_HashIndex index;140141if (hashCode == 0)142{143hashCode = calculateHashCode(key);144TR_ASSERT( hashCode != 0, "invalid hash code\n");145}146147if (locate(key, index, hashCode))148return false;149150if (_nextFree == 0)151{152grow();153bool found = locate(key, index, hashCode);154TR_ASSERT( !found, "buggy TR_HashTable::growAndRehash()\n");155}156157if (_table[index].isValid())158{159_table[index].setCollisionChain(_nextFree);160index = _nextFree;161_nextFree = _table[_nextFree].getCollisionChain();162}163164if (index > _highestIndex)165_highestIndex = index;166167new ((void *)(_table + index)) TR_HashTableEntry(key, data, hashCode);168169return true;170}171172void173TR_HashTable::remove(TR_HashIndex index)174{175TR_ASSERT( _table[index].isValid(), "attempt to remove invalid hash table entry\n");176177// If the entry is in the rehash area, locate the head of the hash chain and178// follow it to unlink this entry from the chain. Then return the rehash area179// space to the free pool.180if (index > _mask + 1)181{182TR_HashIndex headOfChain = (_table[index].getHashCode() & _mask) + 1;183TR_HashIndex collisionIndex;184185for (collisionIndex = headOfChain;186_table[collisionIndex].getCollisionChain() != index;187collisionIndex = _table[collisionIndex].getCollisionChain())188TR_ASSERT( collisionIndex != 0, "cannot find record on expected chain\n");189190_table[collisionIndex].setCollisionChain(_table[index].getCollisionChain());191_table[index].setCollisionChain(_nextFree);192_table[index].invalidate();193_nextFree = index;194}195else196{197// The entry is in the closed hash table section.198// If it has any chained entries in the rehash area, then choose one199// to put in its place.200TR_HashIndex firstCollision;201if (( firstCollision = _table[index].getCollisionChain() ) != 0)202{203memcpy(_table + index, _table + firstCollision, sizeof(TR_HashTableEntry));204_table[firstCollision].setCollisionChain(_nextFree);205_table[firstCollision].invalidate();206_nextFree = firstCollision;207}208else209{210_table[index].invalidate();211}212}213}214215bool216TR_HashTable::isEmpty() const217{218bool empty = true;219for (TR_HashIndex i = 0; i < _tableSize; i++)220{221if (_table[i].isValid())222{223empty = false;224break;225}226}227return empty;228}229230void231TR_HashTable::removeAll()232{233TR_HashIndex i;234235_highestIndex = 0;236237for (i = 0; i <= _mask + 1; i++)238if (_table[i].isValid())239_table[i].invalidate();240241_nextFree = _mask + 2;242243for (i = _nextFree; i < _tableSize - 1; i++)244{245if (_table[i].isValid())246_table[i].invalidate();247248_table[i].setCollisionChain(i + 1);249}250251if (_table[_tableSize - 1].isValid())252_table[_tableSize - 1].invalidate();253254_table[_tableSize - 1].setCollisionChain(0);255}256257void258TR_HashTable::grow(uint32_t newSize)259{260uint32_t closedAreaSize = 2, openAreaSize;261262while (closedAreaSize < newSize)263closedAreaSize <<= 1;264265openAreaSize = closedAreaSize >> 2;266267if (closedAreaSize + openAreaSize < _tableSize)268return;269270growAndRehash(_table, _tableSize, closedAreaSize, openAreaSize);271}272273void274TR_HashTable::grow()275{276uint32_t newSize = (_mask << 1) | 1;277growAndRehash(_table, _tableSize, newSize + 1, (newSize + 1) / 4);278}279280void281TR_HashTable::growAndRehash(TR_HashTableEntry *oldTable,282TR_HashIndex oldSize,283TR_HashIndex closedAreaSize,284TR_HashIndex openAreaSize)285{286_mask = closedAreaSize - 1;287_nextFree = closedAreaSize + 1;288_tableSize = closedAreaSize + openAreaSize;289_highestIndex = 0;290291_table = new (_mem) TR_HashTableEntry[_tableSize];292293TR_HashIndex i;294for (i = 0; i < _nextFree; i++)295_table[i].invalidate();296297for (i = _nextFree; i < _tableSize - 1; i++)298{299_table[i].invalidate();300_table[i].setCollisionChain(i + 1);301}302303_table[_tableSize - 1].invalidate();304_table[_tableSize - 1].setCollisionChain(0);305306for (i = 0; i < oldSize; i++)307{308if (oldTable[i].isValid())309{310TR_HashIndex index;311TR_HashCode oldHashCode = oldTable[i].getHashCode();312313bool found = locate(oldTable[i].getKey(), index, oldHashCode);314TR_ASSERT(!found, "unable to rehash entry %d", i);315316if (_table[index].isValid())317{318_table[index].setCollisionChain(_nextFree);319index = _nextFree;320_nextFree = _table[_nextFree].getCollisionChain();321}322323if (index > _highestIndex)324_highestIndex = index;325326memcpy(_table + index, oldTable + i, sizeof(TR_HashTableEntry));327_table[index].setCollisionChain(0);328}329}330}331332333