diff --git a/src/share/vm/classfile/classLoaderData.cpp b/src/share/vm/classfile/classLoaderData.cpp index 1f25e15ee9f18737d9f5ffeeb6c17cd5b22847c7..d6d1312a3292b49b3269917e49c274dd3ea9b24a 100644 --- a/src/share/vm/classfile/classLoaderData.cpp +++ b/src/share/vm/classfile/classLoaderData.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -78,7 +78,7 @@ ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Depen // The null-class-loader should always be kept alive. _keep_alive(is_anonymous || h_class_loader.is_null()), _metaspace(NULL), _unloading(false), _klasses(NULL), - _claimed(0), _jmethod_ids(NULL), _handles(NULL), _deallocate_list(NULL), + _claimed(0), _jmethod_ids(NULL), _handles(), _deallocate_list(NULL), _next(NULL), _dependencies(dependencies), _metaspace_lock(new Mutex(Monitor::leaf+1, "Metaspace allocation lock", true)) { // empty @@ -96,6 +96,45 @@ void ClassLoaderData::Dependencies::init(TRAPS) { _list_head = oopFactory::new_objectArray(2, CHECK); } +ClassLoaderData::ChunkedHandleList::~ChunkedHandleList() { + Chunk* c = _head; + while (c != NULL) { + Chunk* next = c->_next; + delete c; + c = next; + } +} + +oop* ClassLoaderData::ChunkedHandleList::add(oop o) { + if (_head == NULL || _head->_size == Chunk::CAPACITY) { + Chunk* next = new Chunk(_head); + OrderAccess::release_store_ptr(&_head, next); + } + oop* handle = &_head->_data[_head->_size]; + *handle = o; + OrderAccess::release_store(&_head->_size, _head->_size + 1); + return handle; +} + +inline void ClassLoaderData::ChunkedHandleList::oops_do_chunk(OopClosure* f, Chunk* c, const juint size) { + for (juint i = 0; i < size; i++) { + if (c->_data[i] != NULL) { + f->do_oop(&c->_data[i]); + } + } +} + +void ClassLoaderData::ChunkedHandleList::oops_do(OopClosure* f) { + Chunk* head = (Chunk*) OrderAccess::load_ptr_acquire(&_head); + if (head != NULL) { + // Must be careful when reading size of head + oops_do_chunk(f, head, OrderAccess::load_acquire(&head->_size)); + for (Chunk* c = head->_next; c != NULL; c = c->_next) { + oops_do_chunk(f, c, c->_size); + } + } +} + bool ClassLoaderData::claim() { if (_claimed == 1) { return false; @@ -111,7 +150,7 @@ void ClassLoaderData::oops_do(OopClosure* f, KlassClosure* klass_closure, bool m f->do_oop(&_class_loader); _dependencies.oops_do(f); - _handles->oops_do(f); + _handles.oops_do(f); if (klass_closure != NULL) { classes_do(klass_closure); } @@ -342,11 +381,6 @@ ClassLoaderData::~ClassLoaderData() { _metaspace = NULL; // release the metaspace delete m; - // release the handles - if (_handles != NULL) { - JNIHandleBlock::release_block(_handles); - _handles = NULL; - } } // Clear all the JNI handles for methods @@ -406,15 +440,9 @@ Metaspace* ClassLoaderData::metaspace_non_null() { return _metaspace; } -JNIHandleBlock* ClassLoaderData::handles() const { return _handles; } -void ClassLoaderData::set_handles(JNIHandleBlock* handles) { _handles = handles; } - jobject ClassLoaderData::add_handle(Handle h) { MutexLockerEx ml(metaspace_lock(), Mutex::_no_safepoint_check_flag); - if (handles() == NULL) { - set_handles(JNIHandleBlock::allocate_block()); - } - return handles()->allocate_handle(h()); + return (jobject) _handles.add(h()); } // Add this metadata pointer to be freed when it's safe. This is only during @@ -479,7 +507,6 @@ void ClassLoaderData::dump(outputStream * const out) { p2i(class_loader() != NULL ? class_loader()->klass() : NULL), loader_name()); if (claimed()) out->print(" claimed "); if (is_unloading()) out->print(" unloading "); - out->print(" handles " INTPTR_FORMAT, p2i(handles())); out->cr(); if (metaspace_or_null() != NULL) { out->print_cr("metaspace: " INTPTR_FORMAT, p2i(metaspace_or_null())); diff --git a/src/share/vm/classfile/classLoaderData.hpp b/src/share/vm/classfile/classLoaderData.hpp index e12512dc577560432cb26b59d2d3cbb87a1fbc9b..8083b70c5ada909618db71b8bb669fe97b03541c 100644 --- a/src/share/vm/classfile/classLoaderData.hpp +++ b/src/share/vm/classfile/classLoaderData.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -51,7 +51,6 @@ class ClassLoaderData; class JNIMethodBlock; -class JNIHandleBlock; class Metadebug; // GC root for walking class loader data created @@ -145,6 +144,31 @@ class ClassLoaderData : public CHeapObj { void oops_do(OopClosure* f); }; + class ChunkedHandleList VALUE_OBJ_CLASS_SPEC { + struct Chunk : public CHeapObj { + static const size_t CAPACITY = 32; + + oop _data[CAPACITY]; + volatile juint _size; + Chunk* _next; + + Chunk(Chunk* c) : _next(c), _size(0) { } + }; + + Chunk* _head; + + void oops_do_chunk(OopClosure* f, Chunk* c, const juint size); + + public: + ChunkedHandleList() : _head(NULL) {} + ~ChunkedHandleList(); + + // Only one thread at a time can add, guarded by ClassLoaderData::metaspace_lock(). + // However, multiple threads can execute oops_do concurrently with add. + oop* add(oop o); + void oops_do(OopClosure* f); + }; + friend class ClassLoaderDataGraph; friend class ClassLoaderDataGraphKlassIteratorAtomic; friend class ClassLoaderDataGraphMetaspaceIterator; @@ -169,7 +193,8 @@ class ClassLoaderData : public CHeapObj { // Has to be an int because we cas it. Klass* _klasses; // The classes defined by the class loader. - JNIHandleBlock* _handles; // Handles to constant pool arrays + ChunkedHandleList _handles; // Handles to constant pool arrays, etc, which + // have the same life cycle of the corresponding ClassLoader. // These method IDs are created for the class loader and set to NULL when the // class loader is unloaded. They are rarely freed, only for redefine classes @@ -196,9 +221,6 @@ class ClassLoaderData : public CHeapObj { void set_metaspace(Metaspace* m) { _metaspace = m; } - JNIHandleBlock* handles() const; - void set_handles(JNIHandleBlock* handles); - Mutex* metaspace_lock() const { return _metaspace_lock; } // GC interface.