8201505: Use WeakHandle for ProtectionDomainCacheTable and ResolvedMethodTable
authorcoleenp
Wed, 18 Apr 2018 12:06:53 -0400
changeset 49818 e57e6addb978
parent 49817 a838e3707f3a
child 49819 3cdebcdc8ec0
8201505: Use WeakHandle for ProtectionDomainCacheTable and ResolvedMethodTable 8193524: Redefining a method that removes use of 1 or more lambda expressions causes the JVM to hang Summary: Remove oop pointers from runtime data structures. Reviewed-by: lfoltan, stefank Contributed-by: coleen.phillimore@oracle.com, lois.foltan@oracle.com
src/hotspot/share/classfile/classLoaderData.cpp
src/hotspot/share/classfile/classLoaderData.hpp
src/hotspot/share/classfile/dictionary.cpp
src/hotspot/share/classfile/dictionary.hpp
src/hotspot/share/classfile/protectionDomainCache.cpp
src/hotspot/share/classfile/protectionDomainCache.hpp
src/hotspot/share/classfile/systemDictionary.cpp
src/hotspot/share/gc/g1/g1CollectedHeap.cpp
src/hotspot/share/oops/weakHandle.hpp
src/hotspot/share/prims/resolvedMethodTable.cpp
src/hotspot/share/prims/resolvedMethodTable.hpp
src/hotspot/share/runtime/mutex.hpp
src/hotspot/share/runtime/mutexLocker.cpp
src/hotspot/share/utilities/hashtable.cpp
test/hotspot/jtreg/runtime/MemberName/MemberNameLeak.java
--- a/src/hotspot/share/classfile/classLoaderData.cpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/classfile/classLoaderData.cpp	Wed Apr 18 12:06:53 2018 -0400
@@ -1237,8 +1237,7 @@
 
 // Move class loader data from main list to the unloaded list for unloading
 // and deallocation later.
-bool ClassLoaderDataGraph::do_unloading(BoolObjectClosure* is_alive_closure,
-                                        bool clean_previous_versions) {
+bool ClassLoaderDataGraph::do_unloading(bool clean_previous_versions) {
 
   ClassLoaderData* data = _head;
   ClassLoaderData* prev = NULL;
@@ -1296,7 +1295,7 @@
       // Remove entries in the dictionary of live class loader that have
       // initiated loading classes in a dead class loader.
       if (data->dictionary() != NULL) {
-        data->dictionary()->do_unloading(is_alive_closure);
+        data->dictionary()->do_unloading();
       }
       // Walk a ModuleEntry's reads, and a PackageEntry's exports
       // lists to determine if there are modules on those lists that are now
--- a/src/hotspot/share/classfile/classLoaderData.hpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/classfile/classLoaderData.hpp	Wed Apr 18 12:06:53 2018 -0400
@@ -114,7 +114,7 @@
   static void packages_unloading_do(void f(PackageEntry*));
   static void loaded_classes_do(KlassClosure* klass_closure);
   static void classes_unloading_do(void f(Klass* const));
-  static bool do_unloading(BoolObjectClosure* is_alive_closure, bool clean_previous_versions);
+  static bool do_unloading(bool clean_previous_versions);
 
   // dictionary do
   // Iterate over all klasses in dictionary, but
@@ -220,7 +220,7 @@
 
   static ClassLoaderData * _the_null_class_loader_data;
 
-  WeakHandle<vm_class_loader_data> _holder; // The oop that determines lifetime of this class loader
+  ClassLoaderWeakHandle _holder; // The oop that determines lifetime of this class loader
   oop _class_loader;          // The instance of java/lang/ClassLoader associated with
                               // this ClassLoaderData
 
--- a/src/hotspot/share/classfile/dictionary.cpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/classfile/dictionary.cpp	Wed Apr 18 12:06:53 2018 -0400
@@ -214,13 +214,13 @@
 
 // During class loading we may have cached a protection domain that has
 // since been unreferenced, so this entry should be cleared.
-void Dictionary::clean_cached_protection_domains(BoolObjectClosure* is_alive, DictionaryEntry* probe) {
+void Dictionary::clean_cached_protection_domains(DictionaryEntry* probe) {
   assert_locked_or_safepoint(SystemDictionary_lock);
 
   ProtectionDomainEntry* current = probe->pd_set();
   ProtectionDomainEntry* prev = NULL;
   while (current != NULL) {
-    if (!is_alive->do_object_b(current->object_no_keepalive())) {
+    if (current->object_no_keepalive() == NULL) {
       LogTarget(Debug, protectiondomain) lt;
       if (lt.is_enabled()) {
         ResourceMark rm;
@@ -228,7 +228,6 @@
         LogStream ls(lt);
         ls.print_cr("PD in set is not alive:");
         ls.print("class loader: "); loader_data()->class_loader()->print_value_on(&ls);
-        ls.print(" protection domain: "); current->object_no_keepalive()->print_value_on(&ls);
         ls.print(" loading: "); probe->instance_klass()->print_value_on(&ls);
         ls.cr();
       }
@@ -249,7 +248,7 @@
 }
 
 
-void Dictionary::do_unloading(BoolObjectClosure* is_alive) {
+void Dictionary::do_unloading() {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
 
   // The NULL class loader doesn't initiate loading classes from other class loaders
@@ -276,7 +275,7 @@
         continue;
       }
       // Clean pd_set
-      clean_cached_protection_domains(is_alive, probe);
+      clean_cached_protection_domains(probe);
       p = probe->next_addr();
     }
   }
--- a/src/hotspot/share/classfile/dictionary.hpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/classfile/dictionary.hpp	Wed Apr 18 12:06:53 2018 -0400
@@ -52,7 +52,7 @@
 
   DictionaryEntry* get_entry(int index, unsigned int hash, Symbol* name);
 
-  void clean_cached_protection_domains(BoolObjectClosure* is_alive, DictionaryEntry* probe);
+  void clean_cached_protection_domains(DictionaryEntry* probe);
 
 protected:
   static size_t entry_size();
@@ -72,20 +72,16 @@
 
   InstanceKlass* find_shared_class(int index, unsigned int hash, Symbol* name);
 
-  // GC support
-  void oops_do(OopClosure* f);
-  void roots_oops_do(OopClosure* strong, OopClosure* weak);
-
   void classes_do(void f(InstanceKlass*));
   void classes_do(void f(InstanceKlass*, TRAPS), TRAPS);
   void all_entries_do(void f(InstanceKlass*, ClassLoaderData*));
   void classes_do(MetaspaceClosure* it);
 
-  void unlink(BoolObjectClosure* is_alive);
+  void unlink();
   void remove_classes_in_error_state();
 
   // Unload classes whose defining loaders are unloaded
-  void do_unloading(BoolObjectClosure* is_alive);
+  void do_unloading();
 
   // Protection domains
   InstanceKlass* find(unsigned int hash, Symbol* name, Handle protection_domain);
--- a/src/hotspot/share/classfile/protectionDomainCache.cpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/classfile/protectionDomainCache.cpp	Wed Apr 18 12:06:53 2018 -0400
@@ -30,6 +30,7 @@
 #include "memory/iterator.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/weakHandle.inline.hpp"
 #include "utilities/hashtable.inline.hpp"
 
 unsigned int ProtectionDomainCacheTable::compute_hash(Handle protection_domain) {
@@ -42,26 +43,26 @@
 }
 
 ProtectionDomainCacheTable::ProtectionDomainCacheTable(int table_size)
-  : Hashtable<oop, mtClass>(table_size, sizeof(ProtectionDomainCacheEntry))
+  : Hashtable<ClassLoaderWeakHandle, mtClass>(table_size, sizeof(ProtectionDomainCacheEntry))
 {
 }
 
-void ProtectionDomainCacheTable::unlink(BoolObjectClosure* is_alive) {
+void ProtectionDomainCacheTable::unlink() {
   assert(SafepointSynchronize::is_at_safepoint(), "must be");
   for (int i = 0; i < table_size(); ++i) {
     ProtectionDomainCacheEntry** p = bucket_addr(i);
     ProtectionDomainCacheEntry* entry = bucket(i);
     while (entry != NULL) {
-      if (is_alive->do_object_b(entry->object_no_keepalive())) {
+      oop pd = entry->object_no_keepalive();
+      if (pd != NULL) {
         p = entry->next_addr();
       } else {
         LogTarget(Debug, protectiondomain) lt;
         if (lt.is_enabled()) {
           LogStream ls(lt);
-          ls.print("protection domain unlinked: ");
-          entry->object_no_keepalive()->print_value_on(&ls);
-          ls.cr();
+          ls.print_cr("protection domain unlinked at %d", i);
         }
+        entry->literal().release();
         *p = entry->next();
         free_entry(entry);
       }
@@ -70,16 +71,6 @@
   }
 }
 
-void ProtectionDomainCacheTable::oops_do(OopClosure* f) {
-  for (int index = 0; index < table_size(); index++) {
-    for (ProtectionDomainCacheEntry* probe = bucket(index);
-                                     probe != NULL;
-                                     probe = probe->next()) {
-      probe->oops_do(f);
-    }
-  }
-}
-
 void ProtectionDomainCacheTable::print_on(outputStream* st) const {
   st->print_cr("Protection domain cache table (table_size=%d, classes=%d)",
                table_size(), number_of_entries());
@@ -97,7 +88,7 @@
 }
 
 oop ProtectionDomainCacheEntry::object() {
-  return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(literal_addr());
+  return literal().resolve();
 }
 
 oop ProtectionDomainEntry::object() {
@@ -108,7 +99,7 @@
 // keeping it alive. This is okay to do in the VM thread state if it is not
 // leaked out to become strongly reachable.
 oop ProtectionDomainCacheEntry::object_no_keepalive() {
-  return RootAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(literal_addr());
+  return literal().peek();
 }
 
 oop ProtectionDomainEntry::object_no_keepalive() {
@@ -116,7 +107,7 @@
 }
 
 void ProtectionDomainCacheEntry::verify() {
-  guarantee(oopDesc::is_oop(object_no_keepalive()), "must be an oop");
+  guarantee(object_no_keepalive() == NULL || oopDesc::is_oop(object_no_keepalive()), "must be an oop");
 }
 
 ProtectionDomainCacheEntry* ProtectionDomainCacheTable::get(Handle protection_domain) {
@@ -127,6 +118,8 @@
   if (entry == NULL) {
     entry = add_entry(index, hash, protection_domain);
   }
+  // keep entry alive
+  (void)entry->object();
   return entry;
 }
 
@@ -145,7 +138,8 @@
   assert(index == index_for(protection_domain), "incorrect index?");
   assert(find_entry(index, protection_domain) == NULL, "no double entry");
 
-  ProtectionDomainCacheEntry* p = new_entry(hash, protection_domain);
-  Hashtable<oop, mtClass>::add_entry(index, p);
+  ClassLoaderWeakHandle w = ClassLoaderWeakHandle::create(protection_domain);
+  ProtectionDomainCacheEntry* p = new_entry(hash, w);
+  Hashtable<ClassLoaderWeakHandle, mtClass>::add_entry(index, p);
   return p;
 }
--- a/src/hotspot/share/classfile/protectionDomainCache.hpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/classfile/protectionDomainCache.hpp	Wed Apr 18 12:06:53 2018 -0400
@@ -26,6 +26,7 @@
 #define SHARE_VM_CLASSFILE_PROTECTIONDOMAINCACHE_HPP
 
 #include "oops/oop.hpp"
+#include "oops/weakHandle.hpp"
 #include "memory/iterator.hpp"
 #include "utilities/hashtable.hpp"
 
@@ -34,22 +35,18 @@
 // to dictionary.hpp pd_set for more information about how protection domain entries
 // are used.
 // This table is walked during GC, rather than the class loader data graph dictionaries.
-class ProtectionDomainCacheEntry : public HashtableEntry<oop, mtClass> {
+class ProtectionDomainCacheEntry : public HashtableEntry<ClassLoaderWeakHandle, mtClass> {
   friend class VMStructs;
  public:
   oop object();
   oop object_no_keepalive();
 
   ProtectionDomainCacheEntry* next() {
-    return (ProtectionDomainCacheEntry*)HashtableEntry<oop, mtClass>::next();
+    return (ProtectionDomainCacheEntry*)HashtableEntry<ClassLoaderWeakHandle, mtClass>::next();
   }
 
   ProtectionDomainCacheEntry** next_addr() {
-    return (ProtectionDomainCacheEntry**)HashtableEntry<oop, mtClass>::next_addr();
-  }
-
-  void oops_do(OopClosure* f) {
-    f->do_oop(literal_addr());
+    return (ProtectionDomainCacheEntry**)HashtableEntry<ClassLoaderWeakHandle, mtClass>::next_addr();
   }
 
   void verify();
@@ -64,20 +61,21 @@
 // we only need to iterate over this set.
 // The amount of different protection domains used is typically magnitudes smaller
 // than the number of system dictionary entries (loaded classes).
-class ProtectionDomainCacheTable : public Hashtable<oop, mtClass> {
+class ProtectionDomainCacheTable : public Hashtable<ClassLoaderWeakHandle, mtClass> {
   friend class VMStructs;
 private:
   ProtectionDomainCacheEntry* bucket(int i) const {
-    return (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::bucket(i);
+    return (ProtectionDomainCacheEntry*) Hashtable<ClassLoaderWeakHandle, mtClass>::bucket(i);
   }
 
   // The following method is not MT-safe and must be done under lock.
   ProtectionDomainCacheEntry** bucket_addr(int i) {
-    return (ProtectionDomainCacheEntry**) Hashtable<oop, mtClass>::bucket_addr(i);
+    return (ProtectionDomainCacheEntry**) Hashtable<ClassLoaderWeakHandle, mtClass>::bucket_addr(i);
   }
 
-  ProtectionDomainCacheEntry* new_entry(unsigned int hash, Handle protection_domain) {
-    ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*) Hashtable<oop, mtClass>::new_entry(hash, protection_domain());
+  ProtectionDomainCacheEntry* new_entry(unsigned int hash, ClassLoaderWeakHandle protection_domain) {
+    ProtectionDomainCacheEntry* entry = (ProtectionDomainCacheEntry*)
+      Hashtable<ClassLoaderWeakHandle, mtClass>::new_entry(hash, protection_domain);
     return entry;
   }
 
@@ -91,10 +89,7 @@
   ProtectionDomainCacheTable(int table_size);
   ProtectionDomainCacheEntry* get(Handle protection_domain);
 
-  void unlink(BoolObjectClosure* cl);
-
-  // GC support
-  void oops_do(OopClosure* f);
+  void unlink();
 
   void print_on(outputStream* st) const;
   void verify();
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Wed Apr 18 12:06:53 2018 -0400
@@ -1831,24 +1831,6 @@
 }
 
 
-#ifdef ASSERT
-class VerifySDReachableAndLiveClosure : public OopClosure {
-private:
-  BoolObjectClosure* _is_alive;
-
-  template <class T> void do_oop_work(T* p) {
-    oop obj = RawAccess<>::oop_load(p);
-    guarantee(_is_alive->do_object_b(obj), "Oop in protection domain cache table must be live");
-  }
-
-public:
-  VerifySDReachableAndLiveClosure(BoolObjectClosure* is_alive) : OopClosure(), _is_alive(is_alive) { }
-
-  virtual void do_oop(oop* p)       { do_oop_work(p); }
-  virtual void do_oop(narrowOop* p) { do_oop_work(p); }
-};
-#endif
-
 // Assumes classes in the SystemDictionary are only unloaded at a safepoint
 // Note: anonymous classes are not in the SD.
 bool SystemDictionary::do_unloading(BoolObjectClosure* is_alive,
@@ -1865,8 +1847,7 @@
     GCTraceTime(Debug, gc, phases) t("ClassLoaderData", gc_timer);
 
     // First, mark for unload all ClassLoaderData referencing a dead class loader.
-    unloading_occurred = ClassLoaderDataGraph::do_unloading(is_alive,
-                                                            do_cleaning);
+    unloading_occurred = ClassLoaderDataGraph::do_unloading(do_cleaning);
   }
 
   if (unloading_occurred) {
@@ -1880,17 +1861,12 @@
     // Oops referenced by the protection domain cache table may get unreachable independently
     // of the class loader (eg. cached protection domain oops). So we need to
     // explicitly unlink them here.
-    _pd_cache_table->unlink(is_alive);
-
-#ifdef ASSERT
-    VerifySDReachableAndLiveClosure cl(is_alive);
-    _pd_cache_table->oops_do(&cl);
-#endif
+    _pd_cache_table->unlink();
   }
 
   if (do_cleaning) {
     GCTraceTime(Debug, gc, phases) t("ResolvedMethodTable", gc_timer);
-    ResolvedMethodTable::unlink(is_alive);
+    ResolvedMethodTable::unlink();
   }
 
   return unloading_occurred;
@@ -1906,21 +1882,15 @@
   if (strong == weak || !ClassUnloading) {
     // Only the protection domain oops contain references into the heap. Iterate
     // over all of them.
-    _pd_cache_table->oops_do(strong);
     vm_weak_oop_storage()->oops_do(strong);
   } else {
    if (weak != NULL) {
-     _pd_cache_table->oops_do(weak);
      vm_weak_oop_storage()->oops_do(weak);
    }
   }
 
   // Visit extra methods
   invoke_method_table()->oops_do(strong);
-
-  if (weak != NULL) {
-    ResolvedMethodTable::oops_do(weak);
-  }
 }
 
 void SystemDictionary::oops_do(OopClosure* f) {
@@ -1929,15 +1899,9 @@
   f->do_oop(&_system_loader_lock_obj);
   CDS_ONLY(SystemDictionaryShared::oops_do(f);)
 
-  // Only the protection domain oops contain references into the heap. Iterate
-  // over all of them.
-  _pd_cache_table->oops_do(f);
-
   // Visit extra methods
   invoke_method_table()->oops_do(f);
 
-  ResolvedMethodTable::oops_do(f);
-
   vm_weak_oop_storage()->oops_do(f);
 }
 
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Wed Apr 18 12:06:53 2018 -0400
@@ -3510,11 +3510,10 @@
 };
 
 class G1ResolvedMethodCleaningTask : public StackObj {
-  BoolObjectClosure* _is_alive;
   volatile int       _resolved_method_task_claimed;
 public:
-  G1ResolvedMethodCleaningTask(BoolObjectClosure* is_alive) :
-      _is_alive(is_alive), _resolved_method_task_claimed(0) {}
+  G1ResolvedMethodCleaningTask() :
+      _resolved_method_task_claimed(0) {}
 
   bool claim_resolved_method_task() {
     if (_resolved_method_task_claimed) {
@@ -3526,7 +3525,7 @@
   // These aren't big, one thread can do it all.
   void work() {
     if (claim_resolved_method_task()) {
-      ResolvedMethodTable::unlink(_is_alive);
+      ResolvedMethodTable::unlink();
     }
   }
 };
@@ -3547,7 +3546,7 @@
       _string_symbol_task(is_alive, true, true, G1StringDedup::is_enabled()),
       _code_cache_task(num_workers, is_alive, unloading_occurred),
       _klass_cleaning_task(is_alive),
-      _resolved_method_cleaning_task(is_alive) {
+      _resolved_method_cleaning_task() {
   }
 
   // The parallel work done by all worker threads.
--- a/src/hotspot/share/oops/weakHandle.hpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/oops/weakHandle.hpp	Wed Apr 18 12:06:53 2018 -0400
@@ -63,4 +63,6 @@
   void print_on(outputStream* st) const;
 };
 
+typedef WeakHandle<vm_class_loader_data> ClassLoaderWeakHandle;
+
 #endif // SHARE_VM_OOPS_WEAKHANDLE_HPP
--- a/src/hotspot/share/prims/resolvedMethodTable.cpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/prims/resolvedMethodTable.cpp	Wed Apr 18 12:06:53 2018 -0400
@@ -30,6 +30,7 @@
 #include "oops/oop.inline.hpp"
 #include "oops/method.hpp"
 #include "oops/symbol.hpp"
+#include "oops/weakHandle.inline.hpp"
 #include "prims/resolvedMethodTable.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/mutexLocker.hpp"
@@ -39,7 +40,7 @@
 
 
 oop ResolvedMethodEntry::object() {
-  return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(literal_addr());
+  return literal().resolve();
 }
 
 oop ResolvedMethodEntry::object_no_keepalive() {
@@ -48,11 +49,11 @@
   // not leak out past a thread transition where a safepoint can happen.
   // A subsequent oop_load without AS_NO_KEEPALIVE (the object() accessor)
   // keeps the oop alive before doing so.
-  return RootAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(literal_addr());
+  return literal().peek();
 }
 
 ResolvedMethodTable::ResolvedMethodTable()
-  : Hashtable<oop, mtClass>(_table_size, sizeof(ResolvedMethodEntry)) { }
+  : Hashtable<ClassLoaderWeakHandle, mtClass>(_table_size, sizeof(ResolvedMethodEntry)) { }
 
 oop ResolvedMethodTable::lookup(int index, unsigned int hash, Method* method) {
   for (ResolvedMethodEntry* p = bucket(index); p != NULL; p = p->next()) {
@@ -62,7 +63,7 @@
       oop target = p->object_no_keepalive();
 
       // The method is in the table as a target already
-      if (java_lang_invoke_ResolvedMethodName::vmtarget(target) == method) {
+      if (target != NULL && java_lang_invoke_ResolvedMethodName::vmtarget(target) == method) {
         ResourceMark rm;
         log_debug(membername, table) ("ResolvedMethod entry found for %s index %d",
                                        method->name_and_sig_as_C_string(), index);
@@ -88,7 +89,7 @@
   return lookup(index, hash, method);
 }
 
-oop ResolvedMethodTable::basic_add(Method* method, oop rmethod_name) {
+oop ResolvedMethodTable::basic_add(Method* method, Handle rmethod_name) {
   assert_locked_or_safepoint(ResolvedMethodTable_lock);
 
   unsigned int hash = compute_hash(method);
@@ -100,12 +101,13 @@
     return entry;
   }
 
-  ResolvedMethodEntry* p = (ResolvedMethodEntry*) Hashtable<oop, mtClass>::new_entry(hash, rmethod_name);
-  Hashtable<oop, mtClass>::add_entry(index, p);
+  ClassLoaderWeakHandle w = ClassLoaderWeakHandle::create(rmethod_name);
+  ResolvedMethodEntry* p = (ResolvedMethodEntry*) Hashtable<ClassLoaderWeakHandle, mtClass>::new_entry(hash, w);
+  Hashtable<ClassLoaderWeakHandle, mtClass>::add_entry(index, p);
   ResourceMark rm;
   log_debug(membername, table) ("ResolvedMethod entry added for %s index %d",
                                  method->name_and_sig_as_C_string(), index);
-  return rmethod_name;
+  return rmethod_name();
 }
 
 ResolvedMethodTable* ResolvedMethodTable::_the_table = NULL;
@@ -134,7 +136,7 @@
   // have any membernames in the table.
   method->method_holder()->set_has_resolved_methods();
 
-  return _the_table->basic_add(method, resolved_method_name());
+  return _the_table->basic_add(method, resolved_method_name);
 }
 
 // Removing entries
@@ -143,7 +145,7 @@
 
 // Serially invoke removed unused oops from the table.
 // This is done late during GC.
-void ResolvedMethodTable::unlink(BoolObjectClosure* is_alive) {
+void ResolvedMethodTable::unlink() {
   _oops_removed = 0;
   _oops_counted = 0;
   for (int i = 0; i < _the_table->table_size(); ++i) {
@@ -151,38 +153,27 @@
     ResolvedMethodEntry* entry = _the_table->bucket(i);
     while (entry != NULL) {
       _oops_counted++;
-      if (is_alive->do_object_b(entry->object_no_keepalive())) {
+      oop l = entry->object_no_keepalive();
+      if (l != NULL) {
         p = entry->next_addr();
       } else {
+        // Entry has been removed.
         _oops_removed++;
         if (log_is_enabled(Debug, membername, table)) {
-          Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(entry->object_no_keepalive());
-          ResourceMark rm;
-          log_debug(membername, table) ("ResolvedMethod entry removed for %s index %d",
-                                           m->name_and_sig_as_C_string(), i);
+          log_debug(membername, table) ("ResolvedMethod entry removed for index %d", i);
         }
+        entry->literal().release();
         *p = entry->next();
         _the_table->free_entry(entry);
       }
       // get next entry
-      entry = (ResolvedMethodEntry*)HashtableEntry<oop, mtClass>::make_ptr(*p);
+      entry = (ResolvedMethodEntry*)HashtableEntry<ClassLoaderWeakHandle, mtClass>::make_ptr(*p);
     }
   }
   log_debug(membername, table) ("ResolvedMethod entries counted %d removed %d",
                                 _oops_counted, _oops_removed);
 }
 
-// Serially invoke "f->do_oop" on the locations of all oops in the table.
-void ResolvedMethodTable::oops_do(OopClosure* f) {
-  for (int i = 0; i < _the_table->table_size(); ++i) {
-    ResolvedMethodEntry* entry = _the_table->bucket(i);
-    while (entry != NULL) {
-      f->do_oop(entry->literal_addr());
-      entry = entry->next();
-    }
-  }
-}
-
 #ifndef PRODUCT
 void ResolvedMethodTable::print() {
   for (int i = 0; i < table_size(); ++i) {
@@ -190,9 +181,11 @@
     while (entry != NULL) {
       tty->print("%d : ", i);
       oop rmethod_name = entry->object_no_keepalive();
-      rmethod_name->print();
-      Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(rmethod_name);
-      m->print();
+      if (rmethod_name != NULL) {
+        rmethod_name->print();
+        Method* m = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(rmethod_name);
+        m->print();
+      }
       entry = entry->next();
     }
   }
@@ -205,9 +198,15 @@
   assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
   // For each entry in RMT, change to new method
   for (int i = 0; i < _the_table->table_size(); ++i) {
-    ResolvedMethodEntry* entry = _the_table->bucket(i);
-    while (entry != NULL) {
+    for (ResolvedMethodEntry* entry = _the_table->bucket(i);
+         entry != NULL;
+         entry = entry->next()) {
+
       oop mem_name = entry->object_no_keepalive();
+      // except ones removed
+      if (mem_name == NULL) {
+        continue;
+      }
       Method* old_method = (Method*)java_lang_invoke_ResolvedMethodName::vmtarget(mem_name);
 
       if (old_method->is_old()) {
@@ -235,7 +234,6 @@
           ("ResolvedMethod method update: %s(%s)",
            new_method->name()->as_C_string(), new_method->signature()->as_C_string());
       }
-      entry = entry->next();
     }
   }
 }
--- a/src/hotspot/share/prims/resolvedMethodTable.hpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/prims/resolvedMethodTable.hpp	Wed Apr 18 12:06:53 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,22 +26,23 @@
 #define SHARE_VM_PRIMS_RESOLVEDMETHOD_HPP
 
 #include "oops/symbol.hpp"
+#include "oops/weakHandle.hpp"
 #include "utilities/hashtable.hpp"
 
 // Hashtable to record Method* used in ResolvedMethods, via. ResolvedMethod oops.
 // This is needed for redefinition to replace Method* with redefined versions.
 
-// Entry in a ResolvedMethodTable, mapping a single oop of java_lang_invoke_ResolvedMethodName which
-// holds JVM Method* in vmtarget.
+// Entry in a ResolvedMethodTable, mapping a ClassLoaderWeakHandle for a single oop of
+// java_lang_invoke_ResolvedMethodName which holds JVM Method* in vmtarget.
 
-class ResolvedMethodEntry : public HashtableEntry<oop, mtClass> {
+class ResolvedMethodEntry : public HashtableEntry<ClassLoaderWeakHandle, mtClass> {
  public:
   ResolvedMethodEntry* next() const {
-    return (ResolvedMethodEntry*)HashtableEntry<oop, mtClass>::next();
+    return (ResolvedMethodEntry*)HashtableEntry<ClassLoaderWeakHandle, mtClass>::next();
   }
 
   ResolvedMethodEntry** next_addr() {
-    return (ResolvedMethodEntry**)HashtableEntry<oop, mtClass>::next_addr();
+    return (ResolvedMethodEntry**)HashtableEntry<ClassLoaderWeakHandle, mtClass>::next_addr();
   }
 
   oop object();
@@ -50,7 +51,7 @@
   void print_on(outputStream* st) const;
 };
 
-class ResolvedMethodTable : public Hashtable<oop, mtClass> {
+class ResolvedMethodTable : public Hashtable<ClassLoaderWeakHandle, mtClass> {
   enum Constants {
     _table_size  = 1007
   };
@@ -61,11 +62,11 @@
   static ResolvedMethodTable* _the_table;
 private:
   ResolvedMethodEntry* bucket(int i) {
-    return (ResolvedMethodEntry*) Hashtable<oop, mtClass>::bucket(i);
+    return (ResolvedMethodEntry*) Hashtable<ClassLoaderWeakHandle, mtClass>::bucket(i);
   }
 
   ResolvedMethodEntry** bucket_addr(int i) {
-    return (ResolvedMethodEntry**) Hashtable<oop, mtClass>::bucket_addr(i);
+    return (ResolvedMethodEntry**) Hashtable<ClassLoaderWeakHandle, mtClass>::bucket_addr(i);
   }
 
   unsigned int compute_hash(Method* method);
@@ -75,7 +76,7 @@
   oop lookup(Method* method);
 
   // must be done under ResolvedMethodTable_lock
-  oop basic_add(Method* method, oop rmethod_name);
+  oop basic_add(Method* method, Handle rmethod_name);
 
 public:
   ResolvedMethodTable();
@@ -95,8 +96,7 @@
 #endif // INCLUDE_JVMTI
 
   // Cleanup cleared entries
-  static void unlink(BoolObjectClosure* is_alive);
-  static void oops_do(OopClosure* f);
+  static void unlink();
 
 #ifndef PRODUCT
   void print();
--- a/src/hotspot/share/runtime/mutex.hpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/runtime/mutex.hpp	Wed Apr 18 12:06:53 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -106,7 +106,8 @@
        access         = event          +   1,
        special        = access         +   2,
        suspend_resume = special        +   1,
-       leaf           = suspend_resume +   2,
+       vmweak         = suspend_resume +   2,
+       leaf           = vmweak         +   2,
        safepoint      = leaf           +  10,
        barrier        = safepoint      +   1,
        nonleaf        = barrier        +   1,
--- a/src/hotspot/share/runtime/mutexLocker.cpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/runtime/mutexLocker.cpp	Wed Apr 18 12:06:53 2018 -0400
@@ -182,6 +182,9 @@
   def(CGC_lock                     , PaddedMonitor, special,     true,  Monitor::_safepoint_check_never);      // coordinate between fore- and background GC
   def(STS_lock                     , PaddedMonitor, leaf,        true,  Monitor::_safepoint_check_never);
 
+  def(VMWeakAlloc_lock             , PaddedMutex  , vmweak,      true,  Monitor::_safepoint_check_never);
+  def(VMWeakActive_lock            , PaddedMutex  , vmweak-1,    true,  Monitor::_safepoint_check_never);
+
   if (UseConcMarkSweepGC || UseG1GC) {
     def(FullGCCount_lock           , PaddedMonitor, leaf,        true,  Monitor::_safepoint_check_never);      // in support of ExplicitGCInvokesConcurrent
   }
@@ -262,8 +265,6 @@
   def(JNIGlobalActive_lock         , PaddedMutex  , nonleaf-1,   true,  Monitor::_safepoint_check_never);
   def(JNIWeakAlloc_lock            , PaddedMutex  , nonleaf,     true,  Monitor::_safepoint_check_never);
   def(JNIWeakActive_lock           , PaddedMutex  , nonleaf-1,   true,  Monitor::_safepoint_check_never);
-  def(VMWeakAlloc_lock             , PaddedMutex  , nonleaf,     true,  Monitor::_safepoint_check_never);
-  def(VMWeakActive_lock            , PaddedMutex  , nonleaf-1,   true,  Monitor::_safepoint_check_never);
   def(JNICritical_lock             , PaddedMonitor, nonleaf,     true,  Monitor::_safepoint_check_always);     // used for JNI critical regions
   def(AdapterHandlerLibrary_lock   , PaddedMutex  , nonleaf,     true,  Monitor::_safepoint_check_always);
 
--- a/src/hotspot/share/utilities/hashtable.cpp	Mon Apr 16 12:50:10 2018 +0530
+++ b/src/hotspot/share/utilities/hashtable.cpp	Wed Apr 18 12:06:53 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -35,6 +35,7 @@
 #include "memory/metaspaceShared.hpp"
 #include "memory/resourceArea.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/weakHandle.inline.hpp"
 #include "runtime/safepoint.hpp"
 #include "utilities/dtrace.hpp"
 #include "utilities/hashtable.hpp"
@@ -148,7 +149,6 @@
   }
   // give the new table the free list as well
   new_table->copy_freelist(this);
-  assert(new_table->number_of_entries() == saved_entry_count, "lost entry on dictionary copy?");
 
   // Destroy memory used by the buckets in the hashtable.  The memory
   // for the elements has been used in a new table and is not
@@ -263,6 +263,10 @@
   }
 }
 
+static int literal_size(ClassLoaderWeakHandle v) {
+  return literal_size(v.peek());
+}
+
 template <MEMFLAGS F> bool BasicHashtable<F>::resize(int new_size) {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
 
@@ -382,6 +386,13 @@
 }
 
 #ifndef PRODUCT
+template <class T> void print_literal(T l) {
+  l->print();
+}
+
+static void print_literal(ClassLoaderWeakHandle l) {
+  l.print();
+}
 
 template <class T, MEMFLAGS F> void Hashtable<T, F>::print() {
   ResourceMark rm;
@@ -390,7 +401,7 @@
     HashtableEntry<T, F>* entry = bucket(i);
     while(entry != NULL) {
       tty->print("%d : ", i);
-      entry->literal()->print();
+      print_literal(entry->literal());
       tty->cr();
       entry = entry->next();
     }
@@ -443,21 +454,19 @@
 #endif
 template class Hashtable<ConstantPool*, mtClass>;
 template class RehashableHashtable<Symbol*, mtSymbol>;
-template class RehashableHashtable<oopDesc*, mtSymbol>;
+template class RehashableHashtable<oop, mtSymbol>;
 template class Hashtable<Symbol*, mtSymbol>;
 template class Hashtable<Klass*, mtClass>;
 template class Hashtable<InstanceKlass*, mtClass>;
-template class Hashtable<oop, mtClass>;
+template class Hashtable<ClassLoaderWeakHandle, mtClass>;
 template class Hashtable<Symbol*, mtModule>;
-#if defined(SOLARIS) || defined(CHECK_UNHANDLED_OOPS)
 template class Hashtable<oop, mtSymbol>;
-template class RehashableHashtable<oop, mtSymbol>;
-#endif // SOLARIS || CHECK_UNHANDLED_OOPS
-template class Hashtable<oopDesc*, mtSymbol>;
+template class Hashtable<ClassLoaderWeakHandle, mtSymbol>;
 template class Hashtable<Symbol*, mtClass>;
 template class HashtableEntry<Symbol*, mtSymbol>;
 template class HashtableEntry<Symbol*, mtClass>;
 template class HashtableEntry<oop, mtSymbol>;
+template class HashtableEntry<ClassLoaderWeakHandle, mtSymbol>;
 template class HashtableBucket<mtClass>;
 template class BasicHashtableEntry<mtSymbol>;
 template class BasicHashtableEntry<mtCode>;
--- a/test/hotspot/jtreg/runtime/MemberName/MemberNameLeak.java	Mon Apr 16 12:50:10 2018 +0530
+++ b/test/hotspot/jtreg/runtime/MemberName/MemberNameLeak.java	Wed Apr 18 12:06:53 2018 -0400
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -61,7 +61,7 @@
         OutputAnalyzer output = new OutputAnalyzer(pb.start());
         output.shouldContain("ResolvedMethod entry added for MemberNameLeak$Leak.callMe()V");
         output.shouldContain("ResolvedMethod entry found for MemberNameLeak$Leak.callMe()V");
-        output.shouldContain("ResolvedMethod entry removed for MemberNameLeak$Leak.callMe()V");
+        output.shouldContain("ResolvedMethod entry removed");
         output.shouldHaveExitValue(0);
     }