< 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,186 @@
   // }
   // // 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();
+
+      // We need an oop pointer in case allocation elimination
+      // fails. Allocate a new instance here.
+      MergeMemNode* all_mem = MergeMemNode::make(mem);
+      jint lhelper = vk->layout_helper();
+      assert(lhelper != Klass::_lh_neutral_value, "unsupported");
+
+      AllocateNode* alloc = new AllocateNode(phase->C,
+                                             AllocateNode::alloc_type(Type::TOP),
+                                             ctl,
+                                             mem,
+                                             io,
+                                             phase->MakeConX(Klass::layout_helper_size_in_bytes(lhelper)),
+                                             phase->makecon(TypeKlassPtr::make(vk)),
+                                             phase->intcon(0),
+                                             NULL);
+      alloc->set_req(TypeFunc::FramePtr, call->in(TypeFunc::FramePtr));
+      phase->C->add_safepoint_edges(alloc, call->jvms());
+      Node* n = igvn->transform(alloc);
+      assert(n == alloc, "node shouldn't go away");
+
+      ctl = igvn->transform(new ProjNode(alloc, TypeFunc::Control));
+      mem = igvn->transform(new ProjNode(alloc, TypeFunc::Memory, true));
+      all_mem->set_memory_at(Compile::AliasIdxRaw, mem);
+        
+      io = igvn->transform(new ProjNode(alloc, TypeFunc::I_O, true));
+      Node* catc = igvn->transform(new CatchNode(ctl, io, 2));
+      Node* norm = igvn->transform(new CatchProjNode(catc, CatchProjNode::fall_through_index, CatchProjNode::no_handler_bci));
+      Node* excp = igvn->transform(new CatchProjNode(catc, CatchProjNode::catch_all_index,    CatchProjNode::no_handler_bci));
+
+      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(1, excp);
+      mem_phi->init_req(1, igvn->transform(all_mem));
+      io_phi->init_req(1, io);
+      r->init_req(2, ex_ctl);
+      mem_phi->init_req(2, ex_mem);
+      io_phi->init_req(2, 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);
+
+      ctl = norm;
+      mem = igvn->transform(new ProjNode(alloc, TypeFunc::Memory));
+      io = igvn->transform(new ProjNode(alloc, TypeFunc::I_O, false));
+      Node* rawoop = igvn->transform(new ProjNode(alloc, TypeFunc::Parms));
+
+      MemBarNode* membar = MemBarNode::make(phase->C, Op_Initialize, Compile::AliasIdxRaw, rawoop);
+      membar->set_req(TypeFunc::Control, ctl);
+
+      InitializeNode* init = membar->as_Initialize();
+
+      const TypeOopPtr* oop_type = type()->is_oopptr();
+      MergeMemNode* minit_in = MergeMemNode::make(mem);
+      init->set_req(InitializeNode::Memory, minit_in);
+      n = igvn->transform(membar);
+      assert(n == membar, "node shouldn't go away");
+      ctl = igvn->transform(new ProjNode(membar, TypeFunc::Control));
+      mem = igvn->transform(new ProjNode(membar, TypeFunc::Memory));
+
+      Node* m = projs.fallthrough_memproj;
+      MergeMemNode* out_mem_merge = MergeMemNode::make(m);
+      for (int i = 0, len = vk->nof_nonstatic_fields(); i < len; i++) {
+        ciField* field = vk->nonstatic_field_at(i);
+        if (field->offset() >= TrackedInitializationLimit * HeapWordSize)
+          continue;
+        int fieldidx = phase->C->alias_type(field)->index();
+        minit_in->set_memory_at(fieldidx, m);
+        out_mem_merge->set_memory_at(fieldidx, mem);
+      }
+
+      n = igvn->transform(minit_in);
+      assert(n == minit_in, "node shouldn't go away");
+      out_mem_merge->set_memory_at(Compile::AliasIdxRaw, mem);
+ 
+      Node* javaoop = igvn->transform(new CheckCastPPNode(ctl, rawoop, oop_type));
+
+      // 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, out_mem_merge, javaoop);
+      igvn->set_delay_transform(false);
+      vtptr->set_oop(javaoop);
+
+      mem = igvn->transform(out_mem_merge);
+      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 >