--- old/src/share/vm/opto/arraycopynode.cpp 2017-05-16 14:12:31.446334326 +0200 +++ new/src/share/vm/opto/arraycopynode.cpp 2017-05-16 14:12:26.898313777 +0200 @@ -677,37 +677,77 @@ // 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) { +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(ArrayCopyNode::Dest); - Node* src_pos = in(ArrayCopyNode::SrcPos); - Node* dest_pos = in(ArrayCopyNode::DestPos); - Node* len = in(ArrayCopyNode::Length); + 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) { - 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; - jlong dest_pos_plus_len_hi = (((jlong)dest_pos_t->_hi) + len_t->_hi) * elemsize + header; - jlong dest_pos_lo = ((jlong)dest_pos_t->_lo) * elemsize + header; - jlong dest_pos_hi = ((jlong)dest_pos_t->_hi) * elemsize + header; - - if (must_modify) { - if (offset_lo >= dest_pos_hi && offset_hi < dest_pos_plus_len_lo) { - return true; - } - } else { - if (offset_hi >= dest_pos_lo && offset_lo < dest_pos_plus_len_hi) { - return true; - } + 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; + jlong dest_pos_plus_len_hi = (((jlong)dest_pos_t->_hi) + len_t->_hi) * elemsize + header; + jlong dest_pos_lo = ((jlong)dest_pos_t->_lo) * elemsize + header; + jlong dest_pos_hi = ((jlong)dest_pos_t->_hi) * elemsize + header; + + if (must_modify) { + if (offset_lo >= dest_pos_hi && offset_hi < dest_pos_plus_len_lo) { + return true; } + } 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); + + // Check whether, assuming source and destination are the same + // array, the arraycopy modifies the element from the source we + // would load. + if ((src != dest && in(SrcPos) == in(DestPos)) || !modifies(offset_lo, offset_hi, phase, false)) { + // 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; }