提交 a5b2c84c 编写于 作者: N never

Merge

...@@ -1524,7 +1524,7 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) { ...@@ -1524,7 +1524,7 @@ Node *LockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
ConnectionGraph *cgr = phase->C->congraph(); ConnectionGraph *cgr = phase->C->congraph();
PointsToNode::EscapeState es = PointsToNode::GlobalEscape; PointsToNode::EscapeState es = PointsToNode::GlobalEscape;
if (cgr != NULL) if (cgr != NULL)
es = cgr->escape_state(obj_node(), phase); es = cgr->escape_state(obj_node());
if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) { if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) {
// Mark it eliminated to update any counters // Mark it eliminated to update any counters
this->set_eliminated(); this->set_eliminated();
...@@ -1627,7 +1627,7 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) { ...@@ -1627,7 +1627,7 @@ Node *UnlockNode::Ideal(PhaseGVN *phase, bool can_reshape) {
ConnectionGraph *cgr = phase->C->congraph(); ConnectionGraph *cgr = phase->C->congraph();
PointsToNode::EscapeState es = PointsToNode::GlobalEscape; PointsToNode::EscapeState es = PointsToNode::GlobalEscape;
if (cgr != NULL) if (cgr != NULL)
es = cgr->escape_state(obj_node(), phase); es = cgr->escape_state(obj_node());
if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) { if (es != PointsToNode::UnknownEscape && es != PointsToNode::GlobalEscape) {
// Mark it eliminated to update any counters // Mark it eliminated to update any counters
this->set_eliminated(); this->set_eliminated();
......
...@@ -637,34 +637,6 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr ...@@ -637,34 +637,6 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
if (failing()) return; if (failing()) return;
NOT_PRODUCT( verify_graph_edges(); ) NOT_PRODUCT( verify_graph_edges(); )
// Perform escape analysis
if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) {
TracePhase t2("escapeAnalysis", &_t_escapeAnalysis, true);
// Add ConP#NULL and ConN#NULL nodes before ConnectionGraph construction.
PhaseGVN* igvn = initial_gvn();
Node* oop_null = igvn->zerocon(T_OBJECT);
Node* noop_null = igvn->zerocon(T_NARROWOOP);
_congraph = new(comp_arena()) ConnectionGraph(this);
bool has_non_escaping_obj = _congraph->compute_escape();
#ifndef PRODUCT
if (PrintEscapeAnalysis) {
_congraph->dump();
}
#endif
// Cleanup.
if (oop_null->outcnt() == 0)
igvn->hash_delete(oop_null);
if (noop_null->outcnt() == 0)
igvn->hash_delete(noop_null);
if (!has_non_escaping_obj) {
_congraph = NULL;
}
if (failing()) return;
}
// Now optimize // Now optimize
Optimize(); Optimize();
if (failing()) return; if (failing()) return;
...@@ -1601,6 +1573,20 @@ void Compile::Optimize() { ...@@ -1601,6 +1573,20 @@ void Compile::Optimize() {
if (failing()) return; if (failing()) return;
// Perform escape analysis
if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) {
TracePhase t2("escapeAnalysis", &_t_escapeAnalysis, true);
ConnectionGraph::do_analysis(this, &igvn);
if (failing()) return;
igvn.optimize();
print_method("Iter GVN 3", 2);
if (failing()) return;
}
// Loop transforms on the ideal graph. Range Check Elimination, // Loop transforms on the ideal graph. Range Check Elimination,
// peeling, unrolling, etc. // peeling, unrolling, etc.
......
...@@ -362,6 +362,7 @@ class Compile : public Phase { ...@@ -362,6 +362,7 @@ class Compile : public Phase {
Node* macro_node(int idx) { return _macro_nodes->at(idx); } Node* macro_node(int idx) { return _macro_nodes->at(idx); }
Node* predicate_opaque1_node(int idx) { return _predicate_opaqs->at(idx);} Node* predicate_opaque1_node(int idx) { return _predicate_opaqs->at(idx);}
ConnectionGraph* congraph() { return _congraph;} ConnectionGraph* congraph() { return _congraph;}
void set_congraph(ConnectionGraph* congraph) { _congraph = congraph;}
void add_macro_node(Node * n) { void add_macro_node(Node * n) {
//assert(n->is_macro(), "must be a macro node"); //assert(n->is_macro(), "must be a macro node");
assert(!_macro_nodes->contains(n), " duplicate entry in expand list"); assert(!_macro_nodes->contains(n), " duplicate entry in expand list");
......
...@@ -81,18 +81,18 @@ void PointsToNode::dump(bool print_state) const { ...@@ -81,18 +81,18 @@ void PointsToNode::dump(bool print_state) const {
} }
#endif #endif
ConnectionGraph::ConnectionGraph(Compile * C) : ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn) :
_nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()), _nodes(C->comp_arena(), C->unique(), C->unique(), PointsToNode()),
_processed(C->comp_arena()), _processed(C->comp_arena()),
_collecting(true), _collecting(true),
_compile(C), _compile(C),
_igvn(igvn),
_node_map(C->comp_arena()) { _node_map(C->comp_arena()) {
_phantom_object = C->top()->_idx, _phantom_object = C->top()->_idx,
add_node(C->top(), PointsToNode::JavaObject, PointsToNode::GlobalEscape,true); add_node(C->top(), PointsToNode::JavaObject, PointsToNode::GlobalEscape,true);
// Add ConP(#NULL) and ConN(#NULL) nodes. // Add ConP(#NULL) and ConN(#NULL) nodes.
PhaseGVN* igvn = C->initial_gvn();
Node* oop_null = igvn->zerocon(T_OBJECT); Node* oop_null = igvn->zerocon(T_OBJECT);
_oop_null = oop_null->_idx; _oop_null = oop_null->_idx;
assert(_oop_null < C->unique(), "should be created already"); assert(_oop_null < C->unique(), "should be created already");
...@@ -182,7 +182,7 @@ void ConnectionGraph::add_node(Node *n, PointsToNode::NodeType nt, ...@@ -182,7 +182,7 @@ void ConnectionGraph::add_node(Node *n, PointsToNode::NodeType nt,
_processed.set(n->_idx); _processed.set(n->_idx);
} }
PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n, PhaseTransform *phase) { PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n) {
uint idx = n->_idx; uint idx = n->_idx;
PointsToNode::EscapeState es; PointsToNode::EscapeState es;
...@@ -207,22 +207,26 @@ PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n, PhaseTransform ...@@ -207,22 +207,26 @@ PointsToNode::EscapeState ConnectionGraph::escape_state(Node *n, PhaseTransform
if (n->uncast()->_idx >= nodes_size()) if (n->uncast()->_idx >= nodes_size())
return PointsToNode::UnknownEscape; return PointsToNode::UnknownEscape;
PointsToNode::EscapeState orig_es = es;
// compute max escape state of anything this node could point to // compute max escape state of anything this node could point to
VectorSet ptset(Thread::current()->resource_area()); VectorSet ptset(Thread::current()->resource_area());
PointsTo(ptset, n, phase); PointsTo(ptset, n);
for(VectorSetI i(&ptset); i.test() && es != PointsToNode::GlobalEscape; ++i) { for(VectorSetI i(&ptset); i.test() && es != PointsToNode::GlobalEscape; ++i) {
uint pt = i.elem; uint pt = i.elem;
PointsToNode::EscapeState pes = ptnode_adr(pt)->escape_state(); PointsToNode::EscapeState pes = ptnode_adr(pt)->escape_state();
if (pes > es) if (pes > es)
es = pes; es = pes;
} }
// cache the computed escape state if (orig_es != es) {
assert(es != PointsToNode::UnknownEscape, "should have computed an escape state"); // cache the computed escape state
ptnode_adr(idx)->set_escape_state(es); assert(es != PointsToNode::UnknownEscape, "should have computed an escape state");
ptnode_adr(idx)->set_escape_state(es);
} // orig_es could be PointsToNode::UnknownEscape
return es; return es;
} }
void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase) { void ConnectionGraph::PointsTo(VectorSet &ptset, Node * n) {
VectorSet visited(Thread::current()->resource_area()); VectorSet visited(Thread::current()->resource_area());
GrowableArray<uint> worklist; GrowableArray<uint> worklist;
...@@ -990,7 +994,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) ...@@ -990,7 +994,7 @@ 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 = _igvn;
uint new_index_start = (uint) _compile->num_alias_types(); uint new_index_start = (uint) _compile->num_alias_types();
Arena* arena = Thread::current()->resource_area(); Arena* arena = Thread::current()->resource_area();
VectorSet visited(arena); VectorSet visited(arena);
...@@ -1012,7 +1016,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) ...@@ -1012,7 +1016,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
CallNode *alloc = n->as_Call(); CallNode *alloc = n->as_Call();
// copy escape information to call node // copy escape information to call node
PointsToNode* ptn = ptnode_adr(alloc->_idx); PointsToNode* ptn = ptnode_adr(alloc->_idx);
PointsToNode::EscapeState es = escape_state(alloc, igvn); PointsToNode::EscapeState es = escape_state(alloc);
// We have an allocation or call which returns a Java object, // We have an allocation or call which returns a Java object,
// see if it is unescaped. // see if it is unescaped.
if (es != PointsToNode::NoEscape || !ptn->_scalar_replaceable) if (es != PointsToNode::NoEscape || !ptn->_scalar_replaceable)
...@@ -1123,7 +1127,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) ...@@ -1123,7 +1127,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
} }
} else if (n->is_AddP()) { } else if (n->is_AddP()) {
ptset.Clear(); ptset.Clear();
PointsTo(ptset, get_addp_base(n), igvn); PointsTo(ptset, get_addp_base(n));
assert(ptset.Size() == 1, "AddP address is unique"); assert(ptset.Size() == 1, "AddP address is unique");
uint elem = ptset.getelem(); // Allocation node's index uint elem = ptset.getelem(); // Allocation node's index
if (elem == _phantom_object) { if (elem == _phantom_object) {
...@@ -1143,7 +1147,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist) ...@@ -1143,7 +1147,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
continue; // already processed continue; // already processed
} }
ptset.Clear(); ptset.Clear();
PointsTo(ptset, n, igvn); PointsTo(ptset, n);
if (ptset.Size() == 1) { if (ptset.Size() == 1) {
uint elem = ptset.getelem(); // Allocation node's index uint elem = ptset.getelem(); // Allocation node's index
if (elem == _phantom_object) { if (elem == _phantom_object) {
...@@ -1478,6 +1482,26 @@ bool ConnectionGraph::has_candidates(Compile *C) { ...@@ -1478,6 +1482,26 @@ bool ConnectionGraph::has_candidates(Compile *C) {
return false; return false;
} }
void ConnectionGraph::do_analysis(Compile *C, PhaseIterGVN *igvn) {
// Add ConP#NULL and ConN#NULL nodes before ConnectionGraph construction
// to create space for them in ConnectionGraph::_nodes[].
Node* oop_null = igvn->zerocon(T_OBJECT);
Node* noop_null = igvn->zerocon(T_NARROWOOP);
ConnectionGraph* congraph = new(C->comp_arena()) ConnectionGraph(C, igvn);
// Perform escape analysis
if (congraph->compute_escape()) {
// There are non escaping objects.
C->set_congraph(congraph);
}
// Cleanup.
if (oop_null->outcnt() == 0)
igvn->hash_delete(oop_null);
if (noop_null->outcnt() == 0)
igvn->hash_delete(noop_null);
}
bool ConnectionGraph::compute_escape() { bool ConnectionGraph::compute_escape() {
Compile* C = _compile; Compile* C = _compile;
...@@ -1492,7 +1516,7 @@ bool ConnectionGraph::compute_escape() { ...@@ -1492,7 +1516,7 @@ bool ConnectionGraph::compute_escape() {
} }
GrowableArray<int> cg_worklist; GrowableArray<int> cg_worklist;
PhaseGVN* igvn = C->initial_gvn(); PhaseGVN* igvn = _igvn;
bool has_allocations = false; bool has_allocations = false;
// Push all useful nodes onto CG list and set their type. // Push all useful nodes onto CG list and set their type.
...@@ -1661,6 +1685,12 @@ bool ConnectionGraph::compute_escape() { ...@@ -1661,6 +1685,12 @@ bool ConnectionGraph::compute_escape() {
_collecting = false; _collecting = false;
assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build"); assert(C->unique() == nodes_size(), "there should be no new ideal nodes during ConnectionGraph build");
#ifndef PRODUCT
if (PrintEscapeAnalysis) {
dump(); // Dump ConnectionGraph
}
#endif
bool has_scalar_replaceable_candidates = alloc_worklist.length() > 0; bool has_scalar_replaceable_candidates = alloc_worklist.length() > 0;
if ( has_scalar_replaceable_candidates && if ( has_scalar_replaceable_candidates &&
C->AliasLevel() >= 3 && EliminateAllocations ) { C->AliasLevel() >= 3 && EliminateAllocations ) {
...@@ -1671,10 +1701,6 @@ bool ConnectionGraph::compute_escape() { ...@@ -1671,10 +1701,6 @@ bool ConnectionGraph::compute_escape() {
if (C->failing()) return false; if (C->failing()) return false;
// Clean up after split unique types.
ResourceMark rm;
PhaseRemoveUseless pru(C->initial_gvn(), C->for_igvn());
C->print_method("After Escape Analysis", 2); C->print_method("After Escape Analysis", 2);
#ifdef ASSERT #ifdef ASSERT
...@@ -1711,7 +1737,7 @@ void ConnectionGraph::verify_escape_state(int nidx, VectorSet& ptset, PhaseTrans ...@@ -1711,7 +1737,7 @@ void ConnectionGraph::verify_escape_state(int nidx, VectorSet& ptset, PhaseTrans
int offset = ptn->offset(); int offset = ptn->offset();
Node* base = get_addp_base(n); Node* base = get_addp_base(n);
ptset.Clear(); ptset.Clear();
PointsTo(ptset, base, phase); PointsTo(ptset, base);
int ptset_size = ptset.Size(); int ptset_size = ptset.Size();
// Check if a oop field's initializing value is recorded and add // Check if a oop field's initializing value is recorded and add
...@@ -1889,7 +1915,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha ...@@ -1889,7 +1915,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
arg = get_addp_base(arg); arg = get_addp_base(arg);
} }
ptset.Clear(); ptset.Clear();
PointsTo(ptset, arg, phase); PointsTo(ptset, arg);
for( VectorSetI j(&ptset); j.test(); ++j ) { for( VectorSetI j(&ptset); j.test(); ++j ) {
uint pt = j.elem; uint pt = j.elem;
set_escape_state(pt, PointsToNode::ArgEscape); set_escape_state(pt, PointsToNode::ArgEscape);
...@@ -1934,7 +1960,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha ...@@ -1934,7 +1960,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
} }
ptset.Clear(); ptset.Clear();
PointsTo(ptset, arg, phase); PointsTo(ptset, arg);
for( VectorSetI j(&ptset); j.test(); ++j ) { for( VectorSetI j(&ptset); j.test(); ++j ) {
uint pt = j.elem; uint pt = j.elem;
if (global_escapes) { if (global_escapes) {
...@@ -1970,7 +1996,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha ...@@ -1970,7 +1996,7 @@ void ConnectionGraph::process_call_arguments(CallNode *call, PhaseTransform *pha
Node *arg = call->in(i)->uncast(); Node *arg = call->in(i)->uncast();
set_escape_state(arg->_idx, PointsToNode::GlobalEscape); set_escape_state(arg->_idx, PointsToNode::GlobalEscape);
ptset.Clear(); ptset.Clear();
PointsTo(ptset, arg, phase); PointsTo(ptset, arg);
for( VectorSetI j(&ptset); j.test(); ++j ) { for( VectorSetI j(&ptset); j.test(); ++j ) {
uint pt = j.elem; uint pt = j.elem;
set_escape_state(pt, PointsToNode::GlobalEscape); set_escape_state(pt, PointsToNode::GlobalEscape);
...@@ -2433,7 +2459,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { ...@@ -2433,7 +2459,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
Node *base = get_addp_base(n); Node *base = get_addp_base(n);
// Create a field edge to this node from everything base could point to. // Create a field edge to this node from everything base could point to.
VectorSet ptset(Thread::current()->resource_area()); VectorSet ptset(Thread::current()->resource_area());
PointsTo(ptset, base, phase); PointsTo(ptset, base);
for( VectorSetI i(&ptset); i.test(); ++i ) { for( VectorSetI i(&ptset); i.test(); ++i ) {
uint pt = i.elem; uint pt = i.elem;
add_field_edge(pt, n_idx, address_offset(n, phase)); add_field_edge(pt, n_idx, address_offset(n, phase));
...@@ -2501,7 +2527,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { ...@@ -2501,7 +2527,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
// For everything "adr_base" could point to, create a deferred edge from // For everything "adr_base" could point to, create a deferred edge from
// this node to each field with the same offset. // this node to each field with the same offset.
VectorSet ptset(Thread::current()->resource_area()); VectorSet ptset(Thread::current()->resource_area());
PointsTo(ptset, adr_base, phase); PointsTo(ptset, adr_base);
int offset = address_offset(adr, phase); int offset = address_offset(adr, phase);
for( VectorSetI i(&ptset); i.test(); ++i ) { for( VectorSetI i(&ptset); i.test(); ++i ) {
uint pt = i.elem; uint pt = i.elem;
...@@ -2594,7 +2620,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { ...@@ -2594,7 +2620,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
// For everything "adr_base" could point to, create a deferred edge // For everything "adr_base" could point to, create a deferred edge
// to "val" from each field with the same offset. // to "val" from each field with the same offset.
VectorSet ptset(Thread::current()->resource_area()); VectorSet ptset(Thread::current()->resource_area());
PointsTo(ptset, adr_base, phase); PointsTo(ptset, adr_base);
for( VectorSetI i(&ptset); i.test(); ++i ) { for( VectorSetI i(&ptset); i.test(); ++i ) {
uint pt = i.elem; uint pt = i.elem;
add_edge_from_fields(pt, val->_idx, address_offset(adr, phase)); add_edge_from_fields(pt, val->_idx, address_offset(adr, phase));
...@@ -2638,7 +2664,6 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) { ...@@ -2638,7 +2664,6 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
#ifndef PRODUCT #ifndef PRODUCT
void ConnectionGraph::dump() { void ConnectionGraph::dump() {
PhaseGVN *igvn = _compile->initial_gvn();
bool first = true; bool first = true;
uint size = nodes_size(); uint size = nodes_size();
...@@ -2648,7 +2673,7 @@ void ConnectionGraph::dump() { ...@@ -2648,7 +2673,7 @@ void ConnectionGraph::dump() {
if (ptn_type != PointsToNode::JavaObject || ptn->_node == NULL) if (ptn_type != PointsToNode::JavaObject || ptn->_node == NULL)
continue; continue;
PointsToNode::EscapeState es = escape_state(ptn->_node, igvn); PointsToNode::EscapeState es = escape_state(ptn->_node);
if (ptn->_node->is_Allocate() && (es == PointsToNode::NoEscape || Verbose)) { if (ptn->_node->is_Allocate() && (es == PointsToNode::NoEscape || Verbose)) {
if (first) { if (first) {
tty->cr(); tty->cr();
......
...@@ -227,6 +227,7 @@ private: ...@@ -227,6 +227,7 @@ private:
uint _noop_null; // ConN(#NULL) uint _noop_null; // ConN(#NULL)
Compile * _compile; // Compile object for current compilation Compile * _compile; // Compile object for current compilation
PhaseIterGVN * _igvn; // Value numbering
// Address of an element in _nodes. Used when the element is to be modified // Address of an element in _nodes. Used when the element is to be modified
PointsToNode *ptnode_adr(uint idx) const { PointsToNode *ptnode_adr(uint idx) const {
...@@ -257,7 +258,7 @@ private: ...@@ -257,7 +258,7 @@ private:
// walk the connection graph starting at the node corresponding to "n" and // 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 // add the index of everything it could point to, to "ptset". This may cause
// Phi's encountered to get (re)processed (which requires "phase".) // Phi's encountered to get (re)processed (which requires "phase".)
void PointsTo(VectorSet &ptset, Node * n, PhaseTransform *phase); void PointsTo(VectorSet &ptset, Node * n);
// Edge manipulation. The "from_i" and "to_i" arguments are the // Edge manipulation. The "from_i" and "to_i" arguments are the
// node indices of the source and destination of the edge // node indices of the source and destination of the edge
...@@ -310,7 +311,7 @@ private: ...@@ -310,7 +311,7 @@ private:
// Node: This assumes that escape analysis is run before // Node: This assumes that escape analysis is run before
// PhaseIterGVN creation // PhaseIterGVN creation
void record_for_optimizer(Node *n) { void record_for_optimizer(Node *n) {
_compile->record_for_igvn(n); _igvn->_worklist.push(n);
} }
// Set the escape state of a node // Set the escape state of a node
...@@ -320,16 +321,20 @@ private: ...@@ -320,16 +321,20 @@ private:
void verify_escape_state(int nidx, VectorSet& ptset, PhaseTransform* phase); void verify_escape_state(int nidx, VectorSet& ptset, PhaseTransform* phase);
public: public:
ConnectionGraph(Compile *C); ConnectionGraph(Compile *C, PhaseIterGVN *igvn);
// Check for non-escaping candidates // Check for non-escaping candidates
static bool has_candidates(Compile *C); static bool has_candidates(Compile *C);
// Perform escape analysis
static void do_analysis(Compile *C, PhaseIterGVN *igvn);
// Compute the escape information // Compute the escape information
bool compute_escape(); bool compute_escape();
// escape state of a node // escape state of a node
PointsToNode::EscapeState escape_state(Node *n, PhaseTransform *phase); PointsToNode::EscapeState escape_state(Node *n);
// other information we have collected // other information we have collected
bool is_scalar_replaceable(Node *n) { bool is_scalar_replaceable(Node *n) {
if (_collecting || (n->_idx >= nodes_size())) if (_collecting || (n->_idx >= nodes_size()))
......
/* /*
* Copyright (c) 2003, 2009, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
...@@ -118,34 +118,13 @@ void CodeBlobCollector::do_blob(CodeBlob* cb) { ...@@ -118,34 +118,13 @@ void CodeBlobCollector::do_blob(CodeBlob* cb) {
for (int i=0; i<_global_code_blobs->length(); i++) { for (int i=0; i<_global_code_blobs->length(); i++) {
JvmtiCodeBlobDesc* scb = _global_code_blobs->at(i); JvmtiCodeBlobDesc* scb = _global_code_blobs->at(i);
if (addr == scb->code_begin()) { if (addr == scb->code_begin()) {
ShouldNotReachHere();
return; return;
} }
} }
// we must name the CodeBlob - some CodeBlobs already have names :-
// - stubs used by compiled code to call a (static) C++ runtime routine
// - non-relocatable machine code such as the interpreter, stubroutines, etc.
// - various singleton blobs
//
// others are unnamed so we create a name :-
// - OSR adapter (interpreter frame that has been on-stack replaced)
// - I2C and C2I adapters
const char* name = NULL;
if (cb->is_runtime_stub()) {
name = ((RuntimeStub*)cb)->name();
}
if (cb->is_buffer_blob()) {
name = ((BufferBlob*)cb)->name();
}
if (cb->is_deoptimization_stub() || cb->is_safepoint_stub()) {
name = ((SingletonBlob*)cb)->name();
}
if (cb->is_uncommon_trap_stub() || cb->is_exception_stub()) {
name = ((SingletonBlob*)cb)->name();
}
// record the CodeBlob details as a JvmtiCodeBlobDesc // record the CodeBlob details as a JvmtiCodeBlobDesc
JvmtiCodeBlobDesc* scb = new JvmtiCodeBlobDesc(name, cb->instructions_begin(), JvmtiCodeBlobDesc* scb = new JvmtiCodeBlobDesc(cb->name(), cb->instructions_begin(),
cb->instructions_end()); cb->instructions_end());
_global_code_blobs->append(scb); _global_code_blobs->append(scb);
} }
...@@ -197,7 +176,10 @@ void CodeBlobCollector::collect() { ...@@ -197,7 +176,10 @@ void CodeBlobCollector::collect() {
jvmtiError JvmtiCodeBlobEvents::generate_dynamic_code_events(JvmtiEnv* env) { jvmtiError JvmtiCodeBlobEvents::generate_dynamic_code_events(JvmtiEnv* env) {
CodeBlobCollector collector; CodeBlobCollector collector;
// first collect all the code blobs // First collect all the code blobs. This has to be done in a
// single pass over the code cache with CodeCache_lock held because
// there isn't any safe way to iterate over regular CodeBlobs since
// they can be freed at any point.
{ {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
collector.collect(); collector.collect();
...@@ -213,166 +195,28 @@ jvmtiError JvmtiCodeBlobEvents::generate_dynamic_code_events(JvmtiEnv* env) { ...@@ -213,166 +195,28 @@ jvmtiError JvmtiCodeBlobEvents::generate_dynamic_code_events(JvmtiEnv* env) {
} }
// Support class to describe a nmethod in the CodeCache
class nmethodDesc: public CHeapObj {
private:
jmethodID _jmethod_id;
address _code_begin;
address _code_end;
jvmtiAddrLocationMap* _map;
jint _map_length;
public:
nmethodDesc(jmethodID jmethod_id, address code_begin, address code_end,
jvmtiAddrLocationMap* map, jint map_length) {
_jmethod_id = jmethod_id;
_code_begin = code_begin;
_code_end = code_end;
_map = map;
_map_length = map_length;
}
jmethodID jmethod_id() const { return _jmethod_id; }
address code_begin() const { return _code_begin; }
address code_end() const { return _code_end; }
jvmtiAddrLocationMap* map() const { return _map; }
jint map_length() const { return _map_length; }
};
// Support class to collect a list of the nmethod CodeBlobs in
// the CodeCache.
//
// Usage :-
//
// nmethodCollector collector;
//
// collector.collect();
// JvmtiCodeBlobDesc* blob = collector.first();
// while (blob != NULL) {
// :
// blob = collector.next();
// }
//
class nmethodCollector : StackObj {
private:
GrowableArray<nmethodDesc*>* _nmethods; // collect nmethods
int _pos; // iteration support
// used during a collection
static GrowableArray<nmethodDesc*>* _global_nmethods;
static void do_nmethod(nmethod* nm);
public:
nmethodCollector() {
_nmethods = NULL;
_pos = -1;
}
~nmethodCollector() {
if (_nmethods != NULL) {
for (int i=0; i<_nmethods->length(); i++) {
nmethodDesc* blob = _nmethods->at(i);
if (blob->map()!= NULL) {
FREE_C_HEAP_ARRAY(jvmtiAddrLocationMap, blob->map());
}
}
delete _nmethods;
}
}
// collect list of nmethods in the cache
void collect();
// iteration support - return first code blob
nmethodDesc* first() {
assert(_nmethods != NULL, "not collected");
if (_nmethods->length() == 0) {
return NULL;
}
_pos = 0;
return _nmethods->at(0);
}
// iteration support - return next code blob
nmethodDesc* next() {
assert(_pos >= 0, "iteration not started");
if (_pos+1 >= _nmethods->length()) {
return NULL;
}
return _nmethods->at(++_pos);
}
};
// used during collection
GrowableArray<nmethodDesc*>* nmethodCollector::_global_nmethods;
// called for each nmethod in the CodeCache
//
// This function simply adds a descriptor for each nmethod to the global list.
void nmethodCollector::do_nmethod(nmethod* nm) {
// ignore zombies
if (!nm->is_alive()) {
return;
}
assert(nm->method() != NULL, "checking");
// create the location map for the nmethod.
jvmtiAddrLocationMap* map;
jint map_length;
JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nm, &map, &map_length);
// record the nmethod details
nmethodDesc* snm = new nmethodDesc(nm->get_and_cache_jmethod_id(),
nm->code_begin(),
nm->code_end(),
map,
map_length);
_global_nmethods->append(snm);
}
// collects a list of nmethod in the CodeCache.
//
// The created list is growable array of nmethodDesc - each one describes
// a nmethod and includs its JVMTI address location map.
void nmethodCollector::collect() {
assert_locked_or_safepoint(CodeCache_lock);
assert(_global_nmethods == NULL, "checking");
// create the list
_global_nmethods = new (ResourceObj::C_HEAP) GrowableArray<nmethodDesc*>(100,true);
// any a descriptor for each nmethod to the list.
CodeCache::nmethods_do(do_nmethod);
// make the list the instance list
_nmethods = _global_nmethods;
_global_nmethods = NULL;
}
// Generate a COMPILED_METHOD_LOAD event for each nnmethod // Generate a COMPILED_METHOD_LOAD event for each nnmethod
jvmtiError JvmtiCodeBlobEvents::generate_compiled_method_load_events(JvmtiEnv* env) { jvmtiError JvmtiCodeBlobEvents::generate_compiled_method_load_events(JvmtiEnv* env) {
HandleMark hm; HandleMark hm;
nmethodCollector collector;
// first collect all nmethods // Walk the CodeCache notifying for live nmethods. The code cache
{ // may be changing while this is happening which is ok since newly
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); // created nmethod will notify normally and nmethods which are freed
collector.collect(); // can be safely skipped.
} MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
nmethod* current = CodeCache::first_nmethod();
// iterate over the list and post an event for each nmethod while (current != NULL) {
nmethodDesc* nm_desc = collector.first(); // Lock the nmethod so it can't be freed
while (nm_desc != NULL) { nmethodLocker nml(current);
jmethodID mid = nm_desc->jmethod_id();
assert(mid != NULL, "checking"); // Only notify for live nmethods
JvmtiExport::post_compiled_method_load(env, mid, if (current->is_alive()) {
(jint)(nm_desc->code_end() - nm_desc->code_begin()), // Don't hold the lock over the notify or jmethodID creation
nm_desc->code_begin(), nm_desc->map_length(), MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
nm_desc->map()); current->get_and_cache_jmethod_id();
nm_desc = collector.next(); JvmtiExport::post_compiled_method_load(current);
}
current = CodeCache::next_nmethod(current);
} }
return JVMTI_ERROR_NONE; return JVMTI_ERROR_NONE;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册