< prev index next >

src/share/vm/opto/castnode.cpp

Print this page

        

@@ -27,12 +27,14 @@
 #include "opto/callnode.hpp"
 #include "opto/castnode.hpp"
 #include "opto/connode.hpp"
 #include "opto/matcher.hpp"
 #include "opto/phaseX.hpp"
+#include "opto/rootnode.hpp"
 #include "opto/subnode.hpp"
 #include "opto/type.hpp"
+#include "opto/valuetypenode.hpp"
 
 //=============================================================================
 // If input is already higher or equal to cast type, then this is an identity.
 Node* ConstraintCastNode::Identity(PhaseGVN* phase) {
   Node* dom = dominating_cast(phase);

@@ -278,10 +280,30 @@
 
 //=============================================================================
 //------------------------------Identity---------------------------------------
 // If input is already higher or equal to cast type, then this is an identity.
 Node* CheckCastPPNode::Identity(PhaseGVN* phase) {
+  // This is a value type, its input is a phi. That phi is also a
+  // value type of that same type and its inputs are value types of
+  // the same type: push the cast through the phi.
+  if (phase->is_IterGVN() &&
+      in(0) == NULL &&
+      type()->isa_valuetypeptr() &&
+      in(1) != NULL &&
+      in(1)->is_Phi()) {
+    PhaseIterGVN* igvn = phase->is_IterGVN();
+    Node* phi = in(1);
+    const Type* vtptr = type();
+    for (uint i = 1; i < phi->req(); i++) {
+      if (phi->in(i) != NULL && !phase->type(phi->in(i))->higher_equal(vtptr)) {
+        Node* cast = phase->transform(new CheckCastPPNode(NULL, phi->in(i), vtptr));
+        igvn->replace_input_of(phi, i, cast);
+      }
+    }
+    return phi;
+  }
+
   Node* dom = dominating_cast(phase);
   if (dom != NULL) {
     return dom;
   }
   if (_carry_dependency) {

@@ -373,10 +395,132 @@
   // }
   // // Not joining two pointers
   // return join;
 }
 
+static void replace_in_uses(PhaseIterGVN *igvn, Node* n, Node* m, uint last) {
+  for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
+    Node* u = n->fast_out(i);
+    if (u->_idx < last) {
+      assert(n != u && m != u, "cycle!");
+      igvn->rehash_node_delayed(u);
+      int nb = u->replace_edge(n, m);
+      --i, imax -= nb;
+    }
+  }
+}
+
+Node* CheckCastPPNode::Ideal(PhaseGVN *phase, bool can_reshape) {
+  // This is a value type. Its input is the return of a call: the call
+  // returns a value type and we now know its exact type: build a
+  // ValueTypePtrNode from the call.
+  if (can_reshape &&
+      in(0) == NULL &&
+      phase->C->can_add_value_type_ptr() &&
+      type()->isa_valuetypeptr() &&
+      in(1) != NULL && in(1)->is_Proj() &&
+      in(1)->in(0) != NULL && in(1)->in(0)->is_CallStaticJava() &&
+      in(1)->as_Proj()->_con == TypeFunc::Parms) {
+    ciValueKlass* vk = type()->is_valuetypeptr()->value_type()->value_klass();
+    assert(vk != phase->C->env()->___Value_klass(), "why cast to __Value?");
+    PhaseIterGVN *igvn = phase->is_IterGVN();
+
+    if (ValueTypeReturnedAsFields && vk->can_be_returned_as_fields()) {
+      CallNode* call = in(1)->in(0)->as_Call();
+      // We now know the return type of the call
+      const TypeTuple *range_sig = TypeTuple::make_range(vk, false);
+      const TypeTuple *range_cc = TypeTuple::make_range(vk, true);
+      assert(range_sig != call->_tf->range_sig() && range_cc != call->_tf->range_cc(), "type should change");
+      call->_tf = TypeFunc::make(call->_tf->domain_sig(), call->_tf->domain_cc(),
+                                 range_sig, range_cc);
+      phase->set_type(call, call->Value(phase));
+
+      CallProjections projs;
+      call->extract_projections(&projs, true, true);
+      Node* ctl = projs.fallthrough_catchproj;
+      Node* mem = projs.fallthrough_memproj;
+      Node* io = projs.fallthrough_ioproj;
+      Node* ex_ctl = projs.catchall_catchproj;
+      Node* ex_mem = projs.catchall_memproj;
+      Node* ex_io = projs.catchall_ioproj;
+
+      uint last = phase->C->unique();
+
+      Node* r = new RegionNode(3);
+      Node* mem_phi = new PhiNode(r, Type::MEMORY, TypePtr::BOTTOM);
+      Node* io_phi = new PhiNode(r, Type::ABIO);
+
+      r->init_req(2, ex_ctl);
+      mem_phi->init_req(2, ex_mem);
+      io_phi->init_req(2, ex_io);
+
+      // We need an oop pointer in case allocation elimination
+      // fails. Allocate a new instance here.
+      Node* javaoop = ValueTypeBaseNode::allocate(type(), ctl, mem, io,
+                                                  call->in(TypeFunc::FramePtr),
+                                                  ex_ctl, ex_mem, ex_io,
+                                                  call->jvms(), igvn);
+
+
+
+      r->init_req(1, ex_ctl);
+      mem_phi->init_req(1, ex_mem);
+      io_phi->init_req(1, ex_io);
+
+      r = igvn->transform(r);
+      mem_phi = igvn->transform(mem_phi);
+      io_phi = igvn->transform(io_phi);
+
+      replace_in_uses(igvn, ex_ctl, r, last);
+      replace_in_uses(igvn, ex_mem, mem_phi, last);
+      replace_in_uses(igvn, ex_io, io_phi, last);
+
+      // Create the ValueTypePtrNode. This will add extra projections
+      // to the call.
+      ValueTypePtrNode* vtptr = ValueTypePtrNode::make(igvn, this);
+      igvn->set_delay_transform(true); // stores can be captured. If
+                                       // they are the whole subgraph
+                                       // shouldn't go away.
+
+      // Newly allocated value type must be initialized
+      vtptr->store(igvn, ctl, mem->as_MergeMem(), javaoop);
+      igvn->set_delay_transform(false);
+      vtptr->set_oop(javaoop);
+
+      mem = igvn->transform(mem);
+      replace_in_uses(igvn, projs.fallthrough_catchproj, ctl, last);
+      replace_in_uses(igvn, projs.fallthrough_memproj, mem, last);
+      replace_in_uses(igvn, projs.fallthrough_ioproj, io, last);
+
+      igvn->replace_node(in(1), igvn->transform(vtptr));
+
+      return this;
+    } else {
+      CallNode* call = in(1)->in(0)->as_Call();
+      // We now know the return type of the call
+      const TypeTuple *range = TypeTuple::make_range(vk, false);
+      if (range != call->_tf->range_sig()) {
+        // Build the ValueTypePtrNode by loading the fields. Use call
+        // return as oop edge in the ValueTypePtrNode.
+        call->_tf = TypeFunc::make(call->_tf->domain_sig(), call->_tf->domain_cc(),
+                                   range, range);
+        phase->set_type(call, call->Value(phase));
+        phase->set_type(in(1), in(1)->Value(phase));
+        uint last = phase->C->unique();
+        CallNode* call = in(1)->in(0)->as_Call();
+        CallProjections projs;
+        call->extract_projections(&projs, true, true);
+        Node* mem = projs.fallthrough_memproj;
+        Node* vtptr = ValueTypePtrNode::make(*phase, mem, in(1));
+
+        return vtptr;
+      }
+    }
+  }
+  return NULL;
+}
+
 //=============================================================================
 //------------------------------Value------------------------------------------
 const Type* CastX2PNode::Value(PhaseGVN* phase) const {
   const Type* t = phase->type(in(1));
   if (t == Type::TOP) return Type::TOP;
< prev index next >