# HG changeset patch # User coleenp # Date 1389119216 18000 # Node ID ce86c36b89210ba81f2b1401658acd0cb0f6bbfc # Parent 1a899ea6b7ede2ea35b5971c40c75086adca88cf 8029178: Parallel class loading test anonymous-simple gets SIGSEGV in Metaspace::contains Summary: Metaspace::contains cannot look at purged metaspaces while CMS concurrently deallocates them. Reviewed-by: mgerdin, sspitsyn, jmasa diff -r 1a899ea6b7ed -r ce86c36b8921 src/share/vm/classfile/classLoaderData.cpp --- a/src/share/vm/classfile/classLoaderData.cpp Tue Jan 07 12:32:57 2014 +0100 +++ b/src/share/vm/classfile/classLoaderData.cpp Tue Jan 07 13:26:56 2014 -0500 @@ -648,12 +648,12 @@ return array; } -#ifndef PRODUCT -// for debugging and hsfind(x) -bool ClassLoaderDataGraph::contains(address x) { - // I think we need the _metaspace_lock taken here because the class loader - // data graph could be changing while we are walking it (new entries added, - // new entries being unloaded, etc). +// For profiling and hsfind() only. Otherwise, this is unsafe (and slow). This +// is done lock free to avoid lock inversion problems. It is safe because +// new ClassLoaderData are added to the end of the CLDG, and only removed at +// safepoint. The _unloading list can be deallocated concurrently with CMS so +// this doesn't look in metaspace for classes that have been unloaded. +bool ClassLoaderDataGraph::contains(const void* x) { if (DumpSharedSpaces) { // There are only two metaspaces to worry about. ClassLoaderData* ncld = ClassLoaderData::the_null_class_loader_data(); @@ -670,16 +670,11 @@ } } - // Could also be on an unloading list which is okay, ie. still allocated - // for a little while. - for (ClassLoaderData* ucld = _unloading; ucld != NULL; ucld = ucld->next()) { - if (ucld->metaspace_or_null() != NULL && ucld->metaspace_or_null()->contains(x)) { - return true; - } - } + // Do not check unloading list because deallocation can be concurrent. return false; } +#ifndef PRODUCT bool ClassLoaderDataGraph::contains_loader_data(ClassLoaderData* loader_data) { for (ClassLoaderData* data = _head; data != NULL; data = data->next()) { if (loader_data == data) { diff -r 1a899ea6b7ed -r ce86c36b8921 src/share/vm/classfile/classLoaderData.hpp --- a/src/share/vm/classfile/classLoaderData.hpp Tue Jan 07 12:32:57 2014 +0100 +++ b/src/share/vm/classfile/classLoaderData.hpp Tue Jan 07 13:26:56 2014 -0500 @@ -90,9 +90,9 @@ static void dump() { dump_on(tty); } static void verify(); + // expensive test for pointer in metaspace for debugging + static bool contains(const void* x); #ifndef PRODUCT - // expensive test for pointer in metaspace for debugging - static bool contains(address x); static bool contains_loader_data(ClassLoaderData* loader_data); #endif diff -r 1a899ea6b7ed -r ce86c36b8921 src/share/vm/code/dependencies.cpp --- a/src/share/vm/code/dependencies.cpp Tue Jan 07 12:32:57 2014 +0100 +++ b/src/share/vm/code/dependencies.cpp Tue Jan 07 13:26:56 2014 -0500 @@ -655,8 +655,6 @@ } else { o = _deps->oop_recorder()->metadata_at(i); } - assert(o == NULL || o->is_metaspace_object(), - err_msg("Should be metadata " PTR_FORMAT, o)); return o; } diff -r 1a899ea6b7ed -r ce86c36b8921 src/share/vm/memory/allocation.cpp --- a/src/share/vm/memory/allocation.cpp Tue Jan 07 12:32:57 2014 +0100 +++ b/src/share/vm/memory/allocation.cpp Tue Jan 07 13:26:56 2014 -0500 @@ -71,9 +71,8 @@ return MetaspaceShared::is_in_shared_space(this); } - bool MetaspaceObj::is_metaspace_object() const { - return Metaspace::contains((void*)this); + return ClassLoaderDataGraph::contains((void*)this); } void MetaspaceObj::print_address_on(outputStream* st) const { diff -r 1a899ea6b7ed -r ce86c36b8921 src/share/vm/memory/allocation.hpp --- a/src/share/vm/memory/allocation.hpp Tue Jan 07 12:32:57 2014 +0100 +++ b/src/share/vm/memory/allocation.hpp Tue Jan 07 13:26:56 2014 -0500 @@ -264,7 +264,7 @@ class MetaspaceObj { public: - bool is_metaspace_object() const; // more specific test but slower + bool is_metaspace_object() const; bool is_shared() const; void print_address_on(outputStream* st) const; // nonvirtual address printing diff -r 1a899ea6b7ed -r ce86c36b8921 src/share/vm/memory/metachunk.hpp --- a/src/share/vm/memory/metachunk.hpp Tue Jan 07 12:32:57 2014 +0100 +++ b/src/share/vm/memory/metachunk.hpp Tue Jan 07 13:26:56 2014 -0500 @@ -143,6 +143,8 @@ void set_is_tagged_free(bool v) { _is_tagged_free = v; } #endif + bool contains(const void* ptr) { return bottom() <= ptr && ptr < _top; } + NOT_PRODUCT(void mangle();) void print_on(outputStream* st) const; diff -r 1a899ea6b7ed -r ce86c36b8921 src/share/vm/memory/metaspace.cpp --- a/src/share/vm/memory/metaspace.cpp Tue Jan 07 12:32:57 2014 +0100 +++ b/src/share/vm/memory/metaspace.cpp Tue Jan 07 13:26:56 2014 -0500 @@ -513,8 +513,6 @@ // Unlink empty VirtualSpaceNodes and free it. void purge(ChunkManager* chunk_manager); - bool contains(const void *ptr); - void print_on(outputStream* st) const; class VirtualSpaceListIterator : public StackObj { @@ -558,7 +556,7 @@ private: - // protects allocations and contains. + // protects allocations Mutex* const _lock; // Type of metadata allocated. @@ -595,7 +593,11 @@ private: // Accessors Metachunk* chunks_in_use(ChunkIndex index) const { return _chunks_in_use[index]; } - void set_chunks_in_use(ChunkIndex index, Metachunk* v) { _chunks_in_use[index] = v; } + void set_chunks_in_use(ChunkIndex index, Metachunk* v) { + // ensure lock-free iteration sees fully initialized node + OrderAccess::storestore(); + _chunks_in_use[index] = v; + } BlockFreelist* block_freelists() const { return (BlockFreelist*) &_block_freelists; @@ -708,6 +710,8 @@ void print_on(outputStream* st) const; void locked_print_chunks_in_use_on(outputStream* st) const; + bool contains(const void *ptr); + void verify(); void verify_chunk_size(Metachunk* chunk); NOT_PRODUCT(void mangle_freed_chunks();) @@ -1159,8 +1163,6 @@ } else { assert(new_entry->reserved_words() == vs_word_size, "Reserved memory size differs from requested memory size"); - // ensure lock-free iteration sees fully initialized node - OrderAccess::storestore(); link_vs(new_entry); return true; } @@ -1287,19 +1289,6 @@ } } -bool VirtualSpaceList::contains(const void *ptr) { - VirtualSpaceNode* list = virtual_space_list(); - VirtualSpaceListIterator iter(list); - while (iter.repeat()) { - VirtualSpaceNode* node = iter.get_next(); - if (node->reserved()->contains(ptr)) { - return true; - } - } - return false; -} - - // MetaspaceGC methods // VM_CollectForMetadataAllocation is the vm operation used to GC. @@ -2392,6 +2381,21 @@ return result; } +// This function looks at the chunks in the metaspace without locking. +// The chunks are added with store ordering and not deleted except for at +// unloading time. +bool SpaceManager::contains(const void *ptr) { + for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) + { + Metachunk* curr = chunks_in_use(i); + while (curr != NULL) { + if (curr->contains(ptr)) return true; + curr = curr->next(); + } + } + return false; +} + void SpaceManager::verify() { // If there are blocks in the dictionary, then // verfication of chunks does not work since @@ -3463,17 +3467,12 @@ } } -bool Metaspace::contains(const void * ptr) { - if (MetaspaceShared::is_in_shared_space(ptr)) { - return true; +bool Metaspace::contains(const void* ptr) { + if (vsm()->contains(ptr)) return true; + if (using_class_space()) { + return class_vsm()->contains(ptr); } - // This is checked while unlocked. As long as the virtualspaces are added - // at the end, the pointer will be in one of them. The virtual spaces - // aren't deleted presently. When they are, some sort of locking might - // be needed. Note, locking this can cause inversion problems with the - // caller in MetaspaceObj::is_metadata() function. - return space_list()->contains(ptr) || - (using_class_space() && class_space_list()->contains(ptr)); + return false; } void Metaspace::verify() { diff -r 1a899ea6b7ed -r ce86c36b8921 src/share/vm/memory/metaspace.hpp --- a/src/share/vm/memory/metaspace.hpp Tue Jan 07 12:32:57 2014 +0100 +++ b/src/share/vm/memory/metaspace.hpp Tue Jan 07 13:26:56 2014 -0500 @@ -225,7 +225,7 @@ MetaWord* expand_and_allocate(size_t size, MetadataType mdtype); - static bool contains(const void *ptr); + bool contains(const void* ptr); void dump(outputStream* const out) const; // Free empty virtualspaces diff -r 1a899ea6b7ed -r ce86c36b8921 src/share/vm/oops/klass.cpp --- a/src/share/vm/oops/klass.cpp Tue Jan 07 12:32:57 2014 +0100 +++ b/src/share/vm/oops/klass.cpp Tue Jan 07 13:26:56 2014 -0500 @@ -376,8 +376,6 @@ } bool Klass::is_loader_alive(BoolObjectClosure* is_alive) { - assert(ClassLoaderDataGraph::contains((address)this), "is in the metaspace"); - #ifdef ASSERT // The class is alive iff the class loader is alive. oop loader = class_loader(); diff -r 1a899ea6b7ed -r ce86c36b8921 src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Tue Jan 07 12:32:57 2014 +0100 +++ b/src/share/vm/runtime/os.cpp Tue Jan 07 13:26:56 2014 -0500 @@ -1081,7 +1081,6 @@ } -#ifndef PRODUCT // Check if in metaspace. if (ClassLoaderDataGraph::contains((address)addr)) { // Use addr->print() from the debugger instead (not here) @@ -1089,7 +1088,6 @@ " is pointing into metadata", addr); return; } -#endif // Try an OS specific find if (os::find(addr, st)) {