< prev index next >

src/hotspot/share/classfile/stringTable.cpp

Print this page
@@ -30,10 +30,11 @@
  #include "classfile/altHashing.hpp"
  #include "classfile/compactHashtable.hpp"
  #include "classfile/javaClasses.inline.hpp"
  #include "classfile/stringTable.hpp"
  #include "classfile/vmClasses.hpp"
+ #include "compiler/compileBroker.hpp"
  #include "gc/shared/collectedHeap.hpp"
  #include "gc/shared/oopStorage.inline.hpp"
  #include "gc/shared/oopStorageSet.hpp"
  #include "gc/shared/stringdedup/stringDedup.hpp"
  #include "logging/log.hpp"

@@ -113,10 +114,11 @@
  volatile bool StringTable::_needs_rehashing = false;
  OopStorage*   StringTable::_oop_storage;
  
  static size_t _current_size = 0;
  static volatile size_t _items_count = 0;
+ DEBUG_ONLY(static bool _disable_interning_during_cds_dump = false);
  
  volatile bool _alt_hash = false;
  
  static bool _rehashed = false;
  static uint64_t _alt_hash_seed = 0;

@@ -344,10 +346,14 @@
  
  bool StringTable::has_work() {
    return Atomic::load_acquire(&_has_work);
  }
  
+ size_t StringTable::items_count_acquire() {
+   return Atomic::load_acquire(&_items_count);
+ }
+ 
  void StringTable::trigger_concurrent_work() {
    // Avoid churn on ServiceThread
    if (!has_work()) {
      MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
      Atomic::store(&_has_work, true);

@@ -502,10 +508,13 @@
    oop result = intern(name, CHECK_NULL);
    return result;
  }
  
  oop StringTable::intern(const StringWrapper& name, TRAPS) {
+   assert(!Atomic::load_acquire(&_disable_interning_during_cds_dump),
+          "All threads that may intern strings should have been stopped before CDS starts copying the interned string table");
+ 
    // shared table always uses java_lang_String::hash_code
    unsigned int hash = hash_wrapped_string(name);
    oop found_string = lookup_shared(name, hash);
    if (found_string != nullptr) {
      return found_string;

@@ -791,11 +800,11 @@
    VerifyStrings vs;
    _local_table->do_safepoint_scan(vs);
  }
  
  // Verification and comp
- class VerifyCompStrings : StackObj {
+ class StringTable::VerifyCompStrings : StackObj {
    static unsigned string_hash(oop const& str) {
      return java_lang_String::hash_code_noupdate(str);
    }
    static bool string_equals(oop const& a, oop const& b) {
      return java_lang_String::equals(a, b);

@@ -803,11 +812,11 @@
  
    ResizeableResourceHashtable<oop, bool, AnyObj::C_HEAP, mtInternal,
                                string_hash, string_equals> _table;
   public:
    size_t _errors;
-   VerifyCompStrings() : _table(unsigned(_items_count / 8) + 1, 0 /* do not resize */), _errors(0) {}
+   VerifyCompStrings() : _table(unsigned(items_count_acquire() / 8) + 1, 0 /* do not resize */), _errors(0) {}
    bool operator()(WeakHandle* val) {
      oop s = val->resolve();
      if (s == nullptr) {
        return true;
      }

@@ -937,24 +946,35 @@
    StringWrapper wrapped_name(name, len);
    // len is required but is already part of StringWrapper, so 0 is used
    return _shared_table.lookup(wrapped_name, java_lang_String::hash_code(name, len), 0);
  }
  
- // This is called BEFORE we enter the CDS safepoint. We can allocate heap objects.
- // This should be called when we know no more strings will be added (which will be easy
- // to guarantee because CDS runs with a single Java thread. See JDK-8253495.)
+ // This is called BEFORE we enter the CDS safepoint. We can still allocate Java object arrays to
+ // be used by the shared strings table.
  void StringTable::allocate_shared_strings_array(TRAPS) {
    if (!CDSConfig::is_dumping_heap()) {
      return;
    }
-   assert(CDSConfig::allow_only_single_java_thread(), "No more interned strings can be added");
  
-   if (_items_count > (size_t)max_jint) {
-     fatal("Too many strings to be archived: %zu", _items_count);
+   CompileBroker::wait_for_no_active_tasks();
+ 
+   precond(CDSConfig::allow_only_single_java_thread());
+ 
+   // At this point, no more strings will be added:
+   // - There's only a single Java thread (this thread). It no longer executes Java bytecodes
+   //   so JIT compilation will eventually stop.
+   // - CompileBroker has no more active tasks, so all JIT requests have been processed.
+ 
+   // This flag will be cleared after intern table dumping has completed, so we can run the
+   // compiler again (for future AOT method compilation, etc).
+   DEBUG_ONLY(Atomic::release_store(&_disable_interning_during_cds_dump, true));
+ 
+   if (items_count_acquire() > (size_t)max_jint) {
+     fatal("Too many strings to be archived: %zu", items_count_acquire());
    }
  
-   int total = (int)_items_count;
+   int total = (int)items_count_acquire();
    size_t single_array_size = objArrayOopDesc::object_size(total);
  
    log_info(aot)("allocated string table for %d strings", total);
  
    if (!ArchiveHeapWriter::is_too_large_to_archive(single_array_size)) {

@@ -970,11 +990,11 @@
  
      if (ArchiveHeapWriter::is_too_large_to_archive(secondary_array_size)) {
        // This can only happen if you have an extremely large number of classes that
        // refer to more than 16384 * 16384 = 26M interned strings! Not a practical concern
        // but bail out for safety.
-       log_error(aot)("Too many strings to be archived: %zu", _items_count);
+       log_error(aot)("Too many strings to be archived: %zu", items_count_acquire());
        MetaspaceShared::unrecoverable_writing_error();
      }
  
      objArrayOop primary = oopFactory::new_objArray(vmClasses::Object_klass(), primary_array_length, CHECK);
      objArrayHandle primaryHandle(THREAD, primary);

@@ -1068,11 +1088,11 @@
    return array;
  };
  
  void StringTable::write_shared_table() {
    _shared_table.reset();
-   CompactHashtableWriter writer((int)_items_count, ArchiveBuilder::string_stats());
+   CompactHashtableWriter writer((int)items_count_acquire(), ArchiveBuilder::string_stats());
  
    int index = 0;
    auto copy_into_shared_table = [&] (WeakHandle* val) {
      oop string = val->peek();
      if (string != nullptr && !ArchiveHeapWriter::is_string_too_large_to_archive(string)) {

@@ -1082,17 +1102,25 @@
      }
      return true;
    };
    _local_table->do_safepoint_scan(copy_into_shared_table);
    writer.dump(&_shared_table, "string");
+ 
+   DEBUG_ONLY(Atomic::release_store(&_disable_interning_during_cds_dump, false));
  }
  
  void StringTable::set_shared_strings_array_index(int root_index) {
    _shared_strings_array_root_index = root_index;
  }
  
  void StringTable::serialize_shared_table_header(SerializeClosure* soc) {
+   if (soc->writing() && !CDSConfig::is_dumping_heap()) {
+     _shared_table.reset();
+     _is_two_dimensional_shared_strings_array = false;
+     _shared_strings_array_root_index = -1;
+   }
+ 
    _shared_table.serialize_header(soc);
  
    if (soc->writing()) {
      // Sanity. Make sure we don't use the shared table at dump time
      _shared_table.reset();
< prev index next >