< prev index next >

src/hotspot/share/runtime/synchronizer.cpp

Print this page
@@ -60,10 +60,11 @@
  #include "utilities/align.hpp"
  #include "utilities/concurrentHashTable.inline.hpp"
  #include "utilities/concurrentHashTableTasks.inline.hpp"
  #include "utilities/dtrace.hpp"
  #include "utilities/events.hpp"
+ #include "utilities/fastHash.hpp"
  #include "utilities/globalCounter.inline.hpp"
  #include "utilities/globalDefinitions.hpp"
  #include "utilities/linkedlist.hpp"
  #include "utilities/preserveException.hpp"
  

@@ -596,11 +597,11 @@
  //   (objects allocated back-to-back, in particular).  This could potentially
  //   result in hashtable collisions and reduced hashtable efficiency.
  //   There are simple ways to "diffuse" the middle address bits over the
  //   generated hashCode values:
  
- static intptr_t get_next_hash(Thread* current, oop obj) {
+ intptr_t ObjectSynchronizer::get_next_hash(Thread* current, oop obj) {
    intptr_t value = 0;
    if (hashCode == 0) {
      // This form uses global Park-Miller RNG.
      // On MP system we'll have lots of RW access to a global, so the
      // mechanism induces lots of coherency traffic.

@@ -615,11 +616,11 @@
      value = 1;            // for sensitivity testing
    } else if (hashCode == 3) {
      value = ++GVars.hc_sequence;
    } else if (hashCode == 4) {
      value = cast_from_oop<intptr_t>(obj);
-   } else {
+   } else if (hashCode == 5) {
      // Marsaglia's xor-shift scheme with thread-specific state
      // This is probably the best overall implementation -- we'll
      // likely make this the default in future releases.
      unsigned t = current->_hashStateX;
      t ^= (t << 11);

@@ -628,27 +629,56 @@
      current->_hashStateZ = current->_hashStateW;
      unsigned v = current->_hashStateW;
      v = (v ^ (v >> 19)) ^ (t ^ (t >> 8));
      current->_hashStateW = v;
      value = v;
+   } else {
+     assert(UseCompactObjectHeaders, "Only with compact i-hash");
+ #ifdef _LP64
+     uint64_t val = cast_from_oop<uint64_t>(obj);
+     uint32_t hash = FastHash::get_hash32((uint32_t)val, (uint32_t)(val >> 32));
+ #else
+     uint32_t val = cast_from_oop<uint32_t>(obj);
+     uint32_t hash = FastHash::get_hash32(val, UCONST64(0xAAAAAAAA));
+ #endif
+     value= static_cast<intptr_t>(hash);
    }
  
    value &= markWord::hash_mask;
-   if (value == 0) value = 0xBAD;
-   assert(value != markWord::no_hash, "invariant");
+   if (hashCode != 6 && value == 0) value = 0xBAD;
+   assert(value != markWord::no_hash || hashCode == 6, "invariant");
    return value;
  }
  
  intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) {
    while (true) {
      ObjectMonitor* monitor = nullptr;
      markWord temp, test;
      intptr_t hash;
      markWord mark = obj->mark_acquire();
-     // If UseObjectMonitorTable is set the hash can simply be installed in the
-     // object header, since the monitor isn't in the object header.
-     if (UseObjectMonitorTable || !mark.has_monitor()) {
+     if (UseCompactObjectHeaders) {
+       if (mark.is_hashed()) {
+         return get_hash(mark, obj);
+       }
+       intptr_t hash = get_next_hash(current, obj);  // get a new hash
+       markWord new_mark;
+       if (mark.is_not_hashed_expanded()) {
+         new_mark = mark.set_hashed_expanded();
+         int offset = mark.klass()->hash_offset_in_bytes(obj, mark);
+         obj->int_field_put(offset, (jint) hash);
+       } else {
+         new_mark = mark.set_hashed_not_expanded();
+       }
+       markWord old_mark = obj->cas_set_mark(new_mark, mark);
+       if (old_mark == mark) {
+         return hash;
+       }
+       // CAS failed, retry.
+       continue;
+     } else if (UseObjectMonitorTable || !mark.has_monitor()) {
+       // If UseObjectMonitorTable is set the hash can simply be installed in the
+       // object header, since the monitor isn't in the object header.
        hash = mark.hash();
        if (hash != 0) {                     // if it has a hash, just return it
          return hash;
        }
        hash = get_next_hash(current, obj);  // get a new hash

@@ -733,10 +763,29 @@
      // We finally get the hash.
      return hash;
    }
  }
  
+ 
+ uint32_t ObjectSynchronizer::get_hash(markWord mark, oop obj, Klass* klass) {
+   assert(UseCompactObjectHeaders, "Only with compact i-hash");
+   //assert(mark.is_neutral() | mark.is_fast_locked(), "only from neutral or fast-locked mark: " INTPTR_FORMAT, mark.value());
+   assert(mark.is_hashed(), "only from hashed or copied object");
+   if (mark.is_hashed_expanded()) {
+     return obj->int_field(klass->hash_offset_in_bytes(obj, mark));
+   } else {
+     assert(mark.is_hashed_not_expanded(), "must be hashed");
+     assert(hashCode == 6 || hashCode == 2, "must have idempotent hashCode");
+     // Already marked as hashed, but not yet copied. Recompute hash and return it.
+     return ObjectSynchronizer::get_next_hash(nullptr, obj); // recompute hash
+   }
+ }
+ 
+ uint32_t ObjectSynchronizer::get_hash(markWord mark, oop obj) {
+   return get_hash(mark, obj, mark.klass());
+ }
+ 
  bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current,
                                                     Handle h_obj) {
    assert(current == JavaThread::current(), "Can only be called on current thread");
    oop obj = h_obj();
  

@@ -1468,10 +1517,22 @@
    }
  
    out->flush();
  }
  
+ static uintx objhash(oop obj) {
+   if (UseCompactObjectHeaders) {
+     uintx hash = ObjectSynchronizer::get_hash(obj->mark(), obj);
+     assert(hash != 0, "should have a hash");
+     return hash;
+   } else {
+     uintx hash = obj->mark().hash();
+     assert(hash != 0, "should have a hash");
+     return hash;
+   }
+ }
+ 
  // -----------------------------------------------------------------------------
  // ConcurrentHashTable storing links from objects to ObjectMonitors
  class ObjectMonitorTable : AllStatic {
    struct Config {
      using Value = ObjectMonitor*;

@@ -1499,13 +1560,11 @@
  
     public:
      explicit Lookup(oop obj) : _obj(obj) {}
  
      uintx get_hash() const {
-       uintx hash = _obj->mark().hash();
-       assert(hash != 0, "should have a hash");
-       return hash;
+       return objhash(_obj);
      }
  
      bool equals(ObjectMonitor** value) {
        assert(*value != nullptr, "must be");
        return (*value)->object_refers_to(_obj);

@@ -1608,10 +1667,11 @@
    static ObjectMonitor* monitor_get(Thread* current, oop obj) {
      ObjectMonitor* result = nullptr;
      Lookup lookup_f(obj);
      auto found_f = [&](ObjectMonitor** found) {
        assert((*found)->object_peek() == obj, "must be");
+       assert(objhash(obj) == (uintx)(*found)->hash(), "hash must match");
        result = *found;
      };
      _table->get(current, lookup_f, found_f);
      verify_monitor_get_result(obj, result);
      return result;

@@ -1736,11 +1796,11 @@
      auto printer = [&] (ObjectMonitor** entry) {
         ObjectMonitor* om = *entry;
         oop obj = om->object_peek();
         st->print("monitor=" PTR_FORMAT ", ", p2i(om));
         st->print("object=" PTR_FORMAT, p2i(obj));
-        assert(obj->mark().hash() == om->hash(), "hash must match");
+        assert(objhash(obj) == (uintx)om->hash(), "hash must match");
         st->cr();
         return true;
      };
      if (SafepointSynchronize::is_at_safepoint()) {
        _table->do_safepoint_scan(printer);

@@ -1824,11 +1884,11 @@
  // Add the hashcode to the monitor to match the object and put it in the hashtable.
  ObjectMonitor* ObjectSynchronizer::add_monitor(JavaThread* current, ObjectMonitor* monitor, oop obj) {
    assert(UseObjectMonitorTable, "must be");
    assert(obj == monitor->object(), "must be");
  
-   intptr_t hash = obj->mark().hash();
+   intptr_t hash = objhash(obj);
    assert(hash != 0, "must be set when claiming the object monitor");
    monitor->set_hash(hash);
  
    return ObjectMonitorTable::monitor_put_get(current, monitor, obj);
  }
< prev index next >