< 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 >