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 "logging/log.hpp"
  29 #include "memory/allocation.hpp"
  30 #include "memory/resourceArea.hpp"
  31 #include "oops/access.inline.hpp"
  32 #include "oops/oop.inline.hpp"
  33 #include "oops/method.hpp"
  34 #include "oops/weakHandle.inline.hpp"
  35 #include "prims/resolvedMethodTable.hpp"
  36 #include "runtime/handles.inline.hpp"
  37 #include "runtime/interfaceSupport.inline.hpp"
  38 #include "runtime/mutexLocker.hpp"
  39 #include "runtime/safepointVerifiers.hpp"
  40 #include "runtime/timerTrace.hpp"
  41 #include "utilities/concurrentHashTable.inline.hpp"
  42 #include "utilities/concurrentHashTableTasks.inline.hpp"
  43 #include "utilities/macros.hpp"
  44 
  45 // 2^24 is max size
  46 static const size_t END_SIZE = 24;
  47 // If a chain gets to 32 something might be wrong
  48 static const size_t GROW_HINT = 32;
  49 
  50 static const size_t ResolvedMethodTableSizeLog = 10;
  51 
  52 unsigned int method_hash(const Method* method) {
  53   unsigned int name_hash = method->name()->identity_hash();
  54   unsigned int signature_hash = method->signature()->identity_hash();
  55   return name_hash ^ signature_hash;
  56 }
  57 
  58 class ResolvedMethodTableConfig : public ResolvedMethodTableHash::BaseConfig {
  59  private:
  60  public:
  61   static uintx get_hash(WeakHandle<vm_resolved_method_table_data> const& value,
  62                         bool* is_dead) {
  63     EXCEPTION_MARK;
  64     oop val_oop = value.peek();
  65     if (val_oop == NULL) {
  66       *is_dead = true;
  67       return 0;
  68     }
  69     *is_dead = false;
  70     Method* method = java_lang_invoke_ResolvedMethodName::vmtarget(val_oop);
  71     return method_hash(method);
  72   }
  73 
  74   // We use default allocation/deallocation but counted
  75   static void* allocate_node(size_t size, WeakHandle<vm_resolved_method_table_data> const& value) {
  76     ResolvedMethodTable::item_added();
  77     return ResolvedMethodTableHash::BaseConfig::allocate_node(size, value);
  78   }
  79   static void free_node(void* memory, WeakHandle<vm_resolved_method_table_data> const& value) {
  80     value.release();
  81     ResolvedMethodTableHash::BaseConfig::free_node(memory, value);
  82     ResolvedMethodTable::item_removed();
  83   }
  84 };
  85 
  86 ResolvedMethodTableHash* ResolvedMethodTable::_local_table           = NULL;
  87 size_t                   ResolvedMethodTable::_current_size          = (size_t)1 << ResolvedMethodTableSizeLog;
  88 
  89 OopStorage*              ResolvedMethodTable::_weak_handles          = NULL;
  90 
  91 volatile bool            ResolvedMethodTable::_has_work              = false;
  92 volatile size_t          ResolvedMethodTable::_items_count           = 0;
  93 volatile size_t          ResolvedMethodTable::_uncleaned_items_count = 0;
  94 
  95 void ResolvedMethodTable::create_table() {
  96   _local_table  = new ResolvedMethodTableHash(ResolvedMethodTableSizeLog, END_SIZE, GROW_HINT);
  97   _weak_handles = new OopStorage("ResolvedMethodTable weak",
  98                                  ResolvedMethodTableWeakAlloc_lock,
  99                                  ResolvedMethodTableWeakActive_lock);
 100   log_trace(membername, table)("Start size: " SIZE_FORMAT " (" SIZE_FORMAT ")",
 101                                _current_size, ResolvedMethodTableSizeLog);
 102 }
 103 
 104 size_t ResolvedMethodTable::table_size() {
 105   return (size_t)1 << _local_table->get_size_log2(Thread::current());
 106 }
 107 
 108 class ResolvedMethodTableLookup : StackObj {
 109  private:
 110   Thread*       _thread;
 111   uintx         _hash;
 112   const Method* _method;
 113   Handle        _found;
 114 
 115  public:
 116   ResolvedMethodTableLookup(Thread* thread, uintx hash, const Method* key)
 117     : _thread(thread), _hash(hash), _method(key) {
 118   }
 119   uintx get_hash() const {
 120     return _hash;
 121   }
 122   bool equals(WeakHandle<vm_resolved_method_table_data>* value, bool* is_dead) {
 123     oop val_oop = value->peek();
 124     if (val_oop == NULL) {
 125       // dead oop, mark this hash dead for cleaning
 126       *is_dead = true;
 127       return false;
 128     }
 129     bool equals = _method == java_lang_invoke_ResolvedMethodName::vmtarget(val_oop);
 130     if (!equals) {
 131       return false;
 132     }
 133     // Need to resolve weak handle and Handleize through possible safepoint.
 134     _found = Handle(_thread, value->resolve());
 135     return true;
 136   }
 137 };
 138 
 139 
 140 class ResolvedMethodGet : public StackObj {
 141   Thread*       _thread;
 142   const Method* _method;
 143   Handle        _return;
 144 public:
 145   ResolvedMethodGet(Thread* thread, const Method* method) : _thread(thread), _method(method) {}
 146   void operator()(WeakHandle<vm_resolved_method_table_data>* val) {
 147     oop result = val->resolve();
 148     assert(result != NULL, "Result should be reachable");
 149     _return = Handle(_thread, result);
 150     log_get();
 151   }
 152   oop get_res_oop() {
 153     return _return();
 154   }
 155   void log_get() {
 156     LogTarget(Trace, membername, table) log;
 157     if (log.is_enabled()) {
 158       ResourceMark rm;
 159       log.print("ResolvedMethod entry found for %s",
 160                 _method->name_and_sig_as_C_string());
 161     }
 162   }
 163 };
 164 
 165 oop ResolvedMethodTable::find_method(const Method* method) {
 166   Thread* thread = Thread::current();
 167 
 168   ResolvedMethodTableLookup lookup(thread, method_hash(method), method);
 169   ResolvedMethodGet rmg(thread, method);
 170   _local_table->get(thread, lookup, rmg);
 171 
 172   return rmg.get_res_oop();
 173 }
 174 
 175 static void log_insert(const Method* method) {
 176   LogTarget(Debug, membername, table) log;
 177   if (log.is_enabled()) {
 178     ResourceMark rm;
 179     log_debug(membername, table) ("ResolvedMethod entry added for %s",
 180                                   method->name_and_sig_as_C_string());
 181   }
 182 }
 183 
 184 oop ResolvedMethodTable::add_method(const Method* method, Handle rmethod_name) {
 185   Thread* thread = Thread::current();
 186 
 187   ResolvedMethodTableLookup lookup(thread, method_hash(method), method);
 188   ResolvedMethodGet rmg(thread, method);
 189 
 190   while (true) {
 191     if (_local_table->get(thread, lookup, rmg)) {
 192       return rmg.get_res_oop();
 193     }
 194     WeakHandle<vm_resolved_method_table_data> wh = WeakHandle<vm_resolved_method_table_data>::create(rmethod_name);
 195     // The hash table takes ownership of the WeakHandle, even if it's not inserted.
 196     if (_local_table->insert(thread, lookup, wh)) {
 197       log_insert(method);
 198       return wh.resolve();
 199     }
 200   }
 201 
 202   return rmethod_name();
 203 }
 204 
 205 void ResolvedMethodTable::item_added() {
 206   Atomic::inc(&_items_count);
 207 }
 208 
 209 void ResolvedMethodTable::item_removed() {
 210   Atomic::dec(&_items_count);
 211   log_trace(membername, table) ("ResolvedMethod entry removed");
 212 }
 213 
 214 bool ResolvedMethodTable::has_work() {
 215   return _has_work;
 216 }
 217 
 218 OopStorage* ResolvedMethodTable::weak_storage() {
 219   return _weak_handles;
 220 }
 221 
 222 double ResolvedMethodTable::get_load_factor() {
 223   return (double)_items_count/_current_size;
 224 }
 225 
 226 double ResolvedMethodTable::get_dead_factor() {
 227   return (double)_uncleaned_items_count/_current_size;
 228 }
 229 
 230 static const double PREF_AVG_LIST_LEN = 2.0;
 231 // If we have as many dead items as 50% of the number of bucket
 232 static const double CLEAN_DEAD_HIGH_WATER_MARK = 0.5;
 233 
 234 void ResolvedMethodTable::check_concurrent_work() {
 235   if (_has_work) {
 236     return;
 237   }
 238 
 239   double load_factor = get_load_factor();
 240   double dead_factor = get_dead_factor();
 241   // We should clean/resize if we have more dead than alive,
 242   // more items than preferred load factor or
 243   // more dead items than water mark.
 244   if ((dead_factor > load_factor) ||
 245       (load_factor > PREF_AVG_LIST_LEN) ||
 246       (dead_factor > CLEAN_DEAD_HIGH_WATER_MARK)) {
 247     log_debug(membername, table)("Concurrent work triggered, live factor: %g dead factor: %g",
 248                                  load_factor, dead_factor);
 249     trigger_concurrent_work();
 250   }
 251 }
 252 
 253 void ResolvedMethodTable::trigger_concurrent_work() {
 254   MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
 255   _has_work = true;
 256   Service_lock->notify_all();
 257 }
 258 
 259 void ResolvedMethodTable::do_concurrent_work(JavaThread* jt) {
 260   _has_work = false;
 261   double load_factor = get_load_factor();
 262   log_debug(membername, table)("Concurrent work, live factor: %g", load_factor);
 263   // We prefer growing, since that also removes dead items
 264   if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) {
 265     grow(jt);
 266   } else {
 267     clean_dead_entries(jt);
 268   }
 269 }
 270 
 271 void ResolvedMethodTable::grow(JavaThread* jt) {
 272   ResolvedMethodTableHash::GrowTask gt(_local_table);
 273   if (!gt.prepare(jt)) {
 274     return;
 275   }
 276   log_trace(membername, table)("Started to grow");
 277   {
 278     TraceTime timer("Grow", TRACETIME_LOG(Debug, membername, table, perf));
 279     while (gt.do_task(jt)) {
 280       gt.pause(jt);
 281       {
 282         ThreadBlockInVM tbivm(jt);
 283       }
 284       gt.cont(jt);
 285     }
 286   }
 287   gt.done(jt);
 288   _current_size = table_size();
 289   log_info(membername, table)("Grown to size:" SIZE_FORMAT, _current_size);
 290 }
 291 
 292 struct ResolvedMethodTableDoDelete : StackObj {
 293   void operator()(WeakHandle<vm_resolved_method_table_data>* val) {
 294     /* do nothing */
 295   }
 296 };
 297 
 298 struct ResolvedMethodTableDeleteCheck : StackObj {
 299   long _count;
 300   long _item;
 301   ResolvedMethodTableDeleteCheck() : _count(0), _item(0) {}
 302   bool operator()(WeakHandle<vm_resolved_method_table_data>* val) {
 303     ++_item;
 304     oop tmp = val->peek();
 305     if (tmp == NULL) {
 306       ++_count;
 307       return true;
 308     } else {
 309       return false;
 310     }
 311   }
 312 };
 313 
 314 void ResolvedMethodTable::clean_dead_entries(JavaThread* jt) {
 315   ResolvedMethodTableHash::BulkDeleteTask bdt(_local_table);
 316   if (!bdt.prepare(jt)) {
 317     return;
 318   }
 319   ResolvedMethodTableDeleteCheck stdc;
 320   ResolvedMethodTableDoDelete stdd;
 321   {
 322     TraceTime timer("Clean", TRACETIME_LOG(Debug, membername, table, perf));
 323     while(bdt.do_task(jt, stdc, stdd)) {
 324       bdt.pause(jt);
 325       {
 326         ThreadBlockInVM tbivm(jt);
 327       }
 328       bdt.cont(jt);
 329     }
 330     bdt.done(jt);
 331   }
 332   log_info(membername, table)("Cleaned %ld of %ld", stdc._count, stdc._item);
 333 }
 334 void ResolvedMethodTable::reset_dead_counter() {
 335   _uncleaned_items_count = 0;
 336 }
 337 
 338 void ResolvedMethodTable::inc_dead_counter(size_t ndead) {
 339   size_t total = Atomic::add(ndead, &_uncleaned_items_count);
 340   log_trace(membername, table)(
 341      "Uncleaned items:" SIZE_FORMAT " added: " SIZE_FORMAT " total:" SIZE_FORMAT,
 342      _uncleaned_items_count, ndead, total);
 343 }
 344 
 345 // After the parallel walk this method must be called to trigger
 346 // cleaning. Note it might trigger a resize instead.
 347 void ResolvedMethodTable::finish_dead_counter() {
 348   check_concurrent_work();
 349 
 350 #ifdef ASSERT
 351   if (SafepointSynchronize::is_at_safepoint()) {
 352     size_t fail_cnt = verify_and_compare_entries();
 353     if (fail_cnt != 0) {
 354       tty->print_cr("ERROR: fail_cnt=" SIZE_FORMAT, fail_cnt);
 355       guarantee(fail_cnt == 0, "unexpected ResolvedMethodTable verification failures");
 356     }
 357   }
 358 #endif // ASSERT
 359 }
 360 
 361 #if INCLUDE_JVMTI
 362 class AdjustMethodEntries : public StackObj {
 363   bool* _trace_name_printed;
 364 public:
 365   AdjustMethodEntries(bool* trace_name_printed) : _trace_name_printed(trace_name_printed) {};
 366   bool operator()(WeakHandle<vm_resolved_method_table_data>* entry) {
 367     oop mem_name = entry->peek();
 368     if (mem_name == NULL) {
 369       // Removed
 370       return true;
 371     }
 372 
 373     Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
 374 
 375     if (old_method->is_old()) {
 376 
 377       Method* new_method = (old_method->is_deleted()) ?
 378                             Universe::throw_no_such_method_error() :
 379                             old_method->get_new_method();
 380       java_lang_invoke_ResolvedMethodName::set_vmtarget(mem_name, new_method);
 381 
 382       ResourceMark rm;
 383       if (!(*_trace_name_printed)) {
 384         log_info(redefine, class, update)("adjust: name=%s", old_method->method_holder()->external_name());
 385          *_trace_name_printed = true;
 386       }
 387       log_debug(redefine, class, update, constantpool)
 388         ("ResolvedMethod method update: %s(%s)",
 389          new_method->name()->as_C_string(), new_method->signature()->as_C_string());
 390     }
 391 
 392     return true;
 393   }
 394 };
 395 
 396 // It is called at safepoint only for RedefineClasses
 397 void ResolvedMethodTable::adjust_method_entries(bool * trace_name_printed) {
 398   assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
 399   // For each entry in RMT, change to new method
 400   AdjustMethodEntries adjust(trace_name_printed);
 401   _local_table->do_safepoint_scan(adjust);
 402 }
 403 #endif // INCLUDE_JVMTI
 404 
 405 // Verification and comp
 406 class VerifyCompResolvedMethod : StackObj {
 407   GrowableArray<oop>* _oops;
 408  public:
 409   size_t _errors;
 410   VerifyCompResolvedMethod(GrowableArray<oop>* oops) : _oops(oops), _errors(0) {}
 411   bool operator()(WeakHandle<vm_resolved_method_table_data>* val) {
 412     oop s = val->peek();
 413     if (s == NULL) {
 414       return true;
 415     }
 416     int len = _oops->length();
 417     for (int i = 0; i < len; i++) {
 418       bool eq = s == _oops->at(i);
 419       assert(!eq, "Duplicate entries");
 420       if (eq) {
 421         _errors++;
 422       }
 423     }
 424     _oops->push(s);
 425     return true;
 426   };
 427 };
 428 
 429 size_t ResolvedMethodTable::items_count() {
 430   return _items_count;
 431 }
 432 
 433 size_t ResolvedMethodTable::verify_and_compare_entries() {
 434   Thread* thr = Thread::current();
 435   GrowableArray<oop>* oops =
 436     new (ResourceObj::C_HEAP, mtInternal)
 437       GrowableArray<oop>((int)_current_size, true);
 438 
 439   VerifyCompResolvedMethod vcs(oops);
 440   if (!_local_table->try_scan(thr, vcs)) {
 441     log_info(membername, table)("verify unavailable at this moment");
 442   }
 443   delete oops;
 444   return vcs._errors;
 445 }