diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp index be2971288ef..b01ecb24ac9 100644 --- a/src/hotspot/share/classfile/stringTable.cpp +++ b/src/hotspot/share/classfile/stringTable.cpp @@ -55,6 +55,7 @@ #include "runtime/safepointVerifiers.hpp" #include "runtime/timerTrace.hpp" #include "runtime/trimNativeHeap.hpp" +#include "runtime/vmOperations.hpp" #include "services/diagnosticCommand.hpp" #include "utilities/concurrentHashTable.inline.hpp" #include "utilities/concurrentHashTableTasks.inline.hpp" @@ -267,10 +268,17 @@ size_t StringTable::table_size() { return ((size_t)1) << _local_table->get_size_log2(Thread::current()); } +bool StringTable::has_work() { + return Atomic::load_acquire(&_has_work); +} + void StringTable::trigger_concurrent_work() { - MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); - Atomic::store(&_has_work, true); - Service_lock->notify_all(); + // Avoid churn on ServiceThread + if (!has_work()) { + MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); + Atomic::store(&_has_work, true); + Service_lock->notify_all(); + } } // Probing @@ -308,6 +316,13 @@ class StringTableGet : public StackObj { } }; +void StringTable::update_needs_rehash(bool rehash) { + if (rehash) { + _needs_rehashing = true; + trigger_concurrent_work(); + } +} + oop StringTable::do_lookup(const jchar* name, int len, uintx hash) { Thread* thread = Thread::current(); StringTableLookupJchar lookup(thread, hash, name, len); @@ -499,15 +514,20 @@ void StringTable::gc_notification(size_t num_dead) { } } -bool StringTable::has_work() { - return Atomic::load_acquire(&_has_work); +bool StringTable::should_grow() { + return get_load_factor() > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached(); } void StringTable::do_concurrent_work(JavaThread* jt) { - double load_factor = get_load_factor(); - log_debug(stringtable, perf)("Concurrent work, live factor: %g", load_factor); + // Rehash if needed. Rehashing goes to a safepoint but the rest of this + // work is concurrent. + if (needs_rehashing() && maybe_rehash_table()) { + Atomic::release_store(&_has_work, false); + return; // done, else grow + } + log_debug(stringtable, perf)("Concurrent work, live factor: %g", get_load_factor()); // We prefer growing, since that also removes dead items - if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) { + if (should_grow()) { grow(jt); } else { clean_dead_entries(jt); @@ -515,85 +535,48 @@ void StringTable::do_concurrent_work(JavaThread* jt) { Atomic::release_store(&_has_work, false); } -// Rehash -bool StringTable::do_rehash() { - if (!_local_table->is_safepoint_safe()) { - return false; - } +// Called at VM_Operation safepoint +void StringTable::rehash_table() { + assert(SafepointSynchronize::is_at_safepoint(), "must be called at safepoint"); + // The ServiceThread initiates the rehashing so it is not resizing. + assert (_local_table->is_safepoint_safe(), "Should not be resizing now"); + + _alt_hash_seed = AltHashing::compute_seed(); // We use current size, not max size. size_t new_size = _local_table->get_size_log2(Thread::current()); StringTableHash* new_table = new StringTableHash(new_size, END_SIZE, REHASH_LEN, true); // Use alt hash from now on _alt_hash = true; - if (!_local_table->try_move_nodes_to(Thread::current(), new_table)) { - _alt_hash = false; - delete new_table; - return false; - } + _local_table->rehash_nodes_to(Thread::current(), new_table); // free old table delete _local_table; _local_table = new_table; - return true; + _rehashed = true; + _needs_rehashing = false; } -bool StringTable::should_grow() { - return get_load_factor() > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached(); -} - -bool StringTable::rehash_table_expects_safepoint_rehashing() { - // No rehashing required - if (!needs_rehashing()) { - return false; - } - - // Grow instead of rehash - if (should_grow()) { - return false; - } - - // Already rehashed - if (_rehashed) { - return false; - } - - // Resizing in progress - if (!_local_table->is_safepoint_safe()) { - return false; - } - - return true; -} - -void StringTable::rehash_table() { +bool StringTable::maybe_rehash_table() { log_debug(stringtable)("Table imbalanced, rehashing called."); // Grow instead of rehash. if (should_grow()) { log_debug(stringtable)("Choosing growing over rehashing."); - trigger_concurrent_work(); _needs_rehashing = false; - return; + return false; } // Already rehashed. if (_rehashed) { log_warning(stringtable)("Rehashing already done, still long lists."); - trigger_concurrent_work(); _needs_rehashing = false; - return; + return false; } - _alt_hash_seed = AltHashing::compute_seed(); - { - if (do_rehash()) { - _rehashed = true; - } else { - log_info(stringtable)("Resizes in progress rehashing skipped."); - } - } - _needs_rehashing = false; + VM_RehashStringTable op; + VMThread::execute(&op); + return true; // return true because we tried. } // Statistics diff --git a/src/hotspot/share/classfile/stringTable.hpp b/src/hotspot/share/classfile/stringTable.hpp index 02723a42f42..9f49e797182 100644 --- a/src/hotspot/share/classfile/stringTable.hpp +++ b/src/hotspot/share/classfile/stringTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -71,8 +71,6 @@ class StringTable : AllStatic { static void print_table_statistics(outputStream* st); - static bool do_rehash(); - public: static size_t table_size(); static TableStatistics get_table_statistics(); @@ -94,16 +92,11 @@ class StringTable : AllStatic { // Rehash the string table if it gets out of balance private: static bool should_grow(); - + static bool maybe_rehash_table(); public: - static bool rehash_table_expects_safepoint_rehashing(); static void rehash_table(); static bool needs_rehashing() { return _needs_rehashing; } - static inline void update_needs_rehash(bool rehash) { - if (rehash) { - _needs_rehashing = true; - } - } + static inline void update_needs_rehash(bool rehash); // Sharing #if INCLUDE_CDS_JAVA_HEAP diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp index 53c6bb06bec..1fbc49947bf 100644 --- a/src/hotspot/share/classfile/symbolTable.cpp +++ b/src/hotspot/share/classfile/symbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -246,10 +246,15 @@ size_t SymbolTable::table_size() { return ((size_t)1) << _local_table->get_size_log2(Thread::current()); } +bool SymbolTable::has_work() { return Atomic::load_acquire(&_has_work); } + void SymbolTable::trigger_cleanup() { - MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); - _has_work = true; - Service_lock->notify_all(); + // Avoid churn on ServiceThread + if (!has_work()) { + MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag); + _has_work = true; + Service_lock->notify_all(); + } } class SymbolsDo : StackObj { @@ -413,6 +418,13 @@ public: } }; +void SymbolTable::update_needs_rehash(bool rehash) { + if (rehash) { + _needs_rehashing = true; + trigger_cleanup(); + } +} + Symbol* SymbolTable::do_lookup(const char* name, int len, uintx hash) { Thread* thread = Thread::current(); SymbolTableLookup lookup(name, len, hash); @@ -772,7 +784,7 @@ void SymbolTable::clean_dead_entries(JavaThread* jt) { } void SymbolTable::check_concurrent_work() { - if (_has_work) { + if (has_work()) { return; } // We should clean/resize if we have @@ -785,98 +797,70 @@ void SymbolTable::check_concurrent_work() { } } +bool SymbolTable::should_grow() { + return get_load_factor() > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached(); +} + void SymbolTable::do_concurrent_work(JavaThread* jt) { - double load_factor = get_load_factor(); - log_debug(symboltable, perf)("Concurrent work, live factor: %g", load_factor); + // Rehash if needed. Rehashing goes to a safepoint but the rest of this + // work is concurrent. + if (needs_rehashing() && maybe_rehash_table()) { + Atomic::release_store(&_has_work, false); + return; // done, else grow + } + log_debug(symboltable, perf)("Concurrent work, live factor: %g", get_load_factor()); // We prefer growing, since that also removes dead items - if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) { + if (should_grow()) { grow(jt); } else { clean_dead_entries(jt); } - _has_work = false; + Atomic::release_store(&_has_work, false); } -// Rehash -bool SymbolTable::do_rehash() { - if (!_local_table->is_safepoint_safe()) { - return false; - } +// Called at VM_Operation safepoint +void SymbolTable::rehash_table() { + assert(SafepointSynchronize::is_at_safepoint(), "must be called at safepoint"); + // The ServiceThread initiates the rehashing so it is not resizing. + assert (_local_table->is_safepoint_safe(), "Should not be resizing now"); + + _alt_hash_seed = AltHashing::compute_seed(); // We use current size size_t new_size = _local_table->get_size_log2(Thread::current()); SymbolTableHash* new_table = new SymbolTableHash(new_size, END_SIZE, REHASH_LEN, true); // Use alt hash from now on _alt_hash = true; - if (!_local_table->try_move_nodes_to(Thread::current(), new_table)) { - _alt_hash = false; - delete new_table; - return false; - } + _local_table->rehash_nodes_to(Thread::current(), new_table); // free old table delete _local_table; _local_table = new_table; - return true; + _rehashed = true; + _needs_rehashing = false; } -bool SymbolTable::should_grow() { - return get_load_factor() > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached(); -} - -bool SymbolTable::rehash_table_expects_safepoint_rehashing() { - // No rehashing required - if (!needs_rehashing()) { - return false; - } - - // Grow instead of rehash - if (should_grow()) { - return false; - } - - // Already rehashed - if (_rehashed) { - return false; - } - - // Resizing in progress - if (!_local_table->is_safepoint_safe()) { - return false; - } - - return true; -} - -void SymbolTable::rehash_table() { +bool SymbolTable::maybe_rehash_table() { log_debug(symboltable)("Table imbalanced, rehashing called."); // Grow instead of rehash. if (should_grow()) { log_debug(symboltable)("Choosing growing over rehashing."); - trigger_cleanup(); _needs_rehashing = false; - return; + return false; } // Already rehashed. if (_rehashed) { log_warning(symboltable)("Rehashing already done, still long lists."); - trigger_cleanup(); _needs_rehashing = false; - return; + return false; } - _alt_hash_seed = AltHashing::compute_seed(); - - if (do_rehash()) { - _rehashed = true; - } else { - log_info(symboltable)("Resizes in progress rehashing skipped."); - } - - _needs_rehashing = false; + VM_RehashSymbolTable op; + VMThread::execute(&op); + return true; } //--------------------------------------------------------------------------- diff --git a/src/hotspot/share/classfile/symbolTable.hpp b/src/hotspot/share/classfile/symbolTable.hpp index 282dd574c68..a1e585e97de 100644 --- a/src/hotspot/share/classfile/symbolTable.hpp +++ b/src/hotspot/share/classfile/symbolTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -98,7 +98,6 @@ class SymbolTable : public AllStatic { static void print_table_statistics(outputStream* st); static void try_rehash_table(); - static bool do_rehash(); public: // The symbol table @@ -114,7 +113,7 @@ public: static void create_table(); static void do_concurrent_work(JavaThread* jt); - static bool has_work() { return _has_work; } + static bool has_work(); static void trigger_cleanup(); // Probing @@ -146,16 +145,12 @@ public: // Rehash the string table if it gets out of balance private: static bool should_grow(); + static bool maybe_rehash_table(); public: - static bool rehash_table_expects_safepoint_rehashing(); static void rehash_table(); static bool needs_rehashing() { return _needs_rehashing; } - static inline void update_needs_rehash(bool rehash) { - if (rehash) { - _needs_rehashing = true; - } - } + static inline void update_needs_rehash(bool rehash); // Heap dumper and CDS static void symbols_do(SymbolClosure *cl); diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index a04f1945a5e..47db0bcb625 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -23,9 +23,6 @@ */ #include "precompiled.hpp" -#include "classfile/classLoaderDataGraph.hpp" -#include "classfile/stringTable.hpp" -#include "classfile/symbolTable.hpp" #include "code/codeCache.hpp" #include "code/nmethod.hpp" #include "code/pcDesc.hpp" @@ -510,13 +507,6 @@ void SafepointSynchronize::end() { post_safepoint_end_event(event, safepoint_id()); } -bool SafepointSynchronize::is_cleanup_needed() { - // Need a safepoint if some inline cache buffers is non-empty - if (StringTable::needs_rehashing()) return true; - if (SymbolTable::needs_rehashing()) return true; - return false; -} - class ParallelCleanupTask : public WorkerTask { private: SubTasksDone _subtasks; @@ -548,14 +538,6 @@ public: uint expected_num_workers() const { uint workers = 0; - if (SymbolTable::rehash_table_expects_safepoint_rehashing()) { - workers++; - } - - if (StringTable::rehash_table_expects_safepoint_rehashing()) { - workers++; - } - if (_do_lazy_roots) { workers++; } @@ -564,21 +546,6 @@ public: } void work(uint worker_id) { - // These tasks are ordered by relative length of time to execute so that potentially longer tasks start first. - if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH)) { - if (SymbolTable::needs_rehashing()) { - Tracer t("rehashing symbol table"); - SymbolTable::rehash_table(); - } - } - - if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_STRING_TABLE_REHASH)) { - if (StringTable::needs_rehashing()) { - Tracer t("rehashing string table"); - StringTable::rehash_table(); - } - } - if (_subtasks.try_claim_task(SafepointSynchronize::SAFEPOINT_CLEANUP_LAZY_ROOT_PROCESSING)) { if (_do_lazy_roots) { Tracer t("lazy partial thread root processing"); diff --git a/src/hotspot/share/runtime/safepoint.hpp b/src/hotspot/share/runtime/safepoint.hpp index f6da9881e4c..84db745d3ca 100644 --- a/src/hotspot/share/runtime/safepoint.hpp +++ b/src/hotspot/share/runtime/safepoint.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -71,8 +71,6 @@ class SafepointSynchronize : AllStatic { // The enums are listed in the order of the tasks when done serially. enum SafepointCleanupTasks { SAFEPOINT_CLEANUP_LAZY_ROOT_PROCESSING, - SAFEPOINT_CLEANUP_SYMBOL_TABLE_REHASH, - SAFEPOINT_CLEANUP_STRING_TABLE_REHASH, SAFEPOINT_CLEANUP_REQUEST_OOPSTORAGE_CLEANUP, // Leave this one last. SAFEPOINT_CLEANUP_NUM_TASKS @@ -158,7 +156,6 @@ public: // Exception handling for page polling static void handle_polling_page_exception(JavaThread *thread); - static bool is_cleanup_needed(); static void do_cleanup_tasks(); static void set_is_at_safepoint() { _state = _synchronized; } diff --git a/src/hotspot/share/runtime/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp index d6fac3f14f1..b6625a1d946 100644 --- a/src/hotspot/share/runtime/vmOperation.hpp +++ b/src/hotspot/share/runtime/vmOperation.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -37,7 +37,6 @@ #define VM_OPS_DO(template) \ template(Halt) \ template(SafepointALot) \ - template(Cleanup) \ template(ThreadDump) \ template(PrintThreads) \ template(FindDeadlocks) \ @@ -106,6 +105,8 @@ template(ClassLoaderHierarchyOperation) \ template(DumpHashtable) \ template(CleanClassLoaderDataMetaspaces) \ + template(RehashStringTable) \ + template(RehashSymbolTable) \ template(PrintCompileQueue) \ template(PrintClassHierarchy) \ template(PrintClasses) \ diff --git a/src/hotspot/share/runtime/vmOperations.cpp b/src/hotspot/share/runtime/vmOperations.cpp index 3469e3f2cc0..af9911e0fdc 100644 --- a/src/hotspot/share/runtime/vmOperations.cpp +++ b/src/hotspot/share/runtime/vmOperations.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "classfile/classLoaderDataGraph.hpp" +#include "classfile/stringTable.hpp" +#include "classfile/symbolTable.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" #include "compiler/compileBroker.hpp" @@ -103,6 +105,14 @@ void VM_CleanClassLoaderDataMetaspaces::doit() { ClassLoaderDataGraph::walk_metadata_and_clean_metaspaces(); } +void VM_RehashStringTable::doit() { + StringTable::rehash_table(); +} + +void VM_RehashSymbolTable::doit() { + SymbolTable::rehash_table(); +} + VM_DeoptimizeFrame::VM_DeoptimizeFrame(JavaThread* thread, intptr_t* id, int reason) { _thread = thread; _id = id; diff --git a/src/hotspot/share/runtime/vmOperations.hpp b/src/hotspot/share/runtime/vmOperations.hpp index 8778fe29ade..5ccf689eaf3 100644 --- a/src/hotspot/share/runtime/vmOperations.hpp +++ b/src/hotspot/share/runtime/vmOperations.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, 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 @@ -54,11 +54,6 @@ class VM_SafepointALot: public VM_EmptyOperation { VMOp_Type type() const { return VMOp_SafepointALot; } }; -class VM_Cleanup: public VM_EmptyOperation { - public: - VMOp_Type type() const { return VMOp_Cleanup; } -}; - // empty vm op, evaluated just to force a safepoint class VM_ForceSafepoint: public VM_EmptyOperation { public: @@ -98,6 +93,20 @@ class VM_CleanClassLoaderDataMetaspaces : public VM_Operation { void doit(); }; +class VM_RehashStringTable : public VM_Operation { + public: + VM_RehashStringTable() {} + VMOp_Type type() const { return VMOp_RehashStringTable; } + void doit(); +}; + +class VM_RehashSymbolTable : public VM_Operation { + public: + VM_RehashSymbolTable() {} + VMOp_Type type() const { return VMOp_RehashSymbolTable; } + void doit(); +}; + // Deopt helper that can deoptimize frames in threads other than the // current thread. Only used through Deoptimization::deoptimize_frame. class VM_DeoptimizeFrame: public VM_Operation { diff --git a/src/hotspot/share/runtime/vmThread.cpp b/src/hotspot/share/runtime/vmThread.cpp index 846bbffe106..de0567ab037 100644 --- a/src/hotspot/share/runtime/vmThread.cpp +++ b/src/hotspot/share/runtime/vmThread.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2024, 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 @@ -98,14 +98,14 @@ void VMOperationTimeoutTask::disarm() { // Implementation of VMThread stuff static VM_SafepointALot safepointALot_op; -static VM_Cleanup cleanup_op; +static VM_ForceSafepoint no_op; bool VMThread::_should_terminate = false; bool VMThread::_terminated = false; Monitor* VMThread::_terminate_lock = nullptr; VMThread* VMThread::_vm_thread = nullptr; VM_Operation* VMThread::_cur_vm_operation = nullptr; -VM_Operation* VMThread::_next_vm_operation = &cleanup_op; // Prevent any thread from setting an operation until VM thread is ready. +VM_Operation* VMThread::_next_vm_operation = &no_op; // Prevent any thread from setting an operation until VM thread is ready. PerfCounter* VMThread::_perf_accumulated_vm_operation_time = nullptr; VMOperationTimeoutTask* VMThread::_timeout_task = nullptr; @@ -337,9 +337,7 @@ void VMThread::setup_periodic_safepoint_if_needed() { if (!max_time_exceeded) { return; } - if (SafepointSynchronize::is_cleanup_needed()) { - _next_vm_operation = &cleanup_op; - } else if (SafepointALot) { + if (SafepointALot) { _next_vm_operation = &safepointALot_op; } } @@ -499,7 +497,7 @@ void VMThread::loop() { // Need to set a calling thread for ops not passed // via the normal way. - cleanup_op.set_calling_thread(_vm_thread); + no_op.set_calling_thread(_vm_thread); safepointALot_op.set_calling_thread(_vm_thread); while (true) { diff --git a/src/hotspot/share/utilities/concurrentHashTable.hpp b/src/hotspot/share/utilities/concurrentHashTable.hpp index fe6fdb0a95e..c7d5832048c 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.hpp @@ -524,8 +524,9 @@ class ConcurrentHashTable : public CHeapObj { void statistics_to(Thread* thread, VALUE_SIZE_FUNC& vs_f, outputStream* st, const char* table_name); - // Moves all nodes from this table to to_cht - bool try_move_nodes_to(Thread* thread, ConcurrentHashTable* to_cht); + // Moves all nodes from this table to to_cht with new hash code. + // Must be done at a safepoint. + void rehash_nodes_to(Thread* thread, ConcurrentHashTable* to_cht); // Scoped multi getter. class MultiGetHandle : private ScopedCS { diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index 21277853089..2b30e664109 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -1288,12 +1288,10 @@ inline void ConcurrentHashTable:: } template -inline bool ConcurrentHashTable:: - try_move_nodes_to(Thread* thread, ConcurrentHashTable* to_cht) +inline void ConcurrentHashTable:: + rehash_nodes_to(Thread* thread, ConcurrentHashTable* to_cht) { - if (!try_resize_lock(thread)) { - return false; - } + assert(is_safepoint_safe(), "rehashing is at a safepoint - cannot be resizing"); assert(_new_table == nullptr || _new_table == POISON_PTR, "Must be null"); for (size_t bucket_it = 0; bucket_it < _table->_size; bucket_it++) { Bucket* bucket = _table->get_bucket(bucket_it); @@ -1313,8 +1311,6 @@ inline bool ConcurrentHashTable:: } } } - unlock_resize_lock(thread); - return true; } #endif // SHARE_UTILITIES_CONCURRENTHASHTABLE_INLINE_HPP diff --git a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp index 426e8cb9bfd..47231b414ad 100644 --- a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp +++ b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp @@ -399,7 +399,8 @@ static void cht_move_to(Thread* thr) { EXPECT_TRUE(from_cht->insert(thr, stl3, val3)) << "Insert unique value failed."; SimpleTestTable* to_cht = new SimpleTestTable(); - EXPECT_TRUE(from_cht->try_move_nodes_to(thr, to_cht)) << "Moving nodes to new table failed"; + // This is single threaded and not shared + from_cht->rehash_nodes_to(thr, to_cht); ChtCountScan scan_old; EXPECT_TRUE(from_cht->try_scan(thr, scan_old)) << "Scanning table should work.";