Skip to content

Commit 1228517

Browse files
committed
8256274: C2: Optimize copying of the shared type dictionary
Reviewed-by: neliasso, kvn
1 parent 537b40e commit 1228517

File tree

3 files changed

+112
-177
lines changed

3 files changed

+112
-177
lines changed

src/hotspot/share/libadt/dict.cpp

Lines changed: 88 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -47,7 +47,7 @@ static const short xsum[MAXID] = {3,8,17,34,67,132,261,264,269,278,295,328,393,5
4747
class bucket : public ResourceObj {
4848
public:
4949
uint _cnt, _max; // Size of bucket
50-
void **_keyvals; // Array of keys and values
50+
void** _keyvals; // Array of keys and values
5151
};
5252

5353
//------------------------------Dict-----------------------------------------
@@ -64,75 +64,70 @@ Dict::Dict(CmpKey initcmp, Hash inithash) : _arena(Thread::current()->resource_a
6464

6565
_size = 16; // Size is a power of 2
6666
_cnt = 0; // Dictionary is empty
67-
_bin = (bucket*)_arena->Amalloc_4(sizeof(bucket)*_size);
68-
memset((void*)_bin,0,sizeof(bucket)*_size);
67+
_bin = (bucket*)_arena->Amalloc_4(sizeof(bucket) * _size);
68+
memset((void*)_bin, 0, sizeof(bucket) * _size);
6969
}
7070

71-
Dict::Dict(CmpKey initcmp, Hash inithash, Arena *arena, int size)
71+
Dict::Dict(CmpKey initcmp, Hash inithash, Arena* arena, int size)
7272
: _arena(arena), _hash(inithash), _cmp(initcmp) {
7373
// Size is a power of 2
7474
_size = MAX2(16, round_up_power_of_2(size));
7575

7676
_cnt = 0; // Dictionary is empty
77-
_bin = (bucket*)_arena->Amalloc_4(sizeof(bucket)*_size);
78-
memset((void*)_bin,0,sizeof(bucket)*_size);
77+
_bin = (bucket*)_arena->Amalloc_4(sizeof(bucket) * _size);
78+
memset((void*)_bin, 0, sizeof(bucket) * _size);
7979
}
8080

81-
//------------------------------~Dict------------------------------------------
82-
// Delete an existing dictionary.
83-
Dict::~Dict() {
84-
/*
85-
tty->print("~Dict %d/%d: ",_cnt,_size);
86-
for( uint i=0; i < _size; i++) // For complete new table do
87-
tty->print("%d ",_bin[i]._cnt);
88-
tty->print("\n");*/
89-
/*for( uint i=0; i<_size; i++ ) {
90-
FREE_FAST( _bin[i]._keyvals );
91-
} */
81+
// Deep copy into arena of choice
82+
Dict::Dict(const Dict &d, Arena* arena)
83+
: _arena(arena), _size(d._size), _cnt(d._cnt), _hash(d._hash), _cmp(d._cmp) {
84+
_bin = (bucket*)_arena->Amalloc_4(sizeof(bucket) * _size);
85+
memcpy((void*)_bin, (void*)d._bin, sizeof(bucket) * _size);
86+
for (uint i = 0; i < _size; i++) {
87+
if (!_bin[i]._keyvals) {
88+
continue;
89+
}
90+
_bin[i]._keyvals = (void**)_arena->Amalloc_4(sizeof(void*) * _bin[i]._max * 2);
91+
memcpy(_bin[i]._keyvals, d._bin[i]._keyvals, _bin[i]._cnt * 2 * sizeof(void*));
92+
}
9293
}
9394

94-
//------------------------------Clear----------------------------------------
95-
// Zap to empty; ready for re-use
96-
void Dict::Clear() {
97-
_cnt = 0; // Empty contents
98-
for( uint i=0; i<_size; i++ )
99-
_bin[i]._cnt = 0; // Empty buckets, but leave allocated
100-
// Leave _size & _bin alone, under the assumption that dictionary will
101-
// grow to this size again.
102-
}
95+
//------------------------------~Dict------------------------------------------
96+
// Delete an existing dictionary.
97+
Dict::~Dict() { }
10398

10499
//------------------------------doubhash---------------------------------------
105100
// Double hash table size. If can't do so, just suffer. If can, then run
106101
// thru old hash table, moving things to new table. Note that since hash
107102
// table doubled, exactly 1 new bit is exposed in the mask - so everything
108103
// in the old table ends up on 1 of two lists in the new table; a hi and a
109104
// lo list depending on the value of the bit.
110-
void Dict::doubhash(void) {
105+
void Dict::doubhash() {
111106
uint oldsize = _size;
112107
_size <<= 1; // Double in size
113108
_bin = (bucket*)_arena->Arealloc(_bin, sizeof(bucket) * oldsize, sizeof(bucket) * _size);
114109
memset((void*)(&_bin[oldsize]), 0, oldsize * sizeof(bucket));
115110
// Rehash things to spread into new table
116111
for (uint i = 0; i < oldsize; i++) { // For complete OLD table do
117-
bucket *b = &_bin[i]; // Handy shortcut for _bin[i]
112+
bucket* b = &_bin[i]; // Handy shortcut for _bin[i]
118113
if (!b->_keyvals) continue; // Skip empties fast
119114

120-
bucket *nb = &_bin[i+oldsize]; // New bucket shortcut
115+
bucket* nb = &_bin[i+oldsize]; // New bucket shortcut
121116
uint j = b->_max; // Trim new bucket to nearest power of 2
122117
while (j > b->_cnt) { j >>= 1; } // above old bucket _cnt
123118
if (!j) { j = 1; } // Handle zero-sized buckets
124119
nb->_max = j << 1;
125120
// Allocate worst case space for key-value pairs
126-
nb->_keyvals = (void**)_arena->Amalloc_4(sizeof(void *) * nb->_max * 2);
121+
nb->_keyvals = (void**)_arena->Amalloc_4(sizeof(void* ) * nb->_max * 2);
127122
uint nbcnt = 0;
128123

129-
for (j = 0; j < b->_cnt; ) { // Rehash all keys in this bucket
130-
void *key = b->_keyvals[j + j];
124+
for (j = 0; j < b->_cnt;) { // Rehash all keys in this bucket
125+
void* key = b->_keyvals[j + j];
131126
if ((_hash(key) & (_size-1)) != i) { // Moving to hi bucket?
132127
nb->_keyvals[nbcnt + nbcnt] = key;
133128
nb->_keyvals[nbcnt + nbcnt + 1] = b->_keyvals[j + j + 1];
134129
nb->_cnt = nbcnt = nbcnt + 1;
135-
b->_cnt--; // Remove key/value from lo bucket
130+
b->_cnt--; // Remove key/value from lo bucket
136131
b->_keyvals[j + j] = b->_keyvals[b->_cnt + b->_cnt];
137132
b->_keyvals[j + j + 1] = b->_keyvals[b->_cnt + b->_cnt + 1];
138133
// Don't increment j, hash compacted element also.
@@ -143,135 +138,86 @@ void Dict::doubhash(void) {
143138
} // End of for all buckets
144139
}
145140

146-
//------------------------------Dict-----------------------------------------
147-
// Deep copy a dictionary.
148-
Dict::Dict( const Dict &d ) : ResourceObj(d), _arena(d._arena), _size(d._size), _cnt(d._cnt), _hash(d._hash), _cmp(d._cmp) {
149-
_bin = (bucket*)_arena->Amalloc_4(sizeof(bucket)*_size);
150-
memcpy( (void*)_bin, (void*)d._bin, sizeof(bucket)*_size );
151-
for( uint i=0; i<_size; i++ ) {
152-
if( !_bin[i]._keyvals ) continue;
153-
_bin[i]._keyvals=(void**)_arena->Amalloc_4( sizeof(void *)*_bin[i]._max*2);
154-
memcpy( _bin[i]._keyvals, d._bin[i]._keyvals,_bin[i]._cnt*2*sizeof(void*));
155-
}
156-
}
157-
158-
//------------------------------Dict-----------------------------------------
159-
// Deep copy a dictionary.
160-
Dict &Dict::operator =( const Dict &d ) {
161-
if( _size < d._size ) { // If must have more buckets
162-
_arena = d._arena;
163-
_bin = (bucket*)_arena->Arealloc( _bin, sizeof(bucket)*_size, sizeof(bucket)*d._size );
164-
memset( (void*)(&_bin[_size]), 0, (d._size-_size)*sizeof(bucket) );
165-
_size = d._size;
166-
}
167-
uint i;
168-
for( i=0; i<_size; i++ ) // All buckets are empty
169-
_bin[i]._cnt = 0; // But leave bucket allocations alone
170-
_cnt = d._cnt;
171-
*(Hash*)(&_hash) = d._hash;
172-
*(CmpKey*)(&_cmp) = d._cmp;
173-
for( i=0; i<_size; i++ ) {
174-
bucket *b = &d._bin[i]; // Shortcut to source bucket
175-
for( uint j=0; j<b->_cnt; j++ )
176-
Insert( b->_keyvals[j+j], b->_keyvals[j+j+1] );
177-
}
178-
return *this;
179-
}
180-
181141
//------------------------------Insert----------------------------------------
182142
// Insert or replace a key/value pair in the given dictionary. If the
183143
// dictionary is too full, it's size is doubled. The prior value being
184144
// replaced is returned (NULL if this is a 1st insertion of that key). If
185145
// an old value is found, it's swapped with the prior key-value pair on the
186146
// list. This moves a commonly searched-for value towards the list head.
187-
void *Dict::Insert(void *key, void *val, bool replace) {
188-
uint hash = _hash( key ); // Get hash key
189-
uint i = hash & (_size-1); // Get hash key, corrected for size
190-
bucket *b = &_bin[i]; // Handy shortcut
191-
for( uint j=0; j<b->_cnt; j++ ) {
192-
if( !_cmp(key,b->_keyvals[j+j]) ) {
147+
void*Dict::Insert(void* key, void* val, bool replace) {
148+
uint hash = _hash(key); // Get hash key
149+
uint i = hash & (_size - 1); // Get hash key, corrected for size
150+
bucket* b = &_bin[i];
151+
for (uint j = 0; j < b->_cnt; j++) {
152+
if (!_cmp(key, b->_keyvals[j + j])) {
193153
if (!replace) {
194-
return b->_keyvals[j+j+1];
154+
return b->_keyvals[j + j + 1];
195155
} else {
196-
void *prior = b->_keyvals[j+j+1];
197-
b->_keyvals[j+j ] = key; // Insert current key-value
198-
b->_keyvals[j+j+1] = val;
199-
return prior; // Return prior
156+
void* prior = b->_keyvals[j + j + 1];
157+
b->_keyvals[j + j ] = key;
158+
b->_keyvals[j + j + 1] = val;
159+
return prior;
200160
}
201161
}
202162
}
203-
if( ++_cnt > _size ) { // Hash table is full
163+
if (++_cnt > _size) { // Hash table is full
204164
doubhash(); // Grow whole table if too full
205-
i = hash & (_size-1); // Rehash
206-
b = &_bin[i]; // Handy shortcut
165+
i = hash & (_size - 1); // Rehash
166+
b = &_bin[i];
207167
}
208-
if( b->_cnt == b->_max ) { // Must grow bucket?
209-
if( !b->_keyvals ) {
168+
if (b->_cnt == b->_max) { // Must grow bucket?
169+
if (!b->_keyvals) {
210170
b->_max = 2; // Initial bucket size
211171
b->_keyvals = (void**)_arena->Amalloc_4(sizeof(void*) * b->_max * 2);
212172
} else {
213173
b->_keyvals = (void**)_arena->Arealloc(b->_keyvals, sizeof(void*) * b->_max * 2, sizeof(void*) * b->_max * 4);
214174
b->_max <<= 1; // Double bucket
215175
}
216176
}
217-
b->_keyvals[b->_cnt+b->_cnt ] = key;
218-
b->_keyvals[b->_cnt+b->_cnt+1] = val;
177+
b->_keyvals[b->_cnt + b->_cnt ] = key;
178+
b->_keyvals[b->_cnt + b->_cnt + 1] = val;
219179
b->_cnt++;
220180
return NULL; // Nothing found prior
221181
}
222182

223183
//------------------------------Delete---------------------------------------
224184
// Find & remove a value from dictionary. Return old value.
225-
void *Dict::Delete(void *key) {
226-
uint i = _hash( key ) & (_size-1); // Get hash key, corrected for size
227-
bucket *b = &_bin[i]; // Handy shortcut
228-
for( uint j=0; j<b->_cnt; j++ )
229-
if( !_cmp(key,b->_keyvals[j+j]) ) {
230-
void *prior = b->_keyvals[j+j+1];
185+
void* Dict::Delete(void* key) {
186+
uint i = _hash(key) & (_size - 1); // Get hash key, corrected for size
187+
bucket* b = &_bin[i]; // Handy shortcut
188+
for (uint j = 0; j < b->_cnt; j++) {
189+
if (!_cmp(key, b->_keyvals[j + j])) {
190+
void* prior = b->_keyvals[j + j + 1];
231191
b->_cnt--; // Remove key/value from lo bucket
232-
b->_keyvals[j+j ] = b->_keyvals[b->_cnt+b->_cnt ];
233-
b->_keyvals[j+j+1] = b->_keyvals[b->_cnt+b->_cnt+1];
192+
b->_keyvals[j+j ] = b->_keyvals[b->_cnt + b->_cnt ];
193+
b->_keyvals[j+j+1] = b->_keyvals[b->_cnt + b->_cnt + 1];
234194
_cnt--; // One less thing in table
235195
return prior;
236196
}
197+
}
237198
return NULL;
238199
}
239200

240201
//------------------------------FindDict-------------------------------------
241202
// Find a key-value pair in the given dictionary. If not found, return NULL.
242203
// If found, move key-value pair towards head of list.
243-
void *Dict::operator [](const void *key) const {
244-
uint i = _hash( key ) & (_size-1); // Get hash key, corrected for size
245-
bucket *b = &_bin[i]; // Handy shortcut
246-
for( uint j=0; j<b->_cnt; j++ )
247-
if( !_cmp(key,b->_keyvals[j+j]) )
248-
return b->_keyvals[j+j+1];
249-
return NULL;
250-
}
251-
252-
//------------------------------CmpDict--------------------------------------
253-
// CmpDict compares two dictionaries; they must have the same keys (their
254-
// keys must match using CmpKey) and they must have the same values (pointer
255-
// comparison). If so 1 is returned, if not 0 is returned.
256-
int32_t Dict::operator ==(const Dict &d2) const {
257-
if( _cnt != d2._cnt ) return 0;
258-
if( _hash != d2._hash ) return 0;
259-
if( _cmp != d2._cmp ) return 0;
260-
for( uint i=0; i < _size; i++) { // For complete hash table do
261-
bucket *b = &_bin[i]; // Handy shortcut
262-
if( b->_cnt != d2._bin[i]._cnt ) return 0;
263-
if( memcmp(b->_keyvals, d2._bin[i]._keyvals, b->_cnt*2*sizeof(void*) ) )
264-
return 0; // Key-value pairs must match
204+
void* Dict::operator [](const void* key) const {
205+
uint i = _hash(key) & (_size - 1); // Get hash key, corrected for size
206+
bucket* b = &_bin[i]; // Handy shortcut
207+
for (uint j = 0; j < b->_cnt; j++) {
208+
if (!_cmp(key, b->_keyvals[j + j])) {
209+
return b->_keyvals[j + j + 1];
210+
}
265211
}
266-
return 1; // All match, is OK
212+
return NULL;
267213
}
268214

269215
//------------------------------print------------------------------------------
270216
// Handier print routine
271217
void Dict::print() {
272218
DictI i(this); // Moved definition in iterator here because of g++.
273219
tty->print("Dict@" INTPTR_FORMAT "[%d] = {", p2i(this), _cnt);
274-
for( ; i.test(); ++i ) {
220+
for (; i.test(); ++i) {
275221
tty->print("(" INTPTR_FORMAT "," INTPTR_FORMAT "),", p2i(i._key), p2i(i._value));
276222
}
277223
tty->print_cr("}");
@@ -288,12 +234,12 @@ void Dict::print() {
288234
// be in the range 0-127 (I double & add 1 to force oddness). Keys are
289235
// limited to MAXID characters in length. Experimental evidence on 150K of
290236
// C text shows excellent spreading of values for any size hash table.
291-
int hashstr(const void *t) {
237+
int hashstr(const void* t) {
292238
char c, k = 0;
293239
int32_t sum = 0;
294-
const char *s = (const char *)t;
240+
const char* s = (const char*)t;
295241

296-
while( ((c = *s++) != '\0') && (k < MAXID-1) ) { // Get characters till null or MAXID-1
242+
while (((c = *s++) != '\0') && (k < MAXID-1)) { // Get characters till null or MAXID-1
297243
c = (c << 1) + 1; // Characters are always odd!
298244
sum += c + (c << shft[k++]); // Universal hash function
299245
}
@@ -303,33 +249,37 @@ int hashstr(const void *t) {
303249
//------------------------------hashptr--------------------------------------
304250
// Slimey cheap hash function; no guaranteed performance. Better than the
305251
// default for pointers, especially on MS-DOS machines.
306-
int hashptr(const void *key) {
252+
int hashptr(const void* key) {
307253
return ((intptr_t)key >> 2);
308254
}
309255

310256
// Slimey cheap hash function; no guaranteed performance.
311-
int hashkey(const void *key) {
257+
int hashkey(const void* key) {
312258
return (intptr_t)key;
313259
}
314260

315261
//------------------------------Key Comparator Functions---------------------
316-
int32_t cmpstr(const void *k1, const void *k2) {
317-
return strcmp((const char *)k1,(const char *)k2);
262+
int32_t cmpstr(const void* k1, const void* k2) {
263+
return strcmp((const char*)k1, (const char*)k2);
318264
}
319265

320266
// Cheap key comparator.
321-
int32_t cmpkey(const void *key1, const void *key2) {
322-
if (key1 == key2) return 0;
267+
int32_t cmpkey(const void* key1, const void* key2) {
268+
if (key1 == key2) {
269+
return 0;
270+
}
323271
intptr_t delta = (intptr_t)key1 - (intptr_t)key2;
324-
if (delta > 0) return 1;
272+
if (delta > 0) {
273+
return 1;
274+
}
325275
return -1;
326276
}
327277

328278
//=============================================================================
329279
//------------------------------reset------------------------------------------
330280
// Create an iterator and initialize the first variables.
331-
void DictI::reset( const Dict *dict ) {
332-
_d = dict; // The dictionary
281+
void DictI::reset(const Dict* dict) {
282+
_d = dict;
333283
_i = (uint)-1; // Before the first bin
334284
_j = 0; // Nothing left in the current bin
335285
++(*this); // Step to first real value
@@ -339,15 +289,17 @@ void DictI::reset( const Dict *dict ) {
339289
// Find the next key-value pair in the dictionary, or return a NULL key and
340290
// value.
341291
void DictI::operator ++(void) {
342-
if( _j-- ) { // Still working in current bin?
343-
_key = _d->_bin[_i]._keyvals[_j+_j];
344-
_value = _d->_bin[_i]._keyvals[_j+_j+1];
292+
if (_j--) { // Still working in current bin?
293+
_key = _d->_bin[_i]._keyvals[_j + _j];
294+
_value = _d->_bin[_i]._keyvals[_j + _j + 1];
345295
return;
346296
}
347297

348-
while( ++_i < _d->_size ) { // Else scan for non-zero bucket
298+
while (++_i < _d->_size) { // Else scan for non-zero bucket
349299
_j = _d->_bin[_i]._cnt;
350-
if( !_j ) continue;
300+
if (!_j) {
301+
continue;
302+
}
351303
_j--;
352304
_key = _d->_bin[_i]._keyvals[_j+_j];
353305
_value = _d->_bin[_i]._keyvals[_j+_j+1];

0 commit comments

Comments
 (0)