--- old/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp 2013-09-06 14:11:04.432354396 +0200 +++ new/src/share/vm/gc_implementation/g1/concurrentG1Refine.cpp 2013-09-06 14:11:04.336352658 +0200 @@ -30,7 +30,8 @@ ConcurrentG1Refine::ConcurrentG1Refine(G1CollectedHeap* g1h) : _threads(NULL), _n_threads(0), - _hot_card_cache(g1h) + _hot_card_cache(g1h), + _safe_cards_for_refine(false) { // Ergomonically select initial concurrent refinement parameters if (FLAG_IS_DEFAULT(G1ConcRefinementGreenZone)) { @@ -66,6 +67,13 @@ _threads[i] = t; next = t; } + + _safe_cards_for_refine.initialize(DirtyCardQ_CBL_mon, + DirtyCardQ_FL_lock, + -1, + -1, + Shared_DirtyCardQ_lock, + &JavaThread::dirty_card_queue_set()); } void ConcurrentG1Refine::reset_threshold_step() { @@ -138,3 +146,11 @@ ConcurrentG1RefineThread * ConcurrentG1Refine::sampling_thread() const { return _threads[worker_thread_num()]; } + +void ConcurrentG1Refine::set_card_refinement_closure(CardTableEntryClosure* cl) { + _safe_cards_for_refine.set_closure(cl); +} + +void ConcurrentG1Refine::flush_cards_in_buffers() { + _flush_transfer_closure->do_void(); +} --- old/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp 2013-09-06 14:11:05.056365697 +0200 +++ new/src/share/vm/gc_implementation/g1/concurrentG1Refine.hpp 2013-09-06 14:11:04.960363958 +0200 @@ -66,6 +66,8 @@ // We delay the refinement of 'hot' cards using the hot card cache. G1HotCardCache _hot_card_cache; + DirtyCardQueueSet _safe_cards_for_refine; + VoidClosure* _flush_transfer_closure; // Reset the threshold step value based of the current zone boundaries. void reset_threshold_step(); @@ -106,6 +108,11 @@ int thread_threshold_step() const { return _thread_threshold_step; } G1HotCardCache* hot_card_cache() { return &_hot_card_cache; } + + void set_card_refinement_closure(CardTableEntryClosure* cl); + void set_flush_transfer_closure(VoidClosure* cl) { _flush_transfer_closure = cl; } + void flush_cards_in_buffers(); + DirtyCardQueueSet& cards_ready_for_refinement() { return _safe_cards_for_refine; } }; #endif // SHARE_VM_GC_IMPLEMENTATION_G1_CONCURRENTG1REFINE_HPP --- old/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp 2013-09-06 14:11:05.632376129 +0200 +++ new/src/share/vm/gc_implementation/g1/concurrentG1RefineThread.cpp 2013-09-06 14:11:05.536374391 +0200 @@ -96,7 +96,6 @@ } void ConcurrentG1RefineThread::run_young_rs_sampling() { - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); _vtime_start = os::elapsedVTime(); while(!_should_terminate) { _sts.join(); @@ -118,7 +117,6 @@ } void ConcurrentG1RefineThread::wait_for_completed_buffers() { - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); while (!_should_terminate && !is_active()) { _monitor->wait(Mutex::_no_safepoint_check_flag); @@ -126,7 +124,7 @@ } bool ConcurrentG1RefineThread::is_active() { - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + DirtyCardQueueSet& dcqs = cg1r()->cards_ready_for_refinement(); return _worker_id > 0 ? _active : dcqs.process_completed_buffers(); } @@ -134,13 +132,13 @@ MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); if (_worker_id > 0) { if (G1TraceConcRefinement) { - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + DirtyCardQueueSet& dcqs = cg1r()->cards_ready_for_refinement(); gclog_or_tty->print_cr("G1-Refine-activated worker %d, on threshold %d, current %d", _worker_id, _threshold, (int)dcqs.completed_buffers_num()); } set_active(true); } else { - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + DirtyCardQueueSet& dcqs = cg1r()->cards_ready_for_refinement(); dcqs.set_process_completed(true); } _monitor->notify(); @@ -150,13 +148,13 @@ MutexLockerEx x(_monitor, Mutex::_no_safepoint_check_flag); if (_worker_id > 0) { if (G1TraceConcRefinement) { - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + DirtyCardQueueSet& dcqs = cg1r()->cards_ready_for_refinement(); gclog_or_tty->print_cr("G1-Refine-deactivated worker %d, off threshold %d, current %d", _worker_id, _deactivation_threshold, (int)dcqs.completed_buffers_num()); } set_active(false); } else { - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + DirtyCardQueueSet& dcqs = cg1r()->cards_ready_for_refinement(); dcqs.set_process_completed(false); } } @@ -173,7 +171,8 @@ _vtime_start = os::elapsedVTime(); while (!_should_terminate) { - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + DirtyCardQueueSet& dcqs = cg1r()->cards_ready_for_refinement(); + cg1r()->flush_cards_in_buffers(); // Wait for work wait_for_completed_buffers(); --- old/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp 2013-09-06 14:11:06.212386633 +0200 +++ new/src/share/vm/gc_implementation/g1/dirtyCardQueue.cpp 2013-09-06 14:11:06.116384896 +0200 @@ -29,6 +29,8 @@ #include "runtime/mutexLocker.hpp" #include "runtime/safepoint.hpp" #include "runtime/thread.inline.hpp" +#include "runtime/vmThread.hpp" +#include "runtime/vm_operations.hpp" #include "utilities/workgroup.hpp" bool DirtyCardQueue::apply_closure(CardTableEntryClosure* cl, @@ -115,7 +117,9 @@ } bool DirtyCardQueueSet::mut_process_buffer(void** buf) { - + VMThread::execute (new VM_ForceAsyncSafepoint()); + return false; +#if 0 // Used to determine if we had already claimed a par_id // before entering this method. bool already_claimed = false; @@ -158,6 +162,7 @@ } } return b; +#endif } --- old/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2013-09-06 14:11:06.800397283 +0200 +++ new/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp 2013-09-06 14:11:06.696395399 +0200 @@ -91,16 +91,20 @@ class RefineCardTableEntryClosure: public CardTableEntryClosure { SuspendibleThreadSet* _sts; G1RemSet* _g1rs; - ConcurrentG1Refine* _cg1r; bool _concurrent; public: RefineCardTableEntryClosure(SuspendibleThreadSet* sts, - G1RemSet* g1rs, - ConcurrentG1Refine* cg1r) : - _sts(sts), _g1rs(g1rs), _cg1r(cg1r), _concurrent(true) + G1RemSet* g1rs) : + _sts(sts), _g1rs(g1rs), _concurrent(true) {} bool do_card_ptr(jbyte* card_ptr, int worker_i) { - bool oops_into_cset = _g1rs->refine_card(card_ptr, worker_i, false); + bool oops_into_cset; + if (_concurrent) { + oops_into_cset = _g1rs->refine_card_without_check(card_ptr, worker_i, false); + } else { + assert(SafepointSynchronize::is_at_safepoint(), "only safe if at safepoint"); + oops_into_cset = _g1rs->refine_card(card_ptr, worker_i, false); + } // This path is executed by the concurrent refine or mutator threads, // concurrently, and so we do not care if card_ptr contains references // that point into the collection set. @@ -116,6 +120,39 @@ void set_concurrent(bool b) { _concurrent = b; } }; +class TransferDirtyCardsToRefinementClosure: public CardTableEntryClosure { + public: + class FlushTransferClosure: public VoidClosure { + friend class TransferDirtyCardsToRefinementClosure; + TransferDirtyCardsToRefinementClosure* _cl; + public: + void do_void() { + assert(_cl != NULL, "should be inited"); + _cl->_dcq.flush(); + } + }; + + private: + FlushTransferClosure _flush_cl; + DirtyCardQueue _dcq; + public: + TransferDirtyCardsToRefinementClosure(DirtyCardQueueSet& target) : _dcq(&target) { + _flush_cl._cl = this; + } + + bool do_card_ptr(jbyte* card_ptr, int worker_i) { + assert(SafepointSynchronize::is_at_safepoint(), "only safe to transfer/clean cards at safepoint"); + assert(!G1CollectedHeap::heap()->is_gc_active(), "should not get here if doing a gc"); + _dcq.enqueue(card_ptr); + *card_ptr = CardTableModRefBS::clean_card_val(); + return true; + } + + public: + FlushTransferClosure* flush_cl() { return &_flush_cl; } +}; + + class ClearLoggedCardTableEntryClosure: public CardTableEntryClosure { int _calls; @@ -1939,6 +1976,7 @@ _cg1r(NULL), _summary_bytes_used(0), _g1mm(NULL), _refine_cte_cl(NULL), + _transfer_cte_cl(NULL), _full_collection(false), _free_list("Master Free List"), _secondary_free_list("Secondary Free List"), @@ -2143,9 +2181,14 @@ _refine_cte_cl = new RefineCardTableEntryClosure(ConcurrentG1RefineThread::sts(), - g1_rem_set(), - concurrent_g1_refine()); - JavaThread::dirty_card_queue_set().set_closure(_refine_cte_cl); + g1_rem_set()); + _transfer_cte_cl = + new TransferDirtyCardsToRefinementClosure(concurrent_g1_refine()->cards_ready_for_refinement()); + + concurrent_g1_refine()->set_card_refinement_closure(_refine_cte_cl); + concurrent_g1_refine()->set_flush_transfer_closure(_transfer_cte_cl->flush_cl()); + + JavaThread::dirty_card_queue_set().set_closure(_transfer_cte_cl); JavaThread::satb_mark_queue_set().initialize(SATB_Q_CBL_mon, SATB_Q_FL_lock, @@ -2333,7 +2376,8 @@ } #endif // PRODUCT -void G1CollectedHeap::iterate_dirty_card_closure(CardTableEntryClosure* cl, +int G1CollectedHeap::iterate_dirty_card_closure(CardTableEntryClosure* cl, + CardTableEntryClosure* cleaned_cl, DirtyCardQueue* into_cset_dcq, bool concurrent, int worker_i) { @@ -2341,14 +2385,23 @@ G1HotCardCache* hot_card_cache = _cg1r->hot_card_cache(); hot_card_cache->drain(worker_i, g1_rem_set(), into_cset_dcq); - DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); int n_completed_buffers = 0; + if (worker_i == 0) { + concurrent_g1_refine()->flush_cards_in_buffers(); + } + DirtyCardQueueSet& refinement_dcqs = concurrent_g1_refine()->cards_ready_for_refinement(); + while (refinement_dcqs.apply_closure_to_completed_buffer(cleaned_cl, worker_i, 0, true)) { + n_completed_buffers++; + } + + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); while (dcqs.apply_closure_to_completed_buffer(cl, worker_i, 0, true)) { n_completed_buffers++; } - g1_policy()->phase_times()->record_update_rs_processed_buffers(worker_i, n_completed_buffers); + dcqs.clear_n_completed_buffers(); assert(!dcqs.completed_buffers_exist_dirty(), "Completed buffers exist!"); + return n_completed_buffers; } @@ -3048,6 +3101,11 @@ } } +void G1CollectedHeap::inform_non_gc_safepoint() { + DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); + while (dcqs.apply_closure_to_completed_buffer(0, 0, true)); +} + size_t G1CollectedHeap::max_capacity() const { return _g1_reserved.byte_size(); } @@ -5817,7 +5875,7 @@ dirty_card_queue_set().set_closure(&redirty); dirty_card_queue_set().apply_closure_to_all_completed_buffers(); - DirtyCardQueueSet& dcq = JavaThread::dirty_card_queue_set(); + DirtyCardQueueSet& dcq = concurrent_g1_refine()->cards_ready_for_refinement(); dcq.merge_bufferlists(&dirty_card_queue_set()); assert(dirty_card_queue_set().completed_buffers_num() == 0, "All should be consumed"); } @@ -6357,6 +6415,17 @@ _refine_cte_cl->set_concurrent(concurrent); } +void G1CollectedHeap::set_use_transferring_cte_cl(bool transferring) { + CardTableEntryClosure* cte_cl = NULL; + if (transferring) { + cte_cl = _transfer_cte_cl; + } else { + cte_cl = _refine_cte_cl; + } + JavaThread::dirty_card_queue_set().set_closure(cte_cl); +} + + bool G1CollectedHeap::is_in_closed_subset(const void* p) const { HeapRegion* hr = heap_region_containing(p); if (hr == NULL) { --- old/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp 2013-09-06 14:11:07.500409961 +0200 +++ new/src/share/vm/gc_implementation/g1/g1CollectedHeap.hpp 2013-09-06 14:11:07.400408149 +0200 @@ -194,6 +194,7 @@ }; class RefineCardTableEntryClosure; +class TransferDirtyCardsToRefinementClosure; class G1CollectedHeap : public SharedHeap { friend class VM_G1CollectForAllocation; @@ -797,6 +798,7 @@ // The closure used to refine a single card. RefineCardTableEntryClosure* _refine_cte_cl; + TransferDirtyCardsToRefinementClosure* _transfer_cte_cl; // A function to check the consistency of dirty card logs. void check_ct_logs_at_safepoint(); @@ -1066,6 +1068,7 @@ SubTasksDone* process_strong_tasks() { return _process_strong_tasks; } void set_refine_cte_cl_concurrency(bool concurrent); + void set_use_transferring_cte_cl(bool transferring); RefToScanQueue *task_queue(int i) const; @@ -1147,9 +1150,10 @@ // continues humongous regions too. void reset_gc_time_stamps(HeapRegion* hr); - void iterate_dirty_card_closure(CardTableEntryClosure* cl, - DirtyCardQueue* into_cset_dcq, - bool concurrent, int worker_i); + int iterate_dirty_card_closure(CardTableEntryClosure* cl, + CardTableEntryClosure* cleaned_cl, + DirtyCardQueue* into_cset_dcq, + bool concurrent, int worker_i); // The shared block offset table array. G1BlockOffsetSharedArray* bot_shared() const { return _bot_shared; } @@ -1544,6 +1548,8 @@ return _mark_in_progress; } + void inform_non_gc_safepoint(); + // Print the maximum heap capacity. virtual size_t max_capacity() const; --- old/src/share/vm/gc_implementation/g1/g1RemSet.cpp 2013-09-06 14:11:08.104420899 +0200 +++ new/src/share/vm/gc_implementation/g1/g1RemSet.cpp 2013-09-06 14:11:08.008419161 +0200 @@ -251,7 +251,7 @@ assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), "should be a GC worker"); - if (_g1rs->refine_card(card_ptr, worker_i, true)) { + if (_g1rs->refine_card(card_ptr, worker_i, (_into_cset_dcq != NULL))) { // 'card_ptr' contains references that point into the collection // set. We need to record the card in the DCQS // (G1CollectedHeap::into_cset_dirty_card_queue_set()) @@ -264,12 +264,44 @@ } }; -void G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, int worker_i) { +class RefineTransferredCardsClosure: public CardTableEntryClosure { + G1RemSet* _g1rs; + DirtyCardQueue* _into_cset_dcq; +public: + RefineTransferredCardsClosure(G1CollectedHeap* g1h, + DirtyCardQueue* into_cset_dcq) : + _g1rs(g1h->g1_rem_set()), _into_cset_dcq(into_cset_dcq) + {} + bool do_card_ptr(jbyte* card_ptr, int worker_i) { + // The only time we care about recording cards that + // contain references that point into the collection set + // is during RSet updating within an evacuation pause. + // In this case worker_i should be the id of a GC worker thread. + assert(SafepointSynchronize::is_at_safepoint(), "not during an evacuation pause"); + assert(worker_i < (int) (ParallelGCThreads == 0 ? 1 : ParallelGCThreads), "should be a GC worker"); + + if (_g1rs->refine_card_without_check(card_ptr, worker_i, (_into_cset_dcq != NULL))) { + // 'card_ptr' contains references that point into the collection + // set. We need to record the card in the DCQS + // (G1CollectedHeap::into_cset_dirty_card_queue_set()) + // that's used for that purpose. + // + // Enqueue the card + _into_cset_dcq->enqueue(card_ptr); + } + return true; + } +}; + +void G1RemSet::updateRS(DirtyCardQueue* into_cset_dcq, int worker_i, bool update_accounting) { double start = os::elapsedTime(); // Apply the given closure to all remaining log entries. - RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, into_cset_dcq); + RefineRecordRefsIntoCSCardTableEntryClosure into_cset_update_rs_cl(_g1, update_accounting ? into_cset_dcq : NULL); + RefineTransferredCardsClosure update_cleaned_cards_rs_cl(_g1, update_accounting ? into_cset_dcq : NULL); - _g1->iterate_dirty_card_closure(&into_cset_update_rs_cl, into_cset_dcq, false, worker_i); + int processed_buffers = _g1->iterate_dirty_card_closure(&into_cset_update_rs_cl, + &update_cleaned_cards_rs_cl, + into_cset_dcq, false, worker_i); // Now there should be no dirty cards. if (G1RSLogCheckCardTable) { @@ -280,7 +312,10 @@ guarantee(cl.n() == 0, "Card table should be clean."); } - _g1p->phase_times()->record_update_rs_time(worker_i, (os::elapsedTime() - start) * 1000.0); + if (update_accounting) { + _g1p->phase_times()->record_update_rs_processed_buffers(worker_i, processed_buffers); + _g1p->phase_times()->record_update_rs_time(worker_i, (os::elapsedTime() - start) * 1000.0); + } } void G1RemSet::cleanupHRRS() { @@ -322,7 +357,7 @@ // conditions, we'll revert back to parallel remembered set // updating and scanning. See CRs 6677707 and 6677708. if (G1UseParallelRSetUpdating || (worker_i == 0)) { - updateRS(&into_cset_dcq, worker_i); + updateRS(&into_cset_dcq, worker_i, /* update_accounting */ true); } else { _g1p->phase_times()->record_update_rs_processed_buffers(worker_i, 0); _g1p->phase_times()->record_update_rs_time(worker_i, 0.0); @@ -341,6 +376,7 @@ cleanupHRRS(); ConcurrentG1Refine* cg1r = _g1->concurrent_g1_refine(); _g1->set_refine_cte_cl_concurrency(false); + _g1->set_use_transferring_cte_cl(false); DirtyCardQueueSet& dcqs = JavaThread::dirty_card_queue_set(); dcqs.concatenate_logs(); @@ -428,6 +464,7 @@ _cards_scanned = NULL; // Cleanup after copy _g1->set_refine_cte_cl_concurrency(true); + _g1->set_use_transferring_cte_cl(true); // Set all cards back to clean. _g1->cleanUpCardTable(); @@ -537,6 +574,11 @@ return false; } + return refine_card_without_check(card_ptr, worker_i, check_for_refs_into_cset); +} + +bool G1RemSet::refine_card_without_check(jbyte* card_ptr, int worker_i, + bool check_for_refs_into_cset) { // Construct the region representing the card. HeapWord* start = _ct_bs->addr_for(card_ptr); // And find the region containing it. @@ -733,6 +775,7 @@ summary->print_on(gclog_or_tty); } + void G1RemSet::prepare_for_verify() { if (G1HRRSFlushLogBuffersOnVerify && (VerifyBeforeGC || VerifyAfterGC) @@ -749,7 +792,7 @@ hot_card_cache->set_use_cache(false); DirtyCardQueue into_cset_dcq(&_g1->into_cset_dirty_card_queue_set()); - updateRS(&into_cset_dcq, 0); + updateRS(&into_cset_dcq, 0, /* update_accounting */ false); _g1->into_cset_dirty_card_queue_set().clear(); hot_card_cache->set_use_cache(use_hot_card_cache); --- old/src/share/vm/gc_implementation/g1/g1RemSet.hpp 2013-09-06 14:11:08.696431622 +0200 +++ new/src/share/vm/gc_implementation/g1/g1RemSet.hpp 2013-09-06 14:11:08.600429882 +0200 @@ -99,7 +99,7 @@ void cleanup_after_oops_into_collection_set_do(); void scanRS(OopsInHeapRegionClosure* oc, int worker_i); - void updateRS(DirtyCardQueue* into_cset_dcq, int worker_i); + void updateRS(DirtyCardQueue* into_cset_dcq, int worker_i, bool update_accounting); CardTableModRefBS* ct_bs() { return _ct_bs; } size_t cardsScanned() { return _total_cards_scanned; } @@ -125,18 +125,22 @@ // If check_for_refs_into_cset is true, a true result is returned // if the given card contains oops that have references into the // current collection set. - virtual bool refine_card(jbyte* card_ptr, - int worker_i, - bool check_for_refs_into_cset); + bool refine_card(jbyte* card_ptr, + int worker_i, + bool check_for_refs_into_cset); + + bool refine_card_without_check(jbyte* card_ptr, + int worker_i, + bool check_for_refs_into_cset); // Print accumulated summary info from the start of the VM. - virtual void print_summary_info(); + void print_summary_info(); // Print accumulated summary info from the last time called. - virtual void print_periodic_summary_info(); + void print_periodic_summary_info(); // Prepare remembered set for verification. - virtual void prepare_for_verify(); + void prepare_for_verify(); size_t conc_refine_cards() const { return _conc_refine_cards; --- old/src/share/vm/gc_implementation/g1/ptrQueue.cpp 2013-09-06 14:11:09.276442126 +0200 +++ new/src/share/vm/gc_implementation/g1/ptrQueue.cpp 2013-09-06 14:11:09.180440387 +0200 @@ -45,6 +45,7 @@ for (size_t i = 0; i < _index; i += oopSize) { _buf[byte_index_to_index((int)i)] = NULL; } + assert(_buf != NULL, "must be non-null"); qset()->enqueue_complete_buffer(_buf); } _buf = NULL; @@ -211,6 +212,7 @@ } void PtrQueueSet::enqueue_complete_buffer(void** buf, size_t index) { + assert(buf != NULL, "must be non-null"); MutexLockerEx x(_cbl_mon, Mutex::_no_safepoint_check_flag); BufferNode* cbn = BufferNode::new_from_buffer(buf); cbn->set_index(index); --- old/src/share/vm/gc_implementation/g1/ptrQueue.hpp 2013-09-06 14:11:09.856452630 +0200 +++ new/src/share/vm/gc_implementation/g1/ptrQueue.hpp 2013-09-06 14:11:09.760450892 +0200 @@ -154,7 +154,7 @@ public: BufferNode() : _index(0), _next(NULL) { } BufferNode* next() const { return _next; } - void set_next(BufferNode* n) { _next = n; } + void set_next(BufferNode* n) { assert(n != this, "no loops"); _next = n; } size_t index() const { return _index; } void set_index(size_t i) { _index = i; } --- old/src/share/vm/gc_interface/collectedHeap.hpp 2013-09-06 14:11:10.444463280 +0200 +++ new/src/share/vm/gc_interface/collectedHeap.hpp 2013-09-06 14:11:10.348461540 +0200 @@ -474,6 +474,8 @@ // the context of the vm thread. virtual void collect_as_vm_thread(GCCause::Cause cause); + virtual void inform_non_gc_safepoint() {} + // Callback from VM_CollectForMetadataAllocation operation. MetaWord* satisfy_failed_metadata_allocation(ClassLoaderData* loader_data, size_t size, @@ -663,4 +665,21 @@ } }; +class NonGCSafepointMark : StackObj { + CollectedHeap* _heap; + unsigned int _total_collections; + unsigned int _total_full_collections; +public: + NonGCSafepointMark(CollectedHeap* heap) : _heap(heap), + _total_collections(heap->total_collections()), + _total_full_collections(heap->total_full_collections()) { } + + ~NonGCSafepointMark() { + if (_heap->total_collections() == _total_collections && + _heap->total_full_collections() == _total_full_collections) { + _heap->inform_non_gc_safepoint(); + } + } +}; + #endif // SHARE_VM_GC_INTERFACE_COLLECTEDHEAP_HPP --- old/src/share/vm/runtime/safepoint.cpp 2013-09-06 14:11:11.028473857 +0200 +++ new/src/share/vm/runtime/safepoint.cpp 2013-09-06 14:11:10.932472117 +0200 @@ -541,6 +541,7 @@ if (MemTracker::is_on()) { MemTracker::sync(); } + } --- old/src/share/vm/runtime/vmThread.cpp 2013-09-06 14:11:11.624484651 +0200 +++ new/src/share/vm/runtime/vmThread.cpp 2013-09-06 14:11:11.528482912 +0200 @@ -493,7 +493,9 @@ _vm_queue->set_drain_list(safepoint_ops); // ensure ops can be scanned - SafepointSynchronize::begin(); + SafepointSynchronize::begin(); { + NonGCSafepointMark gc_safepoint_detector(Universe::heap()); + evaluate_operation(_cur_vm_operation); // now process all queued safepoint ops, iteratively draining // the queue until there are none left @@ -535,7 +537,7 @@ _vm_queue->set_drain_list(NULL); // Complete safepoint synchronization - SafepointSynchronize::end(); + } SafepointSynchronize::end(); } else { // not a safepoint operation if (TraceLongCompiles) {