8168914: Crash in ClassLoaderData/JNIHandleBlock::oops_do during concurrent marking

Wed, 26 Apr 2017 10:40:06 -0400

author
shshahma
date
Wed, 26 Apr 2017 10:40:06 -0400
changeset 8762
654eaca01d61
parent 8761
4c3cae5323bb
child 8763
afff7bd98f7d

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.

mercurial