src/share/vm/opto/memnode.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File hotspot Cdiff src/share/vm/opto/memnode.cpp

src/share/vm/opto/memnode.cpp

Print this page
rev 8052 : castpp gcm
rev 8833 : 8130847: Cloned object's fields observed as null after C2 escape analysis
Summary: Eliminated instance/array written to by an array copy variant must be correctly initialized when reallocated at a deopt
Reviewed-by:

*** 106,146 **** extern void print_alias_types(); #endif - static bool membar_for_arraycopy_helper(const TypeOopPtr *t_oop, Node* n, PhaseTransform *phase) { - if (n->is_Proj()) { - n = n->in(0); - if (n->is_Call() && n->as_Call()->may_modify(t_oop, phase)) { - return true; - } - } - return false; - } - - static bool membar_for_arraycopy(const TypeOopPtr *t_oop, MemBarNode* mb, PhaseTransform *phase) { - Node* mem = mb->in(TypeFunc::Memory); - - if (mem->is_MergeMem()) { - Node* n = mem->as_MergeMem()->memory_at(Compile::AliasIdxRaw); - if (membar_for_arraycopy_helper(t_oop, n, phase)) { - return true; - } else if (n->is_Phi()) { - for (uint i = 1; i < n->req(); i++) { - if (n->in(i) != NULL) { - if (membar_for_arraycopy_helper(t_oop, n->in(i), phase)) { - return true; - } - } - } - } - } - - return false; - } - Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypeOopPtr *t_oop, Node *load, PhaseGVN *phase) { assert((t_oop != NULL), "sanity"); bool is_instance = t_oop->is_known_instance_field(); bool is_boxed_value_load = t_oop->is_ptr_to_boxed_value() && (load != NULL) && load->is_Load() && --- 106,115 ----
*** 181,191 **** if (tklass->klass_is_exact() && !tklass->klass()->equals(t_oop->klass())) { result = proj_in->in(TypeFunc::Memory); // not related allocation } } } else if (proj_in->is_MemBar()) { ! if (membar_for_arraycopy(t_oop, proj_in->as_MemBar(), phase)) { break; } result = proj_in->in(TypeFunc::Memory); } else { assert(false, "unexpected projection"); --- 150,160 ---- if (tklass->klass_is_exact() && !tklass->klass()->equals(t_oop->klass())) { result = proj_in->in(TypeFunc::Memory); // not related allocation } } } else if (proj_in->is_MemBar()) { ! if (ArrayCopyNode::membar_for_arraycopy(t_oop, proj_in->as_MemBar(), phase)) { break; } result = proj_in->in(TypeFunc::Memory); } else { assert(false, "unexpected projection");
*** 543,582 **** Node* ld_offs = ld_addp->in(AddPNode::Offset); Node* dest = ac->in(ArrayCopyNode::Dest); if (dest == ld_base) { - Node* src_pos = ac->in(ArrayCopyNode::SrcPos); - Node* dest_pos = ac->in(ArrayCopyNode::DestPos); - Node* len = ac->in(ArrayCopyNode::Length); - - const TypeInt *dest_pos_t = phase->type(dest_pos)->isa_int(); const TypeX *ld_offs_t = phase->type(ld_offs)->isa_intptr_t(); ! const TypeInt *len_t = phase->type(len)->isa_int(); ! const TypeAryPtr* ary_t = phase->type(dest)->isa_aryptr(); ! ! if (dest_pos_t != NULL && ld_offs_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); ! ! intptr_t dest_pos_plus_len_lo = (((intptr_t)dest_pos_t->_lo) + len_t->_lo) * elemsize + header; ! intptr_t dest_pos_plus_len_hi = (((intptr_t)dest_pos_t->_hi) + len_t->_hi) * elemsize + header; ! intptr_t dest_pos_lo = ((intptr_t)dest_pos_t->_lo) * elemsize + header; ! intptr_t dest_pos_hi = ((intptr_t)dest_pos_t->_hi) * elemsize + header; ! ! if (can_see_stored_value) { ! if (ld_offs_t->_lo >= dest_pos_hi && ld_offs_t->_hi < dest_pos_plus_len_lo) { return ac; } ! } else { ! if (ld_offs_t->_hi < dest_pos_lo || ld_offs_t->_lo >= dest_pos_plus_len_hi) { mem = ac->in(TypeFunc::Memory); } - return ac; - } - } } } } } return NULL; --- 512,528 ---- Node* ld_offs = ld_addp->in(AddPNode::Offset); Node* dest = ac->in(ArrayCopyNode::Dest); if (dest == ld_base) { const TypeX *ld_offs_t = phase->type(ld_offs)->isa_intptr_t(); ! if (ac->modifies(ld_offs_t->_lo, ld_offs_t->_hi, phase, can_see_stored_value)) { return ac; } ! if (!can_see_stored_value) { mem = ac->in(TypeFunc::Memory); } } } } } return NULL;
*** 701,711 **** if (!call->may_modify(addr_t, phase)) { mem = call->in(TypeFunc::Memory); continue; // (a) advance through independent call memory } } else if (mem->is_Proj() && mem->in(0)->is_MemBar()) { ! if (membar_for_arraycopy(addr_t, mem->in(0)->as_MemBar(), phase)) { break; } mem = mem->in(0)->in(TypeFunc::Memory); continue; // (a) advance through independent MemBar memory } else if (mem->is_ClearArray()) { --- 647,657 ---- if (!call->may_modify(addr_t, phase)) { mem = call->in(TypeFunc::Memory); continue; // (a) advance through independent call memory } } else if (mem->is_Proj() && mem->in(0)->is_MemBar()) { ! if (ArrayCopyNode::membar_for_arraycopy(addr_t, mem->in(0)->as_MemBar(), phase)) { break; } mem = mem->in(0)->in(TypeFunc::Memory); continue; // (a) advance through independent MemBar memory } else if (mem->is_ClearArray()) {
*** 881,902 **** } // Is the value loaded previously stored by an arraycopy? If so return // a load node that reads from the source array so we may be able to // optimize out the ArrayCopy node later. ! Node* MemNode::can_see_arraycopy_value(Node* st, PhaseTransform* phase) const { Node* ld_adr = in(MemNode::Address); intptr_t ld_off = 0; AllocateNode* ld_alloc = AllocateNode::Ideal_allocation(ld_adr, phase, ld_off); Node* ac = find_previous_arraycopy(phase, ld_alloc, st, true); if (ac != NULL) { assert(ac->is_ArrayCopy(), "what kind of node can this be?"); - assert(is_Load(), "only for loads"); if (ac->as_ArrayCopy()->is_clonebasic()) { assert(ld_alloc != NULL, "need an alloc"); - Node* ld = clone(); Node* addp = in(MemNode::Address)->clone(); assert(addp->is_AddP(), "address must be addp"); assert(addp->in(AddPNode::Base) == ac->in(ArrayCopyNode::Dest)->in(AddPNode::Base), "strange pattern"); assert(addp->in(AddPNode::Address) == ac->in(ArrayCopyNode::Dest)->in(AddPNode::Address), "strange pattern"); addp->set_req(AddPNode::Base, ac->in(ArrayCopyNode::Src)->in(AddPNode::Base)); --- 827,847 ---- } // Is the value loaded previously stored by an arraycopy? If so return // a load node that reads from the source array so we may be able to // optimize out the ArrayCopy node later. ! Node* LoadNode::can_see_arraycopy_value(Node* st, PhaseTransform* phase) const { Node* ld_adr = in(MemNode::Address); intptr_t ld_off = 0; AllocateNode* ld_alloc = AllocateNode::Ideal_allocation(ld_adr, phase, ld_off); Node* ac = find_previous_arraycopy(phase, ld_alloc, st, true); if (ac != NULL) { assert(ac->is_ArrayCopy(), "what kind of node can this be?"); + Node* ld = clone(); if (ac->as_ArrayCopy()->is_clonebasic()) { assert(ld_alloc != NULL, "need an alloc"); Node* addp = in(MemNode::Address)->clone(); assert(addp->is_AddP(), "address must be addp"); assert(addp->in(AddPNode::Base) == ac->in(ArrayCopyNode::Dest)->in(AddPNode::Base), "strange pattern"); assert(addp->in(AddPNode::Address) == ac->in(ArrayCopyNode::Dest)->in(AddPNode::Address), "strange pattern"); addp->set_req(AddPNode::Base, ac->in(ArrayCopyNode::Src)->in(AddPNode::Base));
*** 904,916 **** ld->set_req(MemNode::Address, phase->transform(addp)); if (in(0) != NULL) { assert(ld_alloc->in(0) != NULL, "alloc must have control"); ld->set_req(0, ld_alloc->in(0)); } - return ld; } else { - Node* ld = clone(); Node* addp = in(MemNode::Address)->clone(); assert(addp->in(AddPNode::Base) == addp->in(AddPNode::Address), "should be"); addp->set_req(AddPNode::Base, ac->in(ArrayCopyNode::Src)); addp->set_req(AddPNode::Address, ac->in(ArrayCopyNode::Src)); --- 849,859 ----
*** 931,942 **** if (in(0) != NULL) { assert(ac->in(0) != NULL, "alloc must have control"); ld->set_req(0, ac->in(0)); } - return ld; } } return NULL; } --- 874,887 ---- if (in(0) != NULL) { assert(ac->in(0) != NULL, "alloc must have control"); ld->set_req(0, ac->in(0)); } } + // load depends on the tests that validate the arraycopy + ld->as_Load()->_depends_only_on_test = Pinned; + return ld; } return NULL; }
src/share/vm/opto/memnode.cpp
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File