| /* | |
| * Copyright (c) 2014, 2023, 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 | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| * | |
| */ | |
| #ifndef SHARE_GC_SHARED_STRINGDEDUP_STRINGDEDUPTABLE_HPP | |
| #define SHARE_GC_SHARED_STRINGDEDUP_STRINGDEDUPTABLE_HPP | |
| #include "gc/shared/stringdedup/stringDedup.hpp" | |
| #include "gc/shared/stringdedup/stringDedupStat.hpp" | |
| #include "memory/allStatic.hpp" | |
| #include "oops/typeArrayOop.hpp" | |
| #include "oops/weakHandle.hpp" | |
| #include "utilities/globalDefinitions.hpp" | |
| #include "utilities/macros.hpp" | |
| class OopStorage; | |
| // Provides deduplication. This class keeps track of all the unique byte | |
| // arrays used by deduplicated String objects. | |
| // | |
| // The arrays are in a hashtable, hashed using the bytes in the array. The | |
| // references to the arrays by the hashtable are weak, allowing arrays that | |
| // become unreachable to be collected and their entries pruned from the | |
| // table. The hashtable is dynamically resized to accommodate the current | |
| // number of hashtable entries. There are several command line options | |
| // controlling the growth or shrinkage of the hashtable. | |
| // | |
| // Operations on the table are not thread-safe. Only the deduplication | |
| // thread calls most of the operations on the table. The only exception is | |
| // the GC dead object count notification and the management of its state. | |
| // | |
| // The table supports resizing and removal of entries for byte arrays that | |
| // have become unreferenced. These operations are performed by the | |
| // deduplication thread, in a series of small incremental steps. This | |
| // prevents these potentially long running operations from long blockage of | |
| // safepoints or concurrent deduplication requests from the StringTable. | |
| // | |
| // As a space optimization, when shared StringTable entries exist the shared | |
| // part of the StringTable is also used as a source for byte arrays. This | |
| // permits deduplication of strings against those shared entries without | |
| // recording them in this table too. | |
| class StringDedup::Table : AllStatic { | |
| private: | |
| class Bucket; | |
| class CleanupState; | |
| class Resizer; | |
| class Cleaner; | |
| enum class DeadState; | |
| // Values in the table are weak references to jbyte[] Java objects. The | |
| // String's coder isn't recorded, even though it affects how String access | |
| // would interpret that array. For the purposes of deduplication we don't | |
| // care about that distinction; two Strings with equivalent arrays but | |
| // different coders can be deduplicated to share a single array. We also | |
| // can't depend on the coder value being correct here, since GC requests | |
| // can provide the deduplication thread with access to a String that is | |
| // incompletely constructed; the value could be set before the coder. | |
| using TableValue = WeakHandle; | |
| // Weak storage for the string data in the table. | |
| static OopStorage* _table_storage; | |
| static Bucket* _buckets; | |
| static size_t _number_of_buckets; | |
| static size_t _number_of_entries; | |
| static size_t _grow_threshold; | |
| static CleanupState* _cleanup_state; | |
| static bool _need_bucket_shrinking; | |
| // These are always written while holding StringDedup_lock, but may be | |
| // read by the dedup thread without holding the lock lock. | |
| static volatile size_t _dead_count; | |
| static volatile DeadState _dead_state; | |
| static uint compute_hash(typeArrayOop obj); | |
| static size_t hash_to_index(uint hash_code); | |
| static void add(TableValue tv, uint hash_code); | |
| static TableValue find(typeArrayOop obj, uint hash_code); | |
| static void install(typeArrayOop obj, uint hash_code); | |
| static bool deduplicate_if_permitted(oop java_string, typeArrayOop value); | |
| static bool try_deduplicate_shared(oop java_string); | |
| static bool try_deduplicate_found_shared(oop java_string, oop found); | |
| static Bucket* make_buckets(size_t number_of_buckets, size_t reserve = 0); | |
| static void free_buckets(Bucket* buckets, size_t number_of_buckets); | |
| static bool start_resizer(bool grow_only, size_t number_of_entries); | |
| static bool start_cleaner(size_t number_of_entries, size_t dead_count); | |
| static void num_dead_callback(size_t num_dead); | |
| static bool is_dead_count_good_acquire(); | |
| static void set_dead_state_cleaning(); | |
| public: | |
| static void initialize_storage(); | |
| static void initialize(); | |
| // Deduplicate java_string. If the table already contains the string's | |
| // data array, replace the string's data array with the one in the table. | |
| // Otherwise, add the string's data array to the table. | |
| static void deduplicate(oop java_string); | |
| // Returns true if table needs to grow. | |
| static bool is_grow_needed(); | |
| // Returns true if there are enough dead entries to need cleanup. | |
| static bool is_dead_entry_removal_needed(); | |
| // If cleanup (resizing or removing dead entries) is needed or force | |
| // is true, setup cleanup state and return true. If result is true, | |
| // the caller must eventually call cleanup_end. | |
| // precondition: no cleanup is in progress. | |
| static bool cleanup_start_if_needed(bool grow_only, bool force); | |
| // Perform some cleanup work. Returns true if any progress was made, | |
| // false if there is no further work to do. | |
| // precondition: a cleanup is in progress. | |
| static bool cleanup_step(); | |
| // Record the cleanup complete and cleanup state. | |
| // precondition: a cleanup is in progress. | |
| static void cleanup_end(); | |
| static void verify(); | |
| static void log_statistics(); | |
| }; | |
| #endif // SHARE_GC_SHARED_STRINGDEDUP_STRINGDEDUPTABLE_HPP |