Wed, 09 Dec 2009 19:50:14 -0800
6896727: nsk/logging/LoggingPermission/LoggingPermission/logperm002 fails with G1, EscapeAnalisys
Summary: Move instance store's memory users to corresponding memory slices when updating its memory edge.
Reviewed-by: never
1.1 --- a/src/share/vm/opto/escape.cpp Wed Dec 09 16:40:45 2009 -0800 1.2 +++ b/src/share/vm/opto/escape.cpp Wed Dec 09 19:50:14 2009 -0800 1.3 @@ -543,6 +543,7 @@ 1.4 int alias_idx = _compile->get_alias_index(tinst); 1.5 igvn->set_type(addp, tinst); 1.6 // record the allocation in the node map 1.7 + assert(ptnode_adr(addp->_idx)->_node != NULL, "should be registered"); 1.8 set_map(addp->_idx, get_map(base->_idx)); 1.9 1.10 // Set addp's Base and Address to 'base'. 1.11 @@ -618,9 +619,14 @@ 1.12 const TypePtr *atype = C->get_adr_type(alias_idx); 1.13 result = PhiNode::make(orig_phi->in(0), NULL, Type::MEMORY, atype); 1.14 C->copy_node_notes_to(result, orig_phi); 1.15 - set_map_phi(orig_phi->_idx, result); 1.16 igvn->set_type(result, result->bottom_type()); 1.17 record_for_optimizer(result); 1.18 + 1.19 + debug_only(Node* pn = ptnode_adr(orig_phi->_idx)->_node;) 1.20 + assert(pn == NULL || pn == orig_phi, "wrong node"); 1.21 + set_map(orig_phi->_idx, result); 1.22 + ptnode_adr(orig_phi->_idx)->_node = orig_phi; 1.23 + 1.24 new_created = true; 1.25 return result; 1.26 } 1.27 @@ -711,6 +717,81 @@ 1.28 } 1.29 1.30 // 1.31 +// Move memory users to their memory slices. 1.32 +// 1.33 +void ConnectionGraph::move_inst_mem(Node* n, GrowableArray<PhiNode *> &orig_phis, PhaseGVN *igvn) { 1.34 + Compile* C = _compile; 1.35 + 1.36 + const TypePtr* tp = igvn->type(n->in(MemNode::Address))->isa_ptr(); 1.37 + assert(tp != NULL, "ptr type"); 1.38 + int alias_idx = C->get_alias_index(tp); 1.39 + int general_idx = C->get_general_index(alias_idx); 1.40 + 1.41 + // Move users first 1.42 + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { 1.43 + Node* use = n->fast_out(i); 1.44 + if (use->is_MergeMem()) { 1.45 + MergeMemNode* mmem = use->as_MergeMem(); 1.46 + assert(n == mmem->memory_at(alias_idx), "should be on instance memory slice"); 1.47 + if (n != mmem->memory_at(general_idx) || alias_idx == general_idx) { 1.48 + continue; // Nothing to do 1.49 + } 1.50 + // Replace previous general reference to mem node. 1.51 + uint orig_uniq = C->unique(); 1.52 + Node* m = find_inst_mem(n, general_idx, orig_phis, igvn); 1.53 + assert(orig_uniq == C->unique(), "no new nodes"); 1.54 + mmem->set_memory_at(general_idx, m); 1.55 + --imax; 1.56 + --i; 1.57 + } else if (use->is_MemBar()) { 1.58 + assert(!use->is_Initialize(), "initializing stores should not be moved"); 1.59 + if (use->req() > MemBarNode::Precedent && 1.60 + use->in(MemBarNode::Precedent) == n) { 1.61 + // Don't move related membars. 1.62 + record_for_optimizer(use); 1.63 + continue; 1.64 + } 1.65 + tp = use->as_MemBar()->adr_type()->isa_ptr(); 1.66 + if (tp != NULL && C->get_alias_index(tp) == alias_idx || 1.67 + alias_idx == general_idx) { 1.68 + continue; // Nothing to do 1.69 + } 1.70 + // Move to general memory slice. 1.71 + uint orig_uniq = C->unique(); 1.72 + Node* m = find_inst_mem(n, general_idx, orig_phis, igvn); 1.73 + assert(orig_uniq == C->unique(), "no new nodes"); 1.74 + igvn->hash_delete(use); 1.75 + imax -= use->replace_edge(n, m); 1.76 + igvn->hash_insert(use); 1.77 + record_for_optimizer(use); 1.78 + --i; 1.79 +#ifdef ASSERT 1.80 + } else if (use->is_Mem()) { 1.81 + if (use->Opcode() == Op_StoreCM && use->in(MemNode::OopStore) == n) { 1.82 + // Don't move related cardmark. 1.83 + continue; 1.84 + } 1.85 + // Memory nodes should have new memory input. 1.86 + tp = igvn->type(use->in(MemNode::Address))->isa_ptr(); 1.87 + assert(tp != NULL, "ptr type"); 1.88 + int idx = C->get_alias_index(tp); 1.89 + assert(get_map(use->_idx) != NULL || idx == alias_idx, 1.90 + "Following memory nodes should have new memory input or be on the same memory slice"); 1.91 + } else if (use->is_Phi()) { 1.92 + // Phi nodes should be split and moved already. 1.93 + tp = use->as_Phi()->adr_type()->isa_ptr(); 1.94 + assert(tp != NULL, "ptr type"); 1.95 + int idx = C->get_alias_index(tp); 1.96 + assert(idx == alias_idx, "Following Phi nodes should be on the same memory slice"); 1.97 + } else { 1.98 + use->dump(); 1.99 + assert(false, "should not be here"); 1.100 +#endif 1.101 + } 1.102 + } 1.103 +} 1.104 + 1.105 +// 1.106 // Search memory chain of "mem" to find a MemNode whose address 1.107 // is the specified alias index. 1.108 // 1.109 @@ -775,6 +856,7 @@ 1.110 C->get_alias_index(result->as_Phi()->adr_type()) != alias_idx) { 1.111 Node *un = result->as_Phi()->unique_input(phase); 1.112 if (un != NULL) { 1.113 + orig_phis.append_if_missing(result->as_Phi()); 1.114 result = un; 1.115 } else { 1.116 break; 1.117 @@ -907,10 +989,12 @@ 1.118 void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) { 1.119 GrowableArray<Node *> memnode_worklist; 1.120 GrowableArray<PhiNode *> orig_phis; 1.121 + 1.122 PhaseGVN *igvn = _compile->initial_gvn(); 1.123 uint new_index_start = (uint) _compile->num_alias_types(); 1.124 - VectorSet visited(Thread::current()->resource_area()); 1.125 - VectorSet ptset(Thread::current()->resource_area()); 1.126 + Arena* arena = Thread::current()->resource_area(); 1.127 + VectorSet visited(arena); 1.128 + VectorSet ptset(arena); 1.129 1.130 1.131 // Phase 1: Process possible allocations from alloc_worklist. 1.132 @@ -986,6 +1070,8 @@ 1.133 // - non-escaping 1.134 // - eligible to be a unique type 1.135 // - not determined to be ineligible by escape analysis 1.136 + assert(ptnode_adr(alloc->_idx)->_node != NULL && 1.137 + ptnode_adr(n->_idx)->_node != NULL, "should be registered"); 1.138 set_map(alloc->_idx, n); 1.139 set_map(n->_idx, alloc); 1.140 const TypeOopPtr *t = igvn->type(n)->isa_oopptr(); 1.141 @@ -1182,6 +1268,10 @@ 1.142 return; 1.143 } 1.144 if (mem != n->in(MemNode::Memory)) { 1.145 + // We delay the memory edge update since we need old one in 1.146 + // MergeMem code below when instances memory slices are separated. 1.147 + debug_only(Node* pn = ptnode_adr(n->_idx)->_node;) 1.148 + assert(pn == NULL || pn == n, "wrong node"); 1.149 set_map(n->_idx, mem); 1.150 ptnode_adr(n->_idx)->_node = n; 1.151 } 1.152 @@ -1249,6 +1339,8 @@ 1.153 Node* cur = NULL; 1.154 if (mem == NULL || mem->is_top()) 1.155 continue; 1.156 + // First, update mergemem by moving memory nodes to corresponding slices 1.157 + // if their type became more precise since this mergemem was created. 1.158 while (mem->is_Mem()) { 1.159 const Type *at = igvn->type(mem->in(MemNode::Address)); 1.160 if (at != Type::TOP) { 1.161 @@ -1267,7 +1359,7 @@ 1.162 } 1.163 nmm->set_memory_at(i, (cur != NULL) ? cur : mem); 1.164 // Find any instance of the current type if we haven't encountered 1.165 - // a value of the instance along the chain. 1.166 + // already a memory slice of the instance along the memory chain. 1.167 for (uint ni = new_index_start; ni < new_index_end; ni++) { 1.168 if((uint)_compile->get_general_index(ni) == i) { 1.169 Node *m = (ni >= nmm->req()) ? nmm->empty_memory() : nmm->in(ni); 1.170 @@ -1283,11 +1375,11 @@ 1.171 } 1.172 // Find the rest of instances values 1.173 for (uint ni = new_index_start; ni < new_index_end; ni++) { 1.174 - const TypeOopPtr *tinst = igvn->C->get_adr_type(ni)->isa_oopptr(); 1.175 + const TypeOopPtr *tinst = _compile->get_adr_type(ni)->isa_oopptr(); 1.176 Node* result = step_through_mergemem(nmm, ni, tinst); 1.177 if (result == nmm->base_memory()) { 1.178 // Didn't find instance memory, search through general slice recursively. 1.179 - result = nmm->memory_at(igvn->C->get_general_index(ni)); 1.180 + result = nmm->memory_at(_compile->get_general_index(ni)); 1.181 result = find_inst_mem(result, ni, orig_phis, igvn); 1.182 if (_compile->failing()) { 1.183 return; 1.184 @@ -1325,19 +1417,48 @@ 1.185 } 1.186 1.187 // Update the memory inputs of MemNodes with the value we computed 1.188 - // in Phase 2. 1.189 + // in Phase 2 and move stores memory users to corresponding memory slices. 1.190 +#ifdef ASSERT 1.191 + visited.Clear(); 1.192 + Node_Stack old_mems(arena, _compile->unique() >> 2); 1.193 +#endif 1.194 for (uint i = 0; i < nodes_size(); i++) { 1.195 Node *nmem = get_map(i); 1.196 if (nmem != NULL) { 1.197 Node *n = ptnode_adr(i)->_node; 1.198 - if (n != NULL && n->is_Mem()) { 1.199 + assert(n != NULL, "sanity"); 1.200 + if (n->is_Mem()) { 1.201 +#ifdef ASSERT 1.202 + Node* old_mem = n->in(MemNode::Memory); 1.203 + if (!visited.test_set(old_mem->_idx)) { 1.204 + old_mems.push(old_mem, old_mem->outcnt()); 1.205 + } 1.206 +#endif 1.207 + assert(n->in(MemNode::Memory) != nmem, "sanity"); 1.208 + if (!n->is_Load()) { 1.209 + // Move memory users of a store first. 1.210 + move_inst_mem(n, orig_phis, igvn); 1.211 + } 1.212 + // Now update memory input 1.213 igvn->hash_delete(n); 1.214 n->set_req(MemNode::Memory, nmem); 1.215 igvn->hash_insert(n); 1.216 record_for_optimizer(n); 1.217 + } else { 1.218 + assert(n->is_Allocate() || n->is_CheckCastPP() || 1.219 + n->is_AddP() || n->is_Phi(), "unknown node used for set_map()"); 1.220 } 1.221 } 1.222 } 1.223 +#ifdef ASSERT 1.224 + // Verify that memory was split correctly 1.225 + while (old_mems.is_nonempty()) { 1.226 + Node* old_mem = old_mems.node(); 1.227 + uint old_cnt = old_mems.index(); 1.228 + old_mems.pop(); 1.229 + assert(old_cnt = old_mem->outcnt(), "old mem could be lost"); 1.230 + } 1.231 +#endif 1.232 } 1.233 1.234 bool ConnectionGraph::has_candidates(Compile *C) {
2.1 --- a/src/share/vm/opto/escape.hpp Wed Dec 09 16:40:45 2009 -0800 2.2 +++ b/src/share/vm/opto/escape.hpp Wed Dec 09 19:50:14 2009 -0800 2.3 @@ -291,7 +291,7 @@ 2.4 bool split_AddP(Node *addp, Node *base, PhaseGVN *igvn); 2.5 PhiNode *create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn, bool &new_created); 2.6 PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn); 2.7 - Node *find_mem(Node *mem, int alias_idx, PhaseGVN *igvn); 2.8 + void move_inst_mem(Node* n, GrowableArray<PhiNode *> &orig_phis, PhaseGVN *igvn); 2.9 Node *find_inst_mem(Node *mem, int alias_idx,GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn); 2.10 2.11 // Propagate unique types created for unescaped allocated objects 2.12 @@ -300,7 +300,6 @@ 2.13 2.14 // manage entries in _node_map 2.15 void set_map(int idx, Node *n) { _node_map.map(idx, n); } 2.16 - void set_map_phi(int idx, PhiNode *p) { _node_map.map(idx, (Node *) p); } 2.17 Node *get_map(int idx) { return _node_map[idx]; } 2.18 PhiNode *get_map_phi(int idx) { 2.19 Node *phi = _node_map[idx];
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/test/compiler/6896727/Test.java Wed Dec 09 19:50:14 2009 -0800 3.3 @@ -0,0 +1,48 @@ 3.4 +/* 3.5 + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. 3.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.7 + * 3.8 + * This code is free software; you can redistribute it and/or modify it 3.9 + * under the terms of the GNU General Public License version 2 only, as 3.10 + * published by the Free Software Foundation. 3.11 + * 3.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 3.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 3.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 3.15 + * version 2 for more details (a copy is included in the LICENSE file that 3.16 + * accompanied this code). 3.17 + * 3.18 + * You should have received a copy of the GNU General Public License version 3.19 + * 2 along with this work; if not, write to the Free Software Foundation, 3.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 3.21 + * 3.22 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 3.23 + * CA 95054 USA or visit www.sun.com if you need additional information or 3.24 + * have any questions. 3.25 + * 3.26 + */ 3.27 + 3.28 +/* 3.29 + * @test 3.30 + * @bug 6896727 3.31 + * @summary nsk/logging/LoggingPermission/LoggingPermission/logperm002 fails with G1, EscapeAnalisys w/o COOPs 3.32 + * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:+DoEscapeAnalysis -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC Test 3.33 + */ 3.34 + 3.35 +public class Test { 3.36 + 3.37 + final static String testString = "abracadabra"; 3.38 + public static void main(String args[]) { 3.39 + String params[][] = { 3.40 + {"control", testString} 3.41 + }; 3.42 + for (int i=0; i<params.length; i++) { 3.43 + try { 3.44 + System.out.println("Params :" + testString + " and " + params[i][0] + ", " + params[i][1]); 3.45 + if (params[i][1] == null) { 3.46 + System.exit(97); 3.47 + } 3.48 + } catch (Exception e) {} 3.49 + } 3.50 + } 3.51 +}