< 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 ***
    VerifyStrings vs;
    _local_table->do_safepoint_scan(vs);
  }
  
  // Verification and comp
! class 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);
--- 800,11 ---
    VerifyStrings vs;
    _local_table->do_safepoint_scan(vs);
  }
  
  // Verification and comp
! 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 ***
  
    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) {}
    bool operator()(WeakHandle* val) {
      oop s = val->resolve();
      if (s == nullptr) {
        return true;
      }
--- 812,11 ---
  
    ResizeableResourceHashtable<oop, bool, AnyObj::C_HEAP, mtInternal,
                                string_hash, string_equals> _table;
   public:
    size_t _errors;
!   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 ***
    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.)
  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);
    }
  
!   int total = (int)_items_count;
    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)) {
--- 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 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;
    }
  
!   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_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 ***
  
      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);
        MetaspaceShared::unrecoverable_writing_error();
      }
  
      objArrayOop primary = oopFactory::new_objArray(vmClasses::Object_klass(), primary_array_length, CHECK);
      objArrayHandle primaryHandle(THREAD, primary);
--- 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_acquire());
        MetaspaceShared::unrecoverable_writing_error();
      }
  
      objArrayOop primary = oopFactory::new_objArray(vmClasses::Object_klass(), primary_array_length, CHECK);
      objArrayHandle primaryHandle(THREAD, primary);

*** 1068,11 ***
    return array;
  };
  
  void StringTable::write_shared_table() {
    _shared_table.reset();
!   CompactHashtableWriter writer((int)_items_count, 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)) {
--- 1088,11 ---
    return array;
  };
  
  void StringTable::write_shared_table() {
    _shared_table.reset();
!   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 >