148 void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) { |
148 void G1StringDedupEntryCache::free(G1StringDedupEntry* entry, uint worker_id) { |
149 assert(entry->obj() != NULL, "Double free"); |
149 assert(entry->obj() != NULL, "Double free"); |
150 assert(worker_id < _nlists, "Invalid worker id"); |
150 assert(worker_id < _nlists, "Invalid worker id"); |
151 |
151 |
152 entry->set_obj(NULL); |
152 entry->set_obj(NULL); |
153 entry->set_hash(0); |
153 entry->set_java_hash(0); |
154 |
154 |
155 if (_cached[worker_id].length() < _max_list_length) { |
155 if (_cached[worker_id].length() < _max_list_length) { |
156 // Cache is not full |
156 // Cache is not full |
157 _cached[worker_id].add(entry); |
157 _cached[worker_id].add(entry); |
158 } else { |
158 } else { |
213 uintx G1StringDedupTable::_entries_added = 0; |
213 uintx G1StringDedupTable::_entries_added = 0; |
214 uintx G1StringDedupTable::_entries_removed = 0; |
214 uintx G1StringDedupTable::_entries_removed = 0; |
215 uintx G1StringDedupTable::_resize_count = 0; |
215 uintx G1StringDedupTable::_resize_count = 0; |
216 uintx G1StringDedupTable::_rehash_count = 0; |
216 uintx G1StringDedupTable::_rehash_count = 0; |
217 |
217 |
218 G1StringDedupTable::G1StringDedupTable(size_t size, jint hash_seed) : |
218 G1StringDedupTable::G1StringDedupTable(size_t size, uint64_t hash_seed) : |
219 _size(size), |
219 _size(size), |
220 _entries(0), |
220 _entries(0), |
221 _grow_threshold((uintx)(size * _grow_load_factor)), |
221 _grow_threshold((uintx)(size * _grow_load_factor)), |
222 _shrink_threshold((uintx)(size * _shrink_load_factor)), |
222 _shrink_threshold((uintx)(size * _shrink_load_factor)), |
223 _rehash_needed(false), |
223 _rehash_needed(false), |
235 assert(_table == NULL, "One string deduplication table allowed"); |
235 assert(_table == NULL, "One string deduplication table allowed"); |
236 _entry_cache = new G1StringDedupEntryCache((size_t)(_min_size * _max_cache_factor)); |
236 _entry_cache = new G1StringDedupEntryCache((size_t)(_min_size * _max_cache_factor)); |
237 _table = new G1StringDedupTable(_min_size); |
237 _table = new G1StringDedupTable(_min_size); |
238 } |
238 } |
239 |
239 |
240 void G1StringDedupTable::add(typeArrayOop value, unsigned int hash, G1StringDedupEntry** list) { |
240 void G1StringDedupTable::add(typeArrayOop value, uint64_t hash, G1StringDedupEntry** list) { |
241 G1StringDedupEntry* entry = _entry_cache->alloc(); |
241 G1StringDedupEntry* entry = _entry_cache->alloc(); |
242 entry->set_obj(value); |
242 entry->set_obj(value); |
243 entry->set_hash(hash); |
243 if (use_java_hash()) { |
|
244 entry->set_java_hash((unsigned int)hash); |
|
245 } else { |
|
246 entry->set_alt_hash(hash); |
|
247 } |
244 entry->set_next(*list); |
248 entry->set_next(*list); |
245 *list = entry; |
249 *list = entry; |
246 _entries++; |
250 _entries++; |
247 } |
251 } |
248 |
252 |
253 } |
257 } |
254 |
258 |
255 void G1StringDedupTable::transfer(G1StringDedupEntry** pentry, G1StringDedupTable* dest) { |
259 void G1StringDedupTable::transfer(G1StringDedupEntry** pentry, G1StringDedupTable* dest) { |
256 G1StringDedupEntry* entry = *pentry; |
260 G1StringDedupEntry* entry = *pentry; |
257 *pentry = entry->next(); |
261 *pentry = entry->next(); |
258 unsigned int hash = entry->hash(); |
262 uint64_t hash = use_java_hash() ? entry->java_hash() : entry->alt_hash(); |
259 size_t index = dest->hash_to_index(hash); |
263 size_t index = dest->hash_to_index(hash); |
260 G1StringDedupEntry** list = dest->bucket(index); |
264 G1StringDedupEntry** list = dest->bucket(index); |
261 entry->set_next(*list); |
265 entry->set_next(*list); |
262 *list = entry; |
266 *list = entry; |
263 } |
267 } |
268 (!memcmp(value1->base(T_CHAR), |
272 (!memcmp(value1->base(T_CHAR), |
269 value2->base(T_CHAR), |
273 value2->base(T_CHAR), |
270 value1->length() * sizeof(jchar))))); |
274 value1->length() * sizeof(jchar))))); |
271 } |
275 } |
272 |
276 |
273 typeArrayOop G1StringDedupTable::lookup(typeArrayOop value, unsigned int hash, |
277 typeArrayOop G1StringDedupTable::lookup(typeArrayOop value, uint64_t hash, |
274 G1StringDedupEntry** list, uintx &count) { |
278 G1StringDedupEntry** list, uintx &count) { |
275 for (G1StringDedupEntry* entry = *list; entry != NULL; entry = entry->next()) { |
279 for (G1StringDedupEntry* entry = *list; entry != NULL; entry = entry->next()) { |
276 if (entry->hash() == hash) { |
280 if ((use_java_hash() ? entry->java_hash() : entry->alt_hash()) == hash) { |
277 typeArrayOop existing_value = entry->obj(); |
281 typeArrayOop existing_value = entry->obj(); |
278 if (equals(value, existing_value)) { |
282 if (equals(value, existing_value)) { |
279 // Match found |
283 // Match found |
280 return existing_value; |
284 return existing_value; |
281 } |
285 } |
309 } |
313 } |
310 |
314 |
311 return existing_value; |
315 return existing_value; |
312 } |
316 } |
313 |
317 |
314 unsigned int G1StringDedupTable::hash_code(typeArrayOop value) { |
318 unsigned int G1StringDedupTable::java_hash_code(typeArrayOop value) { |
|
319 assert(use_java_hash(), "Should not use java hash code"); |
315 unsigned int hash; |
320 unsigned int hash; |
316 int length = value->length(); |
321 int length = value->length(); |
317 const jchar* data = (jchar*)value->base(T_CHAR); |
322 const jchar* data = (jchar*)value->base(T_CHAR); |
318 |
323 |
319 if (use_java_hash()) { |
324 hash = java_lang_String::hash_code(data, length); |
320 hash = java_lang_String::hash_code(data, length); |
|
321 } else { |
|
322 hash = AltHashing::murmur3_32(_table->_hash_seed, data, length); |
|
323 } |
|
324 |
325 |
325 return hash; |
326 return hash; |
|
327 } |
|
328 |
|
329 uint64_t G1StringDedupTable::alt_hash_code(typeArrayOop value) { |
|
330 assert(!use_java_hash(), "Should not use alt hash code"); |
|
331 |
|
332 int length = value->length(); |
|
333 const jbyte* data = (jbyte*)value->base(T_BYTE); |
|
334 return AltHashing::halfsiphash_64(_table->_hash_seed, (const int8_t*)data, length); |
326 } |
335 } |
327 |
336 |
328 void G1StringDedupTable::deduplicate(oop java_string, G1StringDedupStat& stat) { |
337 void G1StringDedupTable::deduplicate(oop java_string, G1StringDedupStat& stat) { |
329 assert(java_lang_String::is_instance(java_string), "Must be a string"); |
338 assert(java_lang_String::is_instance(java_string), "Must be a string"); |
330 No_Safepoint_Verifier nsv; |
339 No_Safepoint_Verifier nsv; |
336 // String has no value |
345 // String has no value |
337 stat.inc_skipped(); |
346 stat.inc_skipped(); |
338 return; |
347 return; |
339 } |
348 } |
340 |
349 |
341 unsigned int hash = 0; |
350 uint64_t hash = 0; |
342 |
351 |
343 if (use_java_hash()) { |
352 if (use_java_hash()) { |
344 // Get hash code from cache |
353 // Get hash code from cache |
345 hash = java_lang_String::hash(java_string); |
354 hash = java_lang_String::hash(java_string); |
346 } |
355 } |
347 |
356 |
348 if (hash == 0) { |
357 if (hash == 0) { |
349 // Compute hash |
358 // Compute hash |
350 hash = hash_code(value); |
359 hash = alt_hash_code(value); |
351 stat.inc_hashed(); |
360 stat.inc_hashed(); |
352 } |
361 } |
353 |
362 |
354 if (use_java_hash() && hash != 0) { |
363 if (use_java_hash() && hash != 0) { |
355 // Store hash code in cache |
364 // Store hash code in cache |
499 // in the table. We can't transfer entries into the new table |
508 // in the table. We can't transfer entries into the new table |
500 // at this point since we don't have exclusive access to all |
509 // at this point since we don't have exclusive access to all |
501 // destination partitions. finish_rehash() will do a single |
510 // destination partitions. finish_rehash() will do a single |
502 // threaded transfer of all entries. |
511 // threaded transfer of all entries. |
503 typeArrayOop value = (typeArrayOop)*p; |
512 typeArrayOop value = (typeArrayOop)*p; |
504 unsigned int hash = hash_code(value); |
513 assert(!use_java_hash(), "Should not be using Java hash"); |
505 (*entry)->set_hash(hash); |
514 uint64_t hash = alt_hash_code(value); |
|
515 (*entry)->set_alt_hash(hash); |
506 } |
516 } |
507 |
517 |
508 // Move to next entry |
518 // Move to next entry |
509 entry = (*entry)->next_addr(); |
519 entry = (*entry)->next_addr(); |
510 } |
520 } |
563 typeArrayOop value = (*entry)->obj(); |
573 typeArrayOop value = (*entry)->obj(); |
564 guarantee(value != NULL, "Object must not be NULL"); |
574 guarantee(value != NULL, "Object must not be NULL"); |
565 guarantee(Universe::heap()->is_in_reserved(value), "Object must be on the heap"); |
575 guarantee(Universe::heap()->is_in_reserved(value), "Object must be on the heap"); |
566 guarantee(!value->is_forwarded(), "Object must not be forwarded"); |
576 guarantee(!value->is_forwarded(), "Object must not be forwarded"); |
567 guarantee(value->is_typeArray(), "Object must be a typeArrayOop"); |
577 guarantee(value->is_typeArray(), "Object must be a typeArrayOop"); |
568 unsigned int hash = hash_code(value); |
578 uint64_t hash; |
569 guarantee((*entry)->hash() == hash, "Table entry has inorrect hash"); |
579 if (use_java_hash()) { |
|
580 hash = (*entry)->java_hash(); |
|
581 guarantee(java_hash_code(value) == hash, "Table entry has incorrect hash"); |
|
582 } else { |
|
583 hash = (*entry)->alt_hash(); |
|
584 guarantee(alt_hash_code(value) == hash, "Table entry has incorrect hash"); |
|
585 } |
570 guarantee(_table->hash_to_index(hash) == bucket, "Table entry has incorrect index"); |
586 guarantee(_table->hash_to_index(hash) == bucket, "Table entry has incorrect index"); |
571 entry = (*entry)->next_addr(); |
587 entry = (*entry)->next_addr(); |
572 } |
588 } |
573 |
589 |
574 // Verify that we do not have entries with identical oops or identical arrays. |
590 // Verify that we do not have entries with identical oops or identical arrays. |
579 while (*entry1 != NULL) { |
595 while (*entry1 != NULL) { |
580 typeArrayOop value1 = (*entry1)->obj(); |
596 typeArrayOop value1 = (*entry1)->obj(); |
581 G1StringDedupEntry** entry2 = (*entry1)->next_addr(); |
597 G1StringDedupEntry** entry2 = (*entry1)->next_addr(); |
582 while (*entry2 != NULL) { |
598 while (*entry2 != NULL) { |
583 typeArrayOop value2 = (*entry2)->obj(); |
599 typeArrayOop value2 = (*entry2)->obj(); |
584 guarantee(!equals(value1, value2), "Table entries must not have identical arrays"); |
600 guarantee(value1 != value2, "Table entries must not have the same array"); |
|
601 if (use_java_hash()) { |
|
602 guarantee(!equals(value1, value2), "Table entries must not have identical arrays"); |
|
603 } |
585 entry2 = (*entry2)->next_addr(); |
604 entry2 = (*entry2)->next_addr(); |
586 } |
605 } |
587 entry1 = (*entry1)->next_addr(); |
606 entry1 = (*entry1)->next_addr(); |
588 } |
607 } |
589 } |
608 } |
598 " [Table]\n" |
617 " [Table]\n" |
599 " [Memory Usage: " G1_STRDEDUP_BYTES_FORMAT_NS "]\n" |
618 " [Memory Usage: " G1_STRDEDUP_BYTES_FORMAT_NS "]\n" |
600 " [Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT "]\n" |
619 " [Size: " SIZE_FORMAT ", Min: " SIZE_FORMAT ", Max: " SIZE_FORMAT "]\n" |
601 " [Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT "]\n" |
620 " [Entries: " UINTX_FORMAT ", Load: " G1_STRDEDUP_PERCENT_FORMAT_NS ", Cached: " UINTX_FORMAT ", Added: " UINTX_FORMAT ", Removed: " UINTX_FORMAT "]\n" |
602 " [Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")]\n" |
621 " [Resize Count: " UINTX_FORMAT ", Shrink Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS "), Grow Threshold: " UINTX_FORMAT "(" G1_STRDEDUP_PERCENT_FORMAT_NS ")]\n" |
603 " [Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: 0x%x]\n" |
622 " [Rehash Count: " UINTX_FORMAT ", Rehash Threshold: " UINTX_FORMAT ", Hash Seed: " UINT64_FORMAT_X "]\n" |
604 " [Age Threshold: " UINTX_FORMAT "]", |
623 " [Age Threshold: " UINTX_FORMAT "]", |
605 G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)), |
624 G1_STRDEDUP_BYTES_PARAM(_table->_size * sizeof(G1StringDedupEntry*) + (_table->_entries + _entry_cache->size()) * sizeof(G1StringDedupEntry)), |
606 _table->_size, _min_size, _max_size, |
625 _table->_size, _min_size, _max_size, |
607 _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed, |
626 _table->_entries, (double)_table->_entries / (double)_table->_size * 100.0, _entry_cache->size(), _entries_added, _entries_removed, |
608 _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0, |
627 _resize_count, _table->_shrink_threshold, _shrink_load_factor * 100.0, _table->_grow_threshold, _grow_load_factor * 100.0, |