8009575: Reduce Symbol::_refcount from 4 bytes to 2 bytes
authoriklam
Sun, 23 Jun 2013 22:08:28 -0700
changeset 18438 9ea6bbfe0b83
parent 18437 e5775072e4c7
child 18439 725ce18186b3
child 18479 d14275b3c52d
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
hotspot/src/share/vm/oops/symbol.cpp
hotspot/src/share/vm/oops/symbol.hpp
hotspot/src/share/vm/runtime/atomic.cpp
hotspot/src/share/vm/runtime/atomic.hpp
hotspot/src/share/vm/runtime/vmStructs.cpp
--- 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 */     \