Wed, 26 Apr 2017 10:40:06 -0400
8168914: Crash in ClassLoaderData/JNIHandleBlock::oops_do during concurrent marking
Reviewed-by: dholmes, ehelin
src/share/vm/classfile/classLoaderData.cpp | file | annotate | diff | comparison | revisions | |
src/share/vm/classfile/classLoaderData.hpp | file | annotate | diff | comparison | revisions |
1.1 --- a/src/share/vm/classfile/classLoaderData.cpp Thu Apr 20 04:53:33 2017 -0400 1.2 +++ b/src/share/vm/classfile/classLoaderData.cpp Wed Apr 26 10:40:06 2017 -0400 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -78,7 +78,7 @@ 1.11 // The null-class-loader should always be kept alive. 1.12 _keep_alive(is_anonymous || h_class_loader.is_null()), 1.13 _metaspace(NULL), _unloading(false), _klasses(NULL), 1.14 - _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), 1.15 + _claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL), 1.16 _next(NULL), _dependencies(dependencies), 1.17 _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) { 1.18 // empty 1.19 @@ -96,6 +96,45 @@ 1.20 _list_head = oopFactory::new_objectArray(2, CHECK); 1.21 } 1.22 1.23 +ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() { 1.24 + Chunk* c = _head; 1.25 + while (c != NULL) { 1.26 + Chunk* next = c->_next; 1.27 + delete c; 1.28 + c = next; 1.29 + } 1.30 +} 1.31 + 1.32 +oop* ClassLoaderData::ChunkedHandleList::add(oop o) { 1.33 + if (_head == NULL || _head->_size == Chunk::CAPACITY) { 1.34 + Chunk* next = new Chunk(_head); 1.35 + OrderAccess::release_store_ptr(&_head, next); 1.36 + } 1.37 + oop* handle = &_head->_data[_head->_size]; 1.38 + *handle = o; 1.39 + OrderAccess::release_store(&_head->_size, _head->_size + 1); 1.40 + return handle; 1.41 +} 1.42 + 1.43 +inline void ClassLoaderData::ChunkedHandleList::oops_do_chunk(OopClosure* f, Chunk* c, const juint size) { 1.44 + for (juint i = 0; i < size; i++) { 1.45 + if (c->_data[i] != NULL) { 1.46 + f->do_oop(&c->_data[i]); 1.47 + } 1.48 + } 1.49 +} 1.50 + 1.51 +void ClassLoaderData::ChunkedHandleList::oops_do(OopClosure* f) { 1.52 + Chunk* head = (Chunk*) OrderAccess::load_ptr_acquire(&_head); 1.53 + if (head != NULL) { 1.54 + // Must be careful when reading size of head 1.55 + oops_do_chunk(f, head, OrderAccess::load_acquire(&head->_size)); 1.56 + for (Chunk* c = head->_next; c != NULL; c = c->_next) { 1.57 + oops_do_chunk(f, c, c->_size); 1.58 + } 1.59 + } 1.60 +} 1.61 + 1.62 bool ClassLoaderData::claim() { 1.63 if (_claimed == 1) { 1.64 return false; 1.65 @@ -111,7 +150,7 @@ 1.66 1.67 f->do_oop(&_class_loader); 1.68 _dependencies.oops_do(f); 1.69 - _handles->oops_do(f); 1.70 + _handles.oops_do(f); 1.71 if (klass_closure != NULL) { 1.72 classes_do(klass_closure); 1.73 } 1.74 @@ -342,11 +381,6 @@ 1.75 _metaspace = NULL; 1.76 // release the metaspace 1.77 delete m; 1.78 - // release the handles 1.79 - if (_handles != NULL) { 1.80 - JNIHandleBlock::release_block(_handles); 1.81 - _handles = NULL; 1.82 - } 1.83 } 1.84 1.85 // Clear all the JNI handles for methods 1.86 @@ -406,15 +440,9 @@ 1.87 return _metaspace; 1.88 } 1.89 1.90 -JNIHandleBlock* ClassLoaderData::handles() const { return _handles; } 1.91 -void ClassLoaderData::set_handles(JNIHandleBlock* handles) { _handles = handles; } 1.92 - 1.93 jobject ClassLoaderData::add_handle(Handle h) { 1.94 MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); 1.95 - if (handles() == NULL) { 1.96 - set_handles(JNIHandleBlock::allocate_block()); 1.97 - } 1.98 - return handles()->allocate_handle(h()); 1.99 + return (jobject) _handles.add(h()); 1.100 } 1.101 1.102 // Add this metadata pointer to be freed when it's safe. This is only during 1.103 @@ -479,7 +507,6 @@ 1.104 p2i(class_loader() != NULL ? class_loader()->klass() : NULL), loader_name()); 1.105 if (claimed()) out->print(" claimed "); 1.106 if (is_unloading()) out->print(" unloading "); 1.107 - out->print(" handles " INTPTR_FORMAT, p2i(handles())); 1.108 out->cr(); 1.109 if (metaspace_or_null() != NULL) { 1.110 out->print_cr("metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null()));
2.1 --- a/src/share/vm/classfile/classLoaderData.hpp Thu Apr 20 04:53:33 2017 -0400 2.2 +++ b/src/share/vm/classfile/classLoaderData.hpp Wed Apr 26 10:40:06 2017 -0400 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. 2.6 + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. 2.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.8 * 2.9 * This code is free software; you can redistribute it and/or modify it 2.10 @@ -51,7 +51,6 @@ 2.11 2.12 class ClassLoaderData; 2.13 class JNIMethodBlock; 2.14 -class JNIHandleBlock; 2.15 class Metadebug; 2.16 2.17 // GC root for walking class loader data created 2.18 @@ -145,6 +144,31 @@ 2.19 void oops_do(OopClosure* f); 2.20 }; 2.21 2.22 + class ChunkedHandleList VALUE_OBJ_CLASS_SPEC { 2.23 + struct Chunk : public CHeapObj<mtClass> { 2.24 + static const size_t CAPACITY = 32; 2.25 + 2.26 + oop _data[CAPACITY]; 2.27 + volatile juint _size; 2.28 + Chunk* _next; 2.29 + 2.30 + Chunk(Chunk* c) : _next(c), _size(0) { } 2.31 + }; 2.32 + 2.33 + Chunk* _head; 2.34 + 2.35 + void oops_do_chunk(OopClosure* f, Chunk* c, const juint size); 2.36 + 2.37 + public: 2.38 + ChunkedHandleList() : _head(NULL) {} 2.39 + ~ChunkedHandleList(); 2.40 + 2.41 + // Only one thread at a time can add, guarded by ClassLoaderData::metaspace_lock(). 2.42 + // However, multiple threads can execute oops_do concurrently with add. 2.43 + oop* add(oop o); 2.44 + void oops_do(OopClosure* f); 2.45 + }; 2.46 + 2.47 friend class ClassLoaderDataGraph; 2.48 friend class ClassLoaderDataGraphKlassIteratorAtomic; 2.49 friend class ClassLoaderDataGraphMetaspaceIterator; 2.50 @@ -169,7 +193,8 @@ 2.51 // Has to be an int because we cas it. 2.52 Klass* _klasses; // The classes defined by the class loader. 2.53 2.54 - JNIHandleBlock* _handles; // Handles to constant pool arrays 2.55 + ChunkedHandleList _handles; // Handles to constant pool arrays, etc, which 2.56 + // have the same life cycle of the corresponding ClassLoader. 2.57 2.58 // These method IDs are created for the class loader and set to NULL when the 2.59 // class loader is unloaded. They are rarely freed, only for redefine classes 2.60 @@ -196,9 +221,6 @@ 2.61 2.62 void set_metaspace(Metaspace* m) { _metaspace = m; } 2.63 2.64 - JNIHandleBlock* handles() const; 2.65 - void set_handles(JNIHandleBlock* handles); 2.66 - 2.67 Mutex* metaspace_lock() const { return _metaspace_lock; } 2.68 2.69 // GC interface.