Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openj9
Path: blob/master/runtime/compiler/ras/HashTable.cpp
6000 views
1
/*******************************************************************************
2
* Copyright (c) 2000, 2019 IBM Corp. and others
3
*
4
* This program and the accompanying materials are made available under
5
* the terms of the Eclipse Public License 2.0 which accompanies this
6
* distribution and is available at https://www.eclipse.org/legal/epl-2.0/
7
* or the Apache License, Version 2.0 which accompanies this distribution and
8
* is available at https://www.apache.org/licenses/LICENSE-2.0.
9
*
10
* This Source Code may also be made available under the following
11
* Secondary Licenses when the conditions for such availability set
12
* forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
13
* General Public License, version 2 with the GNU Classpath
14
* Exception [1] and GNU General Public License, version 2 with the
15
* OpenJDK Assembly Exception [2].
16
*
17
* [1] https://www.gnu.org/software/classpath/license.html
18
* [2] http://openjdk.java.net/legal/assembly-exception.html
19
*
20
* 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-exception
21
*******************************************************************************/
22
23
#include "ras/HashTable.hpp"
24
25
#include <stddef.h>
26
#include <stdint.h>
27
#include <string.h>
28
#include "env/TRMemory.hpp"
29
#include "infra/Assert.hpp"
30
31
void *
32
TR_HashTableEntry::operator new[] (size_t s, TR_Memory *mem)
33
{
34
return mem->allocateMemory(s, heapAlloc, TR_MemoryBase::HashTableEntry);
35
}
36
37
void *
38
TR_HashTable::operator new (size_t s, TR_Memory *mem)
39
{
40
return mem->allocateMemory(s, heapAlloc, TR_MemoryBase::HashTable);
41
}
42
43
TR_HashTable::TR_HashTable(TR_Memory *mem, TR_HashIndex numElements)
44
:_mem(mem)
45
{
46
uint32_t closedAreaSize = 2, openAreaSize;
47
48
if (numElements > MINIMUM_HASHTABLE_SIZE)
49
while (closedAreaSize < numElements)
50
closedAreaSize <<= 1;
51
else
52
closedAreaSize = MINIMUM_HASHTABLE_SIZE;
53
54
openAreaSize = closedAreaSize >> 2;
55
56
_mask = closedAreaSize - 1;
57
_nextFree = closedAreaSize + 1;
58
_tableSize = closedAreaSize + openAreaSize;
59
_highestIndex = 0;
60
61
_table = new (_mem) TR_HashTableEntry[_tableSize];
62
63
// Invalidate all hash table entries.
64
TR_HashIndex i;
65
for (i = 0; i < _nextFree; i++)
66
_table[i].invalidate();
67
68
// Initialize the rehash area to link up the free chain.
69
for (i = _nextFree; i < _tableSize - 1; i++)
70
{
71
_table[i].invalidate();
72
_table[i].setCollisionChain(i + 1);
73
}
74
75
_table[_tableSize - 1].invalidate();
76
_table[_tableSize - 1].setCollisionChain(0);
77
}
78
79
TR_HashTable::TR_HashTable(const TR_HashTable &table, TR_Memory *mem)
80
: _mem(mem),
81
_mask(table._mask),
82
_nextFree(table._nextFree),
83
_tableSize(table._tableSize),
84
_highestIndex(table._highestIndex)
85
{
86
_table = new (_mem) TR_HashTableEntry[_tableSize];
87
88
for (TR_HashIndex i = 0; i < _tableSize; i++)
89
{
90
TR_HashTableEntry &entry = table._table[i];
91
if (entry.isValid())
92
{
93
new ((void *)(_table + i)) TR_HashTableEntry(entry);
94
}
95
else
96
{
97
_table[i].invalidate();
98
_table[i].setCollisionChain(entry.getCollisionChain());
99
}
100
}
101
}
102
103
bool
104
TR_HashTable::locate(void *key, TR_HashIndex &index, TR_HashCode hashCode)
105
{
106
if (hashCode == 0)
107
{
108
hashCode = calculateHashCode(key);
109
TR_ASSERT( hashCode != 0, "invalid hash code\n");
110
}
111
112
index = (hashCode & _mask) + 1;
113
TR_ASSERT( index != 0, "invalid index\n");
114
115
if (!_table[index].isValid())
116
return false;
117
118
#ifdef DEBUG
119
uint32_t collisions = 0;
120
TR_HashIndex collisionIndex = index;
121
#endif
122
while ((_table[index].getHashCode() != hashCode) ||
123
!isEqual(key, _table[index].getKey()))
124
{
125
#ifdef DEBUG
126
++collisions;
127
#endif
128
if (_table[index].getCollisionChain() != 0)
129
index = _table[index].getCollisionChain();
130
else
131
return false;
132
}
133
134
return true;
135
}
136
137
bool
138
TR_HashTable::add(void *key, void *data, TR_HashCode hashCode)
139
{
140
TR_HashIndex index;
141
142
if (hashCode == 0)
143
{
144
hashCode = calculateHashCode(key);
145
TR_ASSERT( hashCode != 0, "invalid hash code\n");
146
}
147
148
if (locate(key, index, hashCode))
149
return false;
150
151
if (_nextFree == 0)
152
{
153
grow();
154
bool found = locate(key, index, hashCode);
155
TR_ASSERT( !found, "buggy TR_HashTable::growAndRehash()\n");
156
}
157
158
if (_table[index].isValid())
159
{
160
_table[index].setCollisionChain(_nextFree);
161
index = _nextFree;
162
_nextFree = _table[_nextFree].getCollisionChain();
163
}
164
165
if (index > _highestIndex)
166
_highestIndex = index;
167
168
new ((void *)(_table + index)) TR_HashTableEntry(key, data, hashCode);
169
170
return true;
171
}
172
173
void
174
TR_HashTable::remove(TR_HashIndex index)
175
{
176
TR_ASSERT( _table[index].isValid(), "attempt to remove invalid hash table entry\n");
177
178
// If the entry is in the rehash area, locate the head of the hash chain and
179
// follow it to unlink this entry from the chain. Then return the rehash area
180
// space to the free pool.
181
if (index > _mask + 1)
182
{
183
TR_HashIndex headOfChain = (_table[index].getHashCode() & _mask) + 1;
184
TR_HashIndex collisionIndex;
185
186
for (collisionIndex = headOfChain;
187
_table[collisionIndex].getCollisionChain() != index;
188
collisionIndex = _table[collisionIndex].getCollisionChain())
189
TR_ASSERT( collisionIndex != 0, "cannot find record on expected chain\n");
190
191
_table[collisionIndex].setCollisionChain(_table[index].getCollisionChain());
192
_table[index].setCollisionChain(_nextFree);
193
_table[index].invalidate();
194
_nextFree = index;
195
}
196
else
197
{
198
// The entry is in the closed hash table section.
199
// If it has any chained entries in the rehash area, then choose one
200
// to put in its place.
201
TR_HashIndex firstCollision;
202
if (( firstCollision = _table[index].getCollisionChain() ) != 0)
203
{
204
memcpy(_table + index, _table + firstCollision, sizeof(TR_HashTableEntry));
205
_table[firstCollision].setCollisionChain(_nextFree);
206
_table[firstCollision].invalidate();
207
_nextFree = firstCollision;
208
}
209
else
210
{
211
_table[index].invalidate();
212
}
213
}
214
}
215
216
bool
217
TR_HashTable::isEmpty() const
218
{
219
bool empty = true;
220
for (TR_HashIndex i = 0; i < _tableSize; i++)
221
{
222
if (_table[i].isValid())
223
{
224
empty = false;
225
break;
226
}
227
}
228
return empty;
229
}
230
231
void
232
TR_HashTable::removeAll()
233
{
234
TR_HashIndex i;
235
236
_highestIndex = 0;
237
238
for (i = 0; i <= _mask + 1; i++)
239
if (_table[i].isValid())
240
_table[i].invalidate();
241
242
_nextFree = _mask + 2;
243
244
for (i = _nextFree; i < _tableSize - 1; i++)
245
{
246
if (_table[i].isValid())
247
_table[i].invalidate();
248
249
_table[i].setCollisionChain(i + 1);
250
}
251
252
if (_table[_tableSize - 1].isValid())
253
_table[_tableSize - 1].invalidate();
254
255
_table[_tableSize - 1].setCollisionChain(0);
256
}
257
258
void
259
TR_HashTable::grow(uint32_t newSize)
260
{
261
uint32_t closedAreaSize = 2, openAreaSize;
262
263
while (closedAreaSize < newSize)
264
closedAreaSize <<= 1;
265
266
openAreaSize = closedAreaSize >> 2;
267
268
if (closedAreaSize + openAreaSize < _tableSize)
269
return;
270
271
growAndRehash(_table, _tableSize, closedAreaSize, openAreaSize);
272
}
273
274
void
275
TR_HashTable::grow()
276
{
277
uint32_t newSize = (_mask << 1) | 1;
278
growAndRehash(_table, _tableSize, newSize + 1, (newSize + 1) / 4);
279
}
280
281
void
282
TR_HashTable::growAndRehash(TR_HashTableEntry *oldTable,
283
TR_HashIndex oldSize,
284
TR_HashIndex closedAreaSize,
285
TR_HashIndex openAreaSize)
286
{
287
_mask = closedAreaSize - 1;
288
_nextFree = closedAreaSize + 1;
289
_tableSize = closedAreaSize + openAreaSize;
290
_highestIndex = 0;
291
292
_table = new (_mem) TR_HashTableEntry[_tableSize];
293
294
TR_HashIndex i;
295
for (i = 0; i < _nextFree; i++)
296
_table[i].invalidate();
297
298
for (i = _nextFree; i < _tableSize - 1; i++)
299
{
300
_table[i].invalidate();
301
_table[i].setCollisionChain(i + 1);
302
}
303
304
_table[_tableSize - 1].invalidate();
305
_table[_tableSize - 1].setCollisionChain(0);
306
307
for (i = 0; i < oldSize; i++)
308
{
309
if (oldTable[i].isValid())
310
{
311
TR_HashIndex index;
312
TR_HashCode oldHashCode = oldTable[i].getHashCode();
313
314
bool found = locate(oldTable[i].getKey(), index, oldHashCode);
315
TR_ASSERT(!found, "unable to rehash entry %d", i);
316
317
if (_table[index].isValid())
318
{
319
_table[index].setCollisionChain(_nextFree);
320
index = _nextFree;
321
_nextFree = _table[_nextFree].getCollisionChain();
322
}
323
324
if (index > _highestIndex)
325
_highestIndex = index;
326
327
memcpy(_table + index, oldTable + i, sizeof(TR_HashTableEntry));
328
_table[index].setCollisionChain(0);
329
}
330
}
331
}
332
333