• Java中Object类hashCode的底层实现


    Java中Object类hashCode的底层实现

    openjdkjdksrcshare
    ativejavalangObject.c
    42
    static JNINativeMethod methods[] = {
        {"hashCode",    "()I",                    (void *)&JVM_IHashCode},
        {"wait",        "(J)V",                   (void *)&JVM_MonitorWait},
        {"notify",      "()V",                    (void *)&JVM_MonitorNotify},
        {"notifyAll",   "()V",                    (void *)&JVM_MonitorNotifyAll},
        {"clone",       "()Ljava/lang/Object;",   (void *)&JVM_Clone},
    };
    
    
    本地方法名称对应 JVM_IHashCode
     
    jvm.h
    96
    /*************************************************************************
     PART 1: Functions for Native Libraries
     ************************************************************************/
    /*
     * java.lang.Object
     */
    JNIEXPORT jint JNICALL
    JVM_IHashCode(JNIEnv *env, jobject obj);


    JVM_IHashCode实现:
    jvm.cpp
    533
    // java.lang.Object ///////////////////////////////////////////////
    
    
    JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
      JVMWrapper("JVM_IHashCode");
      // as implemented in the classic virtual machine; return 0 if object is NULL
      return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
    JVM_END

    FastHashCode声明
    synchronizer.hpp
    
    37
    class ObjectSynchronizer : AllStatic {
    100
    static intptr_t FastHashCode (Thread * Self, oop obj) ;
     
    FastHashCode实现:
    synchronizer.cpp
    471
    static markOop ReadStableMark (oop obj) {
      markOop mark = obj->mark() ;
      if (!mark->is_being_inflated()) {
        return mark ;       // normal fast-path return
      }
    
    557
    static inline intptr_t get_next_hash(Thread * Self, oop obj) {
      intptr_t value = 0 ;
      if (hashCode == 0) {
         // This form uses an unguarded global Park-Miller RNG,
         // so it's possible for two threads to race and generate the same RNG.
         // On MP system we'll have lots of RW access to a global, so the
         // mechanism induces lots of coherency traffic.
         value = os::random() ;
      } else
      if (hashCode == 1) {
         // This variation has the property of being stable (idempotent)
         // between STW operations.  This can be useful in some of the 1-0
         // synchronization schemes.
         intptr_t addrBits = intptr_t(obj) >> 3 ;
         value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
      } else
      if (hashCode == 2) {
         value = 1 ;            // for sensitivity testing
      } else
      if (hashCode == 3) {
         value = ++GVars.hcSequence ;
      } else
      if (hashCode == 4) {
         value = intptr_t(obj) ;
      } else {
         // 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 = Self->_hashStateX ;
         t ^= (t << 11) ;
         Self->_hashStateX = Self->_hashStateY ;
         Self->_hashStateY = Self->_hashStateZ ;
         Self->_hashStateZ = Self->_hashStateW ;
         unsigned v = Self->_hashStateW ;
         v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
         Self->_hashStateW = v ;
         value = v ;
      }
     
      value &= markOopDesc::hash_mask;
      if (value == 0) value = 0xBAD ;
      assert (value != markOopDesc::no_hash, "invariant") ;
      TEVENT (hashCode: GENERATE) ;
      return value;
    }  
    
    
    603
    intptr_t ObjectSynchronizer::FastHashCode (Thread * Self, oop obj) {
      if (UseBiasedLocking) {
        // NOTE: many places throughout the JVM do not expect a safepoint
        // to be taken here, in particular most operations on perm gen
        // objects. However, we only ever bias Java instances and all of
        // the call sites of identity_hash that might revoke biases have
        // been checked to make sure they can handle a safepoint. The
        // added check of the bias pattern is to avoid useless calls to
        // thread-local storage.
        if (obj->mark()->has_bias_pattern()) {
          // Box and unbox the raw reference just in case we cause a STW safepoint.
          Handle hobj (Self, obj) ;
          // Relaxing assertion for bug 6320749.
          assert (Universe::verify_in_progress() ||
                  !SafepointSynchronize::is_at_safepoint(),
                 "biases should not be seen by VM thread here");
          BiasedLocking::revoke_and_rebias(hobj, false, JavaThread::current());
          obj = hobj() ;
          assert(!obj->mark()->has_bias_pattern(), "biases should be revoked by now");
        }
      }
    
      // hashCode() is a heap mutator ...
      // Relaxing assertion for bug 6320749.
      assert (Universe::verify_in_progress() ||
              !SafepointSynchronize::is_at_safepoint(), "invariant") ;
      assert (Universe::verify_in_progress() ||
              Self->is_Java_thread() , "invariant") ;
      assert (Universe::verify_in_progress() ||
             ((JavaThread *)Self)->thread_state() != _thread_blocked, "invariant") ;
    
      ObjectMonitor* monitor = NULL;
      markOop temp, test;
      intptr_t hash;
      markOop mark = ReadStableMark (obj);
    
      // object should remain ineligible for biased locking
      assert (!mark->has_bias_pattern(), "invariant") ;
    
      if (mark->is_neutral()) {
        hash = mark->hash();              // this is a normal header
        if (hash) {                       // if it has hash, just return it
          return hash;
        }
        hash = get_next_hash(Self, obj);  // allocate a new hash code
        temp = mark->copy_set_hash(hash); // merge the hash code into header
        // use (machine word version) atomic operation to install the hash
        test = (markOop) Atomic::cmpxchg_ptr(temp, obj->mark_addr(), mark);
        if (test == mark) {
          return hash;
        }
        // If atomic operation failed, we must inflate the header
        // into heavy weight monitor. We could add more code here
        // for fast path, but it does not worth the complexity.
      } else if (mark->has_monitor()) {
        monitor = mark->monitor();
        temp = monitor->header();
        assert (temp->is_neutral(), "invariant") ;
        hash = temp->hash();
        if (hash) {
          return hash;
        }
        // Skip to the following code to reduce code size
      } else if (Self->is_lock_owned((address)mark->locker())) {
        temp = mark->displaced_mark_helper(); // this is a lightweight monitor owned
        assert (temp->is_neutral(), "invariant") ;
        hash = temp->hash();              // by current thread, check if the displaced
        if (hash) {                       // header contains hash code
          return hash;
        }
        // WARNING:
        //   The displaced header is strictly immutable.
        // It can NOT be changed in ANY cases. So we have
        // to inflate the header into heavyweight monitor
        // even the current thread owns the lock. The reason
        // is the BasicLock (stack slot) will be asynchronously
        // read by other threads during the inflate() function.
        // Any change to stack may not propagate to other threads
        // correctly.
      }
    
      // Inflate the monitor to set hash code
      monitor = ObjectSynchronizer::inflate(Self, obj);
      // Load displaced header and check it has hash code
      mark = monitor->header();
      assert (mark->is_neutral(), "invariant") ;
      hash = mark->hash();
      if (hash == 0) {
        hash = get_next_hash(Self, obj);
        temp = mark->copy_set_hash(hash); // merge hash code into header
        assert (temp->is_neutral(), "invariant") ;
        test = (markOop) Atomic::cmpxchg_ptr(temp, monitor, mark);
        if (test != mark) {
          // The only update to the header in the monitor (outside GC)
          // is install the hash code. If someone add new usage of
          // displaced header, please update this code
          hash = test->hash();
          assert (test->is_neutral(), "invariant") ;
          assert (hash != 0, "Trivial unexpected object/monitor header usage.");
        }
      }
      // We finally get the hash
      return hash;
    }

    我们看到最终还是 尝试用 mark->hash()获取hash的
     
    必要信息:
    globalDefinitions.hpp
    
    
    58
    #ifdef _LP64
    const int LogBytesPerWord    = 3;
    #else
    const int LogBytesPerWord    = 2;
    #endif
    
    70
    const int LogBitsPerByte     = 3;
    73
    const int LogBitsPerWord     = LogBitsPerByte + LogBytesPerWord;
    79
    const int BitsPerWord        = 1 << LogBitsPerWord;
    
    
    
    
    
    243
    typedef uintptr_t     address_word; // unsigned integer which will hold a pointer
                                        // except for some implementations of a C++
                                        // linkage pointer to function. Should never
                                        // need one of those to be placed in this
                                        // type anyway.
    
    
    955
    const intptr_t OneBit     =  1; // only right_most bit set in a word
    
    // get a word with the n.th or the right-most or left-most n bits set
    // (note: #define used only so that they can be used in enum constant definitions)
    #define nth_bit(n)        (n >= BitsPerWord ? 0 : OneBit << (n))
    #define right_n_bits(n)   (nth_bit(n) - 1)
    #define left_n_bits(n)    (right_n_bits(n) << (n >= BitsPerWord ? 0 : (BitsPerWord - n)))
    
    960
    #define right_n_bits(n)   (nth_bit(n) - 1)          
    
    966
    inline intptr_t mask_bits      (intptr_t  x, intptr_t m) { return x & m; }

    globalDefinitions_gcc.hpp
    155
    typedef int                     intptr_t;
    typedef unsigned int            uintptr_t;

    oop.hpp
    61
    class oopDesc.....整个都是
    
    
    
    79
    markOop  mark() const         { return _mark; }

    markOop.hpp   markOopDesc继承自oopDesc
    
    
    28
    #include "oops/oop.hpp"
    
    // The markOop describes the header of an object.
    //
    // Note that the mark is not a real oop but just a word.
    // It is placed in the oop hierarchy for historical reasons.
    //
    // Bit-format of an object header (most significant first, big endian layout below):
    //
    //  32 bits:
    //  --------
    //             hash:25 ------------>| age:4    biased_lock:1 lock:2 (normal object)
    //             JavaThread*:23 epoch:2 age:4    biased_lock:1 lock:2 (biased object)
    //             size:32 ------------------------------------------>| (CMS free block)
    //             PromotedObject*:29 ---------->| promo_bits:3 ----->| (CMS promoted object)
    //
    //  64 bits:
    //  --------
    //  unused:25 hash:31 -->| unused:1   age:4    biased_lock:1 lock:2 (normal object)
    //  JavaThread*:54 epoch:2 unused:1   age:4    biased_lock:1 lock:2 (biased object)
    //  PromotedObject*:61 --------------------->| promo_bits:3 ----->| (CMS promoted object)
    //  size:64 ----------------------------------------------------->| (CMS free block)
    //
    //  unused:25 hash:31 -->| cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && normal object)
    //  JavaThread*:54 epoch:2 cms_free:1 age:4    biased_lock:1 lock:2 (COOPs && biased object)
    //  narrowOop:32 unused:24 cms_free:1 unused:4 promo_bits:3 ----->| (COOPs && CMS promoted object)
    //  unused:21 size:35 -->| cms_free:1 unused:7 ------------------>| (COOPs && CMS free block)
    //
    //  - hash contains the identity hash value: largest value is
    //    31 bits, see os::random().  Also, 64-bit vm's require
    //    a hash value no bigger than 32 bits because they will not
    //    properly generate a mask larger than that: see library_call.cpp
    //    and c1_CodePatterns_sparc.cpp.
    //
    //  - the biased lock pattern is used to bias a lock toward a given
    //    thread. When this pattern is set in the low three bits, the lock
    //    is either biased toward a given thread or "anonymously" biased,
    //    indicating that it is possible for it to be biased. When the
    //    lock is biased toward a given thread, locking and unlocking can
    //    be performed by that thread without using atomic operations.
    //    When a lock's bias is revoked, it reverts back to the normal
    //    locking scheme described below.
    //
    //    Note that we are overloading the meaning of the "unlocked" state
    //    of the header. Because we steal a bit from the age we can
    //    guarantee that the bias pattern will never be seen for a truly
    //    unlocked object.
    //
    //    Note also that the biased state contains the age bits normally
    //    contained in the object header. Large increases in scavenge
    //    times were seen when these bits were absent and an arbitrary age
    //    assigned to all biased objects, because they tended to consume a
    //    significant fraction of the eden semispaces and were not
    //    promoted promptly, causing an increase in the amount of copying
    //    performed. The runtime system aligns all JavaThread* pointers to
    //    a very large value (currently 128 bytes (32bVM) or 256 bytes (64bVM))
    //    to make room for the age bits & the epoch bits (used in support of
    //    biased locking), and for the CMS "freeness" bit in the 64bVM (+COOPs).
    //
    //    [JavaThread* | epoch | age | 1 | 01]       lock is biased toward given thread
    //    [0           | epoch | age | 1 | 01]       lock is anonymously biased
    //
    //  - the two lock bits are used to describe three states: locked/unlocked and monitor.
    //
    //    [ptr             | 00]  locked             ptr points to real header on stack
    //    [header      | 0 | 01]  unlocked           regular object header
    //    [ptr             | 10]  monitor            inflated lock (header is wapped out)
    //    [ptr             | 11]  marked             used by markSweep to mark an object
    //                                               not valid at any other time
    //
    //    We assume that stack/thread pointers have the lowest two bits cleared.
    
    
    104
    class markOopDesc: public oopDesc {
     private:
      // Conversion
      uintptr_t value() const { return (uintptr_t) this; }
      ....................
    
    111
    
     enum { age_bits                  = 4,
             lock_bits                = 2,
             biased_lock_bits         = 1,
             max_hash_bits            = BitsPerWord - age_bits - lock_bits - biased_lock_bits,
             hash_bits                = max_hash_bits > 31 ? 31 : max_hash_bits,
             cms_bits                 = LP64_ONLY(1) NOT_LP64(0),
             epoch_bits               = 2
      };
      
    120
    
      // The biased locking code currently requires that the age bits be
      // contiguous to the lock bits.
      enum { lock_shift               = 0,
             biased_lock_shift        = lock_bits,
             age_shift                = lock_bits + biased_lock_bits,
             cms_shift                = age_shift + age_bits,
             hash_shift               = cms_shift + cms_bits,
             epoch_shift              = hash_shift
      };
      
    141
    #ifndef _WIN64
             ,hash_mask               = right_n_bits(hash_bits),
             hash_mask_in_place       = (address_word)hash_mask << hash_shift
    #endif
    .................
    
    227
      bool is_being_inflated() const { return (value() == 0); }
      
    302
      markOop copy_set_hash(intptr_t hash) const {
        intptr_t tmp = value() & (~hash_mask_in_place);
        tmp |= ((hash & hash_mask) << hash_shift);
        return (markOop)tmp;
      }  
      
    342
     // hash operations
      intptr_t hash() const {
        return mask_bits(value() >> hash_shift, hash_mask);//二者进行相与 value() >> hash_shift ,hash_mask
        //注:为了方便看:
                  //hash_shift  = cms_shift(其实=7) + cms_bits(1)
                  //cms_bits    = LP64_ONLY(1) NOT_LP64(0),
                  //hash_mask   = ( hash_bits >= BitsPerWord ? 0 : OneBit << (hash_bits) ) -1 
                  //hash_bits   = max_hash_bits > 31 ? 31 : max_hash_bits
                  //max_hash_bits      = BitsPerWord - 4 - 2 - 1
                  //BitsPerWord = 1 << LogBitsPerWord
                  //LogBitsPerWord     = 3 + 3;
      }
    

    macros.hpp  
    112
    #ifdef  _LP64
    #define LP64_ONLY(code) code
    #define NOT_LP64(code)
    #else  // !_LP64
    #define LP64_ONLY(code)
    #define NOT_LP64(code) code
    #endif // _LP64
    oopsHierarchy.hpp
    40
    #ifndef CHECK_UNHANDLED_OOPS
    ....
    typedef class oopDesc*   oop;
    74
    typedef class   markOopDesc*    markOop;
    ....
    #else
        ...
    class oop {
        oopDesc* _o;
        .....
    }


     
     
  • 相关阅读:
    Total Video Converter v3.71 注册码
    Web下载文件
    语音朗读
    SQLSERVER 删除重复记录
    Windows8[启用IIS8 asp.net功能]
    黑链代码
    在ASP.NET中防止注入攻击[翻译]
    Oracle 正确删除archivelog文件
    浅谈网站黑链检测和清除的方法
    解密SQLServer2000加密存储过程,函数,触发器,视图
  • 原文地址:https://www.cnblogs.com/slankka/p/9158560.html
Copyright © 2020-2023  润新知