Skip to content

Commit

Permalink
New string deduplication
Browse files Browse the repository at this point in the history
  • Loading branch information
kimbarrett committed Apr 24, 2021
1 parent 0257ac1 commit 2df362c
Show file tree
Hide file tree
Showing 97 changed files with 2,310 additions and 3,151 deletions.
19 changes: 1 addition & 18 deletions src/hotspot/share/cds/metaspaceShared.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1402,21 +1402,6 @@ class CountSharedSymbols : public SymbolClosure {

};

// For -XX:PrintSharedArchiveAndExit
class CountSharedStrings : public OopClosure {
private:
int _count;
public:
CountSharedStrings() : _count(0) {}
void do_oop(oop* p) {
_count++;
}
void do_oop(narrowOop* p) {
_count++;
}
int total() { return _count; }
};

// Read the miscellaneous data from the shared file, and
// serialize it out to its various destinations.

Expand Down Expand Up @@ -1471,9 +1456,7 @@ void MetaspaceShared::initialize_shared_spaces() {
CountSharedSymbols cl;
SymbolTable::shared_symbols_do(&cl);
tty->print_cr("Number of shared symbols: %d", cl.total());
CountSharedStrings cs;
StringTable::shared_oops_do(&cs);
tty->print_cr("Number of shared strings: %d", cs.total());
tty->print_cr("Number of shared strings: %zu", StringTable::shared_entry_count());
tty->print_cr("VM version: %s\r\n", static_mapinfo->vm_version());
if (FileMapInfo::current_info() == NULL || _archive_loading_failed) {
tty->print_cr("archive is invalid");
Expand Down
6 changes: 5 additions & 1 deletion src/hotspot/share/classfile/compactHashtable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -222,10 +222,14 @@ class SimpleCompactHashtable {
// Read/Write the table's header from/to the CDS archive
void serialize_header(SerializeClosure* soc) NOT_CDS_RETURN;

inline bool empty() {
inline bool empty() const {
return (_entry_count == 0);
}

inline size_t entry_count() const {
return _entry_count;
}

static size_t calculate_header_size();
};

Expand Down
15 changes: 15 additions & 0 deletions src/hotspot/share/classfile/javaClasses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,13 +201,26 @@ int java_lang_String::_value_offset;
int java_lang_String::_hash_offset;
int java_lang_String::_hashIsZero_offset;
int java_lang_String::_coder_offset;
int java_lang_String::_flags_offset;

bool java_lang_String::_initialized;

bool java_lang_String::is_instance(oop obj) {
return is_instance_inlined(obj);
}

bool java_lang_String::set_flag(oop java_string, uint8_t flag_mask) {
uint8_t* addr = flags_addr(java_string);
uint8_t value = Atomic::load(addr);
while ((value & flag_mask) == 0) {
uint8_t old_value = value;
value |= flag_mask;
value = Atomic::cmpxchg(addr, old_value, value);
if (value == old_value) return true; // Flag bit changed to 1.
}
return false; // Flag bit unchanged, already 1.
}

#define STRING_FIELDS_DO(macro) \
macro(_value_offset, k, vmSymbols::value_name(), byte_array_signature, false); \
macro(_hash_offset, k, "hash", int_signature, false); \
Expand All @@ -221,13 +234,15 @@ void java_lang_String::compute_offsets() {

InstanceKlass* k = vmClasses::String_klass();
STRING_FIELDS_DO(FIELD_COMPUTE_OFFSET);
STRING_INJECTED_FIELDS(INJECTED_FIELD_COMPUTE_OFFSET);

_initialized = true;
}

#if INCLUDE_CDS
void java_lang_String::serialize_offsets(SerializeClosure* f) {
STRING_FIELDS_DO(FIELD_SERIALIZE_OFFSET);
STRING_INJECTED_FIELDS(INJECTED_FIELD_SERIALIZE_OFFSET);
f->do_bool(&_initialized);
}
#endif
Expand Down
28 changes: 28 additions & 0 deletions src/hotspot/share/classfile/javaClasses.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -96,19 +96,31 @@ class java_lang_Object : AllStatic {

// Interface to java.lang.String objects

#define STRING_INJECTED_FIELDS(macro) \
macro(java_lang_String, flags, byte_signature, false)

class java_lang_String : AllStatic {
private:
static int _value_offset;
static int _hash_offset;
static int _hashIsZero_offset;
static int _coder_offset;
static int _flags_offset;

static bool _initialized;

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

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

static const uint8_t _no_deduplication_mask = 1 << 0;
static const uint8_t _deduplication_requested_mask = 1 << 1;

static int flags_offset() { CHECK_INIT(_flags_offset); }
static inline uint8_t* flags_addr(oop java_string);
static inline bool is_flag_set(oop java_string, uint8_t flag_mask);
static bool set_flag(oop java_string, uint8_t flag_mask);

public:

// Coders
Expand Down Expand Up @@ -137,11 +149,26 @@ class java_lang_String : AllStatic {
static inline void set_value_raw(oop string, typeArrayOop buffer);
static inline void set_value(oop string, typeArrayOop buffer);

// Set the no_deduplication flag true. This flag is sticky; once set it
// never gets cleared. This is set when a string is interned in the
// StringTable, to prevent string deduplication from changing the string's
// value array.
static inline void set_no_deduplication(oop java_string);

// Test and set the deduplication_requested flag. Returns true if the
// flag's value is changed, false if it was already set. This flag is
// sticky; once set it never gets cleared. A GC may use this operation to
// determine whether to request deduplication of a string, avoiding
// multiple requests for the same string.
static inline bool set_deduplication_requested(oop java_string);

// Accessors
static inline typeArrayOop value(oop java_string);
static inline typeArrayOop value_no_keepalive(oop java_string);
static inline bool hash_is_set(oop string);
static inline bool is_latin1(oop java_string);
static inline bool no_deduplication(oop java_string);
static inline bool deduplication_requested(oop java_string);
static inline int length(oop java_string);
static inline int length(oop java_string, typeArrayOop string_value);
static int utf8_length(oop java_string);
Expand Down Expand Up @@ -1745,6 +1772,7 @@ class InjectedField {
klass##_##name##_enum,

#define ALL_INJECTED_FIELDS(macro) \
STRING_INJECTED_FIELDS(macro) \
CLASS_INJECTED_FIELDS(macro) \
CLASSLOADER_INJECTED_FIELDS(macro) \
RESOLVEDMETHOD_INJECTED_FIELDS(macro) \
Expand Down
26 changes: 26 additions & 0 deletions src/hotspot/share/classfile/javaClasses.inline.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,32 @@ bool java_lang_String::is_latin1(oop java_string) {
return coder == CODER_LATIN1;
}

uint8_t* java_lang_String::flags_addr(oop java_string) {
assert(_initialized, "Mut be initialized");
assert(is_instance(java_string), "Must be java string");
return java_string->obj_field_addr<uint8_t>(_flags_offset);
}

bool java_lang_String::is_flag_set(oop java_string, uint8_t flag_mask) {
return (Atomic::load(flags_addr(java_string)) & flag_mask) != 0;
}

bool java_lang_String::no_deduplication(oop java_string) {
return is_flag_set(java_string, _no_deduplication_mask);
}

bool java_lang_String::deduplication_requested(oop java_string) {
return is_flag_set(java_string, _deduplication_requested_mask);
}

void java_lang_String::set_no_deduplication(oop java_string) {
set_flag(java_string, _no_deduplication_mask);
}

bool java_lang_String::set_deduplication_requested(oop java_string) {
return set_flag(java_string, _deduplication_requested_mask);
}

int java_lang_String::length(oop java_string, typeArrayOop value) {
assert(_initialized, "Must be initialized");
assert(is_instance(java_string), "must be java_string");
Expand Down
39 changes: 20 additions & 19 deletions src/hotspot/share/classfile/stringTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@
#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"
#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/access.inline.hpp"
#include "oops/compressedOops.hpp"
#include "oops/oop.inline.hpp"
Expand Down Expand Up @@ -346,15 +346,17 @@ oop StringTable::do_intern(Handle string_or_null_h, const jchar* name,
string_h = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
}

// Deduplicate the string before it is interned. Note that we should never
// deduplicate a string after it has been interned. Doing so will counteract
// compiler optimizations done on e.g. interned string literals.
Universe::heap()->deduplicate_string(string_h());

assert(java_lang_String::equals(string_h(), name, len),
"string must be properly initialized");
assert(len == java_lang_String::length(string_h()), "Must be same length");

// Notify deduplication support that the string is being interned. A string
// must never be deduplicated after it has been interned. Doing so interferes
// with compiler optimizations don on e.g. interned string literals.
if (StringDedup::is_enabled()) {
StringDedup::notify_intern(string_h());
}

StringTableLookupOop lookup(THREAD, hash, string_h);
StringTableGet stg(THREAD);

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

// Sharing
#if INCLUDE_CDS_JAVA_HEAP
size_t StringTable::shared_entry_count() {
return _shared_table.entry_count();
}

oop StringTable::lookup_shared(const jchar* name, int len, unsigned int hash) {
assert(hash == java_lang_String::hash_code(name, len),
"hash must be computed using java_lang_String::hash_code");
return _shared_table.lookup(name, hash, len);
}

oop StringTable::lookup_shared(const jchar* name, int len) {
return _shared_table.lookup(name, java_lang_String::hash_code(name, len), len);
}

oop StringTable::create_archived_string(oop s) {
assert(DumpSharedSpaces, "this function is only used with -Xshare:dump");
assert(java_lang_String::is_instance(s), "sanity");
Expand All @@ -724,6 +734,10 @@ oop StringTable::create_archived_string(oop s) {

// adjust the pointer to the 'value' field in the new String oop
java_lang_String::set_value_raw(new_s, new_v);
// Prevent string deduplication from changing the 'value' field to
// something not in the archive before building the archive. Also marks
// the shared string when loaded.
java_lang_String::set_no_deduplication(new_s);
return new_s;
}

Expand Down Expand Up @@ -769,17 +783,4 @@ void StringTable::serialize_shared_table_header(SerializeClosure* soc) {
}
}

class SharedStringIterator {
OopClosure* _oop_closure;
public:
SharedStringIterator(OopClosure* f) : _oop_closure(f) {}
void do_value(oop string) {
_oop_closure->do_oop(&string);
}
};

void StringTable::shared_oops_do(OopClosure* f) {
SharedStringIterator iter(f);
_shared_table.iterate(&iter);
}
#endif //INCLUDE_CDS_JAVA_HEAP
3 changes: 2 additions & 1 deletion src/hotspot/share/classfile/stringTable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,9 @@ class StringTable : public CHeapObj<mtSymbol>{
private:
static oop lookup_shared(const jchar* name, int len, unsigned int hash) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
public:
static oop lookup_shared(const jchar* name, int len) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
static size_t shared_entry_count() NOT_CDS_JAVA_HEAP_RETURN_(0);
static oop create_archived_string(oop s) NOT_CDS_JAVA_HEAP_RETURN_(NULL);
static void shared_oops_do(OopClosure* f) NOT_CDS_JAVA_HEAP_RETURN;
static void write_to_archive(const DumpedInternedStrings* dumped_interned_strings) NOT_CDS_JAVA_HEAP_RETURN;
static void serialize_shared_table_header(SerializeClosure* soc) NOT_CDS_JAVA_HEAP_RETURN;

Expand Down
1 change: 1 addition & 0 deletions src/hotspot/share/classfile/vmSymbols.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@
template(use_unaligned_access_name, "UNALIGNED_ACCESS") \
template(data_cache_line_flush_size_name, "DATA_CACHE_LINE_FLUSH_SIZE") \
template(during_unsafe_access_name, "during_unsafe_access") \
template(no_deduplication_name, "no_deduplication") \
\
/* name symbols needed by intrinsics */ \
VM_INTRINSICS_DO(VM_INTRINSIC_IGNORE, VM_SYMBOL_IGNORE, template, VM_SYMBOL_IGNORE, VM_ALIAS_IGNORE) \
Expand Down
Loading

0 comments on commit 2df362c

Please sign in to comment.