Fri, 25 May 2012 07:53:11 -0700
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: Krystal Mok <sajia@taobao.com>
1.1 --- a/src/share/vm/opto/parse.hpp Thu May 24 18:39:44 2012 -0700 1.2 +++ b/src/share/vm/opto/parse.hpp Fri May 25 07:53:11 2012 -0700 1.3 @@ -527,6 +527,9 @@ 1.4 int repush_if_args(); 1.5 void adjust_map_after_if(BoolTest::mask btest, Node* c, float prob, 1.6 Block* path, Block* other_path); 1.7 + void sharpen_type_after_if(BoolTest::mask btest, 1.8 + Node* con, const Type* tcon, 1.9 + Node* val, const Type* tval); 1.10 IfNode* jump_if_fork_int(Node* a, Node* b, BoolTest::mask mask); 1.11 Node* jump_if_join(Node* iffalse, Node* iftrue); 1.12 void jump_if_true_fork(IfNode *ifNode, int dest_bci_if_true, int prof_table_index);
2.1 --- a/src/share/vm/opto/parse2.cpp Thu May 24 18:39:44 2012 -0700 2.2 +++ b/src/share/vm/opto/parse2.cpp Fri May 25 07:53:11 2012 -0700 2.3 @@ -1233,6 +1233,71 @@ 2.4 if (!have_con) // remaining adjustments need a con 2.5 return; 2.6 2.7 + sharpen_type_after_if(btest, con, tcon, val, tval); 2.8 +} 2.9 + 2.10 + 2.11 +static Node* extract_obj_from_klass_load(PhaseGVN* gvn, Node* n) { 2.12 + Node* ldk; 2.13 + if (n->is_DecodeN()) { 2.14 + if (n->in(1)->Opcode() != Op_LoadNKlass) { 2.15 + return NULL; 2.16 + } else { 2.17 + ldk = n->in(1); 2.18 + } 2.19 + } else if (n->Opcode() != Op_LoadKlass) { 2.20 + return NULL; 2.21 + } else { 2.22 + ldk = n; 2.23 + } 2.24 + assert(ldk != NULL && ldk->is_Load(), "should have found a LoadKlass or LoadNKlass node"); 2.25 + 2.26 + Node* adr = ldk->in(MemNode::Address); 2.27 + intptr_t off = 0; 2.28 + Node* obj = AddPNode::Ideal_base_and_offset(adr, gvn, off); 2.29 + if (obj == NULL || off != oopDesc::klass_offset_in_bytes()) // loading oopDesc::_klass? 2.30 + return NULL; 2.31 + const TypePtr* tp = gvn->type(obj)->is_ptr(); 2.32 + if (tp == NULL || !(tp->isa_instptr() || tp->isa_aryptr())) // is obj a Java object ptr? 2.33 + return NULL; 2.34 + 2.35 + return obj; 2.36 +} 2.37 + 2.38 +void Parse::sharpen_type_after_if(BoolTest::mask btest, 2.39 + Node* con, const Type* tcon, 2.40 + Node* val, const Type* tval) { 2.41 + // Look for opportunities to sharpen the type of a node 2.42 + // whose klass is compared with a constant klass. 2.43 + if (btest == BoolTest::eq && tcon->isa_klassptr()) { 2.44 + Node* obj = extract_obj_from_klass_load(&_gvn, val); 2.45 + const TypeOopPtr* con_type = tcon->isa_klassptr()->as_instance_type(); 2.46 + if (obj != NULL && (con_type->isa_instptr() || con_type->isa_aryptr())) { 2.47 + // Found: 2.48 + // Bool(CmpP(LoadKlass(obj._klass), ConP(Foo.klass)), [eq]) 2.49 + // or the narrowOop equivalent. 2.50 + const Type* obj_type = _gvn.type(obj); 2.51 + const TypeOopPtr* tboth = obj_type->join(con_type)->isa_oopptr(); 2.52 + if (tboth != NULL && tboth != obj_type && tboth->higher_equal(obj_type)) { 2.53 + // obj has to be of the exact type Foo if the CmpP succeeds. 2.54 + assert(tboth->klass_is_exact(), "klass should be exact"); 2.55 + int obj_in_map = map()->find_edge(obj); 2.56 + JVMState* jvms = this->jvms(); 2.57 + if (obj_in_map >= 0 && 2.58 + (jvms->is_loc(obj_in_map) || jvms->is_stk(obj_in_map))) { 2.59 + TypeNode* ccast = new (C, 2) CheckCastPPNode(control(), obj, tboth); 2.60 + const Type* tcc = ccast->as_Type()->type(); 2.61 + assert(tcc != obj_type && tcc->higher_equal(obj_type), "must improve"); 2.62 + // Delay transform() call to allow recovery of pre-cast value 2.63 + // at the control merge. 2.64 + _gvn.set_type_bottom(ccast); 2.65 + record_for_igvn(ccast); 2.66 + // Here's the payoff. 2.67 + replace_in_map(obj, ccast); 2.68 + } 2.69 + } 2.70 + } 2.71 + } 2.72 2.73 int val_in_map = map()->find_edge(val); 2.74 if (val_in_map < 0) return; // replace_in_map would be useless 2.75 @@ -1265,6 +1330,7 @@ 2.76 // Exclude tests vs float/double 0 as these could be 2.77 // either +0 or -0. Just because you are equal to +0 2.78 // doesn't mean you ARE +0! 2.79 + // Note, following code also replaces Long and Oop values. 2.80 if ((!tf || tf->_f != 0.0) && 2.81 (!td || td->_d != 0.0)) 2.82 cast = con; // Replace non-constant val by con.
3.1 --- a/src/share/vm/opto/subnode.cpp Thu May 24 18:39:44 2012 -0700 3.2 +++ b/src/share/vm/opto/subnode.cpp Fri May 25 07:53:11 2012 -0700 3.3 @@ -702,12 +702,84 @@ 3.4 return TypeInt::CC; 3.5 } 3.6 3.7 +static inline Node* isa_java_mirror_load(PhaseGVN* phase, Node* n) { 3.8 + // Return the klass node for 3.9 + // LoadP(AddP(foo:Klass, #java_mirror)) 3.10 + // or NULL if not matching. 3.11 + if (n->Opcode() != Op_LoadP) return NULL; 3.12 + 3.13 + const TypeInstPtr* tp = phase->type(n)->isa_instptr(); 3.14 + if (!tp || tp->klass() != phase->C->env()->Class_klass()) return NULL; 3.15 + 3.16 + Node* adr = n->in(MemNode::Address); 3.17 + intptr_t off = 0; 3.18 + Node* k = AddPNode::Ideal_base_and_offset(adr, phase, off); 3.19 + if (k == NULL) return NULL; 3.20 + const TypeKlassPtr* tkp = phase->type(k)->isa_klassptr(); 3.21 + if (!tkp || off != in_bytes(Klass::java_mirror_offset())) return NULL; 3.22 + 3.23 + // We've found the klass node of a Java mirror load. 3.24 + return k; 3.25 +} 3.26 + 3.27 +static inline Node* isa_const_java_mirror(PhaseGVN* phase, Node* n) { 3.28 + // for ConP(Foo.class) return ConP(Foo.klass) 3.29 + // otherwise return NULL 3.30 + if (!n->is_Con()) return NULL; 3.31 + 3.32 + const TypeInstPtr* tp = phase->type(n)->isa_instptr(); 3.33 + if (!tp) return NULL; 3.34 + 3.35 + ciType* mirror_type = tp->java_mirror_type(); 3.36 + // TypeInstPtr::java_mirror_type() returns non-NULL for compile- 3.37 + // time Class constants only. 3.38 + if (!mirror_type) return NULL; 3.39 + 3.40 + // x.getClass() == int.class can never be true (for all primitive types) 3.41 + // Return a ConP(NULL) node for this case. 3.42 + if (mirror_type->is_classless()) { 3.43 + return phase->makecon(TypePtr::NULL_PTR); 3.44 + } 3.45 + 3.46 + // return the ConP(Foo.klass) 3.47 + assert(mirror_type->is_klass(), "mirror_type should represent a klassOop"); 3.48 + return phase->makecon(TypeKlassPtr::make(mirror_type->as_klass())); 3.49 +} 3.50 + 3.51 //------------------------------Ideal------------------------------------------ 3.52 -// Check for the case of comparing an unknown klass loaded from the primary 3.53 +// Normalize comparisons between Java mirror loads to compare the klass instead. 3.54 +// 3.55 +// Also check for the case of comparing an unknown klass loaded from the primary 3.56 // super-type array vs a known klass with no subtypes. This amounts to 3.57 // checking to see an unknown klass subtypes a known klass with no subtypes; 3.58 // this only happens on an exact match. We can shorten this test by 1 load. 3.59 Node *CmpPNode::Ideal( PhaseGVN *phase, bool can_reshape ) { 3.60 + // Normalize comparisons between Java mirrors into comparisons of the low- 3.61 + // level klass, where a dependent load could be shortened. 3.62 + // 3.63 + // The new pattern has a nice effect of matching the same pattern used in the 3.64 + // fast path of instanceof/checkcast/Class.isInstance(), which allows 3.65 + // redundant exact type check be optimized away by GVN. 3.66 + // For example, in 3.67 + // if (x.getClass() == Foo.class) { 3.68 + // Foo foo = (Foo) x; 3.69 + // // ... use a ... 3.70 + // } 3.71 + // a CmpPNode could be shared between if_acmpne and checkcast 3.72 + { 3.73 + Node* k1 = isa_java_mirror_load(phase, in(1)); 3.74 + Node* k2 = isa_java_mirror_load(phase, in(2)); 3.75 + Node* conk2 = isa_const_java_mirror(phase, in(2)); 3.76 + 3.77 + if (k1 && (k2 || conk2)) { 3.78 + Node* lhs = k1; 3.79 + Node* rhs = (k2 != NULL) ? k2 : conk2; 3.80 + this->set_req(1, lhs); 3.81 + this->set_req(2, rhs); 3.82 + return this; 3.83 + } 3.84 + } 3.85 + 3.86 // Constant pointer on right? 3.87 const TypeKlassPtr* t2 = phase->type(in(2))->isa_klassptr(); 3.88 if (t2 == NULL || !t2->klass_is_exact())