< prev index next >

src/share/vm/opto/arraycopynode.cpp

Print this page
rev 12726 : 8179678: ArrayCopy with same src and dst can cause incorrect execution or compiler crash
Summary: replacing load on dst with load on src only valid if copy doesn't modify src element to load
Reviewed-by:
rev 12727 : review

*** 675,697 **** // in the destination array // if must_modify is false, return true if the copy could write // between offset_lo and offset_hi // if must_modify is true, return true if the copy is guaranteed to // write between offset_lo and offset_hi ! bool ArrayCopyNode::modifies(intptr_t offset_lo, intptr_t offset_hi, PhaseTransform* phase, bool must_modify) { assert(_kind == ArrayCopy || _kind == CopyOf || _kind == CopyOfRange, "only for real array copies"); ! Node* dest = in(ArrayCopyNode::Dest); ! Node* src_pos = in(ArrayCopyNode::SrcPos); ! Node* dest_pos = in(ArrayCopyNode::DestPos); ! Node* len = in(ArrayCopyNode::Length); const TypeInt *dest_pos_t = phase->type(dest_pos)->isa_int(); const TypeInt *len_t = phase->type(len)->isa_int(); const TypeAryPtr* ary_t = phase->type(dest)->isa_aryptr(); ! if (dest_pos_t != NULL && len_t != NULL && ary_t != NULL) { BasicType ary_elem = ary_t->klass()->as_array_klass()->element_type()->basic_type(); uint header = arrayOopDesc::base_offset_in_bytes(ary_elem); uint elemsize = type2aelembytes(ary_elem); jlong dest_pos_plus_len_lo = (((jlong)dest_pos_t->_lo) + len_t->_lo) * elemsize + header; --- 675,699 ---- // in the destination array // if must_modify is false, return true if the copy could write // between offset_lo and offset_hi // if must_modify is true, return true if the copy is guaranteed to // write between offset_lo and offset_hi ! bool ArrayCopyNode::modifies(intptr_t offset_lo, intptr_t offset_hi, PhaseTransform* phase, bool must_modify) const { assert(_kind == ArrayCopy || _kind == CopyOf || _kind == CopyOfRange, "only for real array copies"); ! Node* dest = in(Dest); ! Node* dest_pos = in(DestPos); ! Node* len = in(Length); const TypeInt *dest_pos_t = phase->type(dest_pos)->isa_int(); const TypeInt *len_t = phase->type(len)->isa_int(); const TypeAryPtr* ary_t = phase->type(dest)->isa_aryptr(); ! if (dest_pos_t == NULL || len_t == NULL || ary_t == NULL) { ! return !must_modify; ! } ! BasicType ary_elem = ary_t->klass()->as_array_klass()->element_type()->basic_type(); uint header = arrayOopDesc::base_offset_in_bytes(ary_elem); uint elemsize = type2aelembytes(ary_elem); jlong dest_pos_plus_len_lo = (((jlong)dest_pos_t->_lo) + len_t->_lo) * elemsize + header;
*** 706,713 **** --- 708,757 ---- } else { if (offset_hi >= dest_pos_lo && offset_lo < dest_pos_plus_len_hi) { return true; } } + return false; + } + + // We try to replace a load from the destination of an arraycopy with + // a load from the source so the arraycopy has a chance to be + // eliminated. It's only valid if the arraycopy doesn't change the + // element that would be loaded from the source array. + bool ArrayCopyNode::can_replace_dest_load_with_src_load(intptr_t offset_lo, intptr_t offset_hi, PhaseTransform* phase) const { + assert(_kind == ArrayCopy || _kind == CopyOf || _kind == CopyOfRange, "only for real array copies"); + + Node* src = in(Src); + Node* dest = in(Dest); + + if (src == dest) { + return false; } + + // Check whether, assuming source and destination are the same + // array, the arraycopy modifies the element from the source we + // would load. + if (in(SrcPos) == in(DestPos) || !modifies(offset_lo, offset_hi, phase, true)) { + // if not the transformation is legal + return true; + } + + AllocateNode* src_alloc = AllocateNode::Ideal_allocation(src, phase); + AllocateNode* dest_alloc = AllocateNode::Ideal_allocation(dest, phase); + + // Check whether source and destination can be proved to be + // different arrays + if (MemNode::detect_ptr_independence(src->uncast(), src_alloc, dest->uncast(), dest_alloc, phase)) { + return true; + } + + const TypeOopPtr* t_src = phase->type(src)->isa_oopptr(); + const TypeOopPtr* t_dest = phase->type(dest)->isa_oopptr(); + + if (t_src != NULL && t_dest != NULL && + (t_src->is_known_instance() || t_dest->is_known_instance()) && + t_src->instance_id() != t_dest->instance_id()) { + return true; + } + return false; }
< prev index next >