17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 26 #include "precompiled.hpp" 27 #include "classfile/altHashing.hpp" 28 #include "classfile/classLoaderData.hpp" 29 #include "logging/log.hpp" 30 #include "logging/logStream.hpp" 31 #include "memory/allocation.inline.hpp" 32 #include "memory/resourceArea.hpp" 33 #include "oops/symbol.hpp" 34 #include "runtime/atomic.hpp" 35 #include "runtime/os.hpp" 36 37 Symbol::Symbol(const u1* name, int length, int refcount) { 38 _refcount = refcount; 39 _length = length; 40 _identity_hash = (short)os::random(); 41 for (int i = 0; i < _length; i++) { 42 byte_at_put(i, name[i]); 43 } 44 } 45 46 void* Symbol::operator new(size_t sz, int len, TRAPS) throw() { 47 int alloc_size = size(len)*wordSize; 48 address res = (address) AllocateHeap(alloc_size, mtSymbol); 49 return res; 50 } 51 52 void* Symbol::operator new(size_t sz, int len, Arena* arena, TRAPS) throw() { 53 int alloc_size = size(len)*wordSize; 54 address res = (address)arena->Amalloc_4(alloc_size); 55 return res; 56 } 57 58 void Symbol::operator delete(void *p) { 59 assert(((Symbol*)p)->refcount() == 0, "should not call this"); 60 FreeHeap(p); 61 } 190 191 const char* Symbol::as_klass_external_name() const { 192 char* str = as_C_string(); 193 int length = (int)strlen(str); 194 // Turn all '/'s into '.'s (also for array klasses) 195 for (int index = 0; index < length; index++) { 196 if (str[index] == '/') { 197 str[index] = '.'; 198 } 199 } 200 return str; 201 } 202 203 // Alternate hashing for unbalanced symbol tables. 204 unsigned int Symbol::new_hash(juint seed) { 205 ResourceMark rm; 206 // Use alternate hashing algorithm on this symbol. 207 return AltHashing::murmur3_32(seed, (const jbyte*)as_C_string(), utf8_length()); 208 } 209 210 void Symbol::increment_refcount() { 211 // Only increment the refcount if non-negative. If negative either 212 // overflow has occurred or it is a permanent symbol in a read only 213 // shared archive. 214 if (_refcount >= 0) { // not a permanent symbol 215 Atomic::inc(&_refcount); 216 NOT_PRODUCT(Atomic::inc(&_total_count);) 217 } 218 } 219 220 void Symbol::decrement_refcount() { 221 if (_refcount >= 0) { // not a permanent symbol 222 short new_value = Atomic::add(short(-1), &_refcount); 223 #ifdef ASSERT 224 if (new_value == -1) { // we have transitioned from 0 -> -1 225 print(); 226 assert(false, "reference count underflow for symbol"); 227 } 228 #endif 229 (void)new_value; 230 } 231 } 232 233 void Symbol::metaspace_pointers_do(MetaspaceClosure* it) { 234 if (log_is_enabled(Trace, cds)) { 235 LogStream trace_stream(Log(cds)::trace()); 236 trace_stream.print("Iter(Symbol): %p ", this); 237 print_value_on(&trace_stream); 238 trace_stream.cr(); 239 } 240 } 241 242 void Symbol::print_on(outputStream* st) const { 243 if (this == NULL) { 244 st->print_cr("NULL"); 245 } else { 246 st->print("Symbol: '"); 247 print_symbol_on(st); 248 st->print("'"); 249 st->print(" count %d", refcount()); | 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 26 #include "precompiled.hpp" 27 #include "classfile/altHashing.hpp" 28 #include "classfile/classLoaderData.hpp" 29 #include "logging/log.hpp" 30 #include "logging/logStream.hpp" 31 #include "memory/allocation.inline.hpp" 32 #include "memory/resourceArea.hpp" 33 #include "oops/symbol.hpp" 34 #include "runtime/atomic.hpp" 35 #include "runtime/os.hpp" 36 37 uint32_t Symbol::pack_length_and_refcount(int length, int refcount) { 38 STATIC_ASSERT(max_symbol_length == ((1 << 16) - 1)); 39 STATIC_ASSERT(PERM_REFCOUNT == ((1 << 16) - 1)); 40 assert(length >= 0, "negative length"); 41 assert(length <= max_symbol_length, "too long symbol"); 42 assert(refcount >= 0, "negative refcount"); 43 assert(refcount <= PERM_REFCOUNT, "invalid refcount"); 44 uint32_t hi = length; 45 uint32_t lo = refcount; 46 return (hi << 16) | lo; 47 } 48 49 Symbol::Symbol(const u1* name, int length, int refcount) { 50 _length_and_refcount = pack_length_and_refcount(length, refcount); 51 _identity_hash = (short)os::random(); 52 for (int i = 0; i < length; i++) { 53 byte_at_put(i, name[i]); 54 } 55 } 56 57 void* Symbol::operator new(size_t sz, int len, TRAPS) throw() { 58 int alloc_size = size(len)*wordSize; 59 address res = (address) AllocateHeap(alloc_size, mtSymbol); 60 return res; 61 } 62 63 void* Symbol::operator new(size_t sz, int len, Arena* arena, TRAPS) throw() { 64 int alloc_size = size(len)*wordSize; 65 address res = (address)arena->Amalloc_4(alloc_size); 66 return res; 67 } 68 69 void Symbol::operator delete(void *p) { 70 assert(((Symbol*)p)->refcount() == 0, "should not call this"); 71 FreeHeap(p); 72 } 201 202 const char* Symbol::as_klass_external_name() const { 203 char* str = as_C_string(); 204 int length = (int)strlen(str); 205 // Turn all '/'s into '.'s (also for array klasses) 206 for (int index = 0; index < length; index++) { 207 if (str[index] == '/') { 208 str[index] = '.'; 209 } 210 } 211 return str; 212 } 213 214 // Alternate hashing for unbalanced symbol tables. 215 unsigned int Symbol::new_hash(juint seed) { 216 ResourceMark rm; 217 // Use alternate hashing algorithm on this symbol. 218 return AltHashing::murmur3_32(seed, (const jbyte*)as_C_string(), utf8_length()); 219 } 220 221 // Increment refcount while checking for zero. If the Symbol's refcount becomes zero 222 // a thread could be concurrently removing the Symbol. This is used during SymbolTable 223 // lookup to avoid reviving a dead Symbol. 224 bool Symbol::try_increment_refcount() { 225 uint32_t found = _length_and_refcount; 226 while (true) { 227 uint32_t old_value = found; 228 int refc = extract_refcount(old_value); 229 if (refc == PERM_REFCOUNT) { 230 return true; // sticky max or created permanent 231 } else if (refc == 0) { 232 return false; // dead, can't revive. 233 } else { 234 found = Atomic::cmpxchg(old_value + 1, &_length_and_refcount, old_value); 235 if (found == old_value) { 236 return true; // successfully updated. 237 } 238 // refcount changed, try again. 239 } 240 } 241 } 242 243 // The increment_refcount() is called when not doing lookup. It is assumed that you 244 // have a symbol with a non-zero refcount and it can't become zero while referenced by 245 // this caller. 246 void Symbol::increment_refcount() { 247 if (refcount() != PERM_REFCOUNT) { // not a permanent symbol 248 if (!try_increment_refcount()) { 249 #ifdef ASSERT 250 print(); 251 fatal("refcount has gone to zero"); 252 #endif 253 } 254 NOT_PRODUCT(Atomic::inc(&_total_count);) 255 } 256 } 257 258 // Decrement refcount potentially while racing increment, so we need 259 // to check the value after attempting to decrement so that if another 260 // thread increments to PERM_REFCOUNT the value is not decremented. 261 void Symbol::decrement_refcount() { 262 uint32_t found = _length_and_refcount; 263 while (true) { 264 uint32_t old_value = found; 265 int refc = extract_refcount(old_value); 266 if (refc == PERM_REFCOUNT) { 267 return; // refcount is permanent, permanent is sticky 268 } else if (refc == 0) { 269 #ifdef ASSERT 270 print(); 271 fatal("refcount underflow"); 272 #endif 273 return; 274 } else { 275 found = Atomic::cmpxchg(old_value - 1, &_length_and_refcount, old_value); 276 if (found == old_value) { 277 return; // successfully updated. 278 } 279 // refcount changed, try again. 280 } 281 } 282 } 283 284 void Symbol::metaspace_pointers_do(MetaspaceClosure* it) { 285 if (log_is_enabled(Trace, cds)) { 286 LogStream trace_stream(Log(cds)::trace()); 287 trace_stream.print("Iter(Symbol): %p ", this); 288 print_value_on(&trace_stream); 289 trace_stream.cr(); 290 } 291 } 292 293 void Symbol::print_on(outputStream* st) const { 294 if (this == NULL) { 295 st->print_cr("NULL"); 296 } else { 297 st->print("Symbol: '"); 298 print_symbol_on(st); 299 st->print("'"); 300 st->print(" count %d", refcount()); |