1.1 --- a/src/share/vm/opto/memnode.cpp Thu Mar 20 13:51:55 2008 -0700 1.2 +++ b/src/share/vm/opto/memnode.cpp Thu Mar 20 15:11:44 2008 -0700 1.3 @@ -29,6 +29,8 @@ 1.4 #include "incls/_precompiled.incl" 1.5 #include "incls/_memnode.cpp.incl" 1.6 1.7 +static Node *step_through_mergemem(PhaseGVN *phase, MergeMemNode *mmem, const TypePtr *tp, const TypePtr *adr_check, outputStream *st); 1.8 + 1.9 //============================================================================= 1.10 uint MemNode::size_of() const { return sizeof(*this); } 1.11 1.12 @@ -87,6 +89,60 @@ 1.13 1.14 #endif 1.15 1.16 +Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypePtr *t_adr, PhaseGVN *phase) { 1.17 + const TypeOopPtr *tinst = t_adr->isa_oopptr(); 1.18 + if (tinst == NULL || !tinst->is_instance_field()) 1.19 + return mchain; // don't try to optimize non-instance types 1.20 + uint instance_id = tinst->instance_id(); 1.21 + Node *prev = NULL; 1.22 + Node *result = mchain; 1.23 + while (prev != result) { 1.24 + prev = result; 1.25 + // skip over a call which does not affect this memory slice 1.26 + if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) { 1.27 + Node *proj_in = result->in(0); 1.28 + if (proj_in->is_Call()) { 1.29 + CallNode *call = proj_in->as_Call(); 1.30 + if (!call->may_modify(t_adr, phase)) { 1.31 + result = call->in(TypeFunc::Memory); 1.32 + } 1.33 + } else if (proj_in->is_Initialize()) { 1.34 + AllocateNode* alloc = proj_in->as_Initialize()->allocation(); 1.35 + // Stop if this is the initialization for the object instance which 1.36 + // which contains this memory slice, otherwise skip over it. 1.37 + if (alloc != NULL && alloc->_idx != instance_id) { 1.38 + result = proj_in->in(TypeFunc::Memory); 1.39 + } 1.40 + } else if (proj_in->is_MemBar()) { 1.41 + result = proj_in->in(TypeFunc::Memory); 1.42 + } 1.43 + } else if (result->is_MergeMem()) { 1.44 + result = step_through_mergemem(phase, result->as_MergeMem(), t_adr, NULL, tty); 1.45 + } 1.46 + } 1.47 + return result; 1.48 +} 1.49 + 1.50 +Node *MemNode::optimize_memory_chain(Node *mchain, const TypePtr *t_adr, PhaseGVN *phase) { 1.51 + const TypeOopPtr *t_oop = t_adr->isa_oopptr(); 1.52 + bool is_instance = (t_oop != NULL) && t_oop->is_instance_field(); 1.53 + PhaseIterGVN *igvn = phase->is_IterGVN(); 1.54 + Node *result = mchain; 1.55 + result = optimize_simple_memory_chain(result, t_adr, phase); 1.56 + if (is_instance && igvn != NULL && result->is_Phi()) { 1.57 + PhiNode *mphi = result->as_Phi(); 1.58 + assert(mphi->bottom_type() == Type::MEMORY, "memory phi required"); 1.59 + const TypePtr *t = mphi->adr_type(); 1.60 + if (t == TypePtr::BOTTOM || t == TypeRawPtr::BOTTOM) { 1.61 + // clone the Phi with our address type 1.62 + result = mphi->split_out_instance(t_adr, igvn); 1.63 + } else { 1.64 + assert(phase->C->get_alias_index(t) == phase->C->get_alias_index(t_adr), "correct memory chain"); 1.65 + } 1.66 + } 1.67 + return result; 1.68 +} 1.69 + 1.70 static Node *step_through_mergemem(PhaseGVN *phase, MergeMemNode *mmem, const TypePtr *tp, const TypePtr *adr_check, outputStream *st) { 1.71 uint alias_idx = phase->C->get_alias_index(tp); 1.72 Node *mem = mmem; 1.73 @@ -266,6 +322,8 @@ 1.74 if (offset == Type::OffsetBot) 1.75 return NULL; // cannot unalias unless there are precise offsets 1.76 1.77 + const TypeOopPtr *addr_t = adr->bottom_type()->isa_oopptr(); 1.78 + 1.79 intptr_t size_in_bytes = memory_size(); 1.80 1.81 Node* mem = in(MemNode::Memory); // start searching here... 1.82 @@ -345,6 +403,22 @@ 1.83 return mem; // let caller handle steps (c), (d) 1.84 } 1.85 1.86 + } else if (addr_t != NULL && addr_t->is_instance_field()) { 1.87 + // Can't use optimize_simple_memory_chain() since it needs PhaseGVN. 1.88 + if (mem->is_Proj() && mem->in(0)->is_Call()) { 1.89 + CallNode *call = mem->in(0)->as_Call(); 1.90 + if (!call->may_modify(addr_t, phase)) { 1.91 + mem = call->in(TypeFunc::Memory); 1.92 + continue; // (a) advance through independent call memory 1.93 + } 1.94 + } else if (mem->is_Proj() && mem->in(0)->is_MemBar()) { 1.95 + mem = mem->in(0)->in(TypeFunc::Memory); 1.96 + continue; // (a) advance through independent MemBar memory 1.97 + } else if (mem->is_MergeMem()) { 1.98 + int alias_idx = phase->C->get_alias_index(adr_type()); 1.99 + mem = mem->as_MergeMem()->memory_at(alias_idx); 1.100 + continue; // (a) advance through independent MergeMem memory 1.101 + } 1.102 } 1.103 1.104 // Unless there is an explicit 'continue', we must bail out here, 1.105 @@ -1011,6 +1085,122 @@ 1.106 } 1.107 } 1.108 1.109 + Node* mem = in(MemNode::Memory); 1.110 + const TypePtr *addr_t = phase->type(address)->isa_ptr(); 1.111 + 1.112 + if (addr_t != NULL) { 1.113 + // try to optimize our memory input 1.114 + Node* opt_mem = MemNode::optimize_memory_chain(mem, addr_t, phase); 1.115 + if (opt_mem != mem) { 1.116 + set_req(MemNode::Memory, opt_mem); 1.117 + return this; 1.118 + } 1.119 + const TypeOopPtr *t_oop = addr_t->isa_oopptr(); 1.120 + if (can_reshape && opt_mem->is_Phi() && 1.121 + (t_oop != NULL) && t_oop->is_instance_field()) { 1.122 + assert(t_oop->offset() != Type::OffsetBot && t_oop->offset() != Type::OffsetTop, ""); 1.123 + Node *region = opt_mem->in(0); 1.124 + uint cnt = opt_mem->req(); 1.125 + for( uint i = 1; i < cnt; i++ ) { 1.126 + Node *in = opt_mem->in(i); 1.127 + if( in == NULL ) { 1.128 + region = NULL; // Wait stable graph 1.129 + break; 1.130 + } 1.131 + } 1.132 + if (region != NULL) { 1.133 + // Check for loop invariant. 1.134 + if (cnt == 3) { 1.135 + for( uint i = 1; i < cnt; i++ ) { 1.136 + Node *in = opt_mem->in(i); 1.137 + Node* m = MemNode::optimize_memory_chain(in, addr_t, phase); 1.138 + if (m == opt_mem) { 1.139 + set_req(MemNode::Memory, opt_mem->in(cnt - i)); // Skip this phi. 1.140 + return this; 1.141 + } 1.142 + } 1.143 + } 1.144 + // Split through Phi (see original code in loopopts.cpp). 1.145 + assert(phase->C->have_alias_type(addr_t), "instance should have alias type"); 1.146 + const Type* this_type = this->bottom_type(); 1.147 + int this_index = phase->C->get_alias_index(addr_t); 1.148 + int this_offset = addr_t->offset(); 1.149 + int this_iid = addr_t->is_oopptr()->instance_id(); 1.150 + int wins = 0; 1.151 + PhaseIterGVN *igvn = phase->is_IterGVN(); 1.152 + Node *phi = new (igvn->C, region->req()) PhiNode(region, this_type, NULL, this_iid, this_index, this_offset); 1.153 + for( uint i = 1; i < region->req(); i++ ) { 1.154 + Node *x; 1.155 + Node* the_clone = NULL; 1.156 + if( region->in(i) == phase->C->top() ) { 1.157 + x = phase->C->top(); // Dead path? Use a dead data op 1.158 + } else { 1.159 + x = this->clone(); // Else clone up the data op 1.160 + the_clone = x; // Remember for possible deletion. 1.161 + // Alter data node to use pre-phi inputs 1.162 + if( this->in(0) == region ) { 1.163 + x->set_req( 0, region->in(i) ); 1.164 + } else { 1.165 + x->set_req( 0, NULL ); 1.166 + } 1.167 + for( uint j = 1; j < this->req(); j++ ) { 1.168 + Node *in = this->in(j); 1.169 + if( in->is_Phi() && in->in(0) == region ) 1.170 + x->set_req( j, in->in(i) ); // Use pre-Phi input for the clone 1.171 + } 1.172 + } 1.173 + // Check for a 'win' on some paths 1.174 + const Type *t = x->Value(igvn); 1.175 + 1.176 + bool singleton = t->singleton(); 1.177 + 1.178 + // See comments in PhaseIdealLoop::split_thru_phi(). 1.179 + if( singleton && t == Type::TOP ) { 1.180 + singleton &= region->is_Loop() && (i != LoopNode::EntryControl); 1.181 + } 1.182 + 1.183 + if( singleton ) { 1.184 + wins++; 1.185 + x = igvn->makecon(t); 1.186 + } else { 1.187 + // We now call Identity to try to simplify the cloned node. 1.188 + // Note that some Identity methods call phase->type(this). 1.189 + // Make sure that the type array is big enough for 1.190 + // our new node, even though we may throw the node away. 1.191 + // (This tweaking with igvn only works because x is a new node.) 1.192 + igvn->set_type(x, t); 1.193 + Node *y = x->Identity(igvn); 1.194 + if( y != x ) { 1.195 + wins++; 1.196 + x = y; 1.197 + } else { 1.198 + y = igvn->hash_find(x); 1.199 + if( y ) { 1.200 + wins++; 1.201 + x = y; 1.202 + } else { 1.203 + // Else x is a new node we are keeping 1.204 + // We do not need register_new_node_with_optimizer 1.205 + // because set_type has already been called. 1.206 + igvn->_worklist.push(x); 1.207 + } 1.208 + } 1.209 + } 1.210 + if (x != the_clone && the_clone != NULL) 1.211 + igvn->remove_dead_node(the_clone); 1.212 + phi->set_req(i, x); 1.213 + } 1.214 + if( wins > 0 ) { 1.215 + // Record Phi 1.216 + igvn->register_new_node_with_optimizer(phi); 1.217 + return phi; 1.218 + } else { 1.219 + igvn->remove_dead_node(phi); 1.220 + } 1.221 + } 1.222 + } 1.223 + } 1.224 + 1.225 // Check for prior store with a different base or offset; make Load 1.226 // independent. Skip through any number of them. Bail out if the stores 1.227 // are in an endless dead cycle and report no progress. This is a key