提交 1b653533 编写于 作者: K kvn

7013538: Java memory leak with escape analysis

Summary: Don't allocate VectorSet iterator on C heap. Reuse resource storage in EA.
Reviewed-by: never
上级 5bceb250
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. 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
......@@ -350,28 +350,11 @@ int VectorSet::hash() const
return (int)_xor;
}
//------------------------------iterate----------------------------------------
SetI_ *VectorSet::iterate(uint &elem) const
{
VSetI_ *foo = (new(ResourceObj::C_HEAP) VSetI_(this));
elem = foo->next();
return foo;
}
//=============================================================================
//------------------------------VSetI_-----------------------------------------
// Initialize the innards of a VectorSet iterator
VSetI_::VSetI_( const VectorSet *vset ) : s(vset)
{
i = (uint)-1L;
j = (uint)-1L;
mask = (unsigned)(1L<<31);
}
//------------------------------next-------------------------------------------
// Find and return the next element of a vector set, or return garbage and
// make "VSetI_::test()" fail.
uint VSetI_::next(void)
// make "VectorSetI::test()" fail.
uint VectorSetI::next(void)
{
j++; // Next element in word
mask = (mask & max_jint) << 1;// Next bit in word
......
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. 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
......@@ -98,6 +98,9 @@ public:
uint Size(void) const; // Number of elements in the Set.
void Sort(void); // Sort before iterating
int hash() const; // Hash function
void Reset(void) { // Reset a set
memset( data, 0, size*sizeof(uint32) );
}
/* Removed for MCC BUG
operator const VectorSet* (void) const { return this; } */
......@@ -148,8 +151,7 @@ public:
private:
friend class VSetI_;
SetI_ *iterate(uint&) const;
SetI_ *iterate(uint&) const { ShouldNotCallThis(); return NULL; } // Removed
};
//------------------------------Iteration--------------------------------------
......@@ -158,22 +160,26 @@ private:
// or may not be iterated over; untouched elements will be affected once.
// Usage: for( VectorSetI i(s); i.test(); i++ ) { body = i.elem; }
class VSetI_ : public SetI_ {
class VectorSetI : public StackObj {
friend class VectorSet;
friend class VectorSetI;
const VectorSet *s;
uint i, j;
uint32 mask;
VSetI_(const VectorSet *vset);
uint next(void);
int test(void) { return i < s->size; }
};
class VectorSetI : public SetI {
public:
VectorSetI( const VectorSet *s ) : SetI(s) { }
void operator ++(void) { elem = ((VSetI_*)impl)->next(); }
int test(void) { return ((VSetI_*)impl)->test(); }
uint elem; // The publically accessible element
VectorSetI( const VectorSet *vset ) :
s(vset),
i((uint)-1L),
j((uint)-1L),
mask((unsigned)(1L<<31)) {
elem = next();
}
void operator ++(void) { elem = next(); }
int test(void) { return i < s->size; }
};
#endif // SHARE_VM_LIBADT_VECTSET_HPP
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. 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
......@@ -93,6 +93,9 @@ void PointsToNode::dump(bool print_state) const {
ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
_nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()),
_processed(C->comp_arena()),
pt_ptset(C->comp_arena()),
pt_visited(C->comp_arena()),
pt_worklist(C->comp_arena(), 4, 0, 0),
_collecting(true),
_progress(false),
_compile(C),
......@@ -220,9 +223,7 @@ PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n) {
PointsToNode::EscapeState orig_es = es;
// compute max escape state of anything this node could point to
VectorSet ptset(Thread::current()->resource_area());
PointsTo(ptset, n);
for(VectorSetI i(&ptset); i.test() && es != PointsToNode::GlobalEscape; ++i) {
for(VectorSetI i(PointsTo(n)); i.test() && es != PointsToNode::GlobalEscape; ++i) {
uint pt = i.elem;
PointsToNode::EscapeState pes = ptnode_adr(pt)->escape_state();
if (pes > es)
......@@ -236,9 +237,10 @@ PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n) {
return es;
}
void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n) {
VectorSet visited(Thread::current()->resource_area());
GrowableArray<uint> worklist;
VectorSet* ConnectionGraph::PointsTo(Node * n) {
pt_ptset.Reset();
pt_visited.Reset();
pt_worklist.clear();
#ifdef ASSERT
Node *orig_n = n;
......@@ -249,8 +251,8 @@ void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n) {
// If we have a JavaObject, return just that object
if (npt->node_type() == PointsToNode::JavaObject) {
ptset.set(n->_idx);
return;
pt_ptset.set(n->_idx);
return &pt_ptset;
}
#ifdef ASSERT
if (npt->_node == NULL) {
......@@ -260,10 +262,10 @@ void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n) {
assert(npt->_node != NULL, "unregistered node");
}
#endif
worklist.push(n->_idx);
while(worklist.length() > 0) {
int ni = worklist.pop();
if (visited.test_set(ni))
pt_worklist.push(n->_idx);
while(pt_worklist.length() > 0) {
int ni = pt_worklist.pop();
if (pt_visited.test_set(ni))
continue;
PointsToNode* pn = ptnode_adr(ni);
......@@ -276,10 +278,10 @@ void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n) {
uint etgt = pn->edge_target(e);
PointsToNode::EdgeType et = pn->edge_type(e);
if (et == PointsToNode::PointsToEdge) {
ptset.set(etgt);
pt_ptset.set(etgt);
edges_processed++;
} else if (et == PointsToNode::DeferredEdge) {
worklist.push(etgt);
pt_worklist.push(etgt);
edges_processed++;
} else {
assert(false,"neither PointsToEdge or DeferredEdge");
......@@ -288,16 +290,17 @@ void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n) {
if (edges_processed == 0) {
// no deferred or pointsto edges found. Assume the value was set
// outside this method. Add the phantom object to the pointsto set.
ptset.set(_phantom_object);
pt_ptset.set(_phantom_object);
}
}
return &pt_ptset;
}
void ConnectionGraph::remove_deferred(uint ni, GrowableArray<uint>* deferred_edges, VectorSet* visited) {
// This method is most expensive during ConnectionGraph construction.
// Reuse vectorSet and an additional growable array for deferred edges.
deferred_edges->clear();
visited->Clear();
visited->Reset();
visited->set(ni);
PointsToNode *ptn = ptnode_adr(ni);
......@@ -1009,7 +1012,6 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
uint new_index_start = (uint) _compile->num_alias_types();
Arena* arena = Thread::current()->resource_area();
VectorSet visited(arena);
VectorSet ptset(arena);
// Phase 1: Process possible allocations from alloc_worklist.
......@@ -1137,10 +1139,9 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
}
}
} else if (n->is_AddP()) {
ptset.Clear();
PointsTo(ptset, get_addp_base(n));
assert(ptset.Size() == 1, "AddP address is unique");
uint elem = ptset.getelem(); // Allocation node's index
VectorSet* ptset = PointsTo(get_addp_base(n));
assert(ptset->Size() == 1, "AddP address is unique");
uint elem = ptset->getelem(); // Allocation node's index
if (elem == _phantom_object) {
assert(false, "escaped allocation");
continue; // Assume the value was set outside this method.
......@@ -1157,10 +1158,9 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
assert(n->is_Phi(), "loops only through Phi's");
continue; // already processed
}
ptset.Clear();
PointsTo(ptset, n);
if (ptset.Size() == 1) {
uint elem = ptset.getelem(); // Allocation node's index
VectorSet* ptset = PointsTo(n);
if (ptset->Size() == 1) {
uint elem = ptset->getelem(); // Allocation node's index
if (elem == _phantom_object) {
assert(false, "escaped allocation");
continue; // Assume the value was set outside this method.
......@@ -1434,7 +1434,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
// Update the memory inputs of MemNodes with the value we computed
// in Phase 2 and move stores memory users to corresponding memory slices.
#ifdef ASSERT
visited.Clear();
visited.Reset();
Node_Stack old_mems(arena, _compile->unique() >> 2);
#endif
for (uint i = 0; i < nodes_size(); i++) {
......@@ -1640,7 +1640,6 @@ bool ConnectionGraph::compute_escape() {
#undef CG_BUILD_ITER_LIMIT
Arena* arena = Thread::current()->resource_area();
VectorSet ptset(arena);
VectorSet visited(arena);
worklist.clear();
......@@ -1657,7 +1656,7 @@ bool ConnectionGraph::compute_escape() {
if (n->is_AddP()) {
// Search for objects which are not scalar replaceable
// and adjust their escape state.
verify_escape_state(ni, ptset, igvn);
adjust_escape_state(ni, igvn);
}
}
}
......@@ -1776,8 +1775,8 @@ bool ConnectionGraph::compute_escape() {
return has_non_escaping_obj;
}
// Search for objects which are not scalar replaceable.
void ConnectionGraph::verify_escape_state(int nidx, VectorSet& ptset, PhaseTransform* phase) {
// Adjust escape state after Connection Graph is built.
void ConnectionGraph::adjust_escape_state(int nidx, PhaseTransform* phase) {
PointsToNode* ptn = ptnode_adr(nidx);
Node* n = ptn->_node;
assert(n->is_AddP(), "Should be called for AddP nodes only");
......@@ -1792,9 +1791,8 @@ void ConnectionGraph::verify_escape_state(int nidx, VectorSet& ptset, PhaseTrans
int offset = ptn->offset();
Node* base = get_addp_base(n);
ptset.Clear();
PointsTo(ptset, base);
int ptset_size = ptset.Size();
VectorSet* ptset = PointsTo(base);
int ptset_size = ptset->Size();
// Check if a oop field's initializing value is recorded and add
// a corresponding NULL field's value if it is not recorded.
......@@ -1814,7 +1812,7 @@ void ConnectionGraph::verify_escape_state(int nidx, VectorSet& ptset, PhaseTrans
// Do a simple control flow analysis to distinguish above cases.
//
if (offset != Type::OffsetBot && ptset_size == 1) {
uint elem = ptset.getelem(); // Allocation node's index
uint elem = ptset->getelem(); // Allocation node's index
// It does not matter if it is not Allocation node since
// only non-escaping allocations are scalar replaced.
if (ptnode_adr(elem)->_node->is_Allocate() &&
......@@ -1913,7 +1911,7 @@ void ConnectionGraph::verify_escape_state(int nidx, VectorSet& ptset, PhaseTrans
//
if (ptset_size > 1 || ptset_size != 0 &&
(has_LoadStore || offset == Type::OffsetBot)) {
for( VectorSetI j(&ptset); j.test(); ++j ) {
for( VectorSetI j(ptset); j.test(); ++j ) {
set_escape_state(j.elem, PointsToNode::ArgEscape);
ptnode_adr(j.elem)->_scalar_replaceable = false;
}
......@@ -1937,7 +1935,6 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
// Stub calls, objects do not escape but they are not scale replaceable.
// Adjust escape state for outgoing arguments.
const TypeTuple * d = call->tf()->domain();
VectorSet ptset(Thread::current()->resource_area());
for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
const Type* at = d->field_at(i);
Node *arg = call->in(i)->uncast();
......@@ -1970,9 +1967,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
//
arg = get_addp_base(arg);
}
ptset.Clear();
PointsTo(ptset, arg);
for( VectorSetI j(&ptset); j.test(); ++j ) {
for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) {
uint pt = j.elem;
set_escape_state(pt, PointsToNode::ArgEscape);
}
......@@ -1990,7 +1985,6 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
// fall-through if not a Java method or no analyzer information
if (call_analyzer != NULL) {
const TypeTuple * d = call->tf()->domain();
VectorSet ptset(Thread::current()->resource_area());
bool copy_dependencies = false;
for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
const Type* at = d->field_at(i);
......@@ -2015,9 +2009,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
copy_dependencies = true;
}
ptset.Clear();
PointsTo(ptset, arg);
for( VectorSetI j(&ptset); j.test(); ++j ) {
for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) {
uint pt = j.elem;
if (global_escapes) {
//The argument global escapes, mark everything it could point to
......@@ -2045,15 +2037,12 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
{
// adjust escape state for outgoing arguments
const TypeTuple * d = call->tf()->domain();
VectorSet ptset(Thread::current()->resource_area());
for (uint i = TypeFunc::Parms; i < d->cnt(); i++) {
const Type* at = d->field_at(i);
if (at->isa_oopptr() != NULL) {
Node *arg = call->in(i)->uncast();
set_escape_state(arg->_idx, PointsToNode::GlobalEscape);
ptset.Clear();
PointsTo(ptset, arg);
for( VectorSetI j(&ptset); j.test(); ++j ) {
for( VectorSetI j(PointsTo(arg)); j.test(); ++j ) {
uint pt = j.elem;
set_escape_state(pt, PointsToNode::GlobalEscape);
}
......@@ -2515,9 +2504,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
{
Node *base = get_addp_base(n);
// Create a field edge to this node from everything base could point to.
VectorSet ptset(Thread::current()->resource_area());
PointsTo(ptset, base);
for( VectorSetI i(&ptset); i.test(); ++i ) {
for( VectorSetI i(PointsTo(base)); i.test(); ++i ) {
uint pt = i.elem;
add_field_edge(pt, n_idx, address_offset(n, phase));
}
......@@ -2583,10 +2570,8 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
// For everything "adr_base" could point to, create a deferred edge from
// this node to each field with the same offset.
VectorSet ptset(Thread::current()->resource_area());
PointsTo(ptset, adr_base);
int offset = address_offset(adr, phase);
for( VectorSetI i(&ptset); i.test(); ++i ) {
for( VectorSetI i(PointsTo(adr_base)); i.test(); ++i ) {
uint pt = i.elem;
add_deferred_edge_to_fields(n_idx, pt, offset);
}
......@@ -2676,9 +2661,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
Node *val = n->in(MemNode::ValueIn)->uncast();
// For everything "adr_base" could point to, create a deferred edge
// to "val" from each field with the same offset.
VectorSet ptset(Thread::current()->resource_area());
PointsTo(ptset, adr_base);
for( VectorSetI i(&ptset); i.test(); ++i ) {
for( VectorSetI i(PointsTo(adr_base)); i.test(); ++i ) {
uint pt = i.elem;
add_edge_from_fields(pt, val->_idx, address_offset(adr, phase));
}
......
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2005, 2011, Oracle and/or its affiliates. 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
......@@ -268,7 +268,12 @@ private:
// walk the connection graph starting at the node corresponding to "n" and
// add the index of everything it could point to, to "ptset". This may cause
// Phi's encountered to get (re)processed (which requires "phase".)
void PointsTo(VectorSet &ptset, Node * n);
VectorSet* PointsTo(Node * n);
// Reused structures for PointsTo().
VectorSet pt_ptset;
VectorSet pt_visited;
GrowableArray<uint> pt_worklist;
// Edge manipulation. The "from_i" and "to_i" arguments are the
// node indices of the source and destination of the edge
......@@ -334,8 +339,11 @@ private:
// Set the escape state of a node
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);
// Adjust escape state after Connection Graph is built.
void adjust_escape_state(int nidx, PhaseTransform* phase);
// Compute the escape information
bool compute_escape();
public:
ConnectionGraph(Compile *C, PhaseIterGVN *igvn);
......@@ -346,9 +354,6 @@ public:
// Perform escape analysis
static void do_analysis(Compile *C, PhaseIterGVN *igvn);
// Compute the escape information
bool compute_escape();
// escape state of a node
PointsToNode::EscapeState escape_state(Node *n);
......
/*
* Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1997, 2011, Oracle and/or its affiliates. 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
......@@ -99,16 +99,18 @@ void Phase::print_timers() {
tty->print_cr (" stub compilation : %3.3f sec.", Phase::_t_stubCompilation.seconds());
tty->print_cr (" Phases:");
tty->print_cr (" parse : %3.3f sec", Phase::_t_parser.seconds());
if (DoEscapeAnalysis) {
tty->print_cr (" escape analysis : %3.3f sec", Phase::_t_escapeAnalysis.seconds());
}
tty->print_cr (" optimizer : %3.3f sec", Phase::_t_optimizer.seconds());
if( Verbose || WizardMode ) {
if (DoEscapeAnalysis) {
// EA is part of Optimizer.
tty->print_cr (" escape analysis: %3.3f sec", Phase::_t_escapeAnalysis.seconds());
}
tty->print_cr (" iterGVN : %3.3f sec", Phase::_t_iterGVN.seconds());
tty->print_cr (" idealLoop : %3.3f sec", Phase::_t_idealLoop.seconds());
tty->print_cr (" idealLoopVerify: %3.3f sec", Phase::_t_idealLoopVerify.seconds());
tty->print_cr (" ccp : %3.3f sec", Phase::_t_ccp.seconds());
tty->print_cr (" iterGVN2 : %3.3f sec", Phase::_t_iterGVN2.seconds());
tty->print_cr (" macroExpand : %3.3f sec", Phase::_t_macroExpand.seconds());
tty->print_cr (" graphReshape : %3.3f sec", Phase::_t_graphReshaping.seconds());
double optimizer_subtotal = Phase::_t_iterGVN.seconds() +
Phase::_t_idealLoop.seconds() + Phase::_t_ccp.seconds() +
......@@ -133,18 +135,15 @@ void Phase::print_timers() {
double percent_of_regalloc = ((regalloc_subtotal == 0.0) ? 0.0 : (regalloc_subtotal / Phase::_t_registerAllocation.seconds() * 100.0));
tty->print_cr (" subtotal : %3.3f sec, %3.2f %%", regalloc_subtotal, percent_of_regalloc);
}
tty->print_cr (" macroExpand : %3.3f sec", Phase::_t_macroExpand.seconds());
tty->print_cr (" blockOrdering : %3.3f sec", Phase::_t_blockOrdering.seconds());
tty->print_cr (" peephole : %3.3f sec", Phase::_t_peephole.seconds());
tty->print_cr (" codeGen : %3.3f sec", Phase::_t_codeGeneration.seconds());
tty->print_cr (" install_code : %3.3f sec", Phase::_t_registerMethod.seconds());
tty->print_cr (" -------------- : ----------");
double phase_subtotal = Phase::_t_parser.seconds() +
(DoEscapeAnalysis ? Phase::_t_escapeAnalysis.seconds() : 0.0) +
Phase::_t_optimizer.seconds() + Phase::_t_graphReshaping.seconds() +
Phase::_t_matcher.seconds() + Phase::_t_scheduler.seconds() +
Phase::_t_registerAllocation.seconds() + Phase::_t_blockOrdering.seconds() +
Phase::_t_macroExpand.seconds() + Phase::_t_peephole.seconds() +
Phase::_t_codeGeneration.seconds() + Phase::_t_registerMethod.seconds();
double percent_of_method_compile = ((phase_subtotal == 0.0) ? 0.0 : phase_subtotal / Phase::_t_methodCompilation.seconds()) * 100.0;
// counters inside Compile::CodeGen include time for adapters and stubs
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册