181 for (ret = 1; ((size_t)1 << ret) < val; ++ret);
182 return ret;
183 }
184
185 StringTable::StringTable() : _local_table(NULL), _current_size(0), _has_work(0),
186 _needs_rehashing(false), _weak_handles(NULL), _items(0), _uncleaned_items(0) {
187 _weak_handles = new OopStorage("StringTable weak",
188 StringTableWeakAlloc_lock,
189 StringTableWeakActive_lock);
190 size_t start_size_log_2 = ceil_pow_2(StringTableSize);
191 _current_size = ((size_t)1) << start_size_log_2;
192 log_trace(stringtable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")",
193 _current_size, start_size_log_2);
194 _local_table = new StringTableHash(start_size_log_2, END_SIZE, REHASH_LEN);
195 }
196
197 size_t StringTable::item_added() {
198 return Atomic::add((size_t)1, &(the_table()->_items));
199 }
200
201 size_t StringTable::items_to_clean(size_t ncl) {
202 size_t total = Atomic::add((size_t)ncl, &(the_table()->_uncleaned_items));
203 log_trace(stringtable)(
204 "Uncleaned items:" SIZE_FORMAT " added: " SIZE_FORMAT " total:" SIZE_FORMAT,
205 the_table()->_uncleaned_items, ncl, total);
206 return total;
207 }
208
209 void StringTable::item_removed() {
210 Atomic::add((size_t)-1, &(the_table()->_items));
211 Atomic::add((size_t)-1, &(the_table()->_uncleaned_items));
212 }
213
214 double StringTable::get_load_factor() {
215 return (_items*1.0)/_current_size;
216 }
217
218 double StringTable::get_dead_factor() {
219 return (_uncleaned_items*1.0)/_current_size;
220 }
221
222 size_t StringTable::table_size(Thread* thread) {
223 return ((size_t)(1)) << _local_table->get_size_log2(thread != NULL ? thread
224 : Thread::current());
225 }
226
227 void StringTable::trigger_concurrent_work() {
228 MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
229 the_table()->_has_work = true;
230 Service_lock->notify_all();
231 }
388 _count_total(0) {}
389 bool do_object_b(oop obj) {
390 bool ret = _real_boc->do_object_b(obj);
391 if (!ret) {
392 ++_count;
393 }
394 ++_count_total;
395 return ret;
396 }
397 };
398
399 void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f,
400 int* processed, int* removed) {
401 DoNothingClosure dnc;
402 assert(is_alive != NULL, "No closure");
403 StringTableIsAliveCounter stiac(is_alive);
404 OopClosure* tmp = f != NULL ? f : &dnc;
405
406 StringTable::the_table()->_weak_handles->weak_oops_do(&stiac, tmp);
407
408 StringTable::the_table()->items_to_clean(stiac._count);
409 StringTable::the_table()->check_concurrent_work();
410 if (processed != NULL) {
411 *processed = (int) stiac._count_total;
412 }
413 if (removed != NULL) {
414 *removed = (int) stiac._count;
415 }
416 }
417
418 void StringTable::oops_do(OopClosure* f) {
419 assert(f != NULL, "No closure");
420 StringTable::the_table()->_weak_handles->oops_do(f);
421 }
422
423 void StringTable::possibly_parallel_unlink(
424 OopStorage::ParState<false, false>* _par_state_string, BoolObjectClosure* cl,
425 int* processed, int* removed)
426 {
427 DoNothingClosure dnc;
428 assert(cl != NULL, "No closure");
429 StringTableIsAliveCounter stiac(cl);
430
431 _par_state_string->weak_oops_do(&stiac, &dnc);
432
433 StringTable::the_table()->items_to_clean(stiac._count);
434 StringTable::the_table()->check_concurrent_work();
435 *processed = (int) stiac._count_total;
436 *removed = (int) stiac._count;
437 }
438
439 void StringTable::possibly_parallel_oops_do(
440 OopStorage::ParState<false /* concurrent */, false /* const */>*
441 _par_state_string, OopClosure* f)
442 {
443 assert(f != NULL, "No closure");
444 _par_state_string->oops_do(f);
445 }
446
447 // Concurrent work
448 void StringTable::grow(JavaThread* jt) {
449 StringTableHash::GrowTask gt(_local_table);
450 if (!gt.prepare(jt)) {
451 return;
452 }
453 log_trace(stringtable)("Started to grow");
454 {
455 TraceTime timer("Grow", TRACETIME_LOG(Debug, stringtable, perf));
456 while (gt.doTask(jt)) {
457 gt.pause(jt);
458 {
459 ThreadBlockInVM tbivm(jt);
460 }
461 gt.cont(jt);
462 }
463 }
464 gt.done(jt);
465 _current_size = table_size(jt);
466 log_debug(stringtable)("Grown to size:" SIZE_FORMAT, _current_size);
467 }
468
469 struct StringTableDoDelete : StackObj {
470 long _count;
471 StringTableDoDelete() : _count(0) {}
472 void operator()(WeakHandle<vm_string_table_data>* val) {
473 ++_count;
474 }
475 };
476
477 struct StringTableDeleteCheck : StackObj {
478 long _count;
479 long _item;
480 StringTableDeleteCheck() : _count(0), _item(0) {}
481 bool operator()(WeakHandle<vm_string_table_data>* val) {
482 ++_item;
483 oop tmp = val->peek();
484 if (tmp == NULL) {
485 ++_count;
486 return true;
487 } else {
488 return false;
489 }
490 }
491 };
492
493 void StringTable::clean_dead_entries(JavaThread* jt) {
507 ThreadBlockInVM tbivm(jt);
508 }
509 if (!bdt.cont(jt)) {
510 interrupted = true;
511 break;
512 }
513 }
514 }
515 if (interrupted) {
516 _has_work = true;
517 } else {
518 bdt.done(jt);
519 }
520 log_debug(stringtable)("Cleaned %ld of %ld", stdc._count, stdc._item);
521 }
522
523 void StringTable::check_concurrent_work() {
524 if (_has_work) {
525 return;
526 }
527 double load_factor = StringTable::get_load_factor();
528 double dead_factor = StringTable::get_dead_factor();
529 // We should clean/resize if we have more dead than alive,
530 // more items than preferred load factor or
531 // more dead items than water mark.
532 if ((dead_factor > load_factor) ||
533 (load_factor > PREF_AVG_LIST_LEN) ||
534 (dead_factor > CLEAN_DEAD_HIGH_WATER_MARK)) {
535 log_debug(stringtable)("Concurrent work triggered, live factor:%g dead factor:%g",
536 load_factor, dead_factor);
537 trigger_concurrent_work();
538 }
539 }
540
541 void StringTable::concurrent_work(JavaThread* jt) {
542 _has_work = false;
543 double load_factor = get_load_factor();
544 log_debug(stringtable, perf)("Concurrent work, live factor: %g", load_factor);
545 // We prefer growing, since that also removes dead items
546 if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) {
|
181 for (ret = 1; ((size_t)1 << ret) < val; ++ret);
182 return ret;
183 }
184
185 StringTable::StringTable() : _local_table(NULL), _current_size(0), _has_work(0),
186 _needs_rehashing(false), _weak_handles(NULL), _items(0), _uncleaned_items(0) {
187 _weak_handles = new OopStorage("StringTable weak",
188 StringTableWeakAlloc_lock,
189 StringTableWeakActive_lock);
190 size_t start_size_log_2 = ceil_pow_2(StringTableSize);
191 _current_size = ((size_t)1) << start_size_log_2;
192 log_trace(stringtable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")",
193 _current_size, start_size_log_2);
194 _local_table = new StringTableHash(start_size_log_2, END_SIZE, REHASH_LEN);
195 }
196
197 size_t StringTable::item_added() {
198 return Atomic::add((size_t)1, &(the_table()->_items));
199 }
200
201 size_t StringTable::add_items_to_clean(size_t ndead) {
202 size_t total = Atomic::add((size_t)ndead, &(the_table()->_uncleaned_items));
203 log_trace(stringtable)(
204 "Uncleaned items:" SIZE_FORMAT " added: " SIZE_FORMAT " total:" SIZE_FORMAT,
205 the_table()->_uncleaned_items, ndead, total);
206 return total;
207 }
208
209 void StringTable::item_removed() {
210 Atomic::add((size_t)-1, &(the_table()->_items));
211 }
212
213 double StringTable::get_load_factor() {
214 return (_items*1.0)/_current_size;
215 }
216
217 double StringTable::get_dead_factor() {
218 return (_uncleaned_items*1.0)/_current_size;
219 }
220
221 size_t StringTable::table_size(Thread* thread) {
222 return ((size_t)(1)) << _local_table->get_size_log2(thread != NULL ? thread
223 : Thread::current());
224 }
225
226 void StringTable::trigger_concurrent_work() {
227 MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
228 the_table()->_has_work = true;
229 Service_lock->notify_all();
230 }
387 _count_total(0) {}
388 bool do_object_b(oop obj) {
389 bool ret = _real_boc->do_object_b(obj);
390 if (!ret) {
391 ++_count;
392 }
393 ++_count_total;
394 return ret;
395 }
396 };
397
398 void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f,
399 int* processed, int* removed) {
400 DoNothingClosure dnc;
401 assert(is_alive != NULL, "No closure");
402 StringTableIsAliveCounter stiac(is_alive);
403 OopClosure* tmp = f != NULL ? f : &dnc;
404
405 StringTable::the_table()->_weak_handles->weak_oops_do(&stiac, tmp);
406
407 // This is the serial case without ParState.
408 // Just set the correct number and check for a cleaning phase.
409 the_table()->_uncleaned_items = stiac._count;
410 StringTable::the_table()->check_concurrent_work();
411
412 if (processed != NULL) {
413 *processed = (int) stiac._count_total;
414 }
415 if (removed != NULL) {
416 *removed = (int) stiac._count;
417 }
418 }
419
420 void StringTable::oops_do(OopClosure* f) {
421 assert(f != NULL, "No closure");
422 StringTable::the_table()->_weak_handles->oops_do(f);
423 }
424
425 void StringTable::possibly_parallel_unlink(
426 OopStorage::ParState<false, false>* _par_state_string, BoolObjectClosure* cl,
427 int* processed, int* removed)
428 {
429 DoNothingClosure dnc;
430 assert(cl != NULL, "No closure");
431 StringTableIsAliveCounter stiac(cl);
432
433 _par_state_string->weak_oops_do(&stiac, &dnc);
434
435 // Accumulate the dead strings.
436 the_table()->add_items_to_clean(stiac._count);
437
438 *processed = (int) stiac._count_total;
439 *removed = (int) stiac._count;
440 }
441
442 void StringTable::possibly_parallel_oops_do(
443 OopStorage::ParState<false /* concurrent */, false /* const */>*
444 _par_state_string, OopClosure* f)
445 {
446 assert(f != NULL, "No closure");
447 _par_state_string->oops_do(f);
448 }
449
450 // Concurrent work
451 void StringTable::grow(JavaThread* jt) {
452 StringTableHash::GrowTask gt(_local_table);
453 if (!gt.prepare(jt)) {
454 return;
455 }
456 log_trace(stringtable)("Started to grow");
457 {
458 TraceTime timer("Grow", TRACETIME_LOG(Debug, stringtable, perf));
459 while (gt.doTask(jt)) {
460 gt.pause(jt);
461 {
462 ThreadBlockInVM tbivm(jt);
463 }
464 gt.cont(jt);
465 }
466 }
467 gt.done(jt);
468 _current_size = table_size(jt);
469 log_debug(stringtable)("Grown to size:" SIZE_FORMAT, _current_size);
470 }
471
472 struct StringTableDoDelete : StackObj {
473 void operator()(WeakHandle<vm_string_table_data>* val) {
474 /* do nothing */
475 }
476 };
477
478 struct StringTableDeleteCheck : StackObj {
479 long _count;
480 long _item;
481 StringTableDeleteCheck() : _count(0), _item(0) {}
482 bool operator()(WeakHandle<vm_string_table_data>* val) {
483 ++_item;
484 oop tmp = val->peek();
485 if (tmp == NULL) {
486 ++_count;
487 return true;
488 } else {
489 return false;
490 }
491 }
492 };
493
494 void StringTable::clean_dead_entries(JavaThread* jt) {
508 ThreadBlockInVM tbivm(jt);
509 }
510 if (!bdt.cont(jt)) {
511 interrupted = true;
512 break;
513 }
514 }
515 }
516 if (interrupted) {
517 _has_work = true;
518 } else {
519 bdt.done(jt);
520 }
521 log_debug(stringtable)("Cleaned %ld of %ld", stdc._count, stdc._item);
522 }
523
524 void StringTable::check_concurrent_work() {
525 if (_has_work) {
526 return;
527 }
528
529 double load_factor = StringTable::get_load_factor();
530 double dead_factor = StringTable::get_dead_factor();
531 // We should clean/resize if we have more dead than alive,
532 // more items than preferred load factor or
533 // more dead items than water mark.
534 if ((dead_factor > load_factor) ||
535 (load_factor > PREF_AVG_LIST_LEN) ||
536 (dead_factor > CLEAN_DEAD_HIGH_WATER_MARK)) {
537 log_debug(stringtable)("Concurrent work triggered, live factor:%g dead factor:%g",
538 load_factor, dead_factor);
539 trigger_concurrent_work();
540 }
541 }
542
543 void StringTable::concurrent_work(JavaThread* jt) {
544 _has_work = false;
545 double load_factor = get_load_factor();
546 log_debug(stringtable, perf)("Concurrent work, live factor: %g", load_factor);
547 // We prefer growing, since that also removes dead items
548 if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) {
|