--- old/src/hotspot/share/classfile/classLoaderData.cpp 2018-03-26 13:40:52.933910302 -0400 +++ new/src/hotspot/share/classfile/classLoaderData.cpp 2018-03-26 13:40:52.550874915 -0400 @@ -56,6 +56,7 @@ #include "classfile/packageEntry.hpp" #include "classfile/systemDictionary.hpp" #include "code/codeCache.hpp" +#include "gc/shared/oopStorage.hpp" #include "logging/log.hpp" #include "logging/logStream.hpp" #include "memory/allocation.inline.hpp" @@ -510,6 +511,12 @@ } +void ClassLoaderData::update_holder(Handle holder) { + assert(holder() != NULL, "should be called with non-NULL loader"); + assert(_holder.peek() == NULL, "never replace holders"); + _holder = WeakHandle::create(holder); +} + // 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) { @@ -617,24 +624,14 @@ // 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::oop_load(o); - } else { - return NULL; - } + return _holder.resolve(); } // 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.is_null() + || (_holder.peek() != NULL); // not cleaned by weak reference processing return alive; } @@ -668,6 +665,11 @@ ClassLoaderDataGraph::dec_array_classes(cl.array_class_released()); ClassLoaderDataGraph::dec_instance_classes(cl.instance_class_released()); + // Release the WeakHandle, if already set + if (!_holder.is_null()) { + _holder.release(); + } + // Release C heap allocated hashtable for all the packages. if (_packages != NULL) { // Destroy the table itself @@ -969,7 +971,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); @@ -978,8 +979,13 @@ // Returns the data. return old; } + + // Update the holder if we've won the race + // The holder of this class is the class_loader generically. + cld->update_holder(loader); } + // We won the race, and therefore the task of adding the data to the list of // class loader data ClassLoaderData** list_head = &_head; @@ -1244,6 +1250,8 @@ ClassLoaderData* data = _head; ClassLoaderData* prev = NULL; bool seen_dead_loader = false; + int loaders_processed = 0; + int 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 +1268,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 +1276,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 +1323,8 @@ post_class_unload_events(); } + log_debug(class, loader, data)("do_unloading: loaders processed %d, loaders removed %d", loaders_processed, loaders_removed); + return seen_dead_loader; } --- old/src/hotspot/share/classfile/classLoaderData.hpp 2018-03-26 13:40:53.440957145 -0400 +++ new/src/hotspot/share/classfile/classLoaderData.hpp 2018-03-26 13:40:53.057921758 -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,6 +220,7 @@ static ClassLoaderData * _the_null_class_loader_data; + WeakHandle _holder; // The oop that determines lifetime of this class loader oop _class_loader; // oop used to uniquely identify a class loader // class loader or a canonical class path @@ -308,7 +310,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; } @@ -364,6 +366,8 @@ void inc_keep_alive(); void dec_keep_alive(); + void update_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); --- old/src/hotspot/share/classfile/systemDictionary.cpp 2018-03-26 13:40:53.922001585 -0400 +++ new/src/hotspot/share/classfile/systemDictionary.cpp 2018-03-26 13:40:53.535965922 -0400 @@ -1012,7 +1012,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()->update_holder(Handle(THREAD, k->java_mirror())); { MutexLocker mu_r(Compile_lock, THREAD); @@ -1032,6 +1034,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 --- old/src/hotspot/share/gc/shared/weakProcessor.cpp 2018-03-26 13:40:54.458051107 -0400 +++ new/src/hotspot/share/gc/shared/weakProcessor.cpp 2018-03-26 13:40:54.078015999 -0400 @@ -23,7 +23,9 @@ */ #include "precompiled.hpp" +#include "gc/shared/oopStorage.inline.hpp" #include "gc/shared/weakProcessor.hpp" +#include "memory/universe.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/jniHandles.hpp" #include "trace/tracing.hpp" @@ -32,6 +34,7 @@ void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) { JNIHandles::weak_oops_do(is_alive, keep_alive); JvmtiExport::weak_oops_do(is_alive, keep_alive); + Universe::vm_weak_oop_storage()->weak_oops_do(is_alive, keep_alive); TRACE_WEAK_OOPS_DO(is_alive, keep_alive); } --- old/src/hotspot/share/memory/universe.cpp 2018-03-26 13:40:54.921093885 -0400 +++ new/src/hotspot/share/memory/universe.cpp 2018-03-26 13:40:54.540058684 -0400 @@ -38,6 +38,7 @@ #include "gc/shared/gcLocker.hpp" #include "gc/shared/generation.hpp" #include "gc/shared/gcTraceTime.inline.hpp" +#include "gc/shared/oopStorage.hpp" #include "gc/shared/space.hpp" #include "interpreter/interpreter.hpp" #include "logging/log.hpp" @@ -97,6 +98,7 @@ Klass* Universe::_doubleArrayKlassObj = NULL; Klass* Universe::_typeArrayKlassObjs[T_VOID+1] = { NULL /*, NULL...*/ }; Klass* Universe::_objectArrayKlassObj = NULL; +OopStorage* Universe::_vm_weak_oop_storage = NULL; oop Universe::_int_mirror = NULL; oop Universe::_float_mirror = NULL; oop Universe::_double_mirror = NULL; @@ -688,6 +690,8 @@ return status; } + Universe::initialize_oop_storage(); + Metaspace::global_initialize(); // Initialize performance counters for metaspaces @@ -1343,6 +1347,17 @@ return m; } +void Universe::initialize_oop_storage() { + _vm_weak_oop_storage = + new OopStorage("VM Weak Oop Handles", + VMWeakAlloc_lock, + VMWeakActive_lock); +} + +OopStorage* Universe::vm_weak_oop_storage() { + assert(_vm_weak_oop_storage != NULL, "Uninitialized"); + return _vm_weak_oop_storage; +} #ifdef ASSERT // Release dummy object(s) at bottom of heap --- old/src/hotspot/share/memory/universe.hpp 2018-03-26 13:40:55.418139804 -0400 +++ new/src/hotspot/share/memory/universe.hpp 2018-03-26 13:40:55.036104510 -0400 @@ -39,6 +39,7 @@ class CollectedHeap; class DeferredObjAllocEvent; +class OopStorage; // A helper class for caching a Method* when the user of the cache @@ -124,6 +125,9 @@ static Klass* _objectArrayKlassObj; + // VM weak OopStorage object. + static OopStorage* _vm_weak_oop_storage; + // Known objects in the VM // Primitive objects @@ -229,6 +233,8 @@ static void reinitialize_itables(TRAPS); static void compute_base_vtable_size(); // compute vtable size of class Object + static void initialize_oop_storage(); + static void genesis(TRAPS); // Create the initial world // Mirrors for primitive classes (created eagerly) @@ -288,6 +294,8 @@ return _typeArrayKlassObjs[t]; } + static OopStorage* vm_weak_oop_storage(); + // Known objects in the VM static oop int_mirror() { return check_mirror(_int_mirror); } static oop float_mirror() { return check_mirror(_float_mirror); } --- old/src/hotspot/share/oops/instanceKlass.cpp 2018-03-26 13:40:55.897184060 -0400 +++ new/src/hotspot/share/oops/instanceKlass.cpp 2018-03-26 13:40:55.514148674 -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(); --- old/src/hotspot/share/runtime/mutexLocker.cpp 2018-03-26 13:40:56.444234598 -0400 +++ new/src/hotspot/share/runtime/mutexLocker.cpp 2018-03-26 13:40:56.063199397 -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; @@ -261,6 +263,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); --- old/src/hotspot/share/runtime/mutexLocker.hpp 2018-03-26 13:40:56.914278023 -0400 +++ new/src/hotspot/share/runtime/mutexLocker.hpp 2018-03-26 13:40:56.534242914 -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 --- /dev/null 2018-03-24 19:23:43.035000297 -0400 +++ new/src/hotspot/share/oops/weakHandle.cpp 2018-03-26 13:40:57.002286153 -0400 @@ -0,0 +1,67 @@ +/* + * 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 "gc/shared/oopStorage.hpp" +#include "memory/universe.hpp" +#include "oops/access.inline.hpp" +#include "oops/oop.hpp" +#include "oops/weakHandle.hpp" +#include "utilities/debug.hpp" +#include "utilities/ostream.hpp" + +WeakHandle WeakHandle::create(Handle obj) { + assert(obj() != NULL, "no need to create weak null oop"); + oop* oop_addr = Universe::vm_weak_oop_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::oop_store(oop_addr, obj()); + return WeakHandle(oop_addr); +} + +oop WeakHandle::resolve() const { + if (_obj == NULL) { + return NULL; // for initialization + } + return RootAccess::oop_load(_obj); +} + +oop WeakHandle::peek() const { + if (_obj == NULL) { + return NULL; // needed? + } + return RootAccess::oop_load(_obj); +} + +void WeakHandle::release() const { + Universe::vm_weak_oop_storage()->release(_obj); +} + +void WeakHandle::print() const { print_on(tty); } + +void WeakHandle::print_on(outputStream* st) const { + st->print("WeakHandle: " PTR_FORMAT, p2i(peek())); +} --- /dev/null 2018-03-24 19:23:43.035000297 -0400 +++ new/src/hotspot/share/oops/weakHandle.hpp 2018-03-26 13:40:57.633344453 -0400 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017, 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 WeakHandle { +private: + oop* _obj; + + WeakHandle(oop* w) : _obj(w) {} +public: + WeakHandle() : _obj(NULL) {} // needed for init + + static WeakHandle create(Handle obj); + oop resolve() const; + 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