< prev index next > src/hotspot/share/gc/shared/c2/barrierSetC2.cpp
Print this page
// 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
// 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
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)));
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 >