< prev index next >

src/share/vm/classfile/metadataOnStackMark.cpp

Print this page
rev 6875 : 8056240: Investigate increased GC remark time after class unloading changes in CRM Fuse
Reviewed-by: mgerdin, coleenp, bdelsart

*** 29,57 **** #include "oops/metadata.hpp" #include "prims/jvmtiImpl.hpp" #include "runtime/synchronizer.hpp" #include "runtime/thread.hpp" #include "services/threadService.hpp" ! #include "utilities/growableArray.hpp" - // Keep track of marked on-stack metadata so it can be cleared. - GrowableArray<Metadata*>* _marked_objects = NULL; NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;) // Walk metadata on the stack and mark it so that redefinition doesn't delete // it. Class unloading also walks the previous versions and might try to // delete it, so this class is used by class unloading also. ! MetadataOnStackMark::MetadataOnStackMark() { assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); NOT_PRODUCT(_is_active = true;) - if (_marked_objects == NULL) { - _marked_objects = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(1000, true); - } Threads::metadata_do(Metadata::mark_on_stack); ! if (JvmtiExport::has_redefined_a_class()) { CodeCache::alive_nmethods_do(nmethod::mark_on_stack); } CompileBroker::mark_on_stack(); JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack); ThreadService::metadata_do(Metadata::mark_on_stack); --- 29,55 ---- #include "oops/metadata.hpp" #include "prims/jvmtiImpl.hpp" #include "runtime/synchronizer.hpp" #include "runtime/thread.hpp" #include "services/threadService.hpp" ! #include "utilities/chunkedList.hpp" + volatile MetadataOnStackBuffer* MetadataOnStackMark::_used_buffers = NULL; + volatile MetadataOnStackBuffer* MetadataOnStackMark::_free_buffers = NULL; NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;) // Walk metadata on the stack and mark it so that redefinition doesn't delete // it. Class unloading also walks the previous versions and might try to // delete it, so this class is used by class unloading also. ! MetadataOnStackMark::MetadataOnStackMark(bool visit_code_cache) { assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); + assert(_used_buffers == NULL, "sanity check"); NOT_PRODUCT(_is_active = true;) Threads::metadata_do(Metadata::mark_on_stack); ! if (visit_code_cache) { CodeCache::alive_nmethods_do(nmethod::mark_on_stack); } CompileBroker::mark_on_stack(); JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack); ThreadService::metadata_do(Metadata::mark_on_stack);
*** 60,76 **** MetadataOnStackMark::~MetadataOnStackMark() { assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); // Unmark everything that was marked. Can't do the same walk because // redefine classes messes up the code cache so the set of methods // might not be the same. ! for (int i = 0; i< _marked_objects->length(); i++) { ! _marked_objects->at(i)->set_on_stack(false); } ! _marked_objects->clear(); // reuse growable array for next time. NOT_PRODUCT(_is_active = false;) } // Record which objects are marked so we can unmark the same objects. ! void MetadataOnStackMark::record(Metadata* m) { assert(_is_active, "metadata on stack marking is active"); ! _marked_objects->push(m); } --- 58,152 ---- MetadataOnStackMark::~MetadataOnStackMark() { assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); // Unmark everything that was marked. Can't do the same walk because // redefine classes messes up the code cache so the set of methods // might not be the same. ! ! retire_buffer_for_thread(Thread::current()); ! ! MetadataOnStackBuffer* buffer = const_cast<MetadataOnStackBuffer* >(_used_buffers); ! while (buffer != NULL) { ! // Clear on stack state for all metadata. ! size_t size = buffer->size(); ! for (size_t i = 0; i < size; i++) { ! Metadata* md = buffer->at(i); ! md->set_on_stack(false); ! } ! ! MetadataOnStackBuffer* next = buffer->next_used(); ! ! // Move the buffer to the free list. ! buffer->clear(); ! buffer->set_next_used(NULL); ! buffer->set_next_free(const_cast<MetadataOnStackBuffer*>(_free_buffers)); ! _free_buffers = buffer; ! ! // Step to next used buffer. ! buffer = next; } ! ! _used_buffers = NULL; ! NOT_PRODUCT(_is_active = false;) } + void MetadataOnStackMark::retire_buffer(MetadataOnStackBuffer* buffer) { + if (buffer == NULL) { + return; + } + + MetadataOnStackBuffer* old_head; + + do { + old_head = const_cast<MetadataOnStackBuffer*>(_used_buffers); + buffer->set_next_used(old_head); + } while (Atomic::cmpxchg_ptr(buffer, &_used_buffers, old_head) != old_head); + } + + void MetadataOnStackMark::retire_buffer_for_thread(Thread* thread) { + retire_buffer(thread->metadata_on_stack_buffer()); + thread->set_metadata_on_stack_buffer(NULL); + } + + bool MetadataOnStackMark::has_buffer_for_thread(Thread* thread) { + return thread->metadata_on_stack_buffer() != NULL; + } + + MetadataOnStackBuffer* MetadataOnStackMark::allocate_buffer() { + MetadataOnStackBuffer* allocated; + MetadataOnStackBuffer* new_head; + + do { + allocated = const_cast<MetadataOnStackBuffer*>(_free_buffers); + if (allocated == NULL) { + break; + } + new_head = allocated->next_free(); + } while (Atomic::cmpxchg_ptr(new_head, &_free_buffers, allocated) != allocated); + + if (allocated == NULL) { + allocated = new MetadataOnStackBuffer(); + } + + assert(!allocated->is_full(), err_msg("Should not be full: " PTR_FORMAT, p2i(allocated))); + + return allocated; + } + // Record which objects are marked so we can unmark the same objects. ! void MetadataOnStackMark::record(Metadata* m, Thread* thread) { assert(_is_active, "metadata on stack marking is active"); ! ! MetadataOnStackBuffer* buffer = thread->metadata_on_stack_buffer(); ! ! if (buffer != NULL && buffer->is_full()) { ! retire_buffer(buffer); ! buffer = NULL; ! } ! ! if (buffer == NULL) { ! buffer = allocate_buffer(); ! thread->set_metadata_on_stack_buffer(buffer); ! } ! ! buffer->push(m); }
< prev index next >