< prev index next >

src/hotspot/share/gc/shared/c2/barrierSetC2.cpp

Print this page
*** 702,30 ***
    // Exclude the header but include array length to copy by 8 bytes words.
    // Can't use base_offset_in_bytes(bt) since basic type is unknown.
    int base_off = is_array ? arrayOopDesc::length_offset_in_bytes() :
                              instanceOopDesc::base_offset_in_bytes();
    // base_off:
!   // 8  - 32-bit VM or 64-bit VM, compact headers
    // 12 - 64-bit VM, compressed klass
    // 16 - 64-bit VM, normal klass
    if (base_off % BytesPerLong != 0) {
      assert(UseCompressedClassPointers, "");
-     assert(!UseCompactObjectHeaders, "");
      if (is_array) {
        // Exclude length to copy by 8 bytes words.
        base_off += sizeof(int);
      } else {
!       // Include klass to copy by 8 bytes words.
!       base_off = instanceOopDesc::klass_offset_in_bytes();
      }
!     assert(base_off % BytesPerLong == 0, "expect 8 bytes alignment");
    }
    return base_off;
  }
  
  void BarrierSetC2::clone(GraphKit* kit, Node* src_base, Node* dst_base, Node* size, bool is_array) const {
    int base_off = arraycopy_payload_base_offset(is_array);
    Node* payload_size = size;
    Node* offset = kit->MakeConX(base_off);
    payload_size = kit->gvn().transform(new SubXNode(payload_size, offset));
    if (is_array) {
      // Ensure the array payload size is rounded up to the next BytesPerLong
--- 702,65 ---
    // Exclude the header but include array length to copy by 8 bytes words.
    // Can't use base_offset_in_bytes(bt) since basic type is unknown.
    int base_off = is_array ? arrayOopDesc::length_offset_in_bytes() :
                              instanceOopDesc::base_offset_in_bytes();
    // base_off:
!   // 4  - compact headers
+   // 8  - 32-bit VM
    // 12 - 64-bit VM, compressed klass
    // 16 - 64-bit VM, normal klass
    if (base_off % BytesPerLong != 0) {
      assert(UseCompressedClassPointers, "");
      if (is_array) {
        // Exclude length to copy by 8 bytes words.
        base_off += sizeof(int);
      } else {
!       if (!UseCompactObjectHeaders) {
!         // Include klass to copy by 8 bytes words.
+         base_off = instanceOopDesc::klass_offset_in_bytes();
+       }
      }
!     assert(base_off % BytesPerLong == 0 || UseCompactObjectHeaders, "expect 8 bytes alignment");
    }
    return base_off;
  }
  
  void BarrierSetC2::clone(GraphKit* kit, Node* src_base, Node* dst_base, Node* size, bool is_array) const {
    int base_off = arraycopy_payload_base_offset(is_array);
+   if (UseCompactObjectHeaders && !is_aligned(base_off, BytesPerLong) &&
+       !kit->gvn().type(src_base)->isa_aryptr()) {
+     guarantee(is_aligned(base_off, BytesPerInt), "must be 4-bytes aligned");
+     // The optimized copy routine only copies 8-byte words. For this reason, we must
+     // copy the 4 bytes at offset 4 separately.
+     // Use the correct field-specific alias derived from the typed address, matching
+     // the pattern in PhaseMacroExpand::generate_arraycopy (macroArrayCopy.cpp).
+     // Using AliasIdxRaw would create a mismatch between the typed address and the
+     // raw memory chain, causing an escape analysis assertion failure.
+     //
+     // Skip this when src_base has an array type. With StressReflectiveCode, the
+     // instance path of the clone can be live in the IR even when the type system
+     // knows src_base is an array. The pre-copy is unnecessary on such paths (they
+     // are unreachable at runtime), and creating a LoadNode at the array length
+     // offset would assert (LoadRangeNode required).
+     Node* sptr = kit->basic_plus_adr(src_base, base_off);
+     Node* dptr = kit->basic_plus_adr(dst_base, base_off);
+     const TypePtr* s_adr_type = kit->gvn().type(sptr)->is_ptr();
+     const TypePtr* d_adr_type = kit->gvn().type(dptr)->is_ptr();
+     uint s_alias_idx = Compile::current()->get_alias_index(s_adr_type);
+     uint d_alias_idx = Compile::current()->get_alias_index(d_adr_type);
+     Node* first = kit->gvn().transform(LoadNode::make(kit->gvn(), kit->control(), kit->memory(s_alias_idx),
+                                        sptr, s_adr_type, TypeInt::INT, T_INT,
+                                        MemNode::unordered));
+     Node* st = kit->gvn().transform(StoreNode::make(kit->gvn(), kit->control(), kit->memory(d_alias_idx),
+                                                     dptr, d_adr_type,
+                                                     first, T_INT, MemNode::unordered));
+     kit->set_memory(st, d_alias_idx);
+     kit->record_for_igvn(st);
+     base_off += sizeof(jint);
+     guarantee(is_aligned(base_off, BytesPerLong), "must be 8-bytes aligned");
+   }
+ 
    Node* payload_size = size;
    Node* offset = kit->MakeConX(base_off);
    payload_size = kit->gvn().transform(new SubXNode(payload_size, offset));
    if (is_array) {
      // Ensure the array payload size is rounded up to the next BytesPerLong

*** 845,11 ***
    assert(size->bottom_type()->base() == Type_X,
           "Should be of object size type (int for 32 bits, long for 64 bits)");
  
    // The native clone we are calling here expects the object size in words.
    // Add header/offset size to payload size to get object size.
!   Node* const base_offset = phase->MakeConX(arraycopy_payload_base_offset(ac->is_clone_array()) >> LogBytesPerLong);
    Node* const full_size = phase->transform_later(new AddXNode(size, base_offset));
    // HeapAccess<>::clone expects size in heap words.
    // For 64-bits platforms, this is a no-operation.
    // For 32-bits platforms, we need to multiply full_size by HeapWordsPerLong (2).
    Node* const full_size_in_heap_words = phase->transform_later(new LShiftXNode(full_size, phase->intcon(LogHeapWordsPerLong)));
--- 880,14 ---
    assert(size->bottom_type()->base() == Type_X,
           "Should be of object size type (int for 32 bits, long for 64 bits)");
  
    // The native clone we are calling here expects the object size in words.
    // Add header/offset size to payload size to get object size.
!   // Use the actual offset stored in the ArrayCopyNode (in bytes), not
+   // arraycopy_payload_base_offset(), because clone() may have bumped the
+   // offset past a 4-byte pre-copy for compact object headers.
+   Node* const base_offset = phase->transform_later(new URShiftXNode(ac->in(ArrayCopyNode::SrcPos), phase->intcon(LogBytesPerLong)));
    Node* const full_size = phase->transform_later(new AddXNode(size, base_offset));
    // HeapAccess<>::clone expects size in heap words.
    // For 64-bits platforms, this is a no-operation.
    // For 32-bits platforms, we need to multiply full_size by HeapWordsPerLong (2).
    Node* const full_size_in_heap_words = phase->transform_later(new LShiftXNode(full_size, phase->intcon(LogHeapWordsPerLong)));
< prev index next >