提交 725e8092 编写于 作者: K kvn

7170463: C2 should recognize "obj.getClass() == A.class" code pattern

Summary: optimize this code pattern obj.getClass() == A.class.
Reviewed-by: jrose, kvn
Contributed-by: NKrystal Mok <sajia@taobao.com>
上级 5c35a79f
......@@ -527,6 +527,9 @@ class Parse : public GraphKit {
int repush_if_args();
void adjust_map_after_if(BoolTest::mask btest, Node* c, float prob,
Block* path, Block* other_path);
void sharpen_type_after_if(BoolTest::mask btest,
Node* con, const Type* tcon,
Node* val, const Type* tval);
IfNode* jump_if_fork_int(Node* a, Node* b, BoolTest::mask mask);
Node* jump_if_join(Node* iffalse, Node* iftrue);
void jump_if_true_fork(IfNode *ifNode, int dest_bci_if_true, int prof_table_index);
......
......@@ -1233,6 +1233,71 @@ void Parse::adjust_map_after_if(BoolTest::mask btest, Node* c, float prob,
if (!have_con) // remaining adjustments need a con
return;
sharpen_type_after_if(btest, con, tcon, val, tval);
}
static Node* extract_obj_from_klass_load(PhaseGVN* gvn, Node* n) {
Node* ldk;
if (n->is_DecodeN()) {
if (n->in(1)->Opcode() != Op_LoadNKlass) {
return NULL;
} else {
ldk = n->in(1);
}
} else if (n->Opcode() != Op_LoadKlass) {
return NULL;
} else {
ldk = n;
}
assert(ldk != NULL && ldk->is_Load(), "should have found a LoadKlass or LoadNKlass node");
Node* adr = ldk->in(MemNode::Address);
intptr_t off = 0;
Node* obj = AddPNode::Ideal_base_and_offset(adr, gvn, off);
if (obj == NULL || off != oopDesc::klass_offset_in_bytes()) // loading oopDesc::_klass?
return NULL;
const TypePtr* tp = gvn->type(obj)->is_ptr();
if (tp == NULL || !(tp->isa_instptr() || tp->isa_aryptr())) // is obj a Java object ptr?
return NULL;
return obj;
}
void Parse::sharpen_type_after_if(BoolTest::mask btest,
Node* con, const Type* tcon,
Node* val, const Type* tval) {
// Look for opportunities to sharpen the type of a node
// whose klass is compared with a constant klass.
if (btest == BoolTest::eq && tcon->isa_klassptr()) {
Node* obj = extract_obj_from_klass_load(&_gvn, val);
const TypeOopPtr* con_type = tcon->isa_klassptr()->as_instance_type();
if (obj != NULL && (con_type->isa_instptr() || con_type->isa_aryptr())) {
// Found:
// Bool(CmpP(LoadKlass(obj._klass), ConP(Foo.klass)), [eq])
// or the narrowOop equivalent.
const Type* obj_type = _gvn.type(obj);
const TypeOopPtr* tboth = obj_type->join(con_type)->isa_oopptr();
if (tboth != NULL && tboth != obj_type && tboth->higher_equal(obj_type)) {
// obj has to be of the exact type Foo if the CmpP succeeds.
assert(tboth->klass_is_exact(), "klass should be exact");
int obj_in_map = map()->find_edge(obj);
JVMState* jvms = this->jvms();
if (obj_in_map >= 0 &&
(jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) {
TypeNode* ccast = new (C, 2) CheckCastPPNode(control(), obj, tboth);
const Type* tcc = ccast->as_Type()->type();
assert(tcc != obj_type && tcc->higher_equal(obj_type), "must improve");
// Delay transform() call to allow recovery of pre-cast value
// at the control merge.
_gvn.set_type_bottom(ccast);
record_for_igvn(ccast);
// Here's the payoff.
replace_in_map(obj, ccast);
}
}
}
}
int val_in_map = map()->find_edge(val);
if (val_in_map < 0) return; // replace_in_map would be useless
......@@ -1265,6 +1330,7 @@ void Parse::adjust_map_after_if(BoolTest::mask btest, Node* c, float prob,
// Exclude tests vs float/double 0 as these could be
// either +0 or -0. Just because you are equal to +0
// doesn't mean you ARE +0!
// Note, following code also replaces Long and Oop values.
if ((!tf || tf->_f != 0.0) &&
(!td || td->_d != 0.0))
cast = con; // Replace non-constant val by con.
......
......@@ -702,12 +702,84 @@ const Type *CmpPNode::sub( const Type *t1, const Type *t2 ) const {
return TypeInt::CC;
}
static inline Node* isa_java_mirror_load(PhaseGVN* phase, Node* n) {
// Return the klass node for
// LoadP(AddP(foo:Klass, #java_mirror))
// or NULL if not matching.
if (n->Opcode() != Op_LoadP) return NULL;
const TypeInstPtr* tp = phase->type(n)->isa_instptr();
if (!tp || tp->klass() != phase->C->env()->Class_klass()) return NULL;
Node* adr = n->in(MemNode::Address);
intptr_t off = 0;
Node* k = AddPNode::Ideal_base_and_offset(adr, phase, off);
if (k == NULL) return NULL;
const TypeKlassPtr* tkp = phase->type(k)->isa_klassptr();
if (!tkp || off != in_bytes(Klass::java_mirror_offset())) return NULL;
// We've found the klass node of a Java mirror load.
return k;
}
static inline Node* isa_const_java_mirror(PhaseGVN* phase, Node* n) {
// for ConP(Foo.class) return ConP(Foo.klass)
// otherwise return NULL
if (!n->is_Con()) return NULL;
const TypeInstPtr* tp = phase->type(n)->isa_instptr();
if (!tp) return NULL;
ciType* mirror_type = tp->java_mirror_type();
// TypeInstPtr::java_mirror_type() returns non-NULL for compile-
// time Class constants only.
if (!mirror_type) return NULL;
// x.getClass() == int.class can never be true (for all primitive types)
// Return a ConP(NULL) node for this case.
if (mirror_type->is_classless()) {
return phase->makecon(TypePtr::NULL_PTR);
}
// return the ConP(Foo.klass)
assert(mirror_type->is_klass(), "mirror_type should represent a klassOop");
return phase->makecon(TypeKlassPtr::make(mirror_type->as_klass()));
}
//------------------------------Ideal------------------------------------------
// Check for the case of comparing an unknown klass loaded from the primary
// Normalize comparisons between Java mirror loads to compare the klass instead.
//
// Also check for the case of comparing an unknown klass loaded from the primary
// super-type array vs a known klass with no subtypes. This amounts to
// checking to see an unknown klass subtypes a known klass with no subtypes;
// this only happens on an exact match. We can shorten this test by 1 load.
Node *CmpPNode::Ideal( PhaseGVN *phase, bool can_reshape ) {
// Normalize comparisons between Java mirrors into comparisons of the low-
// level klass, where a dependent load could be shortened.
//
// The new pattern has a nice effect of matching the same pattern used in the
// fast path of instanceof/checkcast/Class.isInstance(), which allows
// redundant exact type check be optimized away by GVN.
// For example, in
// if (x.getClass() == Foo.class) {
// Foo foo = (Foo) x;
// // ... use a ...
// }
// a CmpPNode could be shared between if_acmpne and checkcast
{
Node* k1 = isa_java_mirror_load(phase, in(1));
Node* k2 = isa_java_mirror_load(phase, in(2));
Node* conk2 = isa_const_java_mirror(phase, in(2));
if (k1 && (k2 || conk2)) {
Node* lhs = k1;
Node* rhs = (k2 != NULL) ? k2 : conk2;
this->set_req(1, lhs);
this->set_req(2, rhs);
return this;
}
}
// Constant pointer on right?
const TypeKlassPtr* t2 = phase->type(in(2))->isa_klassptr();
if (t2 == NULL || !t2->klass_is_exact())
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册