6726999: nsk/stress/jck12a/jck12a010 assert(n != null,"Bad immediate dominator info.")

Escape Analysis fixes.

Reviewed-by: never, rasbold
This commit is contained in:
Vladimir Kozlov 2008-07-28 17:12:52 -07:00
parent 2d1fcda0d7
commit 50c4a23cac
15 changed files with 1680 additions and 115 deletions

View File

@ -388,6 +388,9 @@
product(intx, EliminateAllocationArraySizeLimit, 64, \ product(intx, EliminateAllocationArraySizeLimit, 64, \
"Array size (number of elements) limit for scalar replacement") \ "Array size (number of elements) limit for scalar replacement") \
\ \
product(intx, ValueSearchLimit, 1000, \
"Recursion limit in PhaseMacroExpand::value_from_mem_phi") \
\
product(intx, MaxLabelRootDepth, 1100, \ product(intx, MaxLabelRootDepth, 1100, \
"Maximum times call Label_Root to prevent stack overflow") \ "Maximum times call Label_Root to prevent stack overflow") \
\ \

View File

@ -585,6 +585,10 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
// Perform escape analysis // Perform escape analysis
if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) { if (_do_escape_analysis && ConnectionGraph::has_candidates(this)) {
TracePhase t2("escapeAnalysis", &_t_escapeAnalysis, true); 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); _congraph = new(comp_arena()) ConnectionGraph(this);
bool has_non_escaping_obj = _congraph->compute_escape(); bool has_non_escaping_obj = _congraph->compute_escape();
@ -594,6 +598,12 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr
_congraph->dump(); _congraph->dump();
} }
#endif #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) { if (!has_non_escaping_obj) {
_congraph = NULL; _congraph = NULL;
} }

View File

@ -62,10 +62,14 @@ static const char *edge_type_suffix[] = {
"F" // FieldEdge "F" // FieldEdge
}; };
void PointsToNode::dump() const { void PointsToNode::dump(bool print_state) const {
NodeType nt = node_type(); NodeType nt = node_type();
EscapeState es = escape_state(); tty->print("%s ", node_type_names[(int) nt]);
tty->print("%s %s %s [[", node_type_names[(int) nt], esc_names[(int) es], _scalar_replaceable ? "" : "NSR"); if (print_state) {
EscapeState es = escape_state();
tty->print("%s %s ", esc_names[(int) es], _scalar_replaceable ? "":"NSR");
}
tty->print("[[");
for (uint i = 0; i < edge_count(); i++) { for (uint i = 0; i < edge_count(); i++) {
tty->print(" %d%s", edge_target(i), edge_type_suffix[(int) edge_type(i)]); tty->print(" %d%s", edge_target(i), edge_type_suffix[(int) edge_type(i)]);
} }
@ -84,11 +88,22 @@ ConnectionGraph::ConnectionGraph(Compile * C) :
_compile(C), _compile(C),
_node_map(C->comp_arena()) { _node_map(C->comp_arena()) {
_phantom_object = C->top()->_idx; _phantom_object = C->top()->_idx,
PointsToNode *phn = ptnode_adr(_phantom_object); add_node(C->top(), PointsToNode::JavaObject, PointsToNode::GlobalEscape,true);
phn->_node = C->top();
phn->set_node_type(PointsToNode::JavaObject); // Add ConP(#NULL) and ConN(#NULL) nodes.
phn->set_escape_state(PointsToNode::GlobalEscape); PhaseGVN* igvn = C->initial_gvn();
Node* oop_null = igvn->zerocon(T_OBJECT);
_oop_null = oop_null->_idx;
assert(_oop_null < C->unique(), "should be created already");
add_node(oop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true);
if (UseCompressedOops) {
Node* noop_null = igvn->zerocon(T_NARROWOOP);
_noop_null = noop_null->_idx;
assert(_noop_null < C->unique(), "should be created already");
add_node(noop_null, PointsToNode::JavaObject, PointsToNode::NoEscape, true);
}
} }
void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) { void ConnectionGraph::add_pointsto_edge(uint from_i, uint to_i) {
@ -500,29 +515,30 @@ void ConnectionGraph::split_AddP(Node *addp, Node *base, PhaseGVN *igvn) {
igvn->set_type(addp, tinst); igvn->set_type(addp, tinst);
// record the allocation in the node map // record the allocation in the node map
set_map(addp->_idx, get_map(base->_idx)); set_map(addp->_idx, get_map(base->_idx));
// if the Address input is not the appropriate instance type
// (due to intervening casts,) insert a cast // Set addp's Base and Address to 'base'.
Node *adr = addp->in(AddPNode::Address); Node *abase = addp->in(AddPNode::Base);
const TypeOopPtr *atype = igvn->type(adr)->isa_oopptr(); Node *adr = addp->in(AddPNode::Address);
if (atype != NULL && atype->instance_id() != inst_id) { if (adr->is_Proj() && adr->in(0)->is_Allocate() &&
assert(!atype->is_known_instance(), "no conflicting instances"); adr->in(0)->_idx == (uint)inst_id) {
const TypeOopPtr *new_atype = base_t->add_offset(atype->offset())->isa_oopptr(); // Skip AddP cases #3 and #5.
Node *acast = new (_compile, 2) CastPPNode(adr, new_atype); } else {
acast->set_req(0, adr->in(0)); assert(!abase->is_top(), "sanity"); // AddP case #3
igvn->set_type(acast, new_atype); if (abase != base) {
record_for_optimizer(acast); igvn->hash_delete(addp);
Node *bcast = acast; addp->set_req(AddPNode::Base, base);
Node *abase = addp->in(AddPNode::Base); if (abase == adr) {
if (abase != adr) { addp->set_req(AddPNode::Address, base);
bcast = new (_compile, 2) CastPPNode(abase, base_t); } else {
bcast->set_req(0, abase->in(0)); // AddP case #4 (adr is array's element offset AddP node)
igvn->set_type(bcast, base_t); #ifdef ASSERT
record_for_optimizer(bcast); const TypeOopPtr *atype = igvn->type(adr)->isa_oopptr();
assert(adr->is_AddP() && atype != NULL &&
atype->instance_id() == inst_id, "array's element offset should be processed first");
#endif
}
igvn->hash_insert(addp);
} }
igvn->hash_delete(addp);
addp->set_req(AddPNode::Base, bcast);
addp->set_req(AddPNode::Address, acast);
igvn->hash_insert(addp);
} }
// Put on IGVN worklist since at least addp's type was changed above. // Put on IGVN worklist since at least addp's type was changed above.
record_for_optimizer(addp); record_for_optimizer(addp);
@ -660,27 +676,31 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
Compile* C = phase->C; Compile* C = phase->C;
const TypeOopPtr *tinst = C->get_adr_type(alias_idx)->isa_oopptr(); const TypeOopPtr *tinst = C->get_adr_type(alias_idx)->isa_oopptr();
bool is_instance = (tinst != NULL) && tinst->is_known_instance(); bool is_instance = (tinst != NULL) && tinst->is_known_instance();
Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
Node *prev = NULL; Node *prev = NULL;
Node *result = orig_mem; Node *result = orig_mem;
while (prev != result) { while (prev != result) {
prev = result; prev = result;
if (result == start_mem)
break; // hit one of our sentinals
if (result->is_Mem()) { if (result->is_Mem()) {
MemNode *mem = result->as_Mem(); const Type *at = phase->type(result->in(MemNode::Address));
const Type *at = phase->type(mem->in(MemNode::Address));
if (at != Type::TOP) { if (at != Type::TOP) {
assert (at->isa_ptr() != NULL, "pointer type required."); assert (at->isa_ptr() != NULL, "pointer type required.");
int idx = C->get_alias_index(at->is_ptr()); int idx = C->get_alias_index(at->is_ptr());
if (idx == alias_idx) if (idx == alias_idx)
break; break;
} }
result = mem->in(MemNode::Memory); result = result->in(MemNode::Memory);
} }
if (!is_instance) if (!is_instance)
continue; // don't search further for non-instance types continue; // don't search further for non-instance types
// skip over a call which does not affect this memory slice // skip over a call which does not affect this memory slice
if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) { if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) {
Node *proj_in = result->in(0); Node *proj_in = result->in(0);
if (proj_in->is_Call()) { if (proj_in->is_Allocate() && proj_in->_idx == (uint)tinst->instance_id()) {
break; // hit one of our sentinals
} else if (proj_in->is_Call()) {
CallNode *call = proj_in->as_Call(); CallNode *call = proj_in->as_Call();
if (!call->may_modify(tinst, phase)) { if (!call->may_modify(tinst, phase)) {
result = call->in(TypeFunc::Memory); result = call->in(TypeFunc::Memory);
@ -1006,12 +1026,12 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist)
memnode_worklist.append_if_missing(use); memnode_worklist.append_if_missing(use);
} else if (use->is_MergeMem()) { } else if (use->is_MergeMem()) {
mergemem_worklist.append_if_missing(use); mergemem_worklist.append_if_missing(use);
} else if (use->is_Call() && tinst != NULL) { } else if (use->is_SafePoint() && tinst != NULL) {
// Look for MergeMem nodes for calls which reference unique allocation // Look for MergeMem nodes for calls which reference unique allocation
// (through CheckCastPP nodes) even for debug info. // (through CheckCastPP nodes) even for debug info.
Node* m = use->in(TypeFunc::Memory); Node* m = use->in(TypeFunc::Memory);
uint iid = tinst->instance_id(); uint iid = tinst->instance_id();
while (m->is_Proj() && m->in(0)->is_Call() && while (m->is_Proj() && m->in(0)->is_SafePoint() &&
m->in(0) != use && !m->in(0)->_idx != iid) { m->in(0) != use && !m->in(0)->_idx != iid) {
m = m->in(0)->in(TypeFunc::Memory); m = m->in(0)->in(TypeFunc::Memory);
} }
@ -1348,15 +1368,95 @@ bool ConnectionGraph::compute_escape() {
remove_deferred(ni, &deferred_edges, &visited); remove_deferred(ni, &deferred_edges, &visited);
Node *n = ptn->_node; Node *n = ptn->_node;
if (n->is_AddP()) { if (n->is_AddP()) {
// If this AddP computes an address which may point to more that one // Search for objects which are not scalar replaceable.
// object or more then one field (array's element), nothing the address // Mark their escape state as ArgEscape to propagate the state
// points to can be scalar replaceable. // to referenced objects.
// Note: currently there are no difference in compiler optimizations
// for ArgEscape objects and NoEscape objects which are not
// scalar replaceable.
int offset = ptn->offset();
Node *base = get_addp_base(n); Node *base = get_addp_base(n);
ptset.Clear(); ptset.Clear();
PointsTo(ptset, base, igvn); PointsTo(ptset, base, igvn);
if (ptset.Size() > 1 || int ptset_size = ptset.Size();
(ptset.Size() != 0 && ptn->offset() == Type::OffsetBot)) {
// Check if a field's initializing value is recorded and add
// a corresponding NULL field's value if it is not recorded.
// Connection Graph does not record a default initialization by NULL
// captured by Initialize node.
//
// Note: it will disable scalar replacement in some cases:
//
// Point p[] = new Point[1];
// p[0] = new Point(); // Will be not scalar replaced
//
// but it will save us from incorrect optimizations in next cases:
//
// Point p[] = new Point[1];
// if ( x ) p[0] = new Point(); // Will be not scalar replaced
//
// Without a control flow analysis we can't distinguish above cases.
//
if (offset != Type::OffsetBot && ptset_size == 1) {
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() &&
ptnode_adr(elem)->escape_state() == PointsToNode::NoEscape) {
AllocateNode* alloc = ptnode_adr(elem)->_node->as_Allocate();
InitializeNode* ini = alloc->initialization();
Node* value = NULL;
if (ini != NULL) {
BasicType ft = UseCompressedOops ? T_NARROWOOP : T_OBJECT;
Node* store = ini->find_captured_store(offset, type2aelembytes(ft), igvn);
if (store != NULL && store->is_Store())
value = store->in(MemNode::ValueIn);
}
if (value == NULL || value != ptnode_adr(value->_idx)->_node) {
// A field's initializing value was not recorded. Add NULL.
uint null_idx = UseCompressedOops ? _noop_null : _oop_null;
add_pointsto_edge(ni, null_idx);
}
}
}
// An object is not scalar replaceable if the field which may point
// to it has unknown offset (unknown element of an array of objects).
//
if (offset == Type::OffsetBot) {
uint e_cnt = ptn->edge_count();
for (uint ei = 0; ei < e_cnt; ei++) {
uint npi = ptn->edge_target(ei);
set_escape_state(npi, PointsToNode::ArgEscape);
ptnode_adr(npi)->_scalar_replaceable = false;
}
}
// Currently an object is not scalar replaceable if a LoadStore node
// access its field since the field value is unknown after it.
//
bool has_LoadStore = false;
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node *use = n->fast_out(i);
if (use->is_LoadStore()) {
has_LoadStore = true;
break;
}
}
// An object is not scalar replaceable if the address points
// to unknown field (unknown element for arrays, offset is OffsetBot).
//
// Or the address may point to more then one object. This may produce
// the false positive result (set scalar_replaceable to false)
// since the flow-insensitive escape analysis can't separate
// the case when stores overwrite the field's value from the case
// when stores happened on different control branches.
//
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; ptnode_adr(j.elem)->_scalar_replaceable = false;
} }
} }
@ -1855,7 +1955,7 @@ void ConnectionGraph::record_for_escape_analysis(Node *n, PhaseTransform *phase)
case Op_LoadN: case Op_LoadN:
{ {
const Type *t = phase->type(n); const Type *t = phase->type(n);
if (!t->isa_narrowoop() && t->isa_ptr() == NULL) { if (t->make_ptr() == NULL) {
_processed.set(n->_idx); _processed.set(n->_idx);
return; return;
} }
@ -1878,8 +1978,9 @@ void ConnectionGraph::record_for_escape_analysis(Node *n, PhaseTransform *phase)
} }
case Op_Phi: case Op_Phi:
{ {
if (n->as_Phi()->type()->isa_ptr() == NULL) { const Type *t = n->as_Phi()->type();
// nothing to do if not an oop if (t->make_ptr() == NULL) {
// nothing to do if not an oop or narrow oop
_processed.set(n->_idx); _processed.set(n->_idx);
return; return;
} }
@ -2067,7 +2168,7 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
{ {
const Type *t = phase->type(n); const Type *t = phase->type(n);
#ifdef ASSERT #ifdef ASSERT
if (!t->isa_narrowoop() && t->isa_ptr() == NULL) if (t->make_ptr() == NULL)
assert(false, "Op_LoadP"); assert(false, "Op_LoadP");
#endif #endif
@ -2099,7 +2200,8 @@ void ConnectionGraph::build_connection_graph(Node *n, PhaseTransform *phase) {
case Op_Phi: case Op_Phi:
{ {
#ifdef ASSERT #ifdef ASSERT
if (n->as_Phi()->type()->isa_ptr() == NULL) const Type *t = n->as_Phi()->type();
if (t->make_ptr() == NULL)
assert(false, "Op_Phi"); assert(false, "Op_Phi");
#endif #endif
for (uint i = 1; i < n->req() ; i++) { for (uint i = 1; i < n->req() ; i++) {
@ -2213,16 +2315,14 @@ void ConnectionGraph::dump() {
PointsToNode::NodeType ptn_loc_type = ptn_loc->node_type(); PointsToNode::NodeType ptn_loc_type = ptn_loc->node_type();
if ( ptn_loc_type == PointsToNode::LocalVar && ptn_loc->_node != NULL && if ( ptn_loc_type == PointsToNode::LocalVar && ptn_loc->_node != NULL &&
ptn_loc->edge_count() == 1 && ptn_loc->edge_target(0) == ni ) { ptn_loc->edge_count() == 1 && ptn_loc->edge_target(0) == ni ) {
tty->print("%6d LocalVar [[%d]]", li, ni); ptnode_adr(li)->dump(false);
ptnode_adr(li)->_node->dump();
} }
} }
if (Verbose) { if (Verbose) {
// Print all fields which reference this allocation // Print all fields which reference this allocation
for (uint i = 0; i < ptn->edge_count(); i++) { for (uint i = 0; i < ptn->edge_count(); i++) {
uint ei = ptn->edge_target(i); uint ei = ptn->edge_target(i);
tty->print("%6d Field [[%d]]", ei, ni); ptnode_adr(ei)->dump(false);
ptnode_adr(ei)->_node->dump();
} }
} }
tty->cr(); tty->cr();

View File

@ -197,7 +197,7 @@ public:
void remove_edge(uint targIdx, EdgeType et); void remove_edge(uint targIdx, EdgeType et);
#ifndef PRODUCT #ifndef PRODUCT
void dump() const; void dump(bool print_state=true) const;
#endif #endif
}; };
@ -221,6 +221,8 @@ private:
// that pointer values loaded from // that pointer values loaded from
// a field which has not been set // a field which has not been set
// are assumed to point to. // are assumed to point to.
uint _oop_null; // ConP(#NULL)
uint _noop_null; // ConN(#NULL)
Compile * _compile; // Compile object for current compilation Compile * _compile; // Compile object for current compilation

View File

@ -322,7 +322,7 @@ Node *Block::select(PhaseCFG *cfg, Node_List &worklist, int *ready_cnt, VectorSe
uint choice = 0; // Bigger is most important uint choice = 0; // Bigger is most important
uint latency = 0; // Bigger is scheduled first uint latency = 0; // Bigger is scheduled first
uint score = 0; // Bigger is better uint score = 0; // Bigger is better
uint idx; // Index in worklist int idx = -1; // Index in worklist
for( uint i=0; i<cnt; i++ ) { // Inspect entire worklist for( uint i=0; i<cnt; i++ ) { // Inspect entire worklist
// Order in worklist is used to break ties. // Order in worklist is used to break ties.
@ -412,9 +412,10 @@ Node *Block::select(PhaseCFG *cfg, Node_List &worklist, int *ready_cnt, VectorSe
} }
} // End of for all ready nodes in worklist } // End of for all ready nodes in worklist
Node *n = worklist[idx]; // Get the winner assert(idx >= 0, "index should be set");
Node *n = worklist[(uint)idx]; // Get the winner
worklist.map(idx,worklist.pop()); // Compress worklist worklist.map((uint)idx, worklist.pop()); // Compress worklist
return n; return n;
} }
@ -599,7 +600,14 @@ 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->as_Mach()->ideal_Opcode() == Op_MemBarAcquire &&
n->req() > TypeFunc::Parms ) {
// MemBarAcquire could be created without Precedent edge.
// del_req() replaces the specified edge with the last input edge
// and then removes the last edge. If the specified edge > number of
// edges the last edge will be moved outside of the input edges array
// and the edge will be lost. This is why this code should be
// executed only when Precedent (== TypeFunc::Parms) edge is present.
Node *x = n->in(TypeFunc::Parms); Node *x = n->in(TypeFunc::Parms);
n->del_req(TypeFunc::Parms); n->del_req(TypeFunc::Parms);
n->add_prec(x); n->add_prec(x);

View File

@ -578,7 +578,8 @@ Node *PhaseIdealLoop::split_if_with_blocks_pre( Node *n ) {
Node *cmov = conditional_move( n ); Node *cmov = conditional_move( n );
if( cmov ) return cmov; if( cmov ) return cmov;
} }
if( n->is_CFG() || n_op == Op_StorePConditional || n_op == Op_StoreLConditional || n_op == Op_CompareAndSwapI || n_op == Op_CompareAndSwapL ||n_op == Op_CompareAndSwapP) return n; if( n->is_CFG() || n->is_LoadStore() )
return n;
if( n_op == Op_Opaque1 || // Opaque nodes cannot be mod'd if( n_op == Op_Opaque1 || // Opaque nodes cannot be mod'd
n_op == Op_Opaque2 ) { n_op == Op_Opaque2 ) {
if( !C->major_progress() ) // If chance of no more loop opts... if( !C->major_progress() ) // If chance of no more loop opts...

View File

@ -194,9 +194,10 @@ void PhaseMacroExpand::eliminate_card_mark(Node *p2x) {
} }
// Search for a memory operation for the specified memory slice. // Search for a memory operation for the specified memory slice.
static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_mem, Node *alloc) { static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_mem, Node *alloc, PhaseGVN *phase) {
Node *orig_mem = mem; Node *orig_mem = mem;
Node *alloc_mem = alloc->in(TypeFunc::Memory); Node *alloc_mem = alloc->in(TypeFunc::Memory);
const TypeOopPtr *tinst = phase->C->get_adr_type(alias_idx)->isa_oopptr();
while (true) { while (true) {
if (mem == alloc_mem || mem == start_mem ) { if (mem == alloc_mem || mem == start_mem ) {
return mem; // hit one of our sentinals return mem; // hit one of our sentinals
@ -208,7 +209,13 @@ static Node *scan_mem_chain(Node *mem, int alias_idx, int offset, Node *start_me
// already know that the object is safe to eliminate. // already know that the object is safe to eliminate.
if (in->is_Initialize() && in->as_Initialize()->allocation() == alloc) { if (in->is_Initialize() && in->as_Initialize()->allocation() == alloc) {
return in; return in;
} else if (in->is_Call() || in->is_MemBar()) { } else if (in->is_Call()) {
CallNode *call = in->as_Call();
if (!call->may_modify(tinst, phase)) {
mem = call->in(TypeFunc::Memory);
}
mem = in->in(TypeFunc::Memory);
} else if (in->is_MemBar()) {
mem = in->in(TypeFunc::Memory); mem = in->in(TypeFunc::Memory);
} else { } else {
assert(false, "unexpected projection"); assert(false, "unexpected projection");
@ -265,7 +272,7 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *
} }
if (level <= 0) { if (level <= 0) {
return NULL; return NULL; // Give up: phi tree too deep
} }
Node *start_mem = C->start()->proj_out(TypeFunc::Memory); Node *start_mem = C->start()->proj_out(TypeFunc::Memory);
Node *alloc_mem = alloc->in(TypeFunc::Memory); Node *alloc_mem = alloc->in(TypeFunc::Memory);
@ -283,7 +290,7 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *
if (in == NULL || in->is_top()) { if (in == NULL || in->is_top()) {
values.at_put(j, in); values.at_put(j, in);
} else { } else {
Node *val = scan_mem_chain(in, alias_idx, offset, start_mem, alloc); Node *val = scan_mem_chain(in, alias_idx, offset, start_mem, alloc, &_igvn);
if (val == start_mem || val == alloc_mem) { if (val == start_mem || val == alloc_mem) {
// hit a sentinel, return appropriate 0 value // hit a sentinel, return appropriate 0 value
values.at_put(j, _igvn.zerocon(ft)); values.at_put(j, _igvn.zerocon(ft));
@ -308,7 +315,8 @@ Node *PhaseMacroExpand::value_from_mem_phi(Node *mem, BasicType ft, const Type *
} }
values.at_put(j, val); values.at_put(j, val);
} else { } else {
return NULL; // unknown node on this path assert(false, "unknown node on this path");
return NULL; // unknown node on this path
} }
} }
} }
@ -344,7 +352,7 @@ Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, BasicType ft, const Type
if (visited.test_set(mem->_idx)) { if (visited.test_set(mem->_idx)) {
return NULL; // found a loop, give up return NULL; // found a loop, give up
} }
mem = scan_mem_chain(mem, alias_idx, offset, start_mem, alloc); mem = scan_mem_chain(mem, alias_idx, offset, start_mem, alloc, &_igvn);
if (mem == start_mem || mem == alloc_mem) { if (mem == start_mem || mem == alloc_mem) {
done = true; // hit a sentinel, return appropriate 0 value done = true; // hit a sentinel, return appropriate 0 value
} else if (mem->is_Initialize()) { } else if (mem->is_Initialize()) {
@ -368,7 +376,7 @@ Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, BasicType ft, const Type
Node *unique_input = NULL; Node *unique_input = NULL;
Node *top = C->top(); Node *top = C->top();
for (uint i = 1; i < mem->req(); i++) { for (uint i = 1; i < mem->req(); i++) {
Node *n = scan_mem_chain(mem->in(i), alias_idx, offset, start_mem, alloc); Node *n = scan_mem_chain(mem->in(i), alias_idx, offset, start_mem, alloc, &_igvn);
if (n == NULL || n == top || n == mem) { if (n == NULL || n == top || n == mem) {
continue; continue;
} else if (unique_input == NULL) { } else if (unique_input == NULL) {
@ -396,7 +404,7 @@ Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, BasicType ft, const Type
} else if (mem->is_Phi()) { } else if (mem->is_Phi()) {
// attempt to produce a Phi reflecting the values on the input paths of the Phi // attempt to produce a Phi reflecting the values on the input paths of the Phi
Node_Stack value_phis(a, 8); Node_Stack value_phis(a, 8);
Node * phi = value_from_mem_phi(mem, ft, ftype, adr_t, alloc, &value_phis, 8); Node * phi = value_from_mem_phi(mem, ft, ftype, adr_t, alloc, &value_phis, ValueSearchLimit);
if (phi != NULL) { if (phi != NULL) {
return phi; return phi;
} else { } else {
@ -463,7 +471,7 @@ bool PhaseMacroExpand::can_eliminate_allocation(AllocateNode *alloc, GrowableArr
Node* n = use->fast_out(k); Node* n = use->fast_out(k);
if (!n->is_Store() && n->Opcode() != Op_CastP2X) { if (!n->is_Store() && n->Opcode() != Op_CastP2X) {
DEBUG_ONLY(disq_node = n;) DEBUG_ONLY(disq_node = n;)
if (n->is_Load()) { if (n->is_Load() || n->is_LoadStore()) {
NOT_PRODUCT(fail_eliminate = "Field load";) NOT_PRODUCT(fail_eliminate = "Field load";)
} else { } else {
NOT_PRODUCT(fail_eliminate = "Not store field referrence";) NOT_PRODUCT(fail_eliminate = "Not store field referrence";)

View File

@ -94,14 +94,19 @@ Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypePtr *t_adr,
if (tinst == NULL || !tinst->is_known_instance_field()) if (tinst == NULL || !tinst->is_known_instance_field())
return mchain; // don't try to optimize non-instance types return mchain; // don't try to optimize non-instance types
uint instance_id = tinst->instance_id(); uint instance_id = tinst->instance_id();
Node *start_mem = phase->C->start()->proj_out(TypeFunc::Memory);
Node *prev = NULL; Node *prev = NULL;
Node *result = mchain; Node *result = mchain;
while (prev != result) { while (prev != result) {
prev = result; prev = result;
if (result == start_mem)
break; // hit one of our sentinals
// skip over a call which does not affect this memory slice // skip over a call which does not affect this memory slice
if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) { if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) {
Node *proj_in = result->in(0); Node *proj_in = result->in(0);
if (proj_in->is_Call()) { if (proj_in->is_Allocate() && proj_in->_idx == instance_id) {
break; // hit one of our sentinals
} else if (proj_in->is_Call()) {
CallNode *call = proj_in->as_Call(); CallNode *call = proj_in->as_Call();
if (!call->may_modify(t_adr, phase)) { if (!call->may_modify(t_adr, phase)) {
result = call->in(TypeFunc::Memory); result = call->in(TypeFunc::Memory);
@ -115,6 +120,8 @@ Node *MemNode::optimize_simple_memory_chain(Node *mchain, const TypePtr *t_adr,
} }
} else if (proj_in->is_MemBar()) { } else if (proj_in->is_MemBar()) {
result = proj_in->in(TypeFunc::Memory); result = proj_in->in(TypeFunc::Memory);
} else {
assert(false, "unexpected projection");
} }
} 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);

View File

@ -607,6 +607,7 @@ public:
}; };
//------------------------------LoadStoreNode--------------------------- //------------------------------LoadStoreNode---------------------------
// Note: is_Mem() method returns 'true' for this class.
class LoadStoreNode : public Node { class LoadStoreNode : public Node {
public: public:
enum { enum {

View File

@ -1196,8 +1196,10 @@ void SuperWord::construct_bb() {
Node *n = lp()->fast_out(i); Node *n = lp()->fast_out(i);
if (in_bb(n) && (n->is_Phi() && n->bottom_type() == Type::MEMORY)) { if (in_bb(n) && (n->is_Phi() && n->bottom_type() == Type::MEMORY)) {
Node* n_tail = n->in(LoopNode::LoopBackControl); Node* n_tail = n->in(LoopNode::LoopBackControl);
_mem_slice_head.push(n); if (n_tail != n->in(LoopNode::EntryControl)) {
_mem_slice_tail.push(n_tail); _mem_slice_head.push(n);
_mem_slice_tail.push(n_tail);
}
} }
} }

View File

@ -2472,6 +2472,9 @@ jint Arguments::parse(const JavaVMInitArgs* args) {
if (match_option(option, "-XX:+PrintVMOptions", &tail)) { if (match_option(option, "-XX:+PrintVMOptions", &tail)) {
PrintVMOptions = true; PrintVMOptions = true;
} }
if (match_option(option, "-XX:-PrintVMOptions", &tail)) {
PrintVMOptions = false;
}
} }
// Parse default .hotspotrc settings file // Parse default .hotspotrc settings file

View File

@ -1,23 +1,24 @@
/* /*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * 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.
* *
*/ */

View File

@ -1,24 +1,24 @@
/* /*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * 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.
* *
*/ */

View File

@ -1,24 +1,24 @@
/* /*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * 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.
* *
*/ */

File diff suppressed because it is too large Load Diff