--- old/src/share/vm/oops/symbol.cpp 2013-06-20 11:09:45.538637796 -0700 +++ new/src/share/vm/oops/symbol.cpp 2013-06-20 11:09:45.407631323 -0700 @@ -32,7 +32,9 @@ #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" -Symbol::Symbol(const u1* name, int length, int refcount) : _refcount(refcount), _length(length) { +Symbol::Symbol(const u1* name, int length, int refcount) { + _refcount = refcount; + _length = length; _identity_hash = os::random(); for (int i = 0; i < _length; i++) { byte_at_put(i, name[i]); --- old/src/share/vm/oops/symbol.hpp 2013-06-20 11:09:46.060663587 -0700 +++ new/src/share/vm/oops/symbol.hpp 2013-06-20 11:09:45.927657017 -0700 @@ -27,6 +27,7 @@ #include "utilities/utf8.hpp" #include "memory/allocation.hpp" +#include "runtime/atomic.hpp" // A Symbol is a canonicalized string. // All Symbols reside in global SymbolTable and are reference counted. @@ -101,14 +102,25 @@ // type without virtual functions. class ClassLoaderData; -class Symbol : public MetaspaceObj { +// We separate the fields in SymbolBase from Symbol::_body so that +// Symbol::size(int) can correctly calculate the space needed. +class SymbolBase : public MetaspaceObj { friend class VMStructs; friend class SymbolTable; friend class MoveSymbols; - private: - volatile int _refcount; + public: + ATOMIC_SHORT_PAIR( + volatile short _refcount, // needs atomic operation + unsigned short _length // number of UTF8 characters in the symbol (does not need atomic op) + ); int _identity_hash; - unsigned short _length; // number of UTF8 characters in the symbol +}; + +class Symbol : private SymbolBase { + friend class VMStructs; + friend class SymbolTable; + friend class MoveSymbols; + private: jbyte _body[1]; enum { @@ -117,7 +129,7 @@ }; static int size(int length) { - size_t sz = heap_word_size(sizeof(Symbol) + (length > 0 ? length - 1 : 0)); + size_t sz = heap_word_size(sizeof(SymbolBase) + (length > 0 ? length : 0)); return align_object_size(sz); } --- old/src/share/vm/runtime/atomic.cpp 2013-06-20 11:09:46.587689628 -0700 +++ new/src/share/vm/runtime/atomic.cpp 2013-06-20 11:09:46.444682561 -0700 @@ -80,3 +80,32 @@ } return old; } + +void Atomic::inc(volatile short* dest) { + // Most platforms do not support atomic increment on a 2-byte value. However, + // if the value occupies the most significant 16 bits of an aligned 32-bit + // word, then we can do this with an atomic add of 0x10000 to the 32-bit word. + // + // The least significant parts of this 32-bit word will never be affected, even + // in case of overflow/underflow. + // + // Use the ATOMIC_SHORT_PAIR macro to get the desired alignment. +#ifdef VM_LITTLE_ENDIAN + assert((intx(dest) & 0x03) == 0x02, "wrong alignment"); + (void)Atomic::add(0x10000, (volatile int*)(dest-1)); +#else + assert((intx(dest) & 0x03) == 0x00, "wrong alignment"); + (void)Atomic::add(0x10000, (volatile int*)(dest)); +#endif +} + +void Atomic::dec(volatile short* dest) { +#ifdef VM_LITTLE_ENDIAN + assert((intx(dest) & 0x03) == 0x02, "wrong alignment"); + (void)Atomic::add(-0x10000, (volatile int*)(dest-1)); +#else + assert((intx(dest) & 0x03) == 0x00, "wrong alignment"); + (void)Atomic::add(-0x10000, (volatile int*)(dest)); +#endif +} + --- old/src/share/vm/runtime/atomic.hpp 2013-06-20 11:09:47.115715717 -0700 +++ new/src/share/vm/runtime/atomic.hpp 2013-06-20 11:09:46.983709195 -0700 @@ -64,11 +64,13 @@ // Atomically increment location inline static void inc (volatile jint* dest); + static void inc (volatile jshort* dest); inline static void inc_ptr(volatile intptr_t* dest); inline static void inc_ptr(volatile void* dest); // Atomically decrement a location inline static void dec (volatile jint* dest); + static void dec (volatile jshort* dest); inline static void dec_ptr(volatile intptr_t* dest); inline static void dec_ptr(volatile void* dest); @@ -95,4 +97,24 @@ inline static void* cmpxchg_ptr(void* exchange_value, volatile void* dest, void* compare_value); }; +// To use Atomic::inc(jshort* dest) and Atomic::dec(jshort* dest), the address must be specially +// aligned, such that (*dest) occupies the upper 16 bits of an aligned 32-bit word. The best way to +// achieve is to place your short value next to another short value, which doesn't need atomic ops. +// +// Example +// ATOMIC_SHORT_PAIR( +// volatile short _refcount, // needs atomic operation +// unsigned short _length // number of UTF8 characters in the symbol (does not need atomic op) +// ); + +#ifdef VM_LITTLE_ENDIAN +#define ATOMIC_SHORT_PAIR(atomic_decl, non_atomic_decl) \ + non_atomic_decl; \ + atomic_decl +#else +#define ATOMIC_SHORT_PAIR(atomic_decl, non_atomic_decl) \ + atomic_decl ; \ + non_atomic_decl +#endif + #endif // SHARE_VM_RUNTIME_ATOMIC_HPP --- old/src/share/vm/runtime/vmStructs.cpp 2013-06-20 11:09:47.691744178 -0700 +++ new/src/share/vm/runtime/vmStructs.cpp 2013-06-20 11:09:47.551737260 -0700 @@ -379,7 +379,7 @@ nonstatic_field(ConstMethod, _size_of_parameters, u2) \ nonstatic_field(ObjArrayKlass, _element_klass, Klass*) \ nonstatic_field(ObjArrayKlass, _bottom_klass, Klass*) \ - volatile_nonstatic_field(Symbol, _refcount, int) \ + volatile_nonstatic_field(Symbol, _refcount, short) \ nonstatic_field(Symbol, _identity_hash, int) \ nonstatic_field(Symbol, _length, unsigned short) \ unchecked_nonstatic_field(Symbol, _body, sizeof(jbyte)) /* NOTE: no type */ \