< prev index next >
src/hotspot/share/classfile/javaClasses.cpp
Print this page
rev 54472 : 8221836: Avoid recalculating String.hash when zero
Reviewed-by: jrose, adinn
Contributed-by: peter.levart@gmail.com, claes.redestad@oracle.com
@@ -158,10 +158,11 @@
compute_offset(dest_offset, ik, name, signature_symbol, is_static);
}
int java_lang_String::value_offset = 0;
int java_lang_String::hash_offset = 0;
+int java_lang_String::hashIsZero_offset = 0;
int java_lang_String::coder_offset = 0;
bool java_lang_String::initialized = false;
bool java_lang_String::is_instance(oop obj) {
@@ -177,11 +178,12 @@
compute_offset(offset, klass, name, vmSymbols::signature(), is_static)
#define STRING_FIELDS_DO(macro) \
macro(value_offset, k, vmSymbols::value_name(), byte_array_signature, false); \
macro(hash_offset, k, "hash", int_signature, false); \
- macro(coder_offset, k, "coder", byte_signature, false)
+ macro(hashIsZero_offset, k, "hashIsZero", bool_signature, false); \
+ macro(coder_offset, k, "coder", byte_signature, false);
void java_lang_String::compute_offsets() {
if (initialized) {
return;
}
@@ -505,22 +507,42 @@
}
return result;
}
unsigned int java_lang_String::hash_code(oop java_string) {
+ // The hash and hashIsZero fields are subject to a benign data race,
+ // making it crucial to ensure that any observable result of the
+ // calculation in this method stays correct under any possible read of
+ // these fields. Necessary restrictions to allow this to be correct
+ // without explicit memory fences or similar concurrency primitives is
+ // that we can ever only write to one of these two fields for a given
+ // String instance, and that the computation is idempotent and derived
+ // from immutable state
+ assert(initialized && (hash_offset > 0) && (hashIsZero_offset > 0), "Must be initialized");
+ if (java_lang_String::hash_is_set(java_string)) {
+ return java_string->int_field(hash_offset);
+ }
+
typeArrayOop value = java_lang_String::value(java_string);
int length = java_lang_String::length(java_string, value);
- // Zero length string will hash to zero with String.hashCode() function.
- if (length == 0) return 0;
-
bool is_latin1 = java_lang_String::is_latin1(java_string);
+ unsigned int hash = 0;
+ if (length > 0) {
if (is_latin1) {
- return java_lang_String::hash_code(value->byte_at_addr(0), length);
+ hash = java_lang_String::hash_code(value->byte_at_addr(0), length);
+ } else {
+ hash = java_lang_String::hash_code(value->char_at_addr(0), length);
+ }
+ }
+
+ if (hash != 0) {
+ java_string->int_field_put(hash_offset, hash);
} else {
- return java_lang_String::hash_code(value->char_at_addr(0), length);
+ java_string->bool_field_put(hashIsZero_offset, true);
}
+ return hash;
}
char* java_lang_String::as_quoted_ascii(oop java_string) {
typeArrayOop value = java_lang_String::value(java_string);
int length = java_lang_String::length(java_string, value);
< prev index next >