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 }