提交 cd7b05c4 编写于 作者: K kvn

6895383: JCK test throws NPE for method compiled with Escape Analysis

Summary: Add missing checks for MemBar nodes in EA.
Reviewed-by: never
上级 cc2cdc4e
...@@ -1852,6 +1852,7 @@ void Compile::dump_asm(int *pcs, uint pc_limit) { ...@@ -1852,6 +1852,7 @@ void Compile::dump_asm(int *pcs, uint pc_limit) {
!n->is_Phi() && // a few noisely useless nodes !n->is_Phi() && // a few noisely useless nodes
!n->is_Proj() && !n->is_Proj() &&
!n->is_MachTemp() && !n->is_MachTemp() &&
!n->is_SafePointScalarObject() &&
!n->is_Catch() && // Would be nice to print exception table targets !n->is_Catch() && // Would be nice to print exception table targets
!n->is_MergeMem() && // Not very interesting !n->is_MergeMem() && // Not very interesting
!n->is_top() && // Debug info table constants !n->is_top() && // Debug info table constants
......
此差异已折叠。
...@@ -210,6 +210,8 @@ private: ...@@ -210,6 +210,8 @@ private:
Unique_Node_List _delayed_worklist; // Nodes to be processed before Unique_Node_List _delayed_worklist; // Nodes to be processed before
// the call build_connection_graph(). // the call build_connection_graph().
GrowableArray<MergeMemNode *> _mergemem_worklist; // List of all MergeMem nodes
VectorSet _processed; // Records which nodes have been VectorSet _processed; // Records which nodes have been
// processed. // processed.
...@@ -315,6 +317,9 @@ private: ...@@ -315,6 +317,9 @@ private:
// Set the escape state of a node // Set the escape state of a node
void set_escape_state(uint ni, PointsToNode::EscapeState es); void set_escape_state(uint ni, PointsToNode::EscapeState es);
// Search for objects which are not scalar replaceable.
void verify_escape_state(int nidx, VectorSet& ptset, PhaseTransform* phase);
public: public:
ConnectionGraph(Compile *C); ConnectionGraph(Compile *C);
......
...@@ -616,8 +616,9 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, int *ready_cnt, Vect ...@@ -616,8 +616,9 @@ bool Block::schedule_local(PhaseCFG *cfg, Matcher &matcher, int *ready_cnt, Vect
assert(cfg->_bbs[oop_store->_idx]->_dom_depth <= this->_dom_depth, "oop_store must dominate card-mark"); assert(cfg->_bbs[oop_store->_idx]->_dom_depth <= this->_dom_depth, "oop_store must dominate card-mark");
} }
} }
if( n->is_Mach() && n->as_Mach()->ideal_Opcode() == Op_MemBarAcquire && if( n->is_Mach() && n->req() > TypeFunc::Parms &&
n->req() > TypeFunc::Parms ) { (n->as_Mach()->ideal_Opcode() == Op_MemBarAcquire ||
n->as_Mach()->ideal_Opcode() == Op_MemBarVolatile) ) {
// MemBarAcquire could be created without Precedent edge. // MemBarAcquire could be created without Precedent edge.
// del_req() replaces the specified edge with the last input edge // del_req() replaces the specified edge with the last input edge
// and then removes the last edge. If the specified edge > number of // and then removes the last edge. If the specified edge > number of
......
...@@ -316,6 +316,21 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me ...@@ -316,6 +316,21 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me
assert(adr_idx == Compile::AliasIdxRaw, "address must match or be raw"); assert(adr_idx == Compile::AliasIdxRaw, "address must match or be raw");
} }
mem = mem->in(MemNode::Memory); mem = mem->in(MemNode::Memory);
} else if (mem->is_ClearArray()) {
if (!ClearArrayNode::step_through(&mem, alloc->_idx, phase)) {
// Can not bypass initialization of the instance
// we are looking.
debug_only(intptr_t offset;)
assert(alloc == AllocateNode::Ideal_allocation(mem->in(3), phase, offset), "sanity");
InitializeNode* init = alloc->as_Allocate()->initialization();
// We are looking for stored value, return Initialize node
// or memory edge from Allocate node.
if (init != NULL)
return init;
else
return alloc->in(TypeFunc::Memory); // It will produce zero value (see callers).
}
// Otherwise skip it (the call updated 'mem' value).
} else if (mem->Opcode() == Op_SCMemProj) { } else if (mem->Opcode() == Op_SCMemProj) {
assert(mem->in(0)->is_LoadStore(), "sanity"); assert(mem->in(0)->is_LoadStore(), "sanity");
const TypePtr* atype = mem->in(0)->in(MemNode::Address)->bottom_type()->is_ptr(); const TypePtr* atype = mem->in(0)->in(MemNode::Address)->bottom_type()->is_ptr();
...@@ -823,6 +838,18 @@ void PhaseMacroExpand::process_users_of_allocation(AllocateNode *alloc) { ...@@ -823,6 +838,18 @@ void PhaseMacroExpand::process_users_of_allocation(AllocateNode *alloc) {
Node *n = use->last_out(k); Node *n = use->last_out(k);
uint oc2 = use->outcnt(); uint oc2 = use->outcnt();
if (n->is_Store()) { if (n->is_Store()) {
#ifdef ASSERT
// Verify that there is no dependent MemBarVolatile nodes,
// they should be removed during IGVN, see MemBarNode::Ideal().
for (DUIterator_Fast pmax, p = n->fast_outs(pmax);
p < pmax; p++) {
Node* mb = n->fast_out(p);
assert(mb->is_Initialize() || !mb->is_MemBar() ||
mb->req() <= MemBarNode::Precedent ||
mb->in(MemBarNode::Precedent) != n,
"MemBarVolatile should be eliminated for non-escaping object");
}
#endif
_igvn.replace_node(n, n->in(MemNode::Memory)); _igvn.replace_node(n, n->in(MemNode::Memory));
} else { } else {
eliminate_card_mark(n); eliminate_card_mark(n);
......
...@@ -123,6 +123,13 @@ Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypePtr *t_adr, ...@@ -123,6 +123,13 @@ Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypePtr *t_adr,
} else { } else {
assert(false, "unexpected projection"); assert(false, "unexpected projection");
} }
} else if (result->is_ClearArray()) {
if (!ClearArrayNode::step_through(&result, instance_id, phase)) {
// Can not bypass initialization of the instance
// we are looking for.
break;
}
// Otherwise skip it (the call updated 'result' value).
} else if (result->is_MergeMem()) { } else if (result->is_MergeMem()) {
result = step_through_mergemem(phase, result->as_MergeMem(), t_adr, NULL, tty); result = step_through_mergemem(phase, result->as_MergeMem(), t_adr, NULL, tty);
} }
...@@ -537,6 +544,15 @@ Node* MemNode::find_previous_store(PhaseTransform* phase) { ...@@ -537,6 +544,15 @@ Node* MemNode::find_previous_store(PhaseTransform* phase) {
} else if (mem->is_Proj() && mem->in(0)->is_MemBar()) { } else if (mem->is_Proj() && mem->in(0)->is_MemBar()) {
mem = mem->in(0)->in(TypeFunc::Memory); mem = mem->in(0)->in(TypeFunc::Memory);
continue; // (a) advance through independent MemBar memory continue; // (a) advance through independent MemBar memory
} else if (mem->is_ClearArray()) {
if (ClearArrayNode::step_through(&mem, (uint)addr_t->instance_id(), phase)) {
// (the call updated 'mem' value)
continue; // (a) advance through independent allocation memory
} else {
// Can not bypass initialization of the instance
// we are looking for.
return mem;
}
} else if (mem->is_MergeMem()) { } else if (mem->is_MergeMem()) {
int alias_idx = phase->C->get_alias_index(adr_type()); int alias_idx = phase->C->get_alias_index(adr_type());
mem = mem->as_MergeMem()->memory_at(alias_idx); mem = mem->as_MergeMem()->memory_at(alias_idx);
...@@ -2454,6 +2470,31 @@ Node *ClearArrayNode::Ideal(PhaseGVN *phase, bool can_reshape){ ...@@ -2454,6 +2470,31 @@ Node *ClearArrayNode::Ideal(PhaseGVN *phase, bool can_reshape){
return mem; return mem;
} }
//----------------------------step_through----------------------------------
// Return allocation input memory edge if it is different instance
// or itself if it is the one we are looking for.
bool ClearArrayNode::step_through(Node** np, uint instance_id, PhaseTransform* phase) {
Node* n = *np;
assert(n->is_ClearArray(), "sanity");
intptr_t offset;
AllocateNode* alloc = AllocateNode::Ideal_allocation(n->in(3), phase, offset);
// This method is called only before Allocate nodes are expanded during
// macro nodes expansion. Before that ClearArray nodes are only generated
// in LibraryCallKit::generate_arraycopy() which follows allocations.
assert(alloc != NULL, "should have allocation");
if (alloc->_idx == instance_id) {
// Can not bypass initialization of the instance we are looking for.
return false;
}
// Otherwise skip it.
InitializeNode* init = alloc->initialization();
if (init != NULL)
*np = init->in(TypeFunc::Memory);
else
*np = alloc->in(TypeFunc::Memory);
return true;
}
//----------------------------clear_memory------------------------------------- //----------------------------clear_memory-------------------------------------
// Generate code to initialize object storage to zero. // Generate code to initialize object storage to zero.
Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest, Node* ClearArrayNode::clear_memory(Node* ctl, Node* mem, Node* dest,
...@@ -2627,7 +2668,30 @@ MemBarNode* MemBarNode::make(Compile* C, int opcode, int atp, Node* pn) { ...@@ -2627,7 +2668,30 @@ MemBarNode* MemBarNode::make(Compile* C, int opcode, int atp, Node* pn) {
// Return a node which is more "ideal" than the current node. Strip out // Return a node which is more "ideal" than the current node. Strip out
// control copies // control copies
Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) { Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) {
return remove_dead_region(phase, can_reshape) ? this : NULL; if (remove_dead_region(phase, can_reshape)) return this;
// Eliminate volatile MemBars for scalar replaced objects.
if (can_reshape && req() == (Precedent+1) &&
(Opcode() == Op_MemBarAcquire || Opcode() == Op_MemBarVolatile)) {
// Volatile field loads and stores.
Node* my_mem = in(MemBarNode::Precedent);
if (my_mem != NULL && my_mem->is_Mem()) {
const TypeOopPtr* t_oop = my_mem->in(MemNode::Address)->bottom_type()->isa_oopptr();
// Check for scalar replaced object reference.
if( t_oop != NULL && t_oop->is_known_instance_field() &&
t_oop->offset() != Type::OffsetBot &&
t_oop->offset() != Type::OffsetTop) {
// Replace MemBar projections by its inputs.
PhaseIterGVN* igvn = phase->is_IterGVN();
igvn->replace_node(proj_out(TypeFunc::Memory), in(TypeFunc::Memory));
igvn->replace_node(proj_out(TypeFunc::Control), in(TypeFunc::Control));
// Must return either the original node (now dead) or a new node
// (Do not return a top here, since that would break the uniqueness of top.)
return new (phase->C, 1) ConINode(TypeInt::ZERO);
}
}
}
return NULL;
} }
//------------------------------Value------------------------------------------ //------------------------------Value------------------------------------------
......
...@@ -717,7 +717,10 @@ public: ...@@ -717,7 +717,10 @@ public:
//------------------------------ClearArray------------------------------------- //------------------------------ClearArray-------------------------------------
class ClearArrayNode: public Node { class ClearArrayNode: public Node {
public: public:
ClearArrayNode( Node *ctrl, Node *arymem, Node *word_cnt, Node *base ) : Node(ctrl,arymem,word_cnt,base) {} ClearArrayNode( Node *ctrl, Node *arymem, Node *word_cnt, Node *base )
: Node(ctrl,arymem,word_cnt,base) {
init_class_id(Class_ClearArray);
}
virtual int Opcode() const; virtual int Opcode() const;
virtual const Type *bottom_type() const { return Type::MEMORY; } virtual const Type *bottom_type() const { return Type::MEMORY; }
// ClearArray modifies array elements, and so affects only the // ClearArray modifies array elements, and so affects only the
...@@ -743,6 +746,9 @@ public: ...@@ -743,6 +746,9 @@ public:
Node* start_offset, Node* start_offset,
Node* end_offset, Node* end_offset,
PhaseGVN* phase); PhaseGVN* phase);
// Return allocation input memory edge if it is different instance
// or itself if it is the one we are looking for.
static bool step_through(Node** np, uint instance_id, PhaseTransform* phase);
}; };
//------------------------------StrComp------------------------------------- //------------------------------StrComp-------------------------------------
......
...@@ -47,6 +47,7 @@ class CallStaticJavaNode; ...@@ -47,6 +47,7 @@ class CallStaticJavaNode;
class CatchNode; class CatchNode;
class CatchProjNode; class CatchProjNode;
class CheckCastPPNode; class CheckCastPPNode;
class ClearArrayNode;
class CmpNode; class CmpNode;
class CodeBuffer; class CodeBuffer;
class ConstraintCastNode; class ConstraintCastNode;
...@@ -599,8 +600,9 @@ public: ...@@ -599,8 +600,9 @@ public:
DEFINE_CLASS_ID(BoxLock, Node, 10) DEFINE_CLASS_ID(BoxLock, Node, 10)
DEFINE_CLASS_ID(Add, Node, 11) DEFINE_CLASS_ID(Add, Node, 11)
DEFINE_CLASS_ID(Mul, Node, 12) DEFINE_CLASS_ID(Mul, Node, 12)
DEFINE_CLASS_ID(ClearArray, Node, 13)
_max_classes = ClassMask_Mul _max_classes = ClassMask_ClearArray
}; };
#undef DEFINE_CLASS_ID #undef DEFINE_CLASS_ID
...@@ -698,6 +700,7 @@ public: ...@@ -698,6 +700,7 @@ public:
DEFINE_CLASS_QUERY(CatchProj) DEFINE_CLASS_QUERY(CatchProj)
DEFINE_CLASS_QUERY(CheckCastPP) DEFINE_CLASS_QUERY(CheckCastPP)
DEFINE_CLASS_QUERY(ConstraintCast) DEFINE_CLASS_QUERY(ConstraintCast)
DEFINE_CLASS_QUERY(ClearArray)
DEFINE_CLASS_QUERY(CMove) DEFINE_CLASS_QUERY(CMove)
DEFINE_CLASS_QUERY(Cmp) DEFINE_CLASS_QUERY(Cmp)
DEFINE_CLASS_QUERY(CountedLoop) DEFINE_CLASS_QUERY(CountedLoop)
......
...@@ -240,19 +240,19 @@ void Parse::do_put_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool ...@@ -240,19 +240,19 @@ void Parse::do_put_xxx(const TypePtr* obj_type, Node* obj, ciField* field, bool
// membar is dependent on the store, keeping any other membars generated // membar is dependent on the store, keeping any other membars generated
// below from floating up past the store. // below from floating up past the store.
int adr_idx = C->get_alias_index(adr_type); int adr_idx = C->get_alias_index(adr_type);
insert_mem_bar_volatile(Op_MemBarVolatile, adr_idx); insert_mem_bar_volatile(Op_MemBarVolatile, adr_idx, store);
// Now place a membar for AliasIdxBot for the unknown yet-to-be-parsed // Now place a membar for AliasIdxBot for the unknown yet-to-be-parsed
// volatile alias indices. Skip this if the membar is redundant. // volatile alias indices. Skip this if the membar is redundant.
if (adr_idx != Compile::AliasIdxBot) { if (adr_idx != Compile::AliasIdxBot) {
insert_mem_bar_volatile(Op_MemBarVolatile, Compile::AliasIdxBot); insert_mem_bar_volatile(Op_MemBarVolatile, Compile::AliasIdxBot, store);
} }
// Finally, place alias-index-specific membars for each volatile index // Finally, place alias-index-specific membars for each volatile index
// that isn't the adr_idx membar. Typically there's only 1 or 2. // that isn't the adr_idx membar. Typically there's only 1 or 2.
for( int i = Compile::AliasIdxRaw; i < C->num_alias_types(); i++ ) { for( int i = Compile::AliasIdxRaw; i < C->num_alias_types(); i++ ) {
if (i != adr_idx && C->alias_type(i)->is_volatile()) { if (i != adr_idx && C->alias_type(i)->is_volatile()) {
insert_mem_bar_volatile(Op_MemBarVolatile, i); insert_mem_bar_volatile(Op_MemBarVolatile, i, store);
} }
} }
} }
......
/*
* 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 6895383
* @summary JCK test throws NPE for method compiled with Escape Analysis
*
* @run main/othervm -Xcomp Test
*/
public class Test {
public static void main(String argv[]) {
Test test = new Test();
test.testRemove1_IndexOutOfBounds();
test.testAddAll1_IndexOutOfBoundsException();
}
public void testRemove1_IndexOutOfBounds() {
CopyOnWriteArrayList c = new CopyOnWriteArrayList();
}
public void testAddAll1_IndexOutOfBoundsException() {
try {
CopyOnWriteArrayList c = new CopyOnWriteArrayList();
c.addAll(-1, new LinkedList()); // should throw IndexOutOfBoundsException
} catch (IndexOutOfBoundsException e) {
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册