< prev index next >

src/hotspot/share/oops/markWord.hpp

Print this page
*** 44,17 ***
  //  --------
  //  unused:22 hash:31 -->| unused_gap:4  age:4  self-fwd:1  lock:2 (normal object)
  //
  //  64 bits (with compact headers):
  //  -------------------------------
! //  klass:22  hash:31 -->| unused_gap:4  age:4  self-fwd:1  lock:2 (normal object)
  //
  //  - 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
  //
  //  - the two lock bits are used to describe three states: locked/unlocked and monitor.
  //
  //    [ptr             | 00]  locked             ptr points to real header on stack (stack-locking in use)
  //    [header          | 00]  locked             locked regular object header (fast-locking in use)
  //    [header          | 01]  unlocked           regular object header
--- 44,30 ---
  //  --------
  //  unused:22 hash:31 -->| unused_gap:4  age:4  self-fwd:1  lock:2 (normal object)
  //
  //  64 bits (with compact headers):
  //  -------------------------------
! //  klass:22  unused_gap:29 hash:2 -->| unused_gap:4  age:4  self-fwd:1  lock:2 (normal object)
  //
  //  - 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
  //
+ //  - With +UseCompactObjectHeaders:
+ //    hashctrl bits indicate if object has been hashed:
+ //    00 - never hashed
+ //    01 - hashed, but not expanded by GC: will recompute hash
+ //    10 - not hashed, but expanded; special state used only by CDS to deal with scratch classes
+ //    11 - hashed and expanded by GC, and hashcode has been installed in hidden field
+ //
+ //    When identityHashCode() is called, the transitions work as follows:
+ //    00 - set the hashctrl bits to 01, and compute the identity hash
+ //    01 - recompute idendity hash. When GC encounters 01 when moving an object, it will allocate an extra word, if
+ //         necessary, for the object copy, and install 11.
+ //    11 - read hashcode from field
+ //
  //  - the two lock bits are used to describe three states: locked/unlocked and monitor.
  //
  //    [ptr             | 00]  locked             ptr points to real header on stack (stack-locking in use)
  //    [header          | 00]  locked             locked regular object header (fast-locking in use)
  //    [header          | 01]  unlocked           regular object header

*** 103,42 ***
      return !operator==(other);
    }
  
    // Conversion
    uintptr_t value() const { return _value; }
  
    // Constants
    static const int age_bits                       = 4;
    static const int lock_bits                      = 2;
    static const int self_fwd_bits                  = 1;
    static const int max_hash_bits                  = BitsPerWord - age_bits - lock_bits - self_fwd_bits;
    static const int hash_bits                      = max_hash_bits > 31 ? 31 : max_hash_bits;
    static const int unused_gap_bits                = LP64_ONLY(4) NOT_LP64(0); // Reserved for Valhalla.
  
    static const int lock_shift                     = 0;
    static const int self_fwd_shift                 = lock_shift + lock_bits;
    static const int age_shift                      = self_fwd_shift + self_fwd_bits;
    static const int hash_shift                     = age_shift + age_bits + unused_gap_bits;
  
    static const uintptr_t lock_mask                = right_n_bits(lock_bits);
    static const uintptr_t lock_mask_in_place       = lock_mask << lock_shift;
    static const uintptr_t self_fwd_mask            = right_n_bits(self_fwd_bits);
    static const uintptr_t self_fwd_mask_in_place   = self_fwd_mask << self_fwd_shift;
    static const uintptr_t age_mask                 = right_n_bits(age_bits);
    static const uintptr_t age_mask_in_place        = age_mask << age_shift;
    static const uintptr_t hash_mask                = right_n_bits(hash_bits);
    static const uintptr_t hash_mask_in_place       = hash_mask << hash_shift;
  
  #ifdef _LP64
    // Used only with compact headers:
    // We store the (narrow) Klass* in the bits 43 to 64.
  
    // These are for bit-precise extraction of the narrow Klass* from the 64-bit Markword
!   static constexpr int klass_offset_in_bytes      = 4;
!   static constexpr int klass_shift                = hash_shift + hash_bits;
-   static constexpr int klass_shift_at_offset      = klass_shift - klass_offset_in_bytes * BitsPerByte;
-   static constexpr int klass_bits                 = 22;
    static constexpr uintptr_t klass_mask           = right_n_bits(klass_bits);
    static constexpr uintptr_t klass_mask_in_place  = klass_mask << klass_shift;
  #endif
  
  
--- 116,47 ---
      return !operator==(other);
    }
  
    // Conversion
    uintptr_t value() const { return _value; }
+   uint32_t value32() const { return (uint32_t)_value; }
  
    // Constants
    static const int age_bits                       = 4;
    static const int lock_bits                      = 2;
    static const int self_fwd_bits                  = 1;
    static const int max_hash_bits                  = BitsPerWord - age_bits - lock_bits - self_fwd_bits;
    static const int hash_bits                      = max_hash_bits > 31 ? 31 : max_hash_bits;
    static const int unused_gap_bits                = LP64_ONLY(4) NOT_LP64(0); // Reserved for Valhalla.
+   static const int hashctrl_bits                  = 2;
  
    static const int lock_shift                     = 0;
    static const int self_fwd_shift                 = lock_shift + lock_bits;
    static const int age_shift                      = self_fwd_shift + self_fwd_bits;
    static const int hash_shift                     = age_shift + age_bits + unused_gap_bits;
+   static const int hashctrl_shift                 = age_shift + age_bits + unused_gap_bits;
  
    static const uintptr_t lock_mask                = right_n_bits(lock_bits);
    static const uintptr_t lock_mask_in_place       = lock_mask << lock_shift;
    static const uintptr_t self_fwd_mask            = right_n_bits(self_fwd_bits);
    static const uintptr_t self_fwd_mask_in_place   = self_fwd_mask << self_fwd_shift;
    static const uintptr_t age_mask                 = right_n_bits(age_bits);
    static const uintptr_t age_mask_in_place        = age_mask << age_shift;
    static const uintptr_t hash_mask                = right_n_bits(hash_bits);
    static const uintptr_t hash_mask_in_place       = hash_mask << hash_shift;
+   static const uintptr_t hashctrl_mask            = right_n_bits(hashctrl_bits);
+   static const uintptr_t hashctrl_mask_in_place   = hashctrl_mask << hashctrl_shift;
+   static const uintptr_t hashctrl_hashed_mask_in_place    = ((uintptr_t)1) << hashctrl_shift;
+   static const uintptr_t hashctrl_expanded_mask_in_place  = ((uintptr_t)2) << hashctrl_shift;
  
  #ifdef _LP64
    // Used only with compact headers:
    // We store the (narrow) Klass* in the bits 43 to 64.
  
    // These are for bit-precise extraction of the narrow Klass* from the 64-bit Markword
!   static constexpr int klass_shift                = hashctrl_shift + hashctrl_bits;
!   static constexpr int klass_bits                 = 19;
    static constexpr uintptr_t klass_mask           = right_n_bits(klass_bits);
    static constexpr uintptr_t klass_mask_in_place  = klass_mask << klass_shift;
  #endif
  
  

*** 162,11 ***
    }
    bool is_unlocked() const {
      return (mask_bits(value(), lock_mask_in_place) == unlocked_value);
    }
    bool is_marked()   const {
!     return (mask_bits(value(), lock_mask_in_place) == marked_value);
    }
    bool is_forwarded() const {
      // Returns true for normal forwarded (0b011) and self-forwarded (0b1xx).
      return mask_bits(value(), lock_mask_in_place | self_fwd_mask_in_place) >= static_cast<intptr_t>(marked_value);
    }
--- 180,11 ---
    }
    bool is_unlocked() const {
      return (mask_bits(value(), lock_mask_in_place) == unlocked_value);
    }
    bool is_marked()   const {
!     return (value() & (self_fwd_mask_in_place | lock_mask_in_place)) > monitor_value;
    }
    bool is_forwarded() const {
      // Returns true for normal forwarded (0b011) and self-forwarded (0b1xx).
      return mask_bits(value(), lock_mask_in_place | self_fwd_mask_in_place) >= static_cast<intptr_t>(marked_value);
    }

*** 187,11 ***
    // Fast-locking does not use INFLATING.
    static markWord INFLATING() { return zero(); }    // inflate-in-progress
  
    // Should this header be preserved during GC?
    bool must_be_preserved(const oopDesc* obj) const {
!     return (!is_unlocked() || !has_no_hash());
    }
  
    // WARNING: The following routines are used EXCLUSIVELY by
    // synchronization functions. They are not really gc safe.
    // They must get updated if markWord layout get changed.
--- 205,11 ---
    // Fast-locking does not use INFLATING.
    static markWord INFLATING() { return zero(); }    // inflate-in-progress
  
    // Should this header be preserved during GC?
    bool must_be_preserved(const oopDesc* obj) const {
!     return UseCompactObjectHeaders ? !is_unlocked() : (!is_unlocked() || !has_no_hash());
    }
  
    // WARNING: The following routines are used EXCLUSIVELY by
    // synchronization functions. They are not really gc safe.
    // They must get updated if markWord layout get changed.

*** 234,10 ***
--- 252,11 ---
      return (lockbits & unlocked_value) == 0;
    }
    markWord displaced_mark_helper() const;
    void set_displaced_mark_helper(markWord m) const;
    markWord copy_set_hash(intptr_t hash) const {
+     assert(!UseCompactObjectHeaders, "Do not use with compact i-hash");
      uintptr_t tmp = value() & (~hash_mask_in_place);
      tmp |= ((hash & hash_mask) << hash_shift);
      return markWord(tmp);
    }
    // it is only used to be stored into BasicLock as the

*** 274,26 ***
    }
    markWord incr_age()      const { return age() == max_age ? markWord(_value) : set_age(age() + 1); }
  
    // hash operations
    intptr_t hash() const {
      return mask_bits(value() >> hash_shift, hash_mask);
    }
  
    bool has_no_hash() const {
!     return hash() == no_hash;
    }
  
    inline Klass* klass() const;
    inline Klass* klass_or_null() const;
    inline Klass* klass_without_asserts() const;
    inline narrowKlass narrow_klass() const;
    inline markWord set_narrow_klass(narrowKlass narrow_klass) const;
  
    // Prototype mark for initialization
    static markWord prototype() {
!     return markWord( no_hash_in_place | no_lock_in_place );
    }
  
    // Debugging
    void print_on(outputStream* st, bool print_monitor_info = true) const;
  
--- 293,91 ---
    }
    markWord incr_age()      const { return age() == max_age ? markWord(_value) : set_age(age() + 1); }
  
    // hash operations
    intptr_t hash() const {
+     assert(!UseCompactObjectHeaders, "only without compact i-hash");
      return mask_bits(value() >> hash_shift, hash_mask);
    }
  
    bool has_no_hash() const {
!     if (UseCompactObjectHeaders) {
+       return !is_hashed();
+     } else {
+       return hash() == no_hash;
+     }
+   }
+ 
+   inline bool is_hashed_not_expanded() const {
+     assert(UseCompactObjectHeaders, "only with compact i-hash");
+     return (value() & hashctrl_mask_in_place) == hashctrl_hashed_mask_in_place;
+   }
+   inline markWord set_hashed_not_expanded() const {
+     assert(UseCompactObjectHeaders, "only with compact i-hash");
+     return markWord((value() & ~hashctrl_mask_in_place) | hashctrl_hashed_mask_in_place);
+   }
+ 
+   inline bool is_hashed_expanded() const {
+     assert(UseCompactObjectHeaders, "only with compact i-hash");
+     return (value() & hashctrl_mask_in_place) == (hashctrl_hashed_mask_in_place | hashctrl_expanded_mask_in_place);
+   }
+   inline markWord set_hashed_expanded() const {
+     assert(UseCompactObjectHeaders, "only with compact i-hash");
+     return markWord((value() & ~hashctrl_mask_in_place) | (hashctrl_hashed_mask_in_place | hashctrl_expanded_mask_in_place));
+   }
+ 
+   // This is a special hashctrl state (11) that is only used
+   // during CDS archive dumping. There we allocate 'scratch mirrors' for
+   // each real mirror klass. We allocate those scratch mirrors
+   // in a pre-extended form, but without being hashed. When the
+   // real mirror gets hashed, then we turn the scratch mirror into
+   // hashed_moved state, otherwise we leave it in that special state
+   // which indicates that the archived copy will be allocated in the
+   // unhashed form.
+   inline bool is_not_hashed_expanded() const {
+     assert(UseCompactObjectHeaders, "only with compact i-hash");
+     return (value() & hashctrl_mask_in_place) == hashctrl_expanded_mask_in_place;
+   }
+   inline markWord set_not_hashed_expanded() const {
+     assert(UseCompactObjectHeaders, "only with compact i-hash");
+     return markWord((value() & ~hashctrl_mask_in_place) | hashctrl_expanded_mask_in_place);
+   }
+   // Return true when object is either hashed_moved or not_hashed_moved.
+   inline bool is_expanded() const {
+     assert(UseCompactObjectHeaders, "only with compact i-hash");
+     return (value() & hashctrl_expanded_mask_in_place) != 0;
+   }
+   inline bool is_hashed() const {
+     assert(UseCompactObjectHeaders, "only with compact i-hash");
+     return (value() & hashctrl_hashed_mask_in_place) != 0;
+   }
+ 
+   inline markWord copy_hashctrl_from(markWord m) const {
+     if (UseCompactObjectHeaders) {
+       return markWord((value() & ~hashctrl_mask_in_place) | (m.value() & hashctrl_mask_in_place));
+     } else {
+       return markWord(value());
+     }
    }
  
    inline Klass* klass() const;
    inline Klass* klass_or_null() const;
    inline Klass* klass_without_asserts() const;
    inline narrowKlass narrow_klass() const;
    inline markWord set_narrow_klass(narrowKlass narrow_klass) const;
  
+ #ifdef _LP64
+   inline int array_length() { return checked_cast<int>(value() >> 32); }
+ #endif
+ 
    // Prototype mark for initialization
    static markWord prototype() {
!     if (UseCompactObjectHeaders) {
+       return markWord(no_lock_in_place);
+     } else {
+       return markWord(no_hash_in_place | no_lock_in_place);
+     }
    }
  
    // Debugging
    void print_on(outputStream* st, bool print_monitor_info = true) const;
  

*** 303,11 ***
    // Recover address of oop from encoded form used in mark
    inline void* decode_pointer() const { return (void*)clear_lock_bits().value(); }
  
    inline bool is_self_forwarded() const {
      NOT_LP64(assert(LockingMode != LM_LEGACY, "incorrect with LM_LEGACY on 32 bit");)
!     return mask_bits(value(), self_fwd_mask_in_place) != 0;
    }
  
    inline markWord set_self_forwarded() const {
      NOT_LP64(assert(LockingMode != LM_LEGACY, "incorrect with LM_LEGACY on 32 bit");)
      return markWord(value() | self_fwd_mask_in_place);
--- 387,12 ---
    // Recover address of oop from encoded form used in mark
    inline void* decode_pointer() const { return (void*)clear_lock_bits().value(); }
  
    inline bool is_self_forwarded() const {
      NOT_LP64(assert(LockingMode != LM_LEGACY, "incorrect with LM_LEGACY on 32 bit");)
!     // Match 100, 101, 110 but not 111.
+     return mask_bits(value() + 1, (lock_mask_in_place | self_fwd_mask_in_place)) > 4;
    }
  
    inline markWord set_self_forwarded() const {
      NOT_LP64(assert(LockingMode != LM_LEGACY, "incorrect with LM_LEGACY on 32 bit");)
      return markWord(value() | self_fwd_mask_in_place);
< prev index next >