--- old/make/symbols/symbols-unix 2016-07-31 21:09:30.429181137 -0400 +++ new/make/symbols/symbols-unix 2016-07-31 21:09:30.329180641 -0400 @@ -25,6 +25,7 @@ JVM_ArrayCopy JVM_AssertionStatusDirectives JVM_CallStackWalk +JVM_CheckReferencePendingList JVM_ClassDepth JVM_ClassLoaderDepth JVM_Clone @@ -67,6 +68,7 @@ JVM_FreeMemory JVM_GC JVM_GetAllThreads +JVM_GetAndClearReferencePendingList JVM_GetArrayElement JVM_GetArrayLength JVM_GetCallerClass --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java 2016-07-31 21:09:30.985183894 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java 2016-07-31 21:09:30.885183398 -0400 @@ -129,8 +129,6 @@ virtualConstructor.addMapping("CompilerThread", CompilerThread.class); virtualConstructor.addMapping("CodeCacheSweeperThread", CodeCacheSweeperThread.class); } - // for now, use JavaThread itself. fix it later with appropriate class if needed - virtualConstructor.addMapping("ReferencePendingListLockerThread", JavaThread.class); virtualConstructor.addMapping("JvmtiAgentThread", JvmtiAgentThread.class); virtualConstructor.addMapping("ServiceThread", ServiceThread.class); } @@ -172,7 +170,7 @@ return thread; } catch (Exception e) { throw new RuntimeException("Unable to deduce type of thread from address " + threadAddr + - " (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread, ReferencePendingListLockerThread, or CodeCacheSweeperThread)", e); + " (expected type JavaThread, CompilerThread, ServiceThread, JvmtiAgentThread or CodeCacheSweeperThread)", e); } } --- old/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js 2016-07-31 21:09:31.545186671 -0400 +++ new/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/soql/sa.js 2016-07-31 21:09:31.445186175 -0400 @@ -837,7 +837,6 @@ vmType2Class["JavaThread"] = sapkg.runtime.JavaThread; vmType2Class["CompilerThread"] = sapkg.runtime.CompilerThread; vmType2Class["CodeCacheSweeperThread"] = sapkg.runtime.CodeCacheSweeperThread; -vmType2Class["ReferencePendingListLockerThread"] = sapkg.runtime.JavaThread; vmType2Class["DebuggerThread"] = sapkg.runtime.DebuggerThread; // gc --- old/src/share/vm/ci/ciReplay.cpp 2016-07-31 21:09:32.117189508 -0400 +++ new/src/share/vm/ci/ciReplay.cpp 2016-07-31 21:09:32.013188992 -0400 @@ -29,7 +29,6 @@ #include "ci/ciKlass.hpp" #include "ci/ciUtilities.hpp" #include "compiler/compileBroker.hpp" -#include "gc/shared/referencePendingListLocker.hpp" #include "memory/allocation.inline.hpp" #include "memory/oopFactory.hpp" #include "memory/resourceArea.hpp" @@ -577,9 +576,7 @@ Method* method = parse_method(CHECK); if (had_error()) return; /* just copied from Method, to build interpret data*/ - if (ReferencePendingListLocker::is_locked_by_self()) { - return; - } + // To be properly initialized, some profiling in the MDO needs the // method to be rewritten (number of arguments at a call for // instance) --- old/src/share/vm/classfile/javaClasses.cpp 2016-07-31 21:09:32.689192344 -0400 +++ new/src/share/vm/classfile/javaClasses.cpp 2016-07-31 21:09:32.585191828 -0400 @@ -3015,41 +3015,6 @@ } } - -// Support for java_lang_ref_Reference -HeapWord *java_lang_ref_Reference::pending_list_lock_addr() { - InstanceKlass* ik = SystemDictionary::Reference_klass(); - address addr = ik->static_field_addr(static_lock_offset); - return (HeapWord*) addr; -} - -oop java_lang_ref_Reference::pending_list_lock() { - InstanceKlass* ik = SystemDictionary::Reference_klass(); - address addr = ik->static_field_addr(static_lock_offset); - if (UseCompressedOops) { - return oopDesc::load_decode_heap_oop((narrowOop *)addr); - } else { - return oopDesc::load_decode_heap_oop((oop*)addr); - } -} - -HeapWord *java_lang_ref_Reference::pending_list_addr() { - InstanceKlass* ik = SystemDictionary::Reference_klass(); - address addr = ik->static_field_addr(static_pending_offset); - // XXX This might not be HeapWord aligned, almost rather be char *. - return (HeapWord*)addr; -} - -oop java_lang_ref_Reference::pending_list() { - char *addr = (char *)pending_list_addr(); - if (UseCompressedOops) { - return oopDesc::load_decode_heap_oop((narrowOop *)addr); - } else { - return oopDesc::load_decode_heap_oop((oop*)addr); - } -} - - // Support for java_lang_ref_SoftReference jlong java_lang_ref_SoftReference::timestamp(oop ref) { @@ -3625,8 +3590,6 @@ int java_lang_ref_Reference::queue_offset; int java_lang_ref_Reference::next_offset; int java_lang_ref_Reference::discovered_offset; -int java_lang_ref_Reference::static_lock_offset; -int java_lang_ref_Reference::static_pending_offset; int java_lang_ref_Reference::number_of_fake_oop_fields; int java_lang_ref_SoftReference::timestamp_offset; int java_lang_ref_SoftReference::static_clock_offset; @@ -3781,8 +3744,6 @@ java_lang_ref_Reference::queue_offset = java_lang_ref_Reference::hc_queue_offset * x + header; java_lang_ref_Reference::next_offset = java_lang_ref_Reference::hc_next_offset * x + header; java_lang_ref_Reference::discovered_offset = java_lang_ref_Reference::hc_discovered_offset * x + header; - java_lang_ref_Reference::static_lock_offset = java_lang_ref_Reference::hc_static_lock_offset * x; - java_lang_ref_Reference::static_pending_offset = java_lang_ref_Reference::hc_static_pending_offset * x; // Artificial fields for java_lang_ref_Reference // The first field is for the discovered field added in 1.4 java_lang_ref_Reference::number_of_fake_oop_fields = 1; @@ -4015,8 +3976,6 @@ CHECK_OFFSET("java/lang/ref/Reference", java_lang_ref_Reference, next, "Ljava/lang/ref/Reference;"); // Fake field //CHECK_OFFSET("java/lang/ref/Reference", java_lang_ref_Reference, discovered, "Ljava/lang/ref/Reference;"); - CHECK_STATIC_OFFSET("java/lang/ref/Reference", java_lang_ref_Reference, lock, "Ljava/lang/ref/Reference$Lock;"); - CHECK_STATIC_OFFSET("java/lang/ref/Reference", java_lang_ref_Reference, pending, "Ljava/lang/ref/Reference;"); // java.lang.ref.SoftReference --- old/src/share/vm/classfile/javaClasses.hpp 2016-07-31 21:09:33.297195359 -0400 +++ new/src/share/vm/classfile/javaClasses.hpp 2016-07-31 21:09:33.197194863 -0400 @@ -886,17 +886,11 @@ hc_next_offset = 2, hc_discovered_offset = 3 // Is not last, see SoftRefs. }; - enum { - hc_static_lock_offset = 0, - hc_static_pending_offset = 1 - }; static int referent_offset; static int queue_offset; static int next_offset; static int discovered_offset; - static int static_lock_offset; - static int static_pending_offset; static int number_of_fake_oop_fields; // Accessors @@ -912,13 +906,6 @@ static inline void set_discovered(oop ref, oop value); static inline void set_discovered_raw(oop ref, oop value); static inline HeapWord* discovered_addr(oop ref); - - // Accessors for statics - static oop pending_list_lock(); - static oop pending_list(); - - static HeapWord* pending_list_lock_addr(); - static HeapWord* pending_list_addr(); }; --- old/src/share/vm/compiler/compileBroker.cpp 2016-07-31 21:09:33.869198195 -0400 +++ new/src/share/vm/compiler/compileBroker.cpp 2016-07-31 21:09:33.765197680 -0400 @@ -32,7 +32,6 @@ #include "compiler/compileLog.hpp" #include "compiler/compilerOracle.hpp" #include "compiler/directivesParser.hpp" -#include "gc/shared/referencePendingListLocker.hpp" #include "interpreter/linkResolver.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" @@ -893,15 +892,6 @@ return; } - // If the requesting thread is holding the pending list lock - // then we just return. We can't risk blocking while holding - // the pending list lock or a 3-way deadlock may occur - // between the reference handler thread, a GC (instigated - // by a compiler thread), and compiled method registration. - if (ReferencePendingListLocker::is_locked_by_self()) { - return; - } - if (TieredCompilation) { // Tiered policy requires MethodCounters to exist before adding a method to // the queue. Create if we don't have them yet. --- old/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp 2016-07-31 21:09:34.469201171 -0400 +++ new/src/share/vm/gc/cms/concurrentMarkSweepThread.cpp 2016-07-31 21:09:34.365200655 -0400 @@ -28,7 +28,6 @@ #include "gc/cms/concurrentMarkSweepThread.hpp" #include "gc/shared/gcId.hpp" #include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/referencePendingListLocker.hpp" #include "oops/oop.inline.hpp" #include "runtime/init.hpp" #include "runtime/interfaceSupport.hpp" @@ -77,23 +76,6 @@ log_warning(gc)("Couldn't bind CMS thread to processor " UINTX_FORMAT, CPUForCMSThread); } - { - MutexLockerEx x(CGC_lock, true); - set_CMS_flag(CMS_cms_wants_token); - assert(is_init_completed() && Universe::is_fully_initialized(), "ConcurrentGCThread::run() should have waited for this."); - - // Wait until the surrogate locker thread that will do - // pending list locking on our behalf has been created. - // We cannot start the SLT thread ourselves since we need - // to be a JavaThread to do so. - CMSLoopCountWarn loopY("CMS::run", "waiting for SLT installation", 2); - while (!ReferencePendingListLocker::is_initialized() && !should_terminate()) { - CGC_lock->wait(true, 200); - loopY.tick(); - } - clear_CMS_flag(CMS_cms_wants_token); - } - while (!should_terminate()) { sleepBeforeNextCycle(); if (should_terminate()) break; --- old/src/share/vm/gc/cms/vmCMSOperations.cpp 2016-07-31 21:09:35.017203888 -0400 +++ new/src/share/vm/gc/cms/vmCMSOperations.cpp 2016-07-31 21:09:34.913203372 -0400 @@ -37,14 +37,6 @@ ////////////////////////////////////////////////////////// // Methods in abstract class VM_CMS_Operation ////////////////////////////////////////////////////////// -void VM_CMS_Operation::acquire_pending_list_lock() { - _pending_list_locker.lock(); -} - -void VM_CMS_Operation::release_and_notify_pending_list_lock() { - _pending_list_locker.unlock(); -} - void VM_CMS_Operation::verify_before_gc() { if (VerifyBeforeGC && GenCollectedHeap::heap()->total_collections() >= VerifyGCStartAt) { @@ -85,17 +77,10 @@ assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(), "Possible deadlock"); - if (needs_pending_list_lock()) { - acquire_pending_list_lock(); - } - // Get the Heap_lock after the pending_list_lock. Heap_lock->lock(); if (lost_race()) { assert(_prologue_succeeded == false, "Initialized in c'tor"); Heap_lock->unlock(); - if (needs_pending_list_lock()) { - release_and_notify_pending_list_lock(); - } } else { _prologue_succeeded = true; } @@ -108,11 +93,10 @@ assert(!ConcurrentMarkSweepThread::cms_thread_has_cms_token(), "Possible deadlock"); - // Release the Heap_lock first. - Heap_lock->unlock(); - if (needs_pending_list_lock()) { - release_and_notify_pending_list_lock(); + if (Universe::has_reference_pending_list()) { + Heap_lock->notify_all(); } + Heap_lock->unlock(); } ////////////////////////////////////////////////////////// @@ -230,9 +214,11 @@ Thread* thr = Thread::current(); assert(thr->is_Java_thread(), "just checking"); JavaThread* jt = (JavaThread*)thr; - // Release the Heap_lock first. + + if (Universe::has_reference_pending_list()) { + Heap_lock->notify_all(); + } Heap_lock->unlock(); - release_and_notify_pending_list_lock(); // It is fine to test whether completed collections has // exceeded our request count without locking because --- old/src/share/vm/gc/cms/vmCMSOperations.hpp 2016-07-31 21:09:35.577206665 -0400 +++ new/src/share/vm/gc/cms/vmCMSOperations.hpp 2016-07-31 21:09:35.477206169 -0400 @@ -28,7 +28,6 @@ #include "gc/cms/concurrentMarkSweepGeneration.hpp" #include "gc/shared/gcCause.hpp" #include "gc/shared/gcId.hpp" -#include "gc/shared/referencePendingListLocker.hpp" #include "gc/shared/vmGCOperations.hpp" #include "runtime/vm_operations.hpp" @@ -52,9 +51,6 @@ class CMSCollector; class VM_CMS_Operation: public VM_Operation { - private: - ReferencePendingListLocker _pending_list_locker; - protected: CMSCollector* _collector; // associated collector bool _prologue_succeeded; // whether doit_prologue succeeded @@ -62,10 +58,6 @@ bool lost_race() const; - // java.lang.ref.Reference support - void acquire_pending_list_lock(); - void release_and_notify_pending_list_lock(); - public: VM_CMS_Operation(CMSCollector* collector): _collector(collector), --- old/src/share/vm/gc/g1/concurrentMarkThread.cpp 2016-07-31 21:09:36.133209422 -0400 +++ new/src/share/vm/gc/g1/concurrentMarkThread.cpp 2016-07-31 21:09:36.033208926 -0400 @@ -175,7 +175,7 @@ TimeHelper::counter_to_millis(mark_end - mark_start)); CMCheckpointRootsFinalClosure final_cl(_cm); - VM_CGC_Operation op(&final_cl, "Pause Remark", true /* needs_pll */); + VM_CGC_Operation op(&final_cl, "Pause Remark"); VMThread::execute(&op); } if (cm()->restart_for_overflow()) { @@ -199,7 +199,7 @@ delay_to_keep_mmu(g1_policy, false /* cleanup */); CMCleanUp cl_cl(_cm); - VM_CGC_Operation op(&cl_cl, "Pause Cleanup", false /* needs_pll */); + VM_CGC_Operation op(&cl_cl, "Pause Cleanup"); VMThread::execute(&op); } else { // We don't want to update the marking status if a GC pause --- old/src/share/vm/gc/g1/g1CollectedHeap.hpp 2016-07-31 21:09:36.689212179 -0400 +++ new/src/share/vm/gc/g1/g1CollectedHeap.hpp 2016-07-31 21:09:36.585211663 -0400 @@ -1273,12 +1273,6 @@ return true; } - // The reference pending list lock is acquired from from the - // ConcurrentMarkThread. - virtual bool needs_reference_pending_list_locker_thread() const { - return true; - } - inline bool is_in_young(const oop obj); virtual bool is_scavengable(const void* addr); --- old/src/share/vm/gc/g1/vm_operations_g1.cpp 2016-07-31 21:09:37.261215015 -0400 +++ new/src/share/vm/gc/g1/vm_operations_g1.cpp 2016-07-31 21:09:37.161214519 -0400 @@ -204,14 +204,6 @@ } } -void VM_CGC_Operation::acquire_pending_list_lock() { - _pending_list_locker.lock(); -} - -void VM_CGC_Operation::release_and_notify_pending_list_lock() { - _pending_list_locker.unlock(); -} - void VM_CGC_Operation::doit() { GCIdMark gc_id_mark(_gc_id); GCTraceCPUTime tcpu; @@ -222,20 +214,13 @@ } bool VM_CGC_Operation::doit_prologue() { - // Note the relative order of the locks must match that in - // VM_GC_Operation::doit_prologue() or deadlocks can occur - if (_needs_pending_list_lock) { - acquire_pending_list_lock(); - } Heap_lock->lock(); return true; } void VM_CGC_Operation::doit_epilogue() { - // Note the relative order of the unlocks must match that in - // VM_GC_Operation::doit_epilogue() - Heap_lock->unlock(); - if (_needs_pending_list_lock) { - release_and_notify_pending_list_lock(); + if (Universe::has_reference_pending_list()) { + Heap_lock->notify_all(); } + Heap_lock->unlock(); } --- old/src/share/vm/gc/g1/vm_operations_g1.hpp 2016-07-31 21:09:37.817217772 -0400 +++ new/src/share/vm/gc/g1/vm_operations_g1.hpp 2016-07-31 21:09:37.713217257 -0400 @@ -27,7 +27,6 @@ #include "gc/g1/g1AllocationContext.hpp" #include "gc/shared/gcId.hpp" -#include "gc/shared/referencePendingListLocker.hpp" #include "gc/shared/vmGCOperations.hpp" // VM_operations for the G1 collector. @@ -103,20 +102,13 @@ // Concurrent GC stop-the-world operations such as remark and cleanup; // consider sharing these with CMS's counterparts. class VM_CGC_Operation: public VM_Operation { - VoidClosure* _cl; - const char* _printGCMessage; - bool _needs_pending_list_lock; - ReferencePendingListLocker _pending_list_locker; - uint _gc_id; - -protected: - // java.lang.ref.Reference support - void acquire_pending_list_lock(); - void release_and_notify_pending_list_lock(); + VoidClosure* _cl; + const char* _printGCMessage; + uint _gc_id; public: - VM_CGC_Operation(VoidClosure* cl, const char *printGCMsg, bool needs_pending_list_lock) - : _cl(cl), _printGCMessage(printGCMsg), _needs_pending_list_lock(needs_pending_list_lock), _gc_id(GCId::current()) {} + VM_CGC_Operation(VoidClosure* cl, const char *printGCMsg) + : _cl(cl), _printGCMessage(printGCMsg), _gc_id(GCId::current()) {} virtual VMOp_Type type() const { return VMOp_CGC_Operation; } virtual void doit(); virtual bool doit_prologue(); --- old/src/share/vm/gc/shared/collectedHeap.hpp 2016-07-31 21:09:38.365220490 -0400 +++ new/src/share/vm/gc/shared/collectedHeap.hpp 2016-07-31 21:09:38.265219994 -0400 @@ -441,12 +441,6 @@ // remembered set. virtual void flush_deferred_store_barrier(JavaThread* thread); - // Should return true if the reference pending list lock is - // acquired from non-Java threads, such as a concurrent GC thread. - virtual bool needs_reference_pending_list_locker_thread() const { - return false; - } - // Perform a collection of the heap; intended for use in implementing // "System.gc". This probably implies as full a collection as the // "CollectedHeap" supports. --- old/src/share/vm/gc/shared/genCollectedHeap.hpp 2016-07-31 21:09:38.929223287 -0400 +++ new/src/share/vm/gc/shared/genCollectedHeap.hpp 2016-07-31 21:09:38.825222771 -0400 @@ -281,10 +281,6 @@ return UseConcMarkSweepGC; } - virtual bool needs_reference_pending_list_locker_thread() const { - return UseConcMarkSweepGC; - } - // We don't need barriers for stores to objects in the // young gen and, a fortiori, for initializing stores to // objects therein. This applies to DefNew+Tenured and ParNew+CMS --- old/src/share/vm/gc/shared/referenceProcessor.cpp 2016-07-31 21:09:39.497226103 -0400 +++ new/src/share/vm/gc/shared/referenceProcessor.cpp 2016-07-31 21:09:39.393225587 -0400 @@ -289,39 +289,16 @@ complete_gc->do_void(); } - -template -bool enqueue_discovered_ref_helper(ReferenceProcessor* ref, - AbstractRefProcTaskExecutor* task_executor) { - - // Remember old value of pending references list - T* pending_list_addr = (T*)java_lang_ref_Reference::pending_list_addr(); - T old_pending_list_value = *pending_list_addr; - +void ReferenceProcessor::enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor) { // Enqueue references that are not made active again, and // clear the decks for the next collection (cycle). - ref->enqueue_discovered_reflists((HeapWord*)pending_list_addr, task_executor); - // Do the post-barrier on pending_list_addr missed in - // enqueue_discovered_reflist. - oopDesc::bs()->write_ref_field(pending_list_addr, oopDesc::load_decode_heap_oop(pending_list_addr)); + enqueue_discovered_reflists(task_executor); // Stop treating discovered references specially. - ref->disable_discovery(); - - // Return true if new pending references were added - return old_pending_list_value != *pending_list_addr; -} - -bool ReferenceProcessor::enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor) { - if (UseCompressedOops) { - return enqueue_discovered_ref_helper(this, task_executor); - } else { - return enqueue_discovered_ref_helper(this, task_executor); - } + disable_discovery(); } -void ReferenceProcessor::enqueue_discovered_reflist(DiscoveredList& refs_list, - HeapWord* pending_list_addr) { +void ReferenceProcessor::enqueue_discovered_reflist(DiscoveredList& refs_list) { // Given a list of refs linked through the "discovered" field // (java.lang.ref.Reference.discovered), self-loop their "next" field // thus distinguishing them from active References, then @@ -354,10 +331,9 @@ oopDesc::bs()->write_ref_field(java_lang_ref_Reference::discovered_addr(obj), next_d); } else { // This is the last object. - // Swap refs_list into pending_list_addr and - // set obj's discovered to what we read from pending_list_addr. - oop old = oopDesc::atomic_exchange_oop(refs_list.head(), pending_list_addr); - // Need post-barrier on pending_list_addr. See enqueue_discovered_ref_helper() above. + // Swap refs_list into pending list and set obj's + // discovered to what we read from the pending list. + oop old = Universe::swap_reference_pending_list(refs_list.head()); java_lang_ref_Reference::set_discovered_raw(obj, old); // old may be NULL oopDesc::bs()->write_ref_field(java_lang_ref_Reference::discovered_addr(obj), old); } @@ -369,10 +345,8 @@ public: RefProcEnqueueTask(ReferenceProcessor& ref_processor, DiscoveredList discovered_refs[], - HeapWord* pending_list_addr, int n_queues) - : EnqueueTask(ref_processor, discovered_refs, - pending_list_addr, n_queues) + : EnqueueTask(ref_processor, discovered_refs, n_queues) { } virtual void work(unsigned int work_id) { @@ -387,8 +361,7 @@ for (int j = 0; j < ReferenceProcessor::number_of_subclasses_of_ref(); j++, index += _n_queues) { - _ref_processor.enqueue_discovered_reflist( - _refs_lists[index], _pending_list_addr); + _ref_processor.enqueue_discovered_reflist(_refs_lists[index]); _refs_lists[index].set_head(NULL); _refs_lists[index].set_length(0); } @@ -396,17 +369,15 @@ }; // Enqueue references that are not made active again -void ReferenceProcessor::enqueue_discovered_reflists(HeapWord* pending_list_addr, - AbstractRefProcTaskExecutor* task_executor) { +void ReferenceProcessor::enqueue_discovered_reflists(AbstractRefProcTaskExecutor* task_executor) { if (_processing_is_mt && task_executor != NULL) { // Parallel code - RefProcEnqueueTask tsk(*this, _discovered_refs, - pending_list_addr, _max_num_q); + RefProcEnqueueTask tsk(*this, _discovered_refs, _max_num_q); task_executor->execute(tsk); } else { // Serial code: call the parent class's implementation for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) { - enqueue_discovered_reflist(_discovered_refs[i], pending_list_addr); + enqueue_discovered_reflist(_discovered_refs[i]); _discovered_refs[i].set_head(NULL); _discovered_refs[i].set_length(0); } --- old/src/share/vm/gc/shared/referenceProcessor.hpp 2016-07-31 21:09:40.065228920 -0400 +++ new/src/share/vm/gc/shared/referenceProcessor.hpp 2016-07-31 21:09:39.965228424 -0400 @@ -290,7 +290,7 @@ VoidClosure* complete_gc); // Enqueue references with a certain reachability level - void enqueue_discovered_reflist(DiscoveredList& refs_list, HeapWord* pending_list_addr); + void enqueue_discovered_reflist(DiscoveredList& refs_list); // "Preclean" all the discovered reference lists // by removing references with strongly reachable referents. @@ -311,7 +311,7 @@ // occupying the i / _num_q slot. const char* list_name(uint i); - void enqueue_discovered_reflists(HeapWord* pending_list_addr, AbstractRefProcTaskExecutor* task_executor); + void enqueue_discovered_reflists(AbstractRefProcTaskExecutor* task_executor); protected: // "Preclean" the given discovered reference list @@ -424,7 +424,7 @@ GCTimer *gc_timer); // Enqueue references at end of GC (called by the garbage collector) - bool enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor = NULL); + void enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor = NULL); // If a discovery is in process that is being superceded, abandon it: all // the discovered lists will be empty, and all the objects on them will @@ -613,11 +613,9 @@ protected: EnqueueTask(ReferenceProcessor& ref_processor, DiscoveredList refs_lists[], - HeapWord* pending_list_addr, int n_queues) : _ref_processor(ref_processor), _refs_lists(refs_lists), - _pending_list_addr(pending_list_addr), _n_queues(n_queues) { } @@ -627,7 +625,6 @@ protected: ReferenceProcessor& _ref_processor; DiscoveredList* _refs_lists; - HeapWord* _pending_list_addr; int _n_queues; }; --- old/src/share/vm/gc/shared/vmGCOperations.cpp 2016-07-31 21:09:40.637231756 -0400 +++ new/src/share/vm/gc/shared/vmGCOperations.cpp 2016-07-31 21:09:40.533231240 -0400 @@ -62,14 +62,6 @@ HS_DTRACE_WORKAROUND_TAIL_CALL_BUG(); } -void VM_GC_Operation::acquire_pending_list_lock() { - _pending_list_locker.lock(); -} - -void VM_GC_Operation::release_and_notify_pending_list_lock() { - _pending_list_locker.unlock(); -} - // Allocations may fail in several threads at about the same time, // resulting in multiple gc requests. We only want to do one of them. // In case a GC locker is active and the need for a GC is already signaled, @@ -102,16 +94,13 @@ proper_unit_for_byte_size(NewSize))); } - acquire_pending_list_lock(); // If the GC count has changed someone beat us to the collection - // Get the Heap_lock after the pending_list_lock. Heap_lock->lock(); // Check invocations if (skip_operation()) { // skip collection Heap_lock->unlock(); - release_and_notify_pending_list_lock(); _prologue_succeeded = false; } else { _prologue_succeeded = true; @@ -122,9 +111,10 @@ void VM_GC_Operation::doit_epilogue() { assert(Thread::current()->is_Java_thread(), "just checking"); - // Release the Heap_lock first. + if (Universe::has_reference_pending_list()) { + Heap_lock->notify_all(); + } Heap_lock->unlock(); - release_and_notify_pending_list_lock(); } bool VM_GC_HeapInspection::skip_operation() const { --- old/src/share/vm/gc/shared/vmGCOperations.hpp 2016-07-31 21:09:41.189234493 -0400 +++ new/src/share/vm/gc/shared/vmGCOperations.hpp 2016-07-31 21:09:41.089233997 -0400 @@ -27,7 +27,6 @@ #include "gc/shared/collectedHeap.hpp" #include "gc/shared/genCollectedHeap.hpp" -#include "gc/shared/referencePendingListLocker.hpp" #include "memory/heapInspection.hpp" #include "prims/jvmtiExport.hpp" #include "runtime/handles.hpp" @@ -70,9 +69,6 @@ // class VM_GC_Operation: public VM_Operation { - private: - ReferencePendingListLocker _pending_list_locker; - protected: uint _gc_count_before; // gc count before acquiring PLL uint _full_gc_count_before; // full gc count before acquiring PLL @@ -83,10 +79,6 @@ virtual bool skip_operation() const; - // java.lang.ref.Reference support - void acquire_pending_list_lock(); - void release_and_notify_pending_list_lock(); - public: VM_GC_Operation(uint gc_count_before, GCCause::Cause _cause, --- old/src/share/vm/memory/universe.cpp 2016-07-31 21:09:41.741237231 -0400 +++ new/src/share/vm/memory/universe.cpp 2016-07-31 21:09:41.637236715 -0400 @@ -135,6 +135,7 @@ oop Universe::_virtual_machine_error_instance = NULL; oop Universe::_vm_exception = NULL; oop Universe::_allocation_context_notification_obj = NULL; +oop Universe::_reference_pending_list = NULL; Array* Universe::_the_empty_int_array = NULL; Array* Universe::_the_empty_short_array = NULL; @@ -212,6 +213,7 @@ f->do_oop((oop*)&_system_thread_group); f->do_oop((oop*)&_vm_exception); f->do_oop((oop*)&_allocation_context_notification_obj); + f->do_oop((oop*)&_reference_pending_list); debug_only(f->do_oop((oop*)&_fullgc_alot_dummy_array);) } @@ -488,6 +490,35 @@ java_lang_Class::set_fixup_mirror_list(NULL); } +#define assert_pll_locked(test) \ + assert(Heap_lock->test(), "Reference pending list access requires lock") + +#define assert_pll_ownership() assert_pll_locked(owned_by_self) + +oop Universe::reference_pending_list() { + assert_pll_ownership(); + return _reference_pending_list; +} + +void Universe::set_reference_pending_list(oop list) { + assert_pll_ownership(); + _reference_pending_list = list; +} + +bool Universe::has_reference_pending_list() { + assert_pll_ownership(); + return _reference_pending_list != NULL; +} + +oop Universe::swap_reference_pending_list(oop list) { + assert_pll_locked(is_locked); + return (oop)Atomic::xchg_ptr(list, &_reference_pending_list); +} + +#undef assert_pll_locked +#undef assert_pll_ownership + + static bool has_run_finalizers_on_exit = false; void Universe::run_finalizers_on_exit() { @@ -565,12 +596,14 @@ oop Universe::gen_out_of_memory_error(oop default_err) { // generate an out of memory error: - // - if there is a preallocated error with backtrace available then return it wth - // a filled in stack trace. - // - if there are no preallocated errors with backtrace available then return - // an error without backtrace. + // - if there is a preallocated error and stack traces are available + // (j.l.Throwable is initialized), then return the preallocated + // error with a filled in stack trace, and with the message + // provided by the default error. + // - otherwise, return the default error, without a stack trace. int next; - if (_preallocated_out_of_memory_error_avail_count > 0) { + if ((_preallocated_out_of_memory_error_avail_count > 0) && + SystemDictionary::Throwable_klass()->is_initialized()) { next = (int)Atomic::add(-1, &_preallocated_out_of_memory_error_avail_count); assert(next < (int)PreallocatedOutOfMemoryErrorCount, "avail count is corrupt"); } else { --- old/src/share/vm/memory/universe.hpp 2016-07-31 21:09:42.317240087 -0400 +++ new/src/share/vm/memory/universe.hpp 2016-07-31 21:09:42.213239571 -0400 @@ -185,6 +185,9 @@ static oop _allocation_context_notification_obj; + // References waiting to be transferred to the ReferenceHandler + static oop _reference_pending_list; + // The particular choice of collected heap. static CollectedHeap* _collectedHeap; @@ -334,6 +337,17 @@ static inline oop allocation_context_notification_obj(); static inline void set_allocation_context_notification_obj(oop obj); + // Reference pending list manipulation. Access is protected by + // Heap_lock. The getter, setter and predicate require the caller + // owns the lock. Swap is used by parallel non-concurrent reference + // processing threads, where some higher level controller owns + // Heap_lock, so requires the lock is locked, but not necessarily by + // the current thread. + static oop reference_pending_list(); + static void set_reference_pending_list(oop list); + static bool has_reference_pending_list(); + static oop swap_reference_pending_list(oop list); + static Array* the_empty_int_array() { return _the_empty_int_array; } static Array* the_empty_short_array() { return _the_empty_short_array; } static Array* the_empty_method_array() { return _the_empty_method_array; } --- old/src/share/vm/oops/method.cpp 2016-07-31 21:09:42.881242884 -0400 +++ new/src/share/vm/oops/method.cpp 2016-07-31 21:09:42.777242368 -0400 @@ -30,7 +30,6 @@ #include "gc/shared/collectedHeap.inline.hpp" #include "gc/shared/gcLocker.hpp" #include "gc/shared/generation.hpp" -#include "gc/shared/referencePendingListLocker.hpp" #include "interpreter/bytecodeStream.hpp" #include "interpreter/bytecodeTracer.hpp" #include "interpreter/bytecodes.hpp" @@ -399,12 +398,6 @@ return; } - // Do not profile method if current thread holds the pending list lock, - // which avoids deadlock for acquiring the MethodData_lock. - if (ReferencePendingListLocker::is_locked_by_self()) { - return; - } - // Grab a lock here to prevent multiple // MethodData*s from being created. MutexLocker ml(MethodData_lock, THREAD); --- old/src/share/vm/prims/jvm.cpp 2016-07-31 21:09:43.465245779 -0400 +++ new/src/share/vm/prims/jvm.cpp 2016-07-31 21:09:43.361245264 -0400 @@ -3352,6 +3352,36 @@ JVM_END +// java.lang.ref.Reference /////////////////////////////////////////////////////////////// + + +JVM_ENTRY(jobject, JVM_GetAndClearReferencePendingList(JNIEnv* env)) + JVMWrapper("JVM_GetAndClearReferencePendingList"); + + MonitorLockerEx ml(Heap_lock); + oop ref = Universe::reference_pending_list(); + if (ref != NULL) { + Universe::set_reference_pending_list(NULL); + } + return JNIHandles::make_local(env, ref); +JVM_END + +JVM_ENTRY(jboolean, JVM_CheckReferencePendingList(JNIEnv* env, jboolean await)) + JVMWrapper("JVM_CheckReferencePendingList"); + MonitorLockerEx ml(Heap_lock); + if (Universe::reference_pending_list() != NULL) { + return true; + } else if (await) { + do { + ml.wait(); + } while (Universe::reference_pending_list() == NULL); + return true; + } else { + return false; + } +JVM_END + + // ObjectInputStream /////////////////////////////////////////////////////////////// bool force_verify_field_access(Klass* current_class, Klass* field_class, AccessFlags access, bool classloader_only) { --- old/src/share/vm/prims/jvm.h 2016-07-31 21:09:44.065248755 -0400 +++ new/src/share/vm/prims/jvm.h 2016-07-31 21:09:43.965248259 -0400 @@ -297,6 +297,15 @@ JVM_GetSystemPackages(JNIEnv *env); /* + * java.lang.ref.Reference + */ +JNIEXPORT jobject JNICALL +JVM_GetAndClearReferencePendingList(JNIEnv *env); + +JNIEXPORT jboolean JNICALL +JVM_CheckReferencePendingList(JNIEnv *env, jboolean await); + +/* * java.io.ObjectInputStream */ JNIEXPORT jobject JNICALL --- old/src/share/vm/runtime/thread.cpp 2016-07-31 21:09:44.641251611 -0400 +++ new/src/share/vm/runtime/thread.cpp 2016-07-31 21:09:44.537251095 -0400 @@ -35,7 +35,6 @@ #include "compiler/compileTask.hpp" #include "gc/shared/gcId.hpp" #include "gc/shared/gcLocker.inline.hpp" -#include "gc/shared/referencePendingListLocker.hpp" #include "gc/shared/workgroup.hpp" #include "interpreter/interpreter.hpp" #include "interpreter/linkResolver.hpp" @@ -3715,14 +3714,6 @@ Management::record_vm_init_completed(); #endif // INCLUDE_MANAGEMENT - // Note that we do not use CHECK_0 here since we are inside an EXCEPTION_MARK and - // set_init_completed has just been called, causing exceptions not to be shortcut - // anymore. We call vm_exit_during_initialization directly instead. - - // Initialize reference pending list locker - bool needs_locker_thread = Universe::heap()->needs_reference_pending_list_locker_thread(); - ReferencePendingListLocker::initialize(needs_locker_thread, CHECK_JNI_ERR); - // Signal Dispatcher needs to be started before VMInit event is posted os::signal_init(); --- old/src/share/vm/runtime/vmStructs.cpp 2016-07-31 21:09:45.261254685 -0400 +++ new/src/share/vm/runtime/vmStructs.cpp 2016-07-31 21:09:45.153254150 -0400 @@ -54,7 +54,6 @@ #include "gc/shared/genCollectedHeap.hpp" #include "gc/shared/generation.hpp" #include "gc/shared/generationSpec.hpp" -#include "gc/shared/referencePendingListLocker.hpp" #include "gc/shared/space.hpp" #include "interpreter/bytecodeInterpreter.hpp" #include "interpreter/bytecodes.hpp" @@ -1637,7 +1636,6 @@ declare_type(JavaThread, Thread) \ declare_type(JvmtiAgentThread, JavaThread) \ declare_type(ServiceThread, JavaThread) \ - declare_type(ReferencePendingListLockerThread, JavaThread) \ declare_type(CompilerThread, JavaThread) \ declare_type(CodeCacheSweeperThread, JavaThread) \ declare_toplevel_type(OSThread) \ --- old/src/share/vm/gc/shared/referencePendingListLocker.cpp 2016-07-31 21:09:45.853257621 -0400 +++ /dev/null 2016-07-15 13:45:48.462218507 -0400 @@ -1,222 +0,0 @@ -/* - * Copyright (c) 2016, 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/javaClasses.hpp" -#include "classfile/systemDictionary.hpp" -#include "gc/shared/collectedHeap.hpp" -#include "gc/shared/referencePendingListLocker.hpp" -#include "memory/universe.hpp" -#include "runtime/javaCalls.hpp" -#include "utilities/preserveException.hpp" - -ReferencePendingListLockerThread::ReferencePendingListLockerThread() : - JavaThread(&start), - _monitor(Monitor::nonleaf, "ReferencePendingListLocker", false, Monitor::_safepoint_check_sometimes), - _message(NONE) {} - -ReferencePendingListLockerThread* ReferencePendingListLockerThread::create(TRAPS) { - // Create Java thread objects - instanceKlassHandle thread_klass = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK_NULL); - instanceHandle thread_object = thread_klass->allocate_instance_handle(CHECK_NULL); - Handle thread_name = java_lang_String::create_from_str("Reference Pending List Locker", CHECK_NULL); - Handle thread_group = Universe::system_thread_group(); - JavaValue result(T_VOID); - JavaCalls::call_special(&result, - thread_object, - thread_klass, - vmSymbols::object_initializer_name(), - vmSymbols::threadgroup_string_void_signature(), - thread_group, - thread_name, - CHECK_NULL); - - { - MutexLocker ml(Threads_lock); - - // Allocate thread - ReferencePendingListLockerThread* thread = new ReferencePendingListLockerThread(); - if (thread == NULL || thread->osthread() == NULL) { - vm_exit_during_initialization("java.lang.OutOfMemoryError", - os::native_thread_creation_failed_msg()); - } - - // Initialize thread - java_lang_Thread::set_thread(thread_object(), thread); - java_lang_Thread::set_priority(thread_object(), NearMaxPriority); - java_lang_Thread::set_daemon(thread_object()); - thread->set_threadObj(thread_object()); - - // Start thread - Threads::add(thread); - Thread::start(thread); - - return thread; - } -} - -void ReferencePendingListLockerThread::start(JavaThread* thread, TRAPS) { - ReferencePendingListLockerThread* locker_thread = static_cast(thread); - locker_thread->receive_and_handle_messages(); -} - -bool ReferencePendingListLockerThread::is_hidden_from_external_view() const { - return true; -} - -void ReferencePendingListLockerThread::send_message(Message message) { - assert(message != NONE, "Should not be none"); - MonitorLockerEx ml(&_monitor, Monitor::_no_safepoint_check_flag); - - // Wait for completion of current message - while (_message != NONE) { - ml.wait(Monitor::_no_safepoint_check_flag); - } - - // Send new message - _message = message; - ml.notify_all(); - - // Wait for completion of new message - while (_message != NONE) { - ml.wait(Monitor::_no_safepoint_check_flag); - } -} - -void ReferencePendingListLockerThread::receive_and_handle_messages() { - ReferencePendingListLocker pending_list_locker; - MonitorLockerEx ml(&_monitor); - - // Main loop, never terminates - for (;;) { - // Wait for message - while (_message == NONE) { - ml.wait(); - } - - // Handle message - if (_message == LOCK) { - pending_list_locker.lock(); - } else if (_message == UNLOCK) { - pending_list_locker.unlock(); - } else { - ShouldNotReachHere(); - } - - // Clear message - _message = NONE; - ml.notify_all(); - } -} - -void ReferencePendingListLockerThread::lock() { - send_message(LOCK); -} - -void ReferencePendingListLockerThread::unlock() { - send_message(UNLOCK); -} - -bool ReferencePendingListLocker::_is_initialized = false; -ReferencePendingListLockerThread* ReferencePendingListLocker::_locker_thread = NULL; - -void ReferencePendingListLocker::initialize(bool needs_locker_thread, TRAPS) { - if (needs_locker_thread) { - _locker_thread = ReferencePendingListLockerThread::create(CHECK); - } - - _is_initialized = true; -} - -bool ReferencePendingListLocker::is_initialized() { - return _is_initialized; -} - -bool ReferencePendingListLocker::is_locked_by_self() { - oop pending_list_lock = java_lang_ref_Reference::pending_list_lock(); - if (pending_list_lock == NULL) { - return false; - } - - JavaThread* thread = JavaThread::current(); - Handle handle(thread, pending_list_lock); - return ObjectSynchronizer::current_thread_holds_lock(thread, handle); -} - -void ReferencePendingListLocker::lock() { - assert(!Heap_lock->owned_by_self(), "Heap_lock must not be owned by requesting thread"); - - if (Thread::current()->is_Java_thread()) { - assert(java_lang_ref_Reference::pending_list_lock() != NULL, "Not initialized"); - - // We may enter this with a pending exception - PRESERVE_EXCEPTION_MARK; - - HandleMark hm; - Handle handle(THREAD, java_lang_ref_Reference::pending_list_lock()); - - // Lock - ObjectSynchronizer::fast_enter(handle, &_basic_lock, false, THREAD); - - assert(is_locked_by_self(), "Locking failed"); - - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - } - } else { - // Delegate operation to locker thread - assert(_locker_thread != NULL, "Locker thread not created"); - _locker_thread->lock(); - } -} - -void ReferencePendingListLocker::unlock() { - if (Thread::current()->is_Java_thread()) { - assert(java_lang_ref_Reference::pending_list_lock() != NULL, "Not initialized"); - - // We may enter this with a pending exception - PRESERVE_EXCEPTION_MARK; - - HandleMark hm; - Handle handle(THREAD, java_lang_ref_Reference::pending_list_lock()); - - assert(is_locked_by_self(), "Should be locked by self"); - - // Notify waiters if the pending list is non-empty - if (java_lang_ref_Reference::pending_list() != NULL) { - ObjectSynchronizer::notifyall(handle, THREAD); - } - - // Unlock - ObjectSynchronizer::fast_exit(handle(), &_basic_lock, THREAD); - - if (HAS_PENDING_EXCEPTION) { - CLEAR_PENDING_EXCEPTION; - } - } else { - // Delegate operation to locker thread - assert(_locker_thread != NULL, "Locker thread not created"); - _locker_thread->unlock(); - } -} --- old/src/share/vm/gc/shared/referencePendingListLocker.hpp 2016-07-31 21:09:46.177259228 -0400 +++ /dev/null 2016-07-15 13:45:48.462218507 -0400 @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2016, 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_GC_SHARED_REFERENCEPENDINGLISTLOCKER_HPP -#define SHARE_VM_GC_SHARED_REFERENCEPENDINGLISTLOCKER_HPP - -#include "memory/allocation.hpp" -#include "runtime/basicLock.hpp" -#include "runtime/mutex.hpp" -#include "runtime/thread.hpp" -#include "utilities/exceptions.hpp" - -// -// The ReferencePendingListLockerThread locks and unlocks the reference -// pending list lock on behalf a non-Java thread, typically a concurrent -// GC thread. This interface should not be directly accessed. All uses -// should instead go through the ReferencePendingListLocker, which calls -// this thread if needed. -// -class ReferencePendingListLockerThread : public JavaThread { -private: - enum Message { - NONE, - LOCK, - UNLOCK - }; - - Monitor _monitor; - Message _message; - - ReferencePendingListLockerThread(); - - static void start(JavaThread* thread, TRAPS); - - void send_message(Message message); - void receive_and_handle_messages(); - -public: - static ReferencePendingListLockerThread* create(TRAPS); - - virtual bool is_hidden_from_external_view() const; - - void lock(); - void unlock(); -}; - -// -// The ReferencePendingListLocker is the main interface for locking and -// unlocking the reference pending list lock, which needs to be held by -// the GC when adding references to the pending list. Since this is a -// Java-level monitor it can only be locked/unlocked by a Java thread. -// For this reason there is an option to spawn a helper thread, the -// ReferencePendingListLockerThread, during initialization. If a helper -// thread is spawned all lock operations from non-Java threads will be -// delegated to the helper thread. The helper thread is typically needed -// by concurrent GCs. -// -class ReferencePendingListLocker VALUE_OBJ_CLASS_SPEC { -private: - static bool _is_initialized; - static ReferencePendingListLockerThread* _locker_thread; - BasicLock _basic_lock; - -public: - static void initialize(bool needs_locker_thread, TRAPS); - static bool is_initialized(); - - static bool is_locked_by_self(); - - void lock(); - void unlock(); -}; - -#endif // SHARE_VM_GC_SHARED_REFERENCEPENDINGLISTLOCKER_HPP