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