src/hotspot/share/classfile/symbolTable.cpp
changeset 53587 739eaf4ac4ad
parent 52951 722eaae2a785
child 53898 853b82a25d53
equal deleted inserted replaced
53586:5bc1634bc0ca 53587:739eaf4ac4ad
     1 /*
     1 /*
     2  * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
     2  * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     4  *
     4  *
     5  * This code is free software; you can redistribute it and/or modify it
     5  * This code is free software; you can redistribute it and/or modify it
     6  * under the terms of the GNU General Public License version 2 only, as
     6  * under the terms of the GNU General Public License version 2 only, as
     7  * published by the Free Software Foundation.
     7  * published by the Free Software Foundation.
    47 // as the previous table size (used to be 20,011),
    47 // as the previous table size (used to be 20,011),
    48 // which never resized
    48 // which never resized
    49 const size_t END_SIZE = 17;
    49 const size_t END_SIZE = 17;
    50 // If a chain gets to 100 something might be wrong
    50 // If a chain gets to 100 something might be wrong
    51 const size_t REHASH_LEN = 100;
    51 const size_t REHASH_LEN = 100;
    52 // We only get a chance to check whether we need
       
    53 // to clean infrequently (on class unloading),
       
    54 // so if we have even one dead entry then mark table for cleaning
       
    55 const double CLEAN_DEAD_HIGH_WATER_MARK = 0.0;
       
    56 
    52 
    57 const size_t ON_STACK_BUFFER_LENGTH = 128;
    53 const size_t ON_STACK_BUFFER_LENGTH = 128;
    58 
    54 
    59 // --------------------------------------------------------------------------
    55 // --------------------------------------------------------------------------
    60 
    56 
   140 }
   136 }
   141 
   137 
   142 SymbolTable::SymbolTable() :
   138 SymbolTable::SymbolTable() :
   143   _symbols_removed(0), _symbols_counted(0), _local_table(NULL),
   139   _symbols_removed(0), _symbols_counted(0), _local_table(NULL),
   144   _current_size(0), _has_work(0), _needs_rehashing(false),
   140   _current_size(0), _has_work(0), _needs_rehashing(false),
   145   _items_count(0), _uncleaned_items_count(0) {
   141   _items_count(0), _has_items_to_clean(false) {
   146 
   142 
   147   size_t start_size_log_2 = ceil_log2(SymbolTableSize);
   143   size_t start_size_log_2 = ceil_log2(SymbolTableSize);
   148   _current_size = ((size_t)1) << start_size_log_2;
   144   _current_size = ((size_t)1) << start_size_log_2;
   149   log_trace(symboltable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")",
   145   log_trace(symboltable)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")",
   150                          _current_size, start_size_log_2);
   146                          _current_size, start_size_log_2);
   169   if (rehash) {
   165   if (rehash) {
   170     _needs_rehashing = true;
   166     _needs_rehashing = true;
   171   }
   167   }
   172 }
   168 }
   173 
   169 
       
   170 void SymbolTable::reset_has_items_to_clean() { Atomic::store(false, &_has_items_to_clean); }
       
   171 void SymbolTable::mark_has_items_to_clean()  { Atomic::store(true, &_has_items_to_clean); }
       
   172 bool SymbolTable::has_items_to_clean() const { return Atomic::load(&_has_items_to_clean); }
       
   173 
   174 void SymbolTable::item_added() {
   174 void SymbolTable::item_added() {
   175   Atomic::inc(&(SymbolTable::the_table()->_items_count));
   175   Atomic::inc(&(SymbolTable::the_table()->_items_count));
   176 }
       
   177 
       
   178 void SymbolTable::set_item_clean_count(size_t ncl) {
       
   179   Atomic::store(ncl, &(SymbolTable::the_table()->_uncleaned_items_count));
       
   180   log_trace(symboltable)("Set uncleaned items:" SIZE_FORMAT, SymbolTable::the_table()->_uncleaned_items_count);
       
   181 }
       
   182 
       
   183 // Mark one item as needing to be cleaned, but only if no other items are marked yet
       
   184 void SymbolTable::mark_item_clean_count() {
       
   185   if (Atomic::cmpxchg((size_t)1, &(SymbolTable::the_table()->_uncleaned_items_count), (size_t)0) == 0) {
       
   186     log_trace(symboltable)("Marked uncleaned items:" SIZE_FORMAT, SymbolTable::the_table()->_uncleaned_items_count);
       
   187   }
       
   188 }
   176 }
   189 
   177 
   190 void SymbolTable::item_removed() {
   178 void SymbolTable::item_removed() {
   191   Atomic::inc(&(SymbolTable::the_table()->_symbols_removed));
   179   Atomic::inc(&(SymbolTable::the_table()->_symbols_removed));
   192   Atomic::dec(&(SymbolTable::the_table()->_items_count));
   180   Atomic::dec(&(SymbolTable::the_table()->_items_count));
   194 
   182 
   195 double SymbolTable::get_load_factor() const {
   183 double SymbolTable::get_load_factor() const {
   196   return (double)_items_count/_current_size;
   184   return (double)_items_count/_current_size;
   197 }
   185 }
   198 
   186 
   199 double SymbolTable::get_dead_factor() const {
       
   200   return (double)_uncleaned_items_count/_current_size;
       
   201 }
       
   202 
       
   203 size_t SymbolTable::table_size() {
   187 size_t SymbolTable::table_size() {
   204   return ((size_t)1) << _local_table->get_size_log2(Thread::current());
   188   return ((size_t)1) << _local_table->get_size_log2(Thread::current());
   205 }
   189 }
   206 
   190 
   207 void SymbolTable::trigger_concurrent_work() {
   191 void SymbolTable::trigger_cleanup() {
   208   MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
   192   MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
   209   SymbolTable::the_table()->_has_work = true;
   193   SymbolTable::the_table()->_has_work = true;
   210   Service_lock->notify_all();
   194   Service_lock->notify_all();
   211 }
   195 }
   212 
   196 
   488   } while(true);
   472   } while(true);
   489 
   473 
   490   update_needs_rehash(rehash_warning);
   474   update_needs_rehash(rehash_warning);
   491 
   475 
   492   if (clean_hint) {
   476   if (clean_hint) {
   493     // we just found out that there is a dead item,
   477     mark_has_items_to_clean();
   494     // which we were unable to clean right now,
       
   495     // but we have no way of telling whether it's
       
   496     // been previously counted or not, so mark
       
   497     // it only if no other items were found yet
       
   498     mark_item_clean_count();
       
   499     check_concurrent_work();
   478     check_concurrent_work();
   500   }
   479   }
   501 
   480 
   502   assert((sym == NULL) || sym->refcount() != 0, "found dead symbol");
   481   assert((sym == NULL) || sym->refcount() != 0, "found dead symbol");
   503   return sym;
   482   return sym;
   695       {
   674       {
   696         ThreadBlockInVM tbivm(jt);
   675         ThreadBlockInVM tbivm(jt);
   697       }
   676       }
   698       bdt.cont(jt);
   677       bdt.cont(jt);
   699     }
   678     }
   700     SymbolTable::the_table()->set_item_clean_count(0);
   679     SymbolTable::the_table()->reset_has_items_to_clean();
   701     bdt.done(jt);
   680     bdt.done(jt);
   702   }
   681   }
   703 
   682 
   704   Atomic::add(stdc._processed, &_symbols_counted);
   683   Atomic::add(stdc._processed, &_symbols_counted);
   705 
   684 
   709 
   688 
   710 void SymbolTable::check_concurrent_work() {
   689 void SymbolTable::check_concurrent_work() {
   711   if (_has_work) {
   690   if (_has_work) {
   712     return;
   691     return;
   713   }
   692   }
   714   double load_factor = SymbolTable::get_load_factor();
   693   // We should clean/resize if we have
   715   double dead_factor = SymbolTable::get_dead_factor();
       
   716   // We should clean/resize if we have more dead than alive,
       
   717   // more items than preferred load factor or
   694   // more items than preferred load factor or
   718   // more dead items than water mark.
   695   // more dead items than water mark.
   719   if ((dead_factor > load_factor) ||
   696   if (has_items_to_clean() || (get_load_factor() > PREF_AVG_LIST_LEN)) {
   720       (load_factor > PREF_AVG_LIST_LEN) ||
   697     log_debug(symboltable)("Concurrent work triggered, load factor: %f, items to clean: %s",
   721       (dead_factor > CLEAN_DEAD_HIGH_WATER_MARK)) {
   698                            get_load_factor(), has_items_to_clean() ? "true" : "false");
   722     log_debug(symboltable)("Concurrent work triggered, live factor:%f dead factor:%f",
   699     trigger_cleanup();
   723                            load_factor, dead_factor);
       
   724     trigger_concurrent_work();
       
   725   }
   700   }
   726 }
   701 }
   727 
   702 
   728 void SymbolTable::concurrent_work(JavaThread* jt) {
   703 void SymbolTable::concurrent_work(JavaThread* jt) {
   729   double load_factor = get_load_factor();
   704   double load_factor = get_load_factor();
   733     grow(jt);
   708     grow(jt);
   734   } else {
   709   } else {
   735     clean_dead_entries(jt);
   710     clean_dead_entries(jt);
   736   }
   711   }
   737   _has_work = false;
   712   _has_work = false;
   738 }
       
   739 
       
   740 class CountDead : StackObj {
       
   741   size_t _count;
       
   742 public:
       
   743   CountDead() : _count(0) {}
       
   744   bool operator()(Symbol** value) {
       
   745     assert(value != NULL, "expected valid value");
       
   746     assert(*value != NULL, "value should point to a symbol");
       
   747     Symbol* sym = *value;
       
   748     if (sym->refcount() == 0) {
       
   749       _count++;
       
   750     }
       
   751     return true;
       
   752   };
       
   753   size_t get_dead_count() const {
       
   754     return _count;
       
   755   }
       
   756 };
       
   757 
       
   758 void SymbolTable::do_check_concurrent_work() {
       
   759   CountDead counter;
       
   760   if (!SymbolTable::the_table()->_local_table->try_scan(Thread::current(), counter)) {
       
   761     log_info(symboltable)("count dead unavailable at this moment");
       
   762   } else {
       
   763     SymbolTable::the_table()->set_item_clean_count(counter.get_dead_count());
       
   764     SymbolTable::the_table()->check_concurrent_work();
       
   765   }
       
   766 }
   713 }
   767 
   714 
   768 void SymbolTable::do_concurrent_work(JavaThread* jt) {
   715 void SymbolTable::do_concurrent_work(JavaThread* jt) {
   769   SymbolTable::the_table()->concurrent_work(jt);
   716   SymbolTable::the_table()->concurrent_work(jt);
   770 }
   717 }
   798 
   745 
   799   // Grow instead of rehash.
   746   // Grow instead of rehash.
   800   if (get_load_factor() > PREF_AVG_LIST_LEN &&
   747   if (get_load_factor() > PREF_AVG_LIST_LEN &&
   801       !_local_table->is_max_size_reached()) {
   748       !_local_table->is_max_size_reached()) {
   802     log_debug(symboltable)("Choosing growing over rehashing.");
   749     log_debug(symboltable)("Choosing growing over rehashing.");
   803     trigger_concurrent_work();
   750     trigger_cleanup();
   804     _needs_rehashing = false;
   751     _needs_rehashing = false;
   805     return;
   752     return;
   806   }
   753   }
   807 
   754 
   808   // Already rehashed.
   755   // Already rehashed.
   809   if (rehashed) {
   756   if (rehashed) {
   810     log_warning(symboltable)("Rehashing already done, still long lists.");
   757     log_warning(symboltable)("Rehashing already done, still long lists.");
   811     trigger_concurrent_work();
   758     trigger_cleanup();
   812     _needs_rehashing = false;
   759     _needs_rehashing = false;
   813     return;
   760     return;
   814   }
   761   }
   815 
   762 
   816   murmur_seed = AltHashing::compute_seed();
   763   murmur_seed = AltHashing::compute_seed();