< prev index next >
src/hotspot/share/oops/symbol.cpp
Print this page
*** 32,46 ****
#include "memory/resourceArea.hpp"
#include "oops/symbol.hpp"
#include "runtime/atomic.hpp"
#include "runtime/os.hpp"
Symbol::Symbol(const u1* name, int length, int refcount) {
! _refcount = refcount;
! _length = length;
_identity_hash = (short)os::random();
! for (int i = 0; i < _length; i++) {
byte_at_put(i, name[i]);
}
}
void* Symbol::operator new(size_t sz, int len, TRAPS) throw() {
--- 32,57 ----
#include "memory/resourceArea.hpp"
#include "oops/symbol.hpp"
#include "runtime/atomic.hpp"
#include "runtime/os.hpp"
+ uint32_t Symbol::pack_length_and_refcount(int length, int refcount) {
+ STATIC_ASSERT(max_symbol_length == ((1 << 16) - 1));
+ STATIC_ASSERT(PERM_REFCOUNT == ((1 << 16) - 1));
+ assert(length >= 0, "negative length");
+ assert(length <= max_symbol_length, "too long symbol");
+ assert(refcount >= 0, "negative refcount");
+ assert(refcount <= PERM_REFCOUNT, "invalid refcount");
+ uint32_t hi = length;
+ uint32_t lo = refcount;
+ return (hi << 16) | lo;
+ }
+
Symbol::Symbol(const u1* name, int length, int refcount) {
! _length_and_refcount = pack_length_and_refcount(length, refcount);
_identity_hash = (short)os::random();
! for (int i = 0; i < length; i++) {
byte_at_put(i, name[i]);
}
}
void* Symbol::operator new(size_t sz, int len, TRAPS) throw() {
*** 206,237 ****
// Use alternate hashing algorithm on this symbol.
return AltHashing::murmur3_32(seed, (const jbyte*)as_C_string(), utf8_length());
}
void Symbol::increment_refcount() {
! // Only increment the refcount if non-negative. If negative either
! // overflow has occurred or it is a permanent symbol in a read only
! // shared archive.
! if (_refcount >= 0) { // not a permanent symbol
! Atomic::inc(&_refcount);
NOT_PRODUCT(Atomic::inc(&_total_count);)
}
}
void Symbol::decrement_refcount() {
! if (_refcount >= 0) { // not a permanent symbol
! short new_value = Atomic::add(short(-1), &_refcount);
#ifdef ASSERT
! if (new_value == -1) { // we have transitioned from 0 -> -1
print();
! assert(false, "reference count underflow for symbol");
}
#endif
- (void)new_value;
}
}
void Symbol::metaspace_pointers_do(MetaspaceClosure* it) {
if (log_is_enabled(Trace, cds)) {
LogStream trace_stream(Log(cds)::trace());
trace_stream.print("Iter(Symbol): %p ", this);
print_value_on(&trace_stream);
--- 217,275 ----
// Use alternate hashing algorithm on this symbol.
return AltHashing::murmur3_32(seed, (const jbyte*)as_C_string(), utf8_length());
}
void Symbol::increment_refcount() {
! if (refcount() != PERM_REFCOUNT) { // not a permanent symbol
! if (!try_increment_refcount()) {
! #ifdef ASSERT
! print();
! #endif
! fatal("refcount has gone to zero");
! }
NOT_PRODUCT(Atomic::inc(&_total_count);)
}
}
void Symbol::decrement_refcount() {
! if (refcount() != PERM_REFCOUNT) { // not a permanent symbol
! int new_value = Atomic::sub((uint32_t)1, &_length_and_refcount);
#ifdef ASSERT
! // Check if we have transitioned to 0xffff
! if (extract_refcount(new_value) == PERM_REFCOUNT) {
print();
! fatal("refcount underflow");
}
#endif
}
}
+ // Atomically increment while checking for zero, zero is bad.
+ bool Symbol::try_increment_refcount() {
+ uint32_t old_value = _length_and_refcount; // fetch once
+ int refc = extract_refcount(old_value);
+
+ if (refc == PERM_REFCOUNT) {
+ return true;
+ } else if (refc == 0) {
+ return false; // effectively dead, can't revive
+ }
+
+ uint32_t now;
+ while ((now = Atomic::cmpxchg(old_value + 1, &_length_and_refcount, old_value)) != old_value) {
+ // failed to increment, check refcount again.
+ refc = extract_refcount(now);
+ if (refc == 0) {
+ return false; // just died
+ } else if (refc == PERM_REFCOUNT) {
+ return true; // just became permanent
+ }
+ old_value = now; // refcount changed, try again
+ }
+ return true;
+ }
+
void Symbol::metaspace_pointers_do(MetaspaceClosure* it) {
if (log_is_enabled(Trace, cds)) {
LogStream trace_stream(Log(cds)::trace());
trace_stream.print("Iter(Symbol): %p ", this);
print_value_on(&trace_stream);
< prev index next >