1 /*
   2  * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   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
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 #include "classfile/javaClasses.hpp"
  27 #include "gc/shared/oopStorage.inline.hpp"
  28 #include "gc/shared/oopStorageSet.hpp"
  29 #include "logging/log.hpp"
  30 #include "memory/allocation.hpp"
  31 #include "memory/resourceArea.hpp"
  32 #include "memory/universe.hpp"
  33 #include "oops/access.inline.hpp"
  34 #include "oops/method.hpp"
  35 #include "oops/oop.inline.hpp"
  36 #include "oops/weakHandle.inline.hpp"
  37 #include "prims/resolvedMethodTable.hpp"
  38 #include "runtime/handles.inline.hpp"
  39 #include "runtime/interfaceSupport.inline.hpp"
  40 #include "runtime/mutexLocker.hpp"
  41 #include "runtime/safepointVerifiers.hpp"
  42 #include "runtime/timerTrace.hpp"
  43 #include "utilities/concurrentHashTable.inline.hpp"
  44 #include "utilities/concurrentHashTableTasks.inline.hpp"
  45 #include "utilities/macros.hpp"
  46 
  47 // 2^24 is max size
  48 static const size_t END_SIZE = 24;
  49 // If a chain gets to 32 something might be wrong
  50 static const size_t GROW_HINT = 32;
  51 
  52 static const size_t ResolvedMethodTableSizeLog = 10;
  53 
  54 unsigned int method_hash(const Method* method) {
  55   unsigned int name_hash = method->name()->identity_hash();
  56   unsigned int signature_hash = method->signature()->identity_hash();
  57   return name_hash ^ signature_hash;
  58 }
  59 
  60 typedef ConcurrentHashTable<ResolvedMethodTableConfig,
  61                             mtClass> ResolvedMethodTableHash;
  62 
  63 class ResolvedMethodTableConfig : public AllStatic {
  64  private:
  65  public:
  66   typedef WeakHandle<vm_resolved_method_table_data> Value;
  67 
  68   static uintx get_hash(Value const& value, bool* is_dead) {
  69     oop val_oop = value.peek();
  70     if (val_oop == NULL) {
  71       *is_dead = true;
  72       return 0;
  73     }
  74     *is_dead = false;
  75     Method* method = java_lang_invoke_ResolvedMethodName::vmtarget(val_oop);
  76     return method_hash(method);
  77   }
  78 
  79   // We use default allocation/deallocation but counted
  80   static void* allocate_node(size_t size, Value const& value) {
  81     ResolvedMethodTable::item_added();
  82     return AllocateHeap(size, mtClass);
  83   }
  84   static void free_node(void* memory, Value const& value) {
  85     value.release();
  86     FreeHeap(memory);
  87     ResolvedMethodTable::item_removed();
  88   }
  89 };
  90 
  91 static ResolvedMethodTableHash* _local_table           = NULL;
  92 static size_t                   _current_size          = (size_t)1 << ResolvedMethodTableSizeLog;
  93 
  94 volatile bool            ResolvedMethodTable::_has_work              = false;
  95 
  96 volatile size_t          _items_count           = 0;
  97 volatile size_t          _uncleaned_items_count = 0;
  98 
  99 void ResolvedMethodTable::create_table() {
 100   _local_table  = new ResolvedMethodTableHash(ResolvedMethodTableSizeLog, END_SIZE, GROW_HINT);
 101   log_trace(membername, table)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")",
 102                                _current_size, ResolvedMethodTableSizeLog);
 103 }
 104 
 105 size_t ResolvedMethodTable::table_size() {
 106   return (size_t)1 << _local_table->get_size_log2(Thread::current());
 107 }
 108 
 109 class ResolvedMethodTableLookup : StackObj {
 110  private:
 111   Thread*       _thread;
 112   uintx         _hash;
 113   const Method* _method;
 114   Handle        _found;
 115 
 116  public:
 117   ResolvedMethodTableLookup(Thread* thread, uintx hash, const Method* key)
 118     : _thread(thread), _hash(hash), _method(key) {
 119   }
 120   uintx get_hash() const {
 121     return _hash;
 122   }
 123   bool equals(WeakHandle<vm_resolved_method_table_data>* value, bool* is_dead) {
 124     oop val_oop = value->peek();
 125     if (val_oop == NULL) {
 126       // dead oop, mark this hash dead for cleaning
 127       *is_dead = true;
 128       return false;
 129     }
 130     bool equals = _method == java_lang_invoke_ResolvedMethodName::vmtarget(val_oop);
 131     if (!equals) {
 132       return false;
 133     }
 134     // Need to resolve weak handle and Handleize through possible safepoint.
 135     _found = Handle(_thread, value->resolve());
 136     return true;
 137   }
 138 };
 139 
 140 
 141 class ResolvedMethodGet : public StackObj {
 142   Thread*       _thread;
 143   const Method* _method;
 144   Handle        _return;
 145 public:
 146   ResolvedMethodGet(Thread* thread, const Method* method) : _thread(thread), _method(method) {}
 147   void operator()(WeakHandle<vm_resolved_method_table_data>* val) {
 148     oop result = val->resolve();
 149     assert(result != NULL, "Result should be reachable");
 150     _return = Handle(_thread, result);
 151     log_get();
 152   }
 153   oop get_res_oop() {
 154     return _return();
 155   }
 156   void log_get() {
 157     LogTarget(Trace, membername, table) log;
 158     if (log.is_enabled()) {
 159       ResourceMark rm;
 160       log.print("ResolvedMethod entry found for %s",
 161                 _method->name_and_sig_as_C_string());
 162     }
 163   }
 164 };
 165 
 166 oop ResolvedMethodTable::find_method(const Method* method) {
 167   Thread* thread = Thread::current();
 168 
 169   ResolvedMethodTableLookup lookup(thread, method_hash(method), method);
 170   ResolvedMethodGet rmg(thread, method);
 171   _local_table->get(thread, lookup, rmg);
 172 
 173   return rmg.get_res_oop();
 174 }
 175 
 176 static void log_insert(const Method* method) {
 177   LogTarget(Debug, membername, table) log;
 178   if (log.is_enabled()) {
 179     ResourceMark rm;
 180     log.print("ResolvedMethod entry added for %s",
 181               method->name_and_sig_as_C_string());
 182   }
 183 }
 184 
 185 oop ResolvedMethodTable::add_method(const Method* method, Handle rmethod_name) {
 186   Thread* thread = Thread::current();
 187 
 188   ResolvedMethodTableLookup lookup(thread, method_hash(method), method);
 189   ResolvedMethodGet rmg(thread, method);
 190 
 191   while (true) {
 192     if (_local_table->get(thread, lookup, rmg)) {
 193       return rmg.get_res_oop();
 194     }
 195     WeakHandle<vm_resolved_method_table_data> wh = WeakHandle<vm_resolved_method_table_data>::create(rmethod_name);
 196     // The hash table takes ownership of the WeakHandle, even if it's not inserted.
 197     if (_local_table->insert(thread, lookup, wh)) {
 198       log_insert(method);
 199       return wh.resolve();
 200     }
 201   }
 202 }
 203 
 204 void ResolvedMethodTable::item_added() {
 205   Atomic::inc(&_items_count);
 206 }
 207 
 208 void ResolvedMethodTable::item_removed() {
 209   Atomic::dec(&_items_count);
 210   log_trace(membername, table) ("ResolvedMethod entry removed");
 211 }
 212 
 213 double ResolvedMethodTable::get_load_factor() {
 214   return (double)_items_count/_current_size;
 215 }
 216 
 217 double ResolvedMethodTable::get_dead_factor() {
 218   return (double)_uncleaned_items_count/_current_size;
 219 }
 220 
 221 static const double PREF_AVG_LIST_LEN = 2.0;
 222 // If we have as many dead items as 50% of the number of bucket
 223 static const double CLEAN_DEAD_HIGH_WATER_MARK = 0.5;
 224 
 225 void ResolvedMethodTable::check_concurrent_work() {
 226   if (_has_work) {
 227     return;
 228   }
 229 
 230   double load_factor = get_load_factor();
 231   double dead_factor = get_dead_factor();
 232   // We should clean/resize if we have more dead than alive,
 233   // more items than preferred load factor or
 234   // more dead items than water mark.
 235   if ((dead_factor > load_factor) ||
 236       (load_factor > PREF_AVG_LIST_LEN) ||
 237       (dead_factor > CLEAN_DEAD_HIGH_WATER_MARK)) {
 238     log_debug(membername, table)("Concurrent work triggered, live factor: %g dead factor: %g",
 239                                  load_factor, dead_factor);
 240     trigger_concurrent_work();
 241   }
 242 }
 243 
 244 void ResolvedMethodTable::trigger_concurrent_work() {
 245   MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
 246   _has_work = true;
 247   Service_lock->notify_all();
 248 }
 249 
 250 void ResolvedMethodTable::do_concurrent_work(JavaThread* jt) {
 251   _has_work = false;
 252   double load_factor = get_load_factor();
 253   log_debug(membername, table)("Concurrent work, live factor: %g", load_factor);
 254   // We prefer growing, since that also removes dead items
 255   if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) {
 256     grow(jt);
 257   } else {
 258     clean_dead_entries(jt);
 259   }
 260 }
 261 
 262 void ResolvedMethodTable::grow(JavaThread* jt) {
 263   ResolvedMethodTableHash::GrowTask gt(_local_table);
 264   if (!gt.prepare(jt)) {
 265     return;
 266   }
 267   log_trace(membername, table)("Started to grow");
 268   {
 269     TraceTime timer("Grow", TRACETIME_LOG(Debug, membername, table, perf));
 270     while (gt.do_task(jt)) {
 271       gt.pause(jt);
 272       {
 273         ThreadBlockInVM tbivm(jt);
 274       }
 275       gt.cont(jt);
 276     }
 277   }
 278   gt.done(jt);
 279   _current_size = table_size();
 280   log_info(membername, table)("Grown to size:" SIZE_FORMAT, _current_size);
 281 }
 282 
 283 struct ResolvedMethodTableDoDelete : StackObj {
 284   void operator()(WeakHandle<vm_resolved_method_table_data>* val) {
 285     /* do nothing */
 286   }
 287 };
 288 
 289 struct ResolvedMethodTableDeleteCheck : StackObj {
 290   long _count;
 291   long _item;
 292   ResolvedMethodTableDeleteCheck() : _count(0), _item(0) {}
 293   bool operator()(WeakHandle<vm_resolved_method_table_data>* val) {
 294     ++_item;
 295     oop tmp = val->peek();
 296     if (tmp == NULL) {
 297       ++_count;
 298       return true;
 299     } else {
 300       return false;
 301     }
 302   }
 303 };
 304 
 305 void ResolvedMethodTable::clean_dead_entries(JavaThread* jt) {
 306   ResolvedMethodTableHash::BulkDeleteTask bdt(_local_table);
 307   if (!bdt.prepare(jt)) {
 308     return;
 309   }
 310   ResolvedMethodTableDeleteCheck stdc;
 311   ResolvedMethodTableDoDelete stdd;
 312   {
 313     TraceTime timer("Clean", TRACETIME_LOG(Debug, membername, table, perf));
 314     while(bdt.do_task(jt, stdc, stdd)) {
 315       bdt.pause(jt);
 316       {
 317         ThreadBlockInVM tbivm(jt);
 318       }
 319       bdt.cont(jt);
 320     }
 321     bdt.done(jt);
 322   }
 323   log_info(membername, table)("Cleaned %ld of %ld", stdc._count, stdc._item);
 324 }
 325 void ResolvedMethodTable::reset_dead_counter() {
 326   _uncleaned_items_count = 0;
 327 }
 328 
 329 void ResolvedMethodTable::inc_dead_counter(size_t ndead) {
 330   size_t total = Atomic::add(ndead, &_uncleaned_items_count);
 331   log_trace(membername, table)(
 332      "Uncleaned items:" SIZE_FORMAT " added: " SIZE_FORMAT " total:" SIZE_FORMAT,
 333      _uncleaned_items_count, ndead, total);
 334 }
 335 
 336 // After the parallel walk this method must be called to trigger
 337 // cleaning. Note it might trigger a resize instead.
 338 void ResolvedMethodTable::finish_dead_counter() {
 339   check_concurrent_work();
 340 }
 341 
 342 #if INCLUDE_JVMTI
 343 class AdjustMethodEntries : public StackObj {
 344   bool* _trace_name_printed;
 345 public:
 346   AdjustMethodEntries(bool* trace_name_printed) : _trace_name_printed(trace_name_printed) {};
 347   bool operator()(WeakHandle<vm_resolved_method_table_data>* entry) {
 348     oop mem_name = entry->peek();
 349     if (mem_name == NULL) {
 350       // Removed
 351       return true;
 352     }
 353 
 354     Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
 355 
 356     if (old_method->is_old()) {
 357 
 358       Method* new_method = (old_method->is_deleted()) ?
 359                             Universe::throw_no_such_method_error() :
 360                             old_method->get_new_method();
 361       java_lang_invoke_ResolvedMethodName::set_vmtarget(mem_name, new_method);
 362 
 363       ResourceMark rm;
 364       if (!(*_trace_name_printed)) {
 365         log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
 366          *_trace_name_printed = true;
 367       }
 368       log_debug(redefine, class, update, constantpool)
 369         ("ResolvedMethod method update: %s(%s)",
 370          new_method->name()->as_C_string(), new_method->signature()->as_C_string());
 371     }
 372 
 373     return true;
 374   }
 375 };
 376 
 377 // It is called at safepoint only for RedefineClasses
 378 void ResolvedMethodTable::adjust_method_entries(bool * trace_name_printed) {
 379   assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
 380   // For each entry in RMT, change to new method
 381   AdjustMethodEntries adjust(trace_name_printed);
 382   _local_table->do_safepoint_scan(adjust);
 383 }
 384 #endif // INCLUDE_JVMTI
 385 
 386 // Verification
 387 class VerifyResolvedMethod : StackObj {
 388  public:
 389   bool operator()(WeakHandle<vm_resolved_method_table_data>* val) {
 390     oop obj = val->peek();
 391     if (obj != NULL) {
 392       Method* method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(obj);
 393       guarantee(method->is_method(), "Must be");
 394       guarantee(!method->is_old(), "Must be");
 395     }
 396     return true;
 397   };
 398 };
 399 
 400 size_t ResolvedMethodTable::items_count() {
 401   return _items_count;
 402 }
 403 
 404 void ResolvedMethodTable::verify() {
 405   VerifyResolvedMethod vcs;
 406   if (!_local_table->try_scan(Thread::current(), vcs)) {
 407     log_info(membername, table)("verify unavailable at this moment");
 408   }
 409 }