8009575: Reduce Symbol::_refcount from 4 bytes to 2 bytes
Summary: Added Atomic::inc(short*) to support this change.
Reviewed-by: coleenp, dcubed, dholmes, minqi
--- a/hotspot/src/share/vm/oops/symbol.cpp Fri Jun 21 10:55:26 2013 -0700
+++ b/hotspot/src/share/vm/oops/symbol.cpp Sun Jun 23 22:08:28 2013 -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]);
--- a/hotspot/src/share/vm/oops/symbol.hpp Fri Jun 21 10:55:26 2013 -0700
+++ b/hotspot/src/share/vm/oops/symbol.hpp Sun Jun 23 22:08:28 2013 -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,22 @@
// 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 {
+ 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;
+};
+
+class Symbol : private SymbolBase {
friend class VMStructs;
friend class SymbolTable;
friend class MoveSymbols;
private:
- volatile int _refcount;
- int _identity_hash;
- unsigned short _length; // number of UTF8 characters in the symbol
jbyte _body[1];
enum {
@@ -117,7 +126,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);
}
--- a/hotspot/src/share/vm/runtime/atomic.cpp Fri Jun 21 10:55:26 2013 -0700
+++ b/hotspot/src/share/vm/runtime/atomic.cpp Sun Jun 23 22:08:28 2013 -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
+}
+
--- a/hotspot/src/share/vm/runtime/atomic.hpp Fri Jun 21 10:55:26 2013 -0700
+++ b/hotspot/src/share/vm/runtime/atomic.hpp Sun Jun 23 22:08:28 2013 -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
--- a/hotspot/src/share/vm/runtime/vmStructs.cpp Fri Jun 21 10:55:26 2013 -0700
+++ b/hotspot/src/share/vm/runtime/vmStructs.cpp Sun Jun 23 22:08:28 2013 -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 */ \