6896727: nsk/logging/LoggingPermission/LoggingPermission/logperm002 fails with G1, EscapeAnalisys
Move instance store's memory users to corresponding memory slices when updating its memory edge. Reviewed-by: never
This commit is contained in:
parent
9f5ca0249d
commit
00f583219f
@ -543,6 +543,7 @@ bool ConnectionGraph::split_AddP(Node *addp, Node *base, PhaseGVN *igvn) {
|
|||||||
int alias_idx = _compile->get_alias_index(tinst);
|
int alias_idx = _compile->get_alias_index(tinst);
|
||||||
igvn->set_type(addp, tinst);
|
igvn->set_type(addp, tinst);
|
||||||
// record the allocation in the node map
|
// record the allocation in the node map
|
||||||
|
assert(ptnode_adr(addp->_idx)->_node != NULL, "should be registered");
|
||||||
set_map(addp->_idx, get_map(base->_idx));
|
set_map(addp->_idx, get_map(base->_idx));
|
||||||
|
|
||||||
// Set addp's Base and Address to 'base'.
|
// Set addp's Base and Address to 'base'.
|
||||||
@ -618,9 +619,14 @@ PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, Gro
|
|||||||
const TypePtr *atype = C->get_adr_type(alias_idx);
|
const TypePtr *atype = C->get_adr_type(alias_idx);
|
||||||
result = PhiNode::make(orig_phi->in(0), NULL, Type::MEMORY, atype);
|
result = PhiNode::make(orig_phi->in(0), NULL, Type::MEMORY, atype);
|
||||||
C->copy_node_notes_to(result, orig_phi);
|
C->copy_node_notes_to(result, orig_phi);
|
||||||
set_map_phi(orig_phi->_idx, result);
|
|
||||||
igvn->set_type(result, result->bottom_type());
|
igvn->set_type(result, result->bottom_type());
|
||||||
record_for_optimizer(result);
|
record_for_optimizer(result);
|
||||||
|
|
||||||
|
debug_only(Node* pn = ptnode_adr(orig_phi->_idx)->_node;)
|
||||||
|
assert(pn == NULL || pn == orig_phi, "wrong node");
|
||||||
|
set_map(orig_phi->_idx, result);
|
||||||
|
ptnode_adr(orig_phi->_idx)->_node = orig_phi;
|
||||||
|
|
||||||
new_created = true;
|
new_created = true;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -710,6 +716,81 @@ static Node *step_through_mergemem(MergeMemNode *mmem, int alias_idx, const Type
|
|||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Move memory users to their memory slices.
|
||||||
|
//
|
||||||
|
void ConnectionGraph::move_inst_mem(Node* n, GrowableArray<PhiNode *> &orig_phis, PhaseGVN *igvn) {
|
||||||
|
Compile* C = _compile;
|
||||||
|
|
||||||
|
const TypePtr* tp = igvn->type(n->in(MemNode::Address))->isa_ptr();
|
||||||
|
assert(tp != NULL, "ptr type");
|
||||||
|
int alias_idx = C->get_alias_index(tp);
|
||||||
|
int general_idx = C->get_general_index(alias_idx);
|
||||||
|
|
||||||
|
// Move users first
|
||||||
|
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
|
||||||
|
Node* use = n->fast_out(i);
|
||||||
|
if (use->is_MergeMem()) {
|
||||||
|
MergeMemNode* mmem = use->as_MergeMem();
|
||||||
|
assert(n == mmem->memory_at(alias_idx), "should be on instance memory slice");
|
||||||
|
if (n != mmem->memory_at(general_idx) || alias_idx == general_idx) {
|
||||||
|
continue; // Nothing to do
|
||||||
|
}
|
||||||
|
// Replace previous general reference to mem node.
|
||||||
|
uint orig_uniq = C->unique();
|
||||||
|
Node* m = find_inst_mem(n, general_idx, orig_phis, igvn);
|
||||||
|
assert(orig_uniq == C->unique(), "no new nodes");
|
||||||
|
mmem->set_memory_at(general_idx, m);
|
||||||
|
--imax;
|
||||||
|
--i;
|
||||||
|
} else if (use->is_MemBar()) {
|
||||||
|
assert(!use->is_Initialize(), "initializing stores should not be moved");
|
||||||
|
if (use->req() > MemBarNode::Precedent &&
|
||||||
|
use->in(MemBarNode::Precedent) == n) {
|
||||||
|
// Don't move related membars.
|
||||||
|
record_for_optimizer(use);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tp = use->as_MemBar()->adr_type()->isa_ptr();
|
||||||
|
if (tp != NULL && C->get_alias_index(tp) == alias_idx ||
|
||||||
|
alias_idx == general_idx) {
|
||||||
|
continue; // Nothing to do
|
||||||
|
}
|
||||||
|
// Move to general memory slice.
|
||||||
|
uint orig_uniq = C->unique();
|
||||||
|
Node* m = find_inst_mem(n, general_idx, orig_phis, igvn);
|
||||||
|
assert(orig_uniq == C->unique(), "no new nodes");
|
||||||
|
igvn->hash_delete(use);
|
||||||
|
imax -= use->replace_edge(n, m);
|
||||||
|
igvn->hash_insert(use);
|
||||||
|
record_for_optimizer(use);
|
||||||
|
--i;
|
||||||
|
#ifdef ASSERT
|
||||||
|
} else if (use->is_Mem()) {
|
||||||
|
if (use->Opcode() == Op_StoreCM && use->in(MemNode::OopStore) == n) {
|
||||||
|
// Don't move related cardmark.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Memory nodes should have new memory input.
|
||||||
|
tp = igvn->type(use->in(MemNode::Address))->isa_ptr();
|
||||||
|
assert(tp != NULL, "ptr type");
|
||||||
|
int idx = C->get_alias_index(tp);
|
||||||
|
assert(get_map(use->_idx) != NULL || idx == alias_idx,
|
||||||
|
"Following memory nodes should have new memory input or be on the same memory slice");
|
||||||
|
} else if (use->is_Phi()) {
|
||||||
|
// Phi nodes should be split and moved already.
|
||||||
|
tp = use->as_Phi()->adr_type()->isa_ptr();
|
||||||
|
assert(tp != NULL, "ptr type");
|
||||||
|
int idx = C->get_alias_index(tp);
|
||||||
|
assert(idx == alias_idx, "Following Phi nodes should be on the same memory slice");
|
||||||
|
} else {
|
||||||
|
use->dump();
|
||||||
|
assert(false, "should not be here");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Search memory chain of "mem" to find a MemNode whose address
|
// Search memory chain of "mem" to find a MemNode whose address
|
||||||
// is the specified alias index.
|
// is the specified alias index.
|
||||||
@ -775,6 +856,7 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
|
|||||||
C->get_alias_index(result->as_Phi()->adr_type()) != alias_idx) {
|
C->get_alias_index(result->as_Phi()->adr_type()) != alias_idx) {
|
||||||
Node *un = result->as_Phi()->unique_input(phase);
|
Node *un = result->as_Phi()->unique_input(phase);
|
||||||
if (un != NULL) {
|
if (un != NULL) {
|
||||||
|
orig_phis.append_if_missing(result->as_Phi());
|
||||||
result = un;
|
result = un;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -907,10 +989,12 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
|
|||||||
void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) {
|
void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) {
|
||||||
GrowableArray<Node *> memnode_worklist;
|
GrowableArray<Node *> memnode_worklist;
|
||||||
GrowableArray<PhiNode *> orig_phis;
|
GrowableArray<PhiNode *> orig_phis;
|
||||||
|
|
||||||
PhaseGVN *igvn = _compile->initial_gvn();
|
PhaseGVN *igvn = _compile->initial_gvn();
|
||||||
uint new_index_start = (uint) _compile->num_alias_types();
|
uint new_index_start = (uint) _compile->num_alias_types();
|
||||||
VectorSet visited(Thread::current()->resource_area());
|
Arena* arena = Thread::current()->resource_area();
|
||||||
VectorSet ptset(Thread::current()->resource_area());
|
VectorSet visited(arena);
|
||||||
|
VectorSet ptset(arena);
|
||||||
|
|
||||||
|
|
||||||
// Phase 1: Process possible allocations from alloc_worklist.
|
// Phase 1: Process possible allocations from alloc_worklist.
|
||||||
@ -986,6 +1070,8 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
|
|||||||
// - non-escaping
|
// - non-escaping
|
||||||
// - eligible to be a unique type
|
// - eligible to be a unique type
|
||||||
// - not determined to be ineligible by escape analysis
|
// - not determined to be ineligible by escape analysis
|
||||||
|
assert(ptnode_adr(alloc->_idx)->_node != NULL &&
|
||||||
|
ptnode_adr(n->_idx)->_node != NULL, "should be registered");
|
||||||
set_map(alloc->_idx, n);
|
set_map(alloc->_idx, n);
|
||||||
set_map(n->_idx, alloc);
|
set_map(n->_idx, alloc);
|
||||||
const TypeOopPtr *t = igvn->type(n)->isa_oopptr();
|
const TypeOopPtr *t = igvn->type(n)->isa_oopptr();
|
||||||
@ -1182,6 +1268,10 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mem != n->in(MemNode::Memory)) {
|
if (mem != n->in(MemNode::Memory)) {
|
||||||
|
// We delay the memory edge update since we need old one in
|
||||||
|
// MergeMem code below when instances memory slices are separated.
|
||||||
|
debug_only(Node* pn = ptnode_adr(n->_idx)->_node;)
|
||||||
|
assert(pn == NULL || pn == n, "wrong node");
|
||||||
set_map(n->_idx, mem);
|
set_map(n->_idx, mem);
|
||||||
ptnode_adr(n->_idx)->_node = n;
|
ptnode_adr(n->_idx)->_node = n;
|
||||||
}
|
}
|
||||||
@ -1249,6 +1339,8 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
|
|||||||
Node* cur = NULL;
|
Node* cur = NULL;
|
||||||
if (mem == NULL || mem->is_top())
|
if (mem == NULL || mem->is_top())
|
||||||
continue;
|
continue;
|
||||||
|
// First, update mergemem by moving memory nodes to corresponding slices
|
||||||
|
// if their type became more precise since this mergemem was created.
|
||||||
while (mem->is_Mem()) {
|
while (mem->is_Mem()) {
|
||||||
const Type *at = igvn->type(mem->in(MemNode::Address));
|
const Type *at = igvn->type(mem->in(MemNode::Address));
|
||||||
if (at != Type::TOP) {
|
if (at != Type::TOP) {
|
||||||
@ -1267,7 +1359,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
|
|||||||
}
|
}
|
||||||
nmm->set_memory_at(i, (cur != NULL) ? cur : mem);
|
nmm->set_memory_at(i, (cur != NULL) ? cur : mem);
|
||||||
// Find any instance of the current type if we haven't encountered
|
// Find any instance of the current type if we haven't encountered
|
||||||
// a value of the instance along the chain.
|
// already a memory slice of the instance along the memory chain.
|
||||||
for (uint ni = new_index_start; ni < new_index_end; ni++) {
|
for (uint ni = new_index_start; ni < new_index_end; ni++) {
|
||||||
if((uint)_compile->get_general_index(ni) == i) {
|
if((uint)_compile->get_general_index(ni) == i) {
|
||||||
Node *m = (ni >= nmm->req()) ? nmm->empty_memory() : nmm->in(ni);
|
Node *m = (ni >= nmm->req()) ? nmm->empty_memory() : nmm->in(ni);
|
||||||
@ -1283,11 +1375,11 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
|
|||||||
}
|
}
|
||||||
// Find the rest of instances values
|
// Find the rest of instances values
|
||||||
for (uint ni = new_index_start; ni < new_index_end; ni++) {
|
for (uint ni = new_index_start; ni < new_index_end; ni++) {
|
||||||
const TypeOopPtr *tinst = igvn->C->get_adr_type(ni)->isa_oopptr();
|
const TypeOopPtr *tinst = _compile->get_adr_type(ni)->isa_oopptr();
|
||||||
Node* result = step_through_mergemem(nmm, ni, tinst);
|
Node* result = step_through_mergemem(nmm, ni, tinst);
|
||||||
if (result == nmm->base_memory()) {
|
if (result == nmm->base_memory()) {
|
||||||
// Didn't find instance memory, search through general slice recursively.
|
// Didn't find instance memory, search through general slice recursively.
|
||||||
result = nmm->memory_at(igvn->C->get_general_index(ni));
|
result = nmm->memory_at(_compile->get_general_index(ni));
|
||||||
result = find_inst_mem(result, ni, orig_phis, igvn);
|
result = find_inst_mem(result, ni, orig_phis, igvn);
|
||||||
if (_compile->failing()) {
|
if (_compile->failing()) {
|
||||||
return;
|
return;
|
||||||
@ -1325,19 +1417,48 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the memory inputs of MemNodes with the value we computed
|
// Update the memory inputs of MemNodes with the value we computed
|
||||||
// in Phase 2.
|
// in Phase 2 and move stores memory users to corresponding memory slices.
|
||||||
|
#ifdef ASSERT
|
||||||
|
visited.Clear();
|
||||||
|
Node_Stack old_mems(arena, _compile->unique() >> 2);
|
||||||
|
#endif
|
||||||
for (uint i = 0; i < nodes_size(); i++) {
|
for (uint i = 0; i < nodes_size(); i++) {
|
||||||
Node *nmem = get_map(i);
|
Node *nmem = get_map(i);
|
||||||
if (nmem != NULL) {
|
if (nmem != NULL) {
|
||||||
Node *n = ptnode_adr(i)->_node;
|
Node *n = ptnode_adr(i)->_node;
|
||||||
if (n != NULL && n->is_Mem()) {
|
assert(n != NULL, "sanity");
|
||||||
|
if (n->is_Mem()) {
|
||||||
|
#ifdef ASSERT
|
||||||
|
Node* old_mem = n->in(MemNode::Memory);
|
||||||
|
if (!visited.test_set(old_mem->_idx)) {
|
||||||
|
old_mems.push(old_mem, old_mem->outcnt());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
assert(n->in(MemNode::Memory) != nmem, "sanity");
|
||||||
|
if (!n->is_Load()) {
|
||||||
|
// Move memory users of a store first.
|
||||||
|
move_inst_mem(n, orig_phis, igvn);
|
||||||
|
}
|
||||||
|
// Now update memory input
|
||||||
igvn->hash_delete(n);
|
igvn->hash_delete(n);
|
||||||
n->set_req(MemNode::Memory, nmem);
|
n->set_req(MemNode::Memory, nmem);
|
||||||
igvn->hash_insert(n);
|
igvn->hash_insert(n);
|
||||||
record_for_optimizer(n);
|
record_for_optimizer(n);
|
||||||
|
} else {
|
||||||
|
assert(n->is_Allocate() || n->is_CheckCastPP() ||
|
||||||
|
n->is_AddP() || n->is_Phi(), "unknown node used for set_map()");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef ASSERT
|
||||||
|
// Verify that memory was split correctly
|
||||||
|
while (old_mems.is_nonempty()) {
|
||||||
|
Node* old_mem = old_mems.node();
|
||||||
|
uint old_cnt = old_mems.index();
|
||||||
|
old_mems.pop();
|
||||||
|
assert(old_cnt = old_mem->outcnt(), "old mem could be lost");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConnectionGraph::has_candidates(Compile *C) {
|
bool ConnectionGraph::has_candidates(Compile *C) {
|
||||||
|
@ -291,7 +291,7 @@ private:
|
|||||||
bool split_AddP(Node *addp, Node *base, PhaseGVN *igvn);
|
bool split_AddP(Node *addp, Node *base, PhaseGVN *igvn);
|
||||||
PhiNode *create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn, bool &new_created);
|
PhiNode *create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn, bool &new_created);
|
||||||
PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn);
|
PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn);
|
||||||
Node *find_mem(Node *mem, int alias_idx, PhaseGVN *igvn);
|
void move_inst_mem(Node* n, GrowableArray<PhiNode *> &orig_phis, PhaseGVN *igvn);
|
||||||
Node *find_inst_mem(Node *mem, int alias_idx,GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn);
|
Node *find_inst_mem(Node *mem, int alias_idx,GrowableArray<PhiNode *> &orig_phi_worklist, PhaseGVN *igvn);
|
||||||
|
|
||||||
// Propagate unique types created for unescaped allocated objects
|
// Propagate unique types created for unescaped allocated objects
|
||||||
@ -300,7 +300,6 @@ private:
|
|||||||
|
|
||||||
// manage entries in _node_map
|
// manage entries in _node_map
|
||||||
void set_map(int idx, Node *n) { _node_map.map(idx, n); }
|
void set_map(int idx, Node *n) { _node_map.map(idx, n); }
|
||||||
void set_map_phi(int idx, PhiNode *p) { _node_map.map(idx, (Node *) p); }
|
|
||||||
Node *get_map(int idx) { return _node_map[idx]; }
|
Node *get_map(int idx) { return _node_map[idx]; }
|
||||||
PhiNode *get_map_phi(int idx) {
|
PhiNode *get_map_phi(int idx) {
|
||||||
Node *phi = _node_map[idx];
|
Node *phi = _node_map[idx];
|
||||||
|
48
hotspot/test/compiler/6896727/Test.java
Normal file
48
hotspot/test/compiler/6896727/Test.java
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2009 Sun Microsystems, Inc. All Rights Reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||||
|
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||||
|
* have any questions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 6896727
|
||||||
|
* @summary nsk/logging/LoggingPermission/LoggingPermission/logperm002 fails with G1, EscapeAnalisys w/o COOPs
|
||||||
|
* @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -Xcomp -XX:+DoEscapeAnalysis -XX:+UnlockExperimentalVMOptions -XX:+UseG1GC Test
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class Test {
|
||||||
|
|
||||||
|
final static String testString = "abracadabra";
|
||||||
|
public static void main(String args[]) {
|
||||||
|
String params[][] = {
|
||||||
|
{"control", testString}
|
||||||
|
};
|
||||||
|
for (int i=0; i<params.length; i++) {
|
||||||
|
try {
|
||||||
|
System.out.println("Params :" + testString + " and " + params[i][0] + ", " + params[i][1]);
|
||||||
|
if (params[i][1] == null) {
|
||||||
|
System.exit(97);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user