< prev index next >

src/hotspot/share/opto/loopopts.cpp

Print this page

        

@@ -1212,16 +1212,111 @@
   }
 
   return out_le;
 }
 
+bool PhaseIdealLoop::flatten_array_element_type_check(Node *n) {
+  // If the CmpP is a subtype check for a value that has just been
+  // loaded from an array, the subtype checks guarantees the value
+  // can't be stored in a flattened array and the load of the value
+  // happens with a flattened array check then: push the type check
+  // through the phi of the flattened array check. This needs special
+  // logic because the subtype check's input is not a phi but a
+  // LoadKlass that must first be cloned through the phi.
+  if (n->Opcode() != Op_CmpP) {
+    return false;
+  }
+  
+  Node* klassptr = n->in(1);
+  Node* klasscon = n->in(2);
+
+  if (klassptr->is_DecodeNarrowPtr()) {
+    klassptr = klassptr->in(1);
+  }
+  
+  if (klassptr->Opcode() != Op_LoadKlass && klassptr->Opcode() != Op_LoadNKlass) {
+    return false;
+  }
+  
+  if (!klasscon->is_Con()) {
+    return false;
+  }
+  
+  Node* addr = klassptr->in(MemNode::Address);
+  
+  if (!addr->is_AddP()) {
+    return false;
+  }
+  
+  intptr_t offset;
+  Node* obj = AddPNode::Ideal_base_and_offset(addr, &_igvn, offset);
+  assert(obj != NULL && addr->in(AddPNode::Base) == addr->in(AddPNode::Address), "malformed AddP?");
+  if (obj->Opcode() == Op_CastPP) {
+    obj = obj->in(1);
+  }
+
+  if (!obj->is_Phi()) {
+    return false;
+  }
+
+  Node* region = obj->in(0);
+  
+  Node* phi = PhiNode::make_blank(region, n->in(1));
+  for (uint i = 1; i < region->req(); i++) {
+    Node* in = obj->in(i);
+    Node* ctrl = get_ctrl(in);
+    if (addr->in(AddPNode::Base) != obj) {
+      Node* cast = addr->in(AddPNode::Base);
+      assert(cast->Opcode() == Op_CastPP && cast->in(0) != NULL, "inconsistent subgraph");
+      Node* cast_clone = cast->clone();
+      cast_clone->set_req(0, region->in(i));
+      cast_clone->set_req(1, in);
+      register_new_node(cast_clone, region->in(i));
+      _igvn.set_type(cast_clone, cast_clone->Value(&_igvn));
+      in = cast_clone;
+    }
+    Node* addr_clone = addr->clone();
+    addr_clone->set_req(AddPNode::Base, in);
+    addr_clone->set_req(AddPNode::Address, in);
+    register_new_node(addr_clone, ctrl);
+    _igvn.set_type(addr_clone, addr_clone->Value(&_igvn));
+    Node* klassptr_clone = klassptr->clone();
+    klassptr_clone->set_req(2, addr_clone);
+    register_new_node(klassptr_clone, ctrl);
+    _igvn.set_type(klassptr_clone, klassptr_clone->Value(&_igvn));
+    if (klassptr != n->in(1)) {
+      Node* decode = n->in(1);
+      assert(decode->is_DecodeNarrowPtr(), "inconcistent subgraph");
+      Node* decode_clone = decode->clone();
+      decode_clone->set_req(1, klassptr_clone);
+      register_new_node(decode_clone, ctrl);
+      _igvn.set_type(decode_clone, decode_clone->Value(&_igvn));
+      klassptr_clone = decode_clone;
+    }
+    phi->set_req(i, klassptr_clone);
+  }
+  register_new_node(phi, region);
+  Node* orig = n->in(1);
+  _igvn.replace_input_of(n, 1, phi);
+  split_if_with_blocks_post(n);
+  if (n->outcnt() != 0) {
+    _igvn.replace_input_of(n, 1, orig);
+    _igvn._worklist.push(phi);
+  }
+  return true;
+}
+
 //------------------------------split_if_with_blocks_post----------------------
 // Do the real work in a non-recursive function.  CFG hackery wants to be
 // in the post-order, so it can dirty the I-DOM info and not use the dirtied
 // info.
 void PhaseIdealLoop::split_if_with_blocks_post(Node *n) {
 
+  if (flatten_array_element_type_check(n)) {
+    return;
+  }
+  
   // Cloning Cmp through Phi's involves the split-if transform.
   // FastLock is not used by an If
   if (n->is_Cmp() && !n->is_FastLock()) {
     Node *n_ctrl = get_ctrl(n);
     // Determine if the Node has inputs from some local Phi.
< prev index next >