1.1 --- a/src/share/vm/classfile/metadataOnStackMark.cpp Mon Nov 03 12:02:40 2014 -0800 1.2 +++ b/src/share/vm/classfile/metadataOnStackMark.cpp Thu Oct 02 10:55:36 2014 +0200 1.3 @@ -31,25 +31,23 @@ 1.4 #include "runtime/synchronizer.hpp" 1.5 #include "runtime/thread.hpp" 1.6 #include "services/threadService.hpp" 1.7 -#include "utilities/growableArray.hpp" 1.8 +#include "utilities/chunkedList.hpp" 1.9 1.10 +volatile MetadataOnStackBuffer* MetadataOnStackMark::_used_buffers = NULL; 1.11 +volatile MetadataOnStackBuffer* MetadataOnStackMark::_free_buffers = NULL; 1.12 1.13 -// Keep track of marked on-stack metadata so it can be cleared. 1.14 -GrowableArray<Metadata*>* _marked_objects = NULL; 1.15 NOT_PRODUCT(bool MetadataOnStackMark::_is_active = false;) 1.16 1.17 // Walk metadata on the stack and mark it so that redefinition doesn't delete 1.18 // it. Class unloading also walks the previous versions and might try to 1.19 // delete it, so this class is used by class unloading also. 1.20 -MetadataOnStackMark::MetadataOnStackMark() { 1.21 +MetadataOnStackMark::MetadataOnStackMark(bool visit_code_cache) { 1.22 assert(SafepointSynchronize::is_at_safepoint(), "sanity check"); 1.23 + assert(_used_buffers == NULL, "sanity check"); 1.24 NOT_PRODUCT(_is_active = true;) 1.25 - if (_marked_objects == NULL) { 1.26 - _marked_objects = new (ResourceObj::C_HEAP, mtClass) GrowableArray<Metadata*>(1000, true); 1.27 - } 1.28 1.29 Threads::metadata_do(Metadata::mark_on_stack); 1.30 - if (JvmtiExport::has_redefined_a_class()) { 1.31 + if (visit_code_cache) { 1.32 CodeCache::alive_nmethods_do(nmethod::mark_on_stack); 1.33 } 1.34 CompileBroker::mark_on_stack(); 1.35 @@ -62,15 +60,93 @@ 1.36 // Unmark everything that was marked. Can't do the same walk because 1.37 // redefine classes messes up the code cache so the set of methods 1.38 // might not be the same. 1.39 - for (int i = 0; i< _marked_objects->length(); i++) { 1.40 - _marked_objects->at(i)->set_on_stack(false); 1.41 + 1.42 + retire_buffer_for_thread(Thread::current()); 1.43 + 1.44 + MetadataOnStackBuffer* buffer = const_cast<MetadataOnStackBuffer* >(_used_buffers); 1.45 + while (buffer != NULL) { 1.46 + // Clear on stack state for all metadata. 1.47 + size_t size = buffer->size(); 1.48 + for (size_t i = 0; i < size; i++) { 1.49 + Metadata* md = buffer->at(i); 1.50 + md->set_on_stack(false); 1.51 + } 1.52 + 1.53 + MetadataOnStackBuffer* next = buffer->next_used(); 1.54 + 1.55 + // Move the buffer to the free list. 1.56 + buffer->clear(); 1.57 + buffer->set_next_used(NULL); 1.58 + buffer->set_next_free(const_cast<MetadataOnStackBuffer*>(_free_buffers)); 1.59 + _free_buffers = buffer; 1.60 + 1.61 + // Step to next used buffer. 1.62 + buffer = next; 1.63 } 1.64 - _marked_objects->clear(); // reuse growable array for next time. 1.65 + 1.66 + _used_buffers = NULL; 1.67 + 1.68 NOT_PRODUCT(_is_active = false;) 1.69 } 1.70 1.71 +void MetadataOnStackMark::retire_buffer(MetadataOnStackBuffer* buffer) { 1.72 + if (buffer == NULL) { 1.73 + return; 1.74 + } 1.75 + 1.76 + MetadataOnStackBuffer* old_head; 1.77 + 1.78 + do { 1.79 + old_head = const_cast<MetadataOnStackBuffer*>(_used_buffers); 1.80 + buffer->set_next_used(old_head); 1.81 + } while (Atomic::cmpxchg_ptr(buffer, &_used_buffers, old_head) != old_head); 1.82 +} 1.83 + 1.84 +void MetadataOnStackMark::retire_buffer_for_thread(Thread* thread) { 1.85 + retire_buffer(thread->metadata_on_stack_buffer()); 1.86 + thread->set_metadata_on_stack_buffer(NULL); 1.87 +} 1.88 + 1.89 +bool MetadataOnStackMark::has_buffer_for_thread(Thread* thread) { 1.90 + return thread->metadata_on_stack_buffer() != NULL; 1.91 +} 1.92 + 1.93 +MetadataOnStackBuffer* MetadataOnStackMark::allocate_buffer() { 1.94 + MetadataOnStackBuffer* allocated; 1.95 + MetadataOnStackBuffer* new_head; 1.96 + 1.97 + do { 1.98 + allocated = const_cast<MetadataOnStackBuffer*>(_free_buffers); 1.99 + if (allocated == NULL) { 1.100 + break; 1.101 + } 1.102 + new_head = allocated->next_free(); 1.103 + } while (Atomic::cmpxchg_ptr(new_head, &_free_buffers, allocated) != allocated); 1.104 + 1.105 + if (allocated == NULL) { 1.106 + allocated = new MetadataOnStackBuffer(); 1.107 + } 1.108 + 1.109 + assert(!allocated->is_full(), err_msg("Should not be full: " PTR_FORMAT, p2i(allocated))); 1.110 + 1.111 + return allocated; 1.112 +} 1.113 + 1.114 // Record which objects are marked so we can unmark the same objects. 1.115 -void MetadataOnStackMark::record(Metadata* m) { 1.116 +void MetadataOnStackMark::record(Metadata* m, Thread* thread) { 1.117 assert(_is_active, "metadata on stack marking is active"); 1.118 - _marked_objects->push(m); 1.119 + 1.120 + MetadataOnStackBuffer* buffer = thread->metadata_on_stack_buffer(); 1.121 + 1.122 + if (buffer != NULL && buffer->is_full()) { 1.123 + retire_buffer(buffer); 1.124 + buffer = NULL; 1.125 + } 1.126 + 1.127 + if (buffer == NULL) { 1.128 + buffer = allocate_buffer(); 1.129 + thread->set_metadata_on_stack_buffer(buffer); 1.130 + } 1.131 + 1.132 + buffer->push(m); 1.133 }