Skip to content

Commit be0a655

Browse files
Kim Barrettzhengyu123
andcommitted
8254598: StringDedupTable should use OopStorage
Co-authored-by: Kim Barrett <kbarrett@openjdk.org> Co-authored-by: Zhengyu Gu <zgu@openjdk.org> Reviewed-by: coleenp, iklam, tschatzl, ayang
1 parent 360928d commit be0a655

File tree

97 files changed

+2315
-3150
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

97 files changed

+2315
-3150
lines changed

src/hotspot/share/cds/metaspaceShared.cpp

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,21 +1375,6 @@ class CountSharedSymbols : public SymbolClosure {
13751375

13761376
};
13771377

1378-
// For -XX:PrintSharedArchiveAndExit
1379-
class CountSharedStrings : public OopClosure {
1380-
private:
1381-
int _count;
1382-
public:
1383-
CountSharedStrings() : _count(0) {}
1384-
void do_oop(oop* p) {
1385-
_count++;
1386-
}
1387-
void do_oop(narrowOop* p) {
1388-
_count++;
1389-
}
1390-
int total() { return _count; }
1391-
};
1392-
13931378
// Read the miscellaneous data from the shared file, and
13941379
// serialize it out to its various destinations.
13951380

@@ -1444,9 +1429,7 @@ void MetaspaceShared::initialize_shared_spaces() {
14441429
CountSharedSymbols cl;
14451430
SymbolTable::shared_symbols_do(&cl);
14461431
tty->print_cr("Number of shared symbols: %d", cl.total());
1447-
CountSharedStrings cs;
1448-
StringTable::shared_oops_do(&cs);
1449-
tty->print_cr("Number of shared strings: %d", cs.total());
1432+
tty->print_cr("Number of shared strings: %zu", StringTable::shared_entry_count());
14501433
tty->print_cr("VM version: %s\r\n", static_mapinfo->vm_version());
14511434
if (FileMapInfo::current_info() == NULL || _archive_loading_failed) {
14521435
tty->print_cr("archive is invalid");

src/hotspot/share/classfile/compactHashtable.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,10 +222,14 @@ class SimpleCompactHashtable {
222222
// Read/Write the table's header from/to the CDS archive
223223
void serialize_header(SerializeClosure* soc) NOT_CDS_RETURN;
224224

225-
inline bool empty() {
225+
inline bool empty() const {
226226
return (_entry_count == 0);
227227
}
228228

229+
inline size_t entry_count() const {
230+
return _entry_count;
231+
}
232+
229233
static size_t calculate_header_size();
230234
};
231235

src/hotspot/share/classfile/javaClasses.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,13 +201,26 @@ int java_lang_String::_value_offset;
201201
int java_lang_String::_hash_offset;
202202
int java_lang_String::_hashIsZero_offset;
203203
int java_lang_String::_coder_offset;
204+
int java_lang_String::_flags_offset;
204205

205206
bool java_lang_String::_initialized;
206207

207208
bool java_lang_String::is_instance(oop obj) {
208209
return is_instance_inlined(obj);
209210
}
210211

212+
bool java_lang_String::test_and_set_flag(oop java_string, uint8_t flag_mask) {
213+
uint8_t* addr = flags_addr(java_string);
214+
uint8_t value = Atomic::load(addr);
215+
while ((value & flag_mask) == 0) {
216+
uint8_t old_value = value;
217+
value |= flag_mask;
218+
value = Atomic::cmpxchg(addr, old_value, value);
219+
if (value == old_value) return false; // Flag bit changed from 0 to 1.
220+
}
221+
return true; // Flag bit is already 1.
222+
}
223+
211224
#define STRING_FIELDS_DO(macro) \
212225
macro(_value_offset, k, vmSymbols::value_name(), byte_array_signature, false); \
213226
macro(_hash_offset, k, "hash", int_signature, false); \
@@ -221,13 +234,15 @@ void java_lang_String::compute_offsets() {
221234

222235
InstanceKlass* k = vmClasses::String_klass();
223236
STRING_FIELDS_DO(FIELD_COMPUTE_OFFSET);
237+
STRING_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);
224238

225239
_initialized = true;
226240
}
227241

228242
#if INCLUDE_CDS
229243
void java_lang_String::serialize_offsets(SerializeClosure* f) {
230244
STRING_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
245+
STRING_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
231246
f->do_bool(&_initialized);
232247
}
233248
#endif

src/hotspot/share/classfile/javaClasses.hpp

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,19 +96,38 @@ class java_lang_Object : AllStatic {
9696

9797
// Interface to java.lang.String objects
9898

99+
// The flags field is a collection of bits representing boolean values used
100+
// internally by the VM.
101+
#define STRING_INJECTED_FIELDS(macro) \
102+
macro(java_lang_String, flags, byte_signature, false)
103+
99104
class java_lang_String : AllStatic {
100105
private:
101106
static int _value_offset;
102107
static int _hash_offset;
103108
static int _hashIsZero_offset;
104109
static int _coder_offset;
110+
static int _flags_offset;
105111

106112
static bool _initialized;
107113

108114
static Handle basic_create(int length, bool byte_arr, TRAPS);
109115

110116
static inline void set_coder(oop string, jbyte coder);
111117

118+
// Bitmasks for values in the injected flags field.
119+
static const uint8_t _deduplication_forbidden_mask = 1 << 0;
120+
static const uint8_t _deduplication_requested_mask = 1 << 1;
121+
122+
static int flags_offset() { CHECK_INIT(_flags_offset); }
123+
// Return the address of the injected flags field.
124+
static inline uint8_t* flags_addr(oop java_string);
125+
// Test whether the designated bit of the injected flags field is set.
126+
static inline bool is_flag_set(oop java_string, uint8_t flag_mask);
127+
// Atomically test and set the designated bit of the injected flags field,
128+
// returning true if the bit was already set.
129+
static bool test_and_set_flag(oop java_string, uint8_t flag_mask);
130+
112131
public:
113132

114133
// Coders
@@ -137,11 +156,26 @@ class java_lang_String : AllStatic {
137156
static inline void set_value_raw(oop string, typeArrayOop buffer);
138157
static inline void set_value(oop string, typeArrayOop buffer);
139158

159+
// Set the deduplication_forbidden flag true. This flag is sticky; once
160+
// set it never gets cleared. This is set when a String is interned in
161+
// the StringTable, to prevent string deduplication from changing the
162+
// String's value array.
163+
static inline void set_deduplication_forbidden(oop java_string);
164+
165+
// Test and set the deduplication_requested flag. Returns the old value
166+
// of the flag. This flag is sticky; once set it never gets cleared.
167+
// Some GCs may use this flag when deciding whether to request
168+
// deduplication of a String, to avoid multiple requests for the same
169+
// object.
170+
static inline bool test_and_set_deduplication_requested(oop java_string);
171+
140172
// Accessors
141173
static inline typeArrayOop value(oop java_string);
142174
static inline typeArrayOop value_no_keepalive(oop java_string);
143175
static inline bool hash_is_set(oop string);
144176
static inline bool is_latin1(oop java_string);
177+
static inline bool deduplication_forbidden(oop java_string);
178+
static inline bool deduplication_requested(oop java_string);
145179
static inline int length(oop java_string);
146180
static inline int length(oop java_string, typeArrayOop string_value);
147181
static int utf8_length(oop java_string);
@@ -1735,6 +1769,7 @@ class InjectedField {
17351769
klass##_##name##_enum,
17361770

17371771
#define ALL_INJECTED_FIELDS(macro) \
1772+
STRING_INJECTED_FIELDS(macro) \
17381773
CLASS_INJECTED_FIELDS(macro) \
17391774
CLASSLOADER_INJECTED_FIELDS(macro) \
17401775
RESOLVEDMETHOD_INJECTED_FIELDS(macro) \

src/hotspot/share/classfile/javaClasses.inline.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,32 @@ bool java_lang_String::is_latin1(oop java_string) {
7373
return coder == CODER_LATIN1;
7474
}
7575

76+
uint8_t* java_lang_String::flags_addr(oop java_string) {
77+
assert(_initialized, "Must be initialized");
78+
assert(is_instance(java_string), "Must be java string");
79+
return java_string->obj_field_addr<uint8_t>(_flags_offset);
80+
}
81+
82+
bool java_lang_String::is_flag_set(oop java_string, uint8_t flag_mask) {
83+
return (Atomic::load(flags_addr(java_string)) & flag_mask) != 0;
84+
}
85+
86+
bool java_lang_String::deduplication_forbidden(oop java_string) {
87+
return is_flag_set(java_string, _deduplication_forbidden_mask);
88+
}
89+
90+
bool java_lang_String::deduplication_requested(oop java_string) {
91+
return is_flag_set(java_string, _deduplication_requested_mask);
92+
}
93+
94+
void java_lang_String::set_deduplication_forbidden(oop java_string) {
95+
test_and_set_flag(java_string, _deduplication_forbidden_mask);
96+
}
97+
98+
bool java_lang_String::test_and_set_deduplication_requested(oop java_string) {
99+
return test_and_set_flag(java_string, _deduplication_requested_mask);
100+
}
101+
76102
int java_lang_String::length(oop java_string, typeArrayOop value) {
77103
assert(_initialized, "Must be initialized");
78104
assert(is_instance(java_string), "must be java_string");

src/hotspot/share/classfile/stringTable.cpp

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@
3333
#include "gc/shared/collectedHeap.hpp"
3434
#include "gc/shared/oopStorage.inline.hpp"
3535
#include "gc/shared/oopStorageSet.hpp"
36+
#include "gc/shared/stringdedup/stringDedup.hpp"
3637
#include "logging/log.hpp"
3738
#include "logging/logStream.hpp"
3839
#include "memory/allocation.inline.hpp"
3940
#include "memory/resourceArea.hpp"
40-
#include "memory/universe.hpp"
4141
#include "oops/access.inline.hpp"
4242
#include "oops/compressedOops.hpp"
4343
#include "oops/oop.inline.hpp"
@@ -346,15 +346,17 @@ oop StringTable::do_intern(Handle string_or_null_h, const jchar* name,
346346
string_h = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
347347
}
348348

349-
// Deduplicate the string before it is interned. Note that we should never
350-
// deduplicate a string after it has been interned. Doing so will counteract
351-
// compiler optimizations done on e.g. interned string literals.
352-
Universe::heap()->deduplicate_string(string_h());
353-
354349
assert(java_lang_String::equals(string_h(), name, len),
355350
"string must be properly initialized");
356351
assert(len == java_lang_String::length(string_h()), "Must be same length");
357352

353+
// Notify deduplication support that the string is being interned. A string
354+
// must never be deduplicated after it has been interned. Doing so interferes
355+
// with compiler optimizations done on e.g. interned string literals.
356+
if (StringDedup::is_enabled()) {
357+
StringDedup::notify_intern(string_h());
358+
}
359+
358360
StringTableLookupOop lookup(THREAD, hash, string_h);
359361
StringTableGet stg(THREAD);
360362

@@ -700,12 +702,20 @@ void StringtableDCmd::execute(DCmdSource source, TRAPS) {
700702

701703
// Sharing
702704
#if INCLUDE_CDS_JAVA_HEAP
705+
size_t StringTable::shared_entry_count() {
706+
return _shared_table.entry_count();
707+
}
708+
703709
oop StringTable::lookup_shared(const jchar* name, int len, unsigned int hash) {
704710
assert(hash == java_lang_String::hash_code(name, len),
705711
"hash must be computed using java_lang_String::hash_code");
706712
return _shared_table.lookup(name, hash, len);
707713
}
708714

715+
oop StringTable::lookup_shared(const jchar* name, int len) {
716+
return _shared_table.lookup(name, java_lang_String::hash_code(name, len), len);
717+
}
718+
709719
oop StringTable::create_archived_string(oop s) {
710720
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
711721
assert(java_lang_String::is_instance(s), "sanity");
@@ -724,6 +734,10 @@ oop StringTable::create_archived_string(oop s) {
724734

725735
// adjust the pointer to the 'value' field in the new String oop
726736
java_lang_String::set_value_raw(new_s, new_v);
737+
// Prevent string deduplication from changing the 'value' field to
738+
// something not in the archive before building the archive. Also marks
739+
// the shared string when loaded.
740+
java_lang_String::set_deduplication_forbidden(new_s);
727741
return new_s;
728742
}
729743

@@ -769,17 +783,4 @@ void StringTable::serialize_shared_table_header(SerializeClosure* soc) {
769783
}
770784
}
771785

772-
class SharedStringIterator {
773-
OopClosure* _oop_closure;
774-
public:
775-
SharedStringIterator(OopClosure* f) : _oop_closure(f) {}
776-
void do_value(oop string) {
777-
_oop_closure->do_oop(&string);
778-
}
779-
};
780-
781-
void StringTable::shared_oops_do(OopClosure* f) {
782-
SharedStringIterator iter(f);
783-
_shared_table.iterate(&iter);
784-
}
785786
#endif //INCLUDE_CDS_JAVA_HEAP

src/hotspot/share/classfile/stringTable.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,9 @@ class StringTable : public CHeapObj<mtSymbol>{
107107
private:
108108
static oop lookup_shared(const jchar* name, int len, unsigned int hash) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
109109
public:
110+
static oop lookup_shared(const jchar* name, int len) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
111+
static size_t shared_entry_count() NOT_CDS_JAVA_HEAP_RETURN_(0);
110112
static oop create_archived_string(oop s) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
111-
static void shared_oops_do(OopClosure* f) NOT_CDS_JAVA_HEAP_RETURN;
112113
static void write_to_archive(const DumpedInternedStrings* dumped_interned_strings) NOT_CDS_JAVA_HEAP_RETURN;
113114
static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;
114115

0 commit comments

Comments
 (0)