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
--- 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