changeset 49663:a7bc87a63dd8

8198313: Wrap holder object for ClassLoaderData in a WeakHandle Summary: Use WeakHandle for ClassLoaderData::_holder so that is_alive closure is not needed Reviewed-by: rehn, kbarrett
author coleenp
date Tue, 10 Apr 2018 10:06:42 -0400
parents 01960eec4570
children 00805b129186
files src/hotspot/share/ci/ciInstanceKlass.cpp src/hotspot/share/classfile/classLoaderData.cpp src/hotspot/share/classfile/classLoaderData.hpp src/hotspot/share/classfile/systemDictionary.cpp src/hotspot/share/classfile/systemDictionary.hpp src/hotspot/share/memory/universe.cpp src/hotspot/share/oops/instanceKlass.cpp src/hotspot/share/oops/instanceKlass.hpp src/hotspot/share/oops/weakHandle.cpp src/hotspot/share/oops/weakHandle.hpp src/hotspot/share/oops/weakHandle.inline.hpp src/hotspot/share/runtime/mutexLocker.cpp src/hotspot/share/runtime/mutexLocker.hpp
diffstat 13 files changed, 273 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/src/hotspot/share/ci/ciInstanceKlass.cpp	Tue Apr 10 08:15:40 2018 -0400
+++ b/src/hotspot/share/ci/ciInstanceKlass.cpp	Tue Apr 10 10:06:42 2018 -0400
@@ -72,7 +72,7 @@
   // by the GC but need to be strong roots if reachable from a current compilation.
   // InstanceKlass are created for both weak and strong metadata.  Ensuring this metadata
   // alive covers the cases where there are weak roots without performance cost.
-  oop holder = ik->klass_holder_phantom();
+  oop holder = ik->holder_phantom();
   if (ik->is_anonymous()) {
     // Though ciInstanceKlass records class loader oop, it's not enough to keep
     // VM anonymous classes alive (loader == NULL). Klass holder should be used instead.
--- a/src/hotspot/share/classfile/classLoaderData.cpp	Tue Apr 10 08:15:40 2018 -0400
+++ b/src/hotspot/share/classfile/classLoaderData.cpp	Tue Apr 10 10:06:42 2018 -0400
@@ -55,26 +55,22 @@
 #include "classfile/moduleEntry.hpp"
 #include "classfile/packageEntry.hpp"
 #include "classfile/systemDictionary.hpp"
-#include "code/codeCache.hpp"
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/metadataFactory.hpp"
 #include "memory/metaspaceShared.hpp"
-#include "memory/oopFactory.hpp"
 #include "memory/resourceArea.hpp"
+#include "memory/universe.hpp"
 #include "oops/access.inline.hpp"
-#include "oops/objArrayOop.inline.hpp"
 #include "oops/oop.inline.hpp"
+#include "oops/weakHandle.inline.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/handles.inline.hpp"
-#include "runtime/javaCalls.hpp"
-#include "runtime/jniHandles.hpp"
 #include "runtime/mutex.hpp"
 #include "runtime/orderAccess.hpp"
 #include "runtime/safepoint.hpp"
 #include "runtime/safepointVerifiers.hpp"
-#include "runtime/synchronizer.hpp"
 #include "utilities/growableArray.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/ostream.hpp"
@@ -113,17 +109,21 @@
   // The null-class-loader should always be kept alive.
   _keep_alive((is_anonymous || h_class_loader.is_null()) ? 1 : 0),
   _metaspace(NULL), _unloading(false), _klasses(NULL),
-  _modules(NULL), _packages(NULL),
+  _modules(NULL), _packages(NULL), _unnamed_module(NULL), _dictionary(NULL),
   _claimed(0), _modified_oops(true), _accumulated_modified_oops(false),
   _jmethod_ids(NULL), _handles(), _deallocate_list(NULL),
   _next(NULL),
   _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true,
                             Monitor::_safepoint_check_never)) {
 
-  // A ClassLoaderData created solely for an anonymous class should never have a
-  // ModuleEntryTable or PackageEntryTable created for it. The defining package
-  // and module for an anonymous class will be found in its host class.
   if (!is_anonymous) {
+    // The holder is initialized later for anonymous classes, and before calling anything
+    // that call class_loader().
+    initialize_holder(h_class_loader);
+
+    // A ClassLoaderData created solely for an anonymous class should never have a
+    // ModuleEntryTable or PackageEntryTable created for it. The defining package
+    // and module for an anonymous class will be found in its host class.
     _packages = new PackageEntryTable(PackageEntryTable::_packagetable_entry_size);
     if (h_class_loader.is_null()) {
       // Create unnamed module for boot loader
@@ -133,10 +133,6 @@
       _unnamed_module = ModuleEntry::create_unnamed_module(this);
     }
     _dictionary = create_dictionary();
-  } else {
-    _packages = NULL;
-    _unnamed_module = NULL;
-    _dictionary = NULL;
   }
 
   NOT_PRODUCT(_dependency_count = 0); // number of class loader dependencies
@@ -510,6 +506,13 @@
 }
 
 
+void ClassLoaderData::initialize_holder(Handle loader_or_mirror) {
+  if (loader_or_mirror() != NULL) {
+    assert(_holder.is_null(), "never replace holders");
+    _holder = WeakHandle<vm_class_loader_data>::create(loader_or_mirror);
+  }
+}
+
 // Remove a klass from the _klasses list for scratch_class during redefinition
 // or parsed class in the case of an error.
 void ClassLoaderData::remove_class(Klass* scratch_class) {
@@ -611,30 +614,23 @@
 }
 
 // Tell the GC to keep this klass alive while iterating ClassLoaderDataGraph
-oop ClassLoaderData::holder_phantom() {
+oop ClassLoaderData::holder_phantom() const {
   // A klass that was previously considered dead can be looked up in the
   // CLD/SD, and its _java_mirror or _class_loader can be stored in a root
   // or a reachable object making it alive again. The SATB part of G1 needs
   // to get notified about this potential resurrection, otherwise the marking
   // might not find the object.
-  if (!keep_alive()) {
-    oop* o = is_anonymous() ? _klasses->java_mirror_handle().ptr_raw() : &_class_loader;
-    return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(o);
+  if (!_holder.is_null()) {  // NULL class_loader
+    return _holder.resolve();
   } else {
     return NULL;
   }
 }
 
 // Unloading support
-oop ClassLoaderData::keep_alive_object() const {
-  assert_locked_or_safepoint(_metaspace_lock);
-  assert(!keep_alive(), "Don't use with CLDs that are artificially kept alive");
-  return is_anonymous() ? _klasses->java_mirror() : class_loader();
-}
-
-bool ClassLoaderData::is_alive(BoolObjectClosure* is_alive_closure) const {
-  bool alive = keep_alive() // null class loader and incomplete anonymous klasses.
-      || is_alive_closure->do_object_b(keep_alive_object());
+bool ClassLoaderData::is_alive() const {
+  bool alive = keep_alive()         // null class loader and incomplete anonymous klasses.
+      || (_holder.peek() != NULL);  // not cleaned by weak reference processing
 
   return alive;
 }
@@ -668,6 +664,9 @@
   ClassLoaderDataGraph::dec_array_classes(cl.array_class_released());
   ClassLoaderDataGraph::dec_instance_classes(cl.instance_class_released());
 
+  // Release the WeakHandle
+  _holder.release();
+
   // Release C heap allocated hashtable for all the packages.
   if (_packages != NULL) {
     // Destroy the table itself
@@ -969,7 +968,6 @@
 
   ClassLoaderData* cld = new ClassLoaderData(loader, is_anonymous);
 
-
   if (!is_anonymous) {
     // First, Atomically set it
     ClassLoaderData* old = java_lang_ClassLoader::cmpxchg_loader_data(cld, loader(), NULL);
@@ -1244,6 +1242,8 @@
   ClassLoaderData* data = _head;
   ClassLoaderData* prev = NULL;
   bool seen_dead_loader = false;
+  uint loaders_processed = 0;
+  uint loaders_removed = 0;
 
   // Mark metadata seen on the stack only so we can delete unneeded entries.
   // Only walk all metadata, including the expensive code cache walk, for Full GC
@@ -1260,7 +1260,7 @@
 
   data = _head;
   while (data != NULL) {
-    if (data->is_alive(is_alive_closure)) {
+    if (data->is_alive()) {
       // clean metaspace
       if (walk_all_metadata) {
         data->classes_do(InstanceKlass::purge_previous_versions);
@@ -1268,9 +1268,11 @@
       data->free_deallocate_list();
       prev = data;
       data = data->next();
+      loaders_processed++;
       continue;
     }
     seen_dead_loader = true;
+    loaders_removed++;
     ClassLoaderData* dead = data;
     dead->unload();
     data = data->next();
@@ -1313,6 +1315,8 @@
     post_class_unload_events();
   }
 
+  log_debug(class, loader, data)("do_unloading: loaders processed %u, loaders removed %u", loaders_processed, loaders_removed);
+
   return seen_dead_loader;
 }
 
--- a/src/hotspot/share/classfile/classLoaderData.hpp	Tue Apr 10 08:15:40 2018 -0400
+++ b/src/hotspot/share/classfile/classLoaderData.hpp	Tue Apr 10 10:06:42 2018 -0400
@@ -30,6 +30,7 @@
 #include "memory/metaspace.hpp"
 #include "memory/metaspaceCounters.hpp"
 #include "oops/oopHandle.hpp"
+#include "oops/weakHandle.hpp"
 #include "runtime/mutex.hpp"
 #include "trace/traceMacros.hpp"
 #include "utilities/growableArray.hpp"
@@ -113,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, bool clean_previous_versions);
+  static bool do_unloading(BoolObjectClosure* is_alive_closure, bool clean_previous_versions);
 
   // dictionary do
   // Iterate over all klasses in dictionary, but
@@ -219,8 +220,9 @@
 
   static ClassLoaderData * _the_null_class_loader_data;
 
-  oop _class_loader;          // oop used to uniquely identify a class loader
-                              // class loader or a canonical class path
+  WeakHandle<vm_class_loader_data> _holder; // The oop that determines lifetime of this class loader
+  oop _class_loader;          // The instance of java/lang/ClassLoader associated with
+                              // this ClassLoaderData
 
   ClassLoaderMetaspace * volatile _metaspace;  // Meta-space where meta-data defined by the
                                     // classes in the class loader are allocated.
@@ -286,7 +288,8 @@
 
   void unload();
   bool keep_alive() const       { return _keep_alive > 0; }
-  oop  holder_phantom();
+
+  oop holder_phantom() const;
   void classes_do(void f(Klass*));
   void loaded_classes_do(KlassClosure* klass_closure);
   void classes_do(void f(InstanceKlass*));
@@ -308,7 +311,7 @@
   bool claimed() const { return _claimed == 1; }
   bool claim();
 
-  bool is_alive(BoolObjectClosure* is_alive_closure) const;
+  bool is_alive() const;
 
   // Accessors
   ClassLoaderMetaspace* metaspace_or_null() const { return _metaspace; }
@@ -348,7 +351,7 @@
   // method will allocate a Metaspace if needed.
   ClassLoaderMetaspace* metaspace_non_null();
 
-  oop class_loader() const      { return _class_loader; }
+  oop class_loader() const { return _class_loader; }
 
   // The object the GC is using to keep this ClassLoaderData alive.
   oop keep_alive_object() const;
@@ -364,6 +367,8 @@
   void inc_keep_alive();
   void dec_keep_alive();
 
+  void initialize_holder(Handle holder);
+
   inline unsigned int identity_hash() const { return (unsigned int)(((intptr_t)this) >> 3); }
 
   void oops_do(OopClosure* f, bool must_claim, bool clear_modified_oops = false);
--- a/src/hotspot/share/classfile/systemDictionary.cpp	Tue Apr 10 08:15:40 2018 -0400
+++ b/src/hotspot/share/classfile/systemDictionary.cpp	Tue Apr 10 10:06:42 2018 -0400
@@ -44,6 +44,7 @@
 #include "code/codeCache.hpp"
 #include "compiler/compileBroker.hpp"
 #include "gc/shared/gcTraceTime.inline.hpp"
+#include "gc/shared/oopStorage.inline.hpp"
 #include "interpreter/bytecodeStream.hpp"
 #include "interpreter/interpreter.hpp"
 #include "logging/log.hpp"
@@ -117,6 +118,8 @@
 
 const int defaultProtectionDomainCacheSize = 1009;
 
+OopStorage* SystemDictionary::_vm_weak_oop_storage = NULL;
+
 
 // ----------------------------------------------------------------------------
 // Java-level SystemLoader and PlatformLoader
@@ -1012,7 +1015,9 @@
                                                       CHECK_NULL);
 
   if (host_klass != NULL && k != NULL) {
-    // If it's anonymous, initialize it now, since nobody else will.
+    // Anonymous classes must update ClassLoaderData holder (was host_klass loader)
+    // so that they can be unloaded when the mirror is no longer referenced.
+    k->class_loader_data()->initialize_holder(Handle(THREAD, k->java_mirror()));
 
     {
       MutexLocker mu_r(Compile_lock, THREAD);
@@ -1032,6 +1037,8 @@
     if (cp_patches != NULL) {
       k->constants()->patch_resolved_references(cp_patches);
     }
+
+    // If it's anonymous, initialize it now, since nobody else will.
     k->eager_initialize(CHECK_NULL);
 
     // notify jvmti
@@ -1848,6 +1855,10 @@
                                     GCTimer* gc_timer,
                                     bool do_cleaning) {
 
+  {
+    GCTraceTime(Debug, gc, phases) t("SystemDictionary WeakHandle cleaning", gc_timer);
+    vm_weak_oop_storage()->weak_oops_do(is_alive, &do_nothing_cl);
+  }
 
   bool unloading_occurred;
   {
@@ -1896,9 +1907,11 @@
     // 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);
    }
   }
 
@@ -1924,6 +1937,8 @@
   invoke_method_table()->oops_do(f);
 
   ResolvedMethodTable::oops_do(f);
+
+  vm_weak_oop_storage()->oops_do(f);
 }
 
 // CDS: scan and relocate all classes in the system dictionary.
@@ -3105,3 +3120,15 @@
   return (loader_data->class_loader() == NULL ? "<bootloader>" :
           SystemDictionary::loader_name(loader_data->class_loader()));
 }
+
+void SystemDictionary::initialize_oop_storage() {
+  _vm_weak_oop_storage =
+    new OopStorage("VM Weak Oop Handles",
+                   VMWeakAlloc_lock,
+                   VMWeakActive_lock);
+}
+
+OopStorage* SystemDictionary::vm_weak_oop_storage() {
+  assert(_vm_weak_oop_storage != NULL, "Uninitialized");
+  return _vm_weak_oop_storage;
+}
--- a/src/hotspot/share/classfile/systemDictionary.hpp	Tue Apr 10 08:15:40 2018 -0400
+++ b/src/hotspot/share/classfile/systemDictionary.hpp	Tue Apr 10 10:06:42 2018 -0400
@@ -84,6 +84,7 @@
 class ProtectionDomainCacheTable;
 class ProtectionDomainCacheEntry;
 class GCTimer;
+class OopStorage;
 
 // Certain classes are preloaded, such as java.lang.Object and java.lang.String.
 // They are all "well-known", in the sense that no class loader is allowed
@@ -637,6 +638,9 @@
   // ProtectionDomain cache
   static ProtectionDomainCacheTable*   _pd_cache_table;
 
+  // VM weak OopStorage object.
+  static OopStorage*             _vm_weak_oop_storage;
+
 protected:
   static void validate_protection_domain(InstanceKlass* klass,
                                          Handle class_loader,
@@ -689,6 +693,9 @@
     return !m->is_public() && m->method_holder() == SystemDictionary::Object_klass();
   }
 
+  static void initialize_oop_storage();
+  static OopStorage* vm_weak_oop_storage();
+
 protected:
   static InstanceKlass* find_shared_class(Symbol* class_name);
 
--- a/src/hotspot/share/memory/universe.cpp	Tue Apr 10 08:15:40 2018 -0400
+++ b/src/hotspot/share/memory/universe.cpp	Tue Apr 10 10:06:42 2018 -0400
@@ -689,6 +689,8 @@
     return status;
   }
 
+  SystemDictionary::initialize_oop_storage();
+
   Metaspace::global_initialize();
 
   // Initialize performance counters for metaspaces
--- a/src/hotspot/share/oops/instanceKlass.cpp	Tue Apr 10 08:15:40 2018 -0400
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Tue Apr 10 10:06:42 2018 -0400
@@ -1901,7 +1901,7 @@
 }
 
 void InstanceKlass::clean_implementors_list(BoolObjectClosure* is_alive) {
-  assert(class_loader_data()->is_alive(is_alive), "this klass should be live");
+  assert(class_loader_data()->is_alive(), "this klass should be live");
   if (is_interface()) {
     if (ClassUnloading) {
       Klass* impl = implementor();
@@ -3407,14 +3407,8 @@
   }
 }
 
-oop InstanceKlass::klass_holder_phantom() {
-  oop* addr;
-  if (is_anonymous()) {
-    addr = _java_mirror.ptr_raw();
-  } else {
-    addr = &class_loader_data()->_class_loader;
-  }
-  return RootAccess<IN_CONCURRENT_ROOT | ON_PHANTOM_OOP_REF>::oop_load(addr);
+oop InstanceKlass::holder_phantom() const {
+  return class_loader_data()->holder_phantom();
 }
 
 #ifdef ASSERT
--- a/src/hotspot/share/oops/instanceKlass.hpp	Tue Apr 10 08:15:40 2018 -0400
+++ b/src/hotspot/share/oops/instanceKlass.hpp	Tue Apr 10 10:06:42 2018 -0400
@@ -646,10 +646,10 @@
     return is_anonymous() ? java_mirror() : class_loader();
   }
 
-  // Load the klass_holder as a phantom. This is useful when a weak Klass
+  // Load the klass's holder as a phantom. This is useful when a weak Klass
   // pointer has been "peeked" and then must be kept alive before it may
   // be used safely.
-  oop klass_holder_phantom();
+  oop holder_phantom() const;
 
   bool is_contended() const                {
     return (_misc_flags & _misc_is_contended) != 0;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/oops/weakHandle.cpp	Tue Apr 10 10:06:42 2018 -0400
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "gc/shared/oopStorage.hpp"
+#include "oops/access.inline.hpp"
+#include "oops/oop.hpp"
+#include "oops/weakHandle.inline.hpp"
+#include "utilities/debug.hpp"
+#include "utilities/ostream.hpp"
+
+template <> OopStorage* WeakHandle<vm_class_loader_data>::get_storage() {
+  return SystemDictionary::vm_weak_oop_storage();
+}
+
+template <WeakHandleType T>
+WeakHandle<T> WeakHandle<T>::create(Handle obj) {
+  assert(obj() != NULL, "no need to create weak null oop");
+  oop* oop_addr = get_storage()->allocate();
+  if (oop_addr == NULL) {
+    vm_exit_out_of_memory(sizeof(oop*), OOM_MALLOC_ERROR, "Unable to create new weak oop handle in OopStorage");
+  }
+  // Create WeakHandle with address returned and store oop into it.
+  RootAccess<ON_PHANTOM_OOP_REF>::oop_store(oop_addr, obj());
+  return WeakHandle(oop_addr);
+}
+
+template <WeakHandleType T>
+void WeakHandle<T>::release() const {
+  // Only release if the pointer to the object has been created.
+  if (_obj != NULL) {
+    // Clear the WeakHandle.  For class loader data race, the handle may not have
+    // been previously cleared by GC.
+    RootAccess<ON_PHANTOM_OOP_REF>::oop_store(_obj, (oop)NULL);
+    get_storage()->release(_obj);
+  }
+}
+
+template <WeakHandleType T>
+void WeakHandle<T>::print() const { print_on(tty); }
+
+template <WeakHandleType T>
+void WeakHandle<T>::print_on(outputStream* st) const {
+  st->print("WeakHandle: " PTR_FORMAT, p2i(peek()));
+}
+
+// Provide instantiation.
+template class WeakHandle<vm_class_loader_data>;
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/oops/weakHandle.hpp	Tue Apr 10 10:06:42 2018 -0400
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_OOPS_WEAKHANDLE_HPP
+#define SHARE_VM_OOPS_WEAKHANDLE_HPP
+
+#include "oops/oop.hpp"
+#include "runtime/handles.hpp"
+
+class outputStream;
+class OopStorage;
+
+// A WeakHandle is a pointer to an oop that is stored in an OopStorage that is
+// processed weakly by GC.  The runtime structures that point to the oop must
+// either peek or resolve the oop, the latter will keep the oop alive for
+// the GC cycle.  The runtime structures that reference the oop must test
+// if the value is NULL.  If it is NULL, it has been cleaned out by GC.
+// This is the vm version of jweak but has different GC lifetimes and policies,
+// depending on the type.
+
+enum WeakHandleType { vm_class_loader_data, vm_string };
+
+template <WeakHandleType T>
+class WeakHandle {
+ public:
+
+ private:
+  oop* _obj;
+
+  WeakHandle(oop* w) : _obj(w) {}
+  static OopStorage* get_storage();
+ public:
+  WeakHandle() : _obj(NULL) {} // needed for init
+
+  static WeakHandle create(Handle obj);
+  inline oop resolve() const;
+  inline oop peek() const;
+  void release() const;
+  bool is_null() const { return _obj == NULL; }
+
+  void print() const;
+  void print_on(outputStream* st) const;
+};
+
+#endif // SHARE_VM_OOPS_WEAKHANDLE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/oops/weakHandle.inline.hpp	Tue Apr 10 10:06:42 2018 -0400
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 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
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef SHARE_VM_OOPS_WEAKHANDLE_INLINE_HPP
+#define SHARE_VM_OOPS_WEAKHANDLE_INLINE_HPP
+
+#include "oops/weakHandle.hpp"
+#include "oops/access.inline.hpp"
+
+template <WeakHandleType T>
+oop WeakHandle<T>::resolve() const {
+  assert(!is_null(), "Must be created");
+  return RootAccess<ON_PHANTOM_OOP_REF>::oop_load(_obj);
+}
+
+template <WeakHandleType T>
+oop WeakHandle<T>::peek() const {
+  assert(!is_null(), "Must be created");
+  return RootAccess<ON_PHANTOM_OOP_REF | AS_NO_KEEPALIVE>::oop_load(_obj);
+}
+
+#endif // SHARE_VM_OOPS_WEAKHANDLE_INLINE_HPP
--- a/src/hotspot/share/runtime/mutexLocker.cpp	Tue Apr 10 08:15:40 2018 -0400
+++ b/src/hotspot/share/runtime/mutexLocker.cpp	Tue Apr 10 10:06:42 2018 -0400
@@ -48,6 +48,8 @@
 Mutex*   JNIWeakAlloc_lock            = NULL;
 Mutex*   JNIWeakActive_lock           = NULL;
 Mutex*   JNIHandleBlockFreeList_lock  = NULL;
+Mutex*   VMWeakAlloc_lock             = NULL;
+Mutex*   VMWeakActive_lock            = NULL;
 Mutex*   ResolvedMethodTable_lock     = NULL;
 Mutex*   JmethodIdCreation_lock       = NULL;
 Mutex*   JfieldIdCreation_lock        = NULL;
@@ -260,6 +262,8 @@
   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/runtime/mutexLocker.hpp	Tue Apr 10 08:15:40 2018 -0400
+++ b/src/hotspot/share/runtime/mutexLocker.hpp	Tue Apr 10 10:06:42 2018 -0400
@@ -41,6 +41,8 @@
 extern Mutex*   JNIWeakAlloc_lock;               // JNI weak storage allocate list lock
 extern Mutex*   JNIWeakActive_lock;              // JNI weak storage active list lock
 extern Mutex*   JNIHandleBlockFreeList_lock;     // a lock on the JNI handle block free list
+extern Mutex*   VMWeakAlloc_lock;                // VM Weak Handles storage allocate list lock
+extern Mutex*   VMWeakActive_lock;               // VM Weak Handles storage active list lock
 extern Mutex*   ResolvedMethodTable_lock;        // a lock on the ResolvedMethodTable updates
 extern Mutex*   JmethodIdCreation_lock;          // a lock on creating JNI method identifiers
 extern Mutex*   JfieldIdCreation_lock;           // a lock on creating JNI static field identifiers