提交 53f4ef4a 编写于 作者: K kvn

6673473: (Escape Analysis) Add the instance's field information to PhiNode

Summary: Avoid an infinite generation of instance's field values Phi nodes.
Reviewed-by: never
上级 0f778da5
...@@ -110,14 +110,15 @@ class JProjNode : public ProjNode { ...@@ -110,14 +110,15 @@ class JProjNode : public ProjNode {
// input in slot 0. // input in slot 0.
class PhiNode : public TypeNode { class PhiNode : public TypeNode {
const TypePtr* const _adr_type; // non-null only for Type::MEMORY nodes. const TypePtr* const _adr_type; // non-null only for Type::MEMORY nodes.
const int _inst_id; // Instance id of the memory slice.
const int _inst_index; // Alias index of the instance memory slice.
// Array elements references have the same alias_idx but different offset.
const int _inst_offset; // Offset of the instance memory slice.
// Size is bigger to hold the _adr_type field. // Size is bigger to hold the _adr_type field.
virtual uint hash() const; // Check the type virtual uint hash() const; // Check the type
virtual uint cmp( const Node &n ) const; virtual uint cmp( const Node &n ) const;
virtual uint size_of() const { return sizeof(*this); } virtual uint size_of() const { return sizeof(*this); }
// Determine a unique non-trivial input, if any.
// Ignore casts if it helps. Return NULL on failure.
Node* unique_input(PhaseTransform *phase);
// Determine if CMoveNode::is_cmove_id can be used at this join point. // Determine if CMoveNode::is_cmove_id can be used at this join point.
Node* is_cmove_id(PhaseTransform* phase, int true_path); Node* is_cmove_id(PhaseTransform* phase, int true_path);
...@@ -127,8 +128,16 @@ public: ...@@ -127,8 +128,16 @@ public:
Input // Input values are [1..len) Input // Input values are [1..len)
}; };
PhiNode( Node *r, const Type *t, const TypePtr* at = NULL ) PhiNode( Node *r, const Type *t, const TypePtr* at = NULL,
: TypeNode(t,r->req()), _adr_type(at) { const int iid = TypeOopPtr::UNKNOWN_INSTANCE,
const int iidx = Compile::AliasIdxTop,
const int ioffs = Type::OffsetTop )
: TypeNode(t,r->req()),
_adr_type(at),
_inst_id(iid),
_inst_index(iidx),
_inst_offset(ioffs)
{
init_class_id(Class_Phi); init_class_id(Class_Phi);
init_req(0, r); init_req(0, r);
verify_adr_type(); verify_adr_type();
...@@ -152,6 +161,10 @@ public: ...@@ -152,6 +161,10 @@ public:
return NULL; // not a copy! return NULL; // not a copy!
} }
// Determine a unique non-trivial input, if any.
// Ignore casts if it helps. Return NULL on failure.
Node* unique_input(PhaseTransform *phase);
// Check for a simple dead loop. // Check for a simple dead loop.
enum LoopSafety { Safe = 0, Unsafe, UnsafeLoop }; enum LoopSafety { Safe = 0, Unsafe, UnsafeLoop };
LoopSafety simple_data_loop_check(Node *in) const; LoopSafety simple_data_loop_check(Node *in) const;
...@@ -161,6 +174,18 @@ public: ...@@ -161,6 +174,18 @@ public:
virtual int Opcode() const; virtual int Opcode() const;
virtual bool pinned() const { return in(0) != 0; } virtual bool pinned() const { return in(0) != 0; }
virtual const TypePtr *adr_type() const { verify_adr_type(true); return _adr_type; } virtual const TypePtr *adr_type() const { verify_adr_type(true); return _adr_type; }
const int inst_id() const { return _inst_id; }
const int inst_index() const { return _inst_index; }
const int inst_offset() const { return _inst_offset; }
bool is_same_inst_field(const Type* tp, int id, int index, int offset) {
return type()->basic_type() == tp->basic_type() &&
inst_id() == id &&
inst_index() == index &&
inst_offset() == offset &&
type()->higher_equal(tp);
}
virtual const Type *Value( PhaseTransform *phase ) const; virtual const Type *Value( PhaseTransform *phase ) const;
virtual Node *Identity( PhaseTransform *phase ); virtual Node *Identity( PhaseTransform *phase );
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
......
...@@ -32,7 +32,18 @@ Node *PhaseIdealLoop::split_thru_phi( Node *n, Node *region, int policy ) { ...@@ -32,7 +32,18 @@ Node *PhaseIdealLoop::split_thru_phi( Node *n, Node *region, int policy ) {
int wins = 0; int wins = 0;
assert( !n->is_CFG(), "" ); assert( !n->is_CFG(), "" );
assert( region->is_Region(), "" ); assert( region->is_Region(), "" );
Node *phi = new (C, region->req()) PhiNode( region, n->bottom_type() );
const Type* type = n->bottom_type();
const TypeOopPtr *t_oop = _igvn.type(n)->isa_oopptr();
Node *phi;
if( t_oop != NULL && t_oop->is_instance_field() ) {
int iid = t_oop->instance_id();
int index = C->get_alias_index(t_oop);
int offset = t_oop->offset();
phi = new (C,region->req()) PhiNode(region, type, NULL, iid, index, offset);
} else {
phi = new (C,region->req()) PhiNode(region, type);
}
uint old_unique = C->unique(); uint old_unique = C->unique();
for( uint i = 1; i < region->req(); i++ ) { for( uint i = 1; i < region->req(); i++ ) {
Node *x; Node *x;
......
...@@ -87,6 +87,58 @@ extern void print_alias_types(); ...@@ -87,6 +87,58 @@ extern void print_alias_types();
#endif #endif
static Node *step_through_mergemem(PhaseGVN *phase, MergeMemNode *mmem, const TypePtr *tp, const TypePtr *adr_check, outputStream *st) {
uint alias_idx = phase->C->get_alias_index(tp);
Node *mem = mmem;
#ifdef ASSERT
{
// Check that current type is consistent with the alias index used during graph construction
assert(alias_idx >= Compile::AliasIdxRaw, "must not be a bad alias_idx");
bool consistent = adr_check == NULL || adr_check->empty() ||
phase->C->must_alias(adr_check, alias_idx );
// Sometimes dead array references collapse to a[-1], a[-2], or a[-3]
if( !consistent && adr_check != NULL && !adr_check->empty() &&
tp->isa_aryptr() && tp->offset() == Type::OffsetBot &&
adr_check->isa_aryptr() && adr_check->offset() != Type::OffsetBot &&
( adr_check->offset() == arrayOopDesc::length_offset_in_bytes() ||
adr_check->offset() == oopDesc::klass_offset_in_bytes() ||
adr_check->offset() == oopDesc::mark_offset_in_bytes() ) ) {
// don't assert if it is dead code.
consistent = true;
}
if( !consistent ) {
st->print("alias_idx==%d, adr_check==", alias_idx);
if( adr_check == NULL ) {
st->print("NULL");
} else {
adr_check->dump();
}
st->cr();
print_alias_types();
assert(consistent, "adr_check must match alias idx");
}
}
#endif
// TypeInstPtr::NOTNULL+any is an OOP with unknown offset - generally
// means an array I have not precisely typed yet. Do not do any
// alias stuff with it any time soon.
const TypeOopPtr *tinst = tp->isa_oopptr();
if( tp->base() != Type::AnyPtr &&
!(tinst &&
tinst->klass()->is_java_lang_Object() &&
tinst->offset() == Type::OffsetBot) ) {
// compress paths and change unreachable cycles to TOP
// If not, we can update the input infinitely along a MergeMem cycle
// Equivalent code in PhiNode::Ideal
Node* m = phase->transform(mmem);
// If tranformed to a MergeMem, get the desired slice
// Otherwise the returned node represents memory for every slice
mem = (m->is_MergeMem())? m->as_MergeMem()->memory_at(alias_idx) : m;
// Update input if it is progress over what we have now
}
return mem;
}
//--------------------------Ideal_common--------------------------------------- //--------------------------Ideal_common---------------------------------------
// Look for degenerate control and memory inputs. Bypass MergeMem inputs. // Look for degenerate control and memory inputs. Bypass MergeMem inputs.
// Unhook non-raw memories from complete (macro-expanded) initializations. // Unhook non-raw memories from complete (macro-expanded) initializations.
...@@ -119,48 +171,8 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) { ...@@ -119,48 +171,8 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) {
if (mem->is_MergeMem()) { if (mem->is_MergeMem()) {
MergeMemNode* mmem = mem->as_MergeMem(); MergeMemNode* mmem = mem->as_MergeMem();
const TypePtr *tp = t_adr->is_ptr(); const TypePtr *tp = t_adr->is_ptr();
uint alias_idx = phase->C->get_alias_index(tp);
#ifdef ASSERT mem = step_through_mergemem(phase, mmem, tp, adr_type(), tty);
{
// Check that current type is consistent with the alias index used during graph construction
assert(alias_idx >= Compile::AliasIdxRaw, "must not be a bad alias_idx");
const TypePtr *adr_t = adr_type();
bool consistent = adr_t == NULL || adr_t->empty() || phase->C->must_alias(adr_t, alias_idx );
// Sometimes dead array references collapse to a[-1], a[-2], or a[-3]
if( !consistent && adr_t != NULL && !adr_t->empty() &&
tp->isa_aryptr() && tp->offset() == Type::OffsetBot &&
adr_t->isa_aryptr() && adr_t->offset() != Type::OffsetBot &&
( adr_t->offset() == arrayOopDesc::length_offset_in_bytes() ||
adr_t->offset() == oopDesc::klass_offset_in_bytes() ||
adr_t->offset() == oopDesc::mark_offset_in_bytes() ) ) {
// don't assert if it is dead code.
consistent = true;
}
if( !consistent ) {
tty->print("alias_idx==%d, adr_type()==", alias_idx); if( adr_t == NULL ) { tty->print("NULL"); } else { adr_t->dump(); }
tty->cr();
print_alias_types();
assert(consistent, "adr_type must match alias idx");
}
}
#endif
// TypeInstPtr::NOTNULL+any is an OOP with unknown offset - generally
// means an array I have not precisely typed yet. Do not do any
// alias stuff with it any time soon.
const TypeInstPtr *tinst = tp->isa_instptr();
if( tp->base() != Type::AnyPtr &&
!(tinst &&
tinst->klass()->is_java_lang_Object() &&
tinst->offset() == Type::OffsetBot) ) {
// compress paths and change unreachable cycles to TOP
// If not, we can update the input infinitely along a MergeMem cycle
// Equivalent code in PhiNode::Ideal
Node* m = phase->transform(mmem);
// If tranformed to a MergeMem, get the desired slice
// Otherwise the returned node represents memory for every slice
mem = (m->is_MergeMem())? m->as_MergeMem()->memory_at(alias_idx) : m;
// Update input if it is progress over what we have now
}
} }
if (mem != old_mem) { if (mem != old_mem) {
...@@ -534,7 +546,10 @@ Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) { ...@@ -534,7 +546,10 @@ Node *MemNode::Ideal_DU_postCCP( PhaseCCP *ccp ) {
const Node* call = adr->in(0); const Node* call = adr->in(0);
if (call->is_CallStaticJava()) { if (call->is_CallStaticJava()) {
const CallStaticJavaNode* call_java = call->as_CallStaticJava(); const CallStaticJavaNode* call_java = call->as_CallStaticJava();
assert(call_java && call_java->method() == NULL, "must be runtime call"); const TypeTuple *r = call_java->tf()->range();
assert(r->cnt() > TypeFunc::Parms, "must return value");
const Type* ret_type = r->field_at(TypeFunc::Parms);
assert(ret_type && ret_type->isa_ptr(), "must return pointer");
// We further presume that this is one of // We further presume that this is one of
// new_instance_Java, new_array_Java, or // new_instance_Java, new_array_Java, or
// the like, but do not assert for this. // the like, but do not assert for this.
...@@ -732,6 +747,21 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const { ...@@ -732,6 +747,21 @@ Node* MemNode::can_see_stored_value(Node* st, PhaseTransform* phase) const {
return NULL; return NULL;
} }
//----------------------is_instance_field_load_with_local_phi------------------
bool LoadNode::is_instance_field_load_with_local_phi(Node* ctrl) {
if( in(MemNode::Memory)->is_Phi() && in(MemNode::Memory)->in(0) == ctrl &&
in(MemNode::Address)->is_AddP() ) {
const TypeOopPtr* t_oop = in(MemNode::Address)->bottom_type()->isa_oopptr();
// Only instances.
if( t_oop != NULL && t_oop->is_instance_field() &&
t_oop->offset() != Type::OffsetBot &&
t_oop->offset() != Type::OffsetTop) {
return true;
}
}
return false;
}
//------------------------------Identity--------------------------------------- //------------------------------Identity---------------------------------------
// Loads are identity if previous store is to same address // Loads are identity if previous store is to same address
Node *LoadNode::Identity( PhaseTransform *phase ) { Node *LoadNode::Identity( PhaseTransform *phase ) {
...@@ -754,6 +784,25 @@ Node *LoadNode::Identity( PhaseTransform *phase ) { ...@@ -754,6 +784,25 @@ Node *LoadNode::Identity( PhaseTransform *phase ) {
// usually runs first, producing the singleton type of the Con.) // usually runs first, producing the singleton type of the Con.)
return value; return value;
} }
// Search for an existing data phi which was generated before for the same
// instance's field to avoid infinite genertion of phis in a loop.
Node *region = mem->in(0);
if (is_instance_field_load_with_local_phi(region)) {
const TypePtr *addr_t = in(MemNode::Address)->bottom_type()->isa_ptr();
int this_index = phase->C->get_alias_index(addr_t);
int this_offset = addr_t->offset();
int this_id = addr_t->is_oopptr()->instance_id();
const Type* this_type = bottom_type();
for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) {
Node* phi = region->fast_out(i);
if (phi->is_Phi() && phi != mem &&
phi->as_Phi()->is_same_inst_field(this_type, this_id, this_index, this_offset)) {
return phi;
}
}
}
return this; return this;
} }
...@@ -1189,6 +1238,17 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const { ...@@ -1189,6 +1238,17 @@ const Type *LoadNode::Value( PhaseTransform *phase ) const {
return value->bottom_type(); return value->bottom_type();
} }
const TypeOopPtr *tinst = tp->isa_oopptr();
if (tinst != NULL && tinst->is_instance_field()) {
// If we have an instance type and our memory input is the
// programs's initial memory state, there is no matching store,
// so just return a zero of the appropriate type
Node *mem = in(MemNode::Memory);
if (mem->is_Parm() && mem->in(0)->is_Start()) {
assert(mem->as_Parm()->_con == TypeFunc::Memory, "must be memory Parm");
return Type::get_zero_type(_type->basic_type());
}
}
return _type; return _type;
} }
...@@ -1712,7 +1772,7 @@ bool StoreNode::value_never_loaded( PhaseTransform *phase) const { ...@@ -1712,7 +1772,7 @@ bool StoreNode::value_never_loaded( PhaseTransform *phase) const {
const TypeOopPtr *adr_oop = phase->type(adr)->isa_oopptr(); const TypeOopPtr *adr_oop = phase->type(adr)->isa_oopptr();
if (adr_oop == NULL) if (adr_oop == NULL)
return false; return false;
if (!adr_oop->is_instance()) if (!adr_oop->is_instance_field())
return false; // if not a distinct instance, there may be aliases of the address return false; // if not a distinct instance, there may be aliases of the address
for (DUIterator_Fast imax, i = adr->fast_outs(imax); i < imax; i++) { for (DUIterator_Fast imax, i = adr->fast_outs(imax); i < imax; i++) {
Node *use = adr->fast_out(i); Node *use = adr->fast_out(i);
...@@ -3244,7 +3304,7 @@ Node *MergeMemNode::Ideal(PhaseGVN *phase, bool can_reshape) { ...@@ -3244,7 +3304,7 @@ Node *MergeMemNode::Ideal(PhaseGVN *phase, bool can_reshape) {
} }
} }
assert(verify_sparse(), "please, no dups of base"); assert(progress || verify_sparse(), "please, no dups of base");
return progress; return progress;
} }
......
...@@ -172,6 +172,9 @@ public: ...@@ -172,6 +172,9 @@ public:
// Map a load opcode to its corresponding store opcode. // Map a load opcode to its corresponding store opcode.
virtual int store_Opcode() const = 0; virtual int store_Opcode() const = 0;
// Check if the load's memory input is a Phi node with the same control.
bool is_instance_field_load_with_local_phi(Node* ctrl);
#ifndef PRODUCT #ifndef PRODUCT
virtual void dump_spec(outputStream *st) const; virtual void dump_spec(outputStream *st) const;
#endif #endif
......
...@@ -3164,7 +3164,7 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const { ...@@ -3164,7 +3164,7 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
case TopPTR: case TopPTR:
// Compute new klass on demand, do not use tap->_klass // Compute new klass on demand, do not use tap->_klass
xk = (tap->_klass_is_exact | this->_klass_is_exact); xk = (tap->_klass_is_exact | this->_klass_is_exact);
return make( ptr, const_oop(), tary, lazy_klass, xk, off ); return make( ptr, const_oop(), tary, lazy_klass, xk, off, iid );
case Constant: { case Constant: {
ciObject* o = const_oop(); ciObject* o = const_oop();
if( _ptr == Constant ) { if( _ptr == Constant ) {
...@@ -3176,7 +3176,7 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const { ...@@ -3176,7 +3176,7 @@ const Type *TypeAryPtr::xmeet( const Type *t ) const {
o = tap->const_oop(); o = tap->const_oop();
} }
xk = true; xk = true;
return TypeAryPtr::make( ptr, o, tary, tap->_klass, xk, off ); return TypeAryPtr::make( ptr, o, tary, tap->_klass, xk, off, iid );
} }
case NotNull: case NotNull:
case BotPTR: case BotPTR:
...@@ -3263,14 +3263,21 @@ void TypeAryPtr::dump2( Dict &d, uint depth, outputStream *st ) const { ...@@ -3263,14 +3263,21 @@ void TypeAryPtr::dump2( Dict &d, uint depth, outputStream *st ) const {
break; break;
} }
st->print("*"); if( _offset != 0 ) {
int header_size = objArrayOopDesc::header_size() * wordSize;
if( _offset == OffsetTop ) st->print("+undefined");
else if( _offset == OffsetBot ) st->print("+any");
else if( _offset < header_size ) st->print("+%d", _offset);
else {
BasicType basic_elem_type = elem()->basic_type();
int array_base = arrayOopDesc::base_offset_in_bytes(basic_elem_type);
int elem_size = type2aelembytes(basic_elem_type);
st->print("[%d]", (_offset - array_base)/elem_size);
}
}
st->print(" *");
if (_instance_id != UNKNOWN_INSTANCE) if (_instance_id != UNKNOWN_INSTANCE)
st->print(",iid=%d",_instance_id); st->print(",iid=%d",_instance_id);
if( !_offset ) return;
if( _offset == OffsetTop ) st->print("+undefined");
else if( _offset == OffsetBot ) st->print("+any");
else if( _offset < 12 ) st->print("+%d",_offset);
else st->print("[%d]", (_offset-12)/4 );
} }
#endif #endif
......
...@@ -686,6 +686,7 @@ public: ...@@ -686,6 +686,7 @@ public:
bool klass_is_exact() const { return _klass_is_exact; } bool klass_is_exact() const { return _klass_is_exact; }
bool is_instance() const { return _instance_id != UNKNOWN_INSTANCE; } bool is_instance() const { return _instance_id != UNKNOWN_INSTANCE; }
uint instance_id() const { return _instance_id; } uint instance_id() const { return _instance_id; }
bool is_instance_field() const { return _instance_id != UNKNOWN_INSTANCE && _offset >= 0; }
virtual intptr_t get_con() const; virtual intptr_t get_con() const;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册