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