< prev index next >

src/share/vm/opto/valuetypenode.cpp

Print this page

        

@@ -23,10 +23,11 @@
  */
 
 #include "precompiled.hpp"
 #include "ci/ciValueKlass.hpp"
 #include "opto/addnode.hpp"
+#include "opto/castnode.hpp"
 #include "opto/graphKit.hpp"
 #include "opto/rootnode.hpp"
 #include "opto/valuetypenode.hpp"
 #include "opto/phaseX.hpp"
 

@@ -192,57 +193,54 @@
       --i; imax -= nb;
     }
   }
 }
 
-ValueTypeNode* ValueTypeNode::make(PhaseGVN& gvn, ciValueKlass* klass) {
-  // Create a new ValueTypeNode with uninitialized values and NULL oop
-  const TypeValueType* type = TypeValueType::make(klass);
-  return new ValueTypeNode(type, gvn.zerocon(T_VALUETYPE));
-}
-
-Node* ValueTypeNode::make_default(PhaseGVN& gvn, ciValueKlass* vk) {
-  // TODO re-use constant oop of pre-allocated default value type here?
-  // Create a new ValueTypeNode with default values
-  ValueTypeNode* vt = ValueTypeNode::make(gvn, vk);
-  for (uint i = 0; i < vt->field_count(); ++i) {
+void ValueTypeBaseNode::make(PhaseGVN* gvn, Node* n, ValueTypeBaseNode* vt, ciValueKlass* base_vk, int base_offset, int base_input, bool in) {
+  assert(base_offset >= 0, "offset in value type always positive");
+  for (uint i = 0; i < vt->field_count(); i++) {
     ciType* field_type = vt->field_type(i);
-    Node* value = NULL;
+    int offset = base_offset + vt->field_offset(i);
     if (field_type->is_valuetype()) {
-      value = ValueTypeNode::make_default(gvn, field_type->as_value_klass());
+      ciValueKlass* embedded_vk = field_type->as_value_klass();
+      ValueTypeNode* embedded_vt = ValueTypeNode::make(*gvn, embedded_vk);
+      ValueTypeBaseNode::make(gvn, n, embedded_vt, base_vk, offset - vt->value_klass()->first_field_offset(), base_input, in);
+      vt->set_field_value(i, gvn->transform(embedded_vt));
     } else {
-      value = gvn.zerocon(field_type->basic_type());
+      int j = 0; int extra = 0;
+      for (; j < base_vk->nof_nonstatic_fields(); j++) {
+        ciField* f = base_vk->nonstatic_field_at(j);
+        if (offset == f->offset()) {
+          assert(f->type() == field_type, "inconsistent field type");
+          break;
+        }
+        BasicType bt = f->type()->basic_type();
+        if (bt == T_LONG || bt == T_DOUBLE) {
+          extra++;
+        }
+      }
+      assert(j != base_vk->nof_nonstatic_fields(), "must find");
+      Node* parm = NULL;
+      if (n->is_Start()) {
+        assert(in, "return from start?");
+        parm = gvn->transform(new ParmNode(n->as_Start(), base_input + j + extra));
+      } else {
+        if (in) {
+          assert(n->is_Call(), "nothing else here");
+          parm = n->in(base_input + j + extra);
+        } else {
+          parm = gvn->transform(new ProjNode(n->as_Call(), base_input + j + extra));
+        }
+      }
+      vt->set_field_value(i, parm);
+      // Record all these guys for later GVN.
+      gvn->record_for_igvn(parm);
     }
-    vt->set_field_value(i, value);
   }
-  return gvn.transform(vt);
-}
-
-Node* ValueTypeNode::make(PhaseGVN& gvn, Node* mem, Node* oop) {
-  // Create and initialize a ValueTypeNode by loading all field
-  // values from a heap-allocated version and also save the oop.
-  const TypeValueType* type = gvn.type(oop)->is_valuetypeptr()->value_type();
-  ValueTypeNode* vt = new ValueTypeNode(type, oop);
-  vt->load(gvn, mem, oop, oop, type->value_klass());
-  assert(vt->is_allocated(&gvn), "value type should be allocated");
-  assert(oop->is_Con() || oop->is_CheckCastPP() || oop->Opcode() == Op_ValueTypePtr || vt->is_loaded(&gvn, type) == oop, "value type should be loaded");
-  return gvn.transform(vt);
-}
-
-Node* ValueTypeNode::make(PhaseGVN& gvn, ciValueKlass* vk, Node* mem, Node* obj, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
-  // Create and initialize a ValueTypeNode by loading all field values from
-  // a flattened value type field at 'holder_offset' or from a value type array.
-  ValueTypeNode* vt = make(gvn, vk);
-  // The value type is flattened into the object without an oop header. Subtract the
-  // offset of the first field to account for the missing header when loading the values.
-  holder_offset -= vk->first_field_offset();
-  vt->load(gvn, mem, obj, ptr, holder, holder_offset);
-  assert(vt->is_loaded(&gvn, vt->type()->isa_valuetype()) != obj, "holder oop should not be used as flattened value type oop");
-  return gvn.transform(vt)->as_ValueType();
 }
 
-void ValueTypeNode::load(PhaseGVN& gvn, Node* mem, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
+void ValueTypeBaseNode::load(PhaseGVN& gvn, Node* mem, Node* base, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
   // Initialize the value type by loading its field values from
   // memory and adding the values as input edges to the node.
   for (uint i = 0; i < field_count(); ++i) {
     int offset = holder_offset + field_offset(i);
     ciType* ftype = field_type(i);

@@ -283,10 +281,202 @@
     }
     set_field_value(i, gvn.transform(value));
   }
 }
 
+void ValueTypeBaseNode::store_flattened(PhaseGVN* gvn, Node* ctl, MergeMemNode* mem, Node* base, ciValueKlass* holder, int holder_offset) const {
+  // The value type is embedded into the object without an oop header. Subtract the
+  // offset of the first field to account for the missing header when storing the values.
+  holder_offset -= value_klass()->first_field_offset();
+  store(gvn, ctl, mem, base, holder, holder_offset);
+}
+
+void ValueTypeBaseNode::store(PhaseGVN* gvn, Node* ctl, MergeMemNode* mem, Node* base, ciValueKlass* holder, int holder_offset) const {
+  if (holder == NULL) {
+    holder = value_klass();
+  }
+  // Write field values to memory
+  for (uint i = 0; i < field_count(); ++i) {
+    int offset = holder_offset + field_offset(i);
+    Node* value = field_value(i);
+    if (value->is_ValueType()) {
+      // Recursively store the flattened value type field
+      value->isa_ValueTypeBase()->store_flattened(gvn, ctl, mem, base, holder, offset);
+    } else {
+      const Type* base_type = gvn->type(base);
+      const TypePtr* adr_type = NULL;
+      if (base_type->isa_aryptr()) {
+        // In the case of a flattened value type array, each field has its own slice
+        adr_type = base_type->is_aryptr()->with_field_offset(offset)->add_offset(Type::OffsetBot);
+      } else {
+        ciField* field = holder->get_field_by_offset(offset, false);
+        adr_type = gvn->C->alias_type(field)->adr_type();
+      }
+      Node* adr = gvn->transform(new AddPNode(base, base, gvn->MakeConX(offset)));
+      BasicType bt = type2field[field_type(i)->basic_type()];
+      uint alias_idx = gvn->C->get_alias_index(adr_type);
+      Node* st = StoreNode::make(*gvn, ctl, mem->memory_at(alias_idx), adr, adr_type, value, bt, MemNode::unordered);
+      mem->set_memory_at(alias_idx, gvn->transform(st));
+    }
+  }
+}
+
+// When a call returns multiple values, it has several result
+// projections, one per field. Replacing the result of the call by a
+// value type node (after late inlining) requires that for each result
+// projection, we find the corresponding value type field.
+void ValueTypeBaseNode::replace_call_results(Node* call, Compile* C) {
+  ciValueKlass* vk = value_klass();
+  for (DUIterator_Fast imax, i = call->fast_outs(imax); i < imax; i++) {
+    ProjNode *pn = call->fast_out(i)->as_Proj();
+    uint con = pn->_con;
+    if (con >= TypeFunc::Parms+1) {
+      uint field_nb = con - (TypeFunc::Parms+1);
+      int extra = 0;
+      for (uint j = 0; j < field_nb - extra; j++) {
+        ciField* f = vk->nonstatic_field_at(j);
+        BasicType bt = f->type()->basic_type();
+        if (bt == T_LONG || bt == T_DOUBLE) {
+          extra++;
+        }
+      }
+      ciField* f = vk->nonstatic_field_at(field_nb - extra);
+      Node* field = field_value_by_offset(f->offset(), true);
+
+      C->gvn_replace_by(pn, field);
+      C->initial_gvn()->hash_delete(pn);
+      pn->set_req(0, C->top());
+      --i; --imax;
+    }
+  }
+}
+
+Node* ValueTypeBaseNode::allocate(const Type* type, Node*& ctl, Node*& mem, Node*& io, Node* frameptr, Node*& ex_ctl, Node*& ex_mem, Node*& ex_io, JVMState* jvms, PhaseIterGVN *igvn) {
+  ciValueKlass* vk = type->is_valuetypeptr()->value_type()->value_klass();
+  Node* initial_mem = mem;
+  uint last = igvn->C->unique();
+  MergeMemNode* all_mem = MergeMemNode::make(mem);
+  jint lhelper = vk->layout_helper();
+  assert(lhelper != Klass::_lh_neutral_value, "unsupported");
+
+  AllocateNode* alloc = new AllocateNode(igvn->C,
+                                         AllocateNode::alloc_type(Type::TOP),
+                                         ctl,
+                                         mem,
+                                         io,
+                                         igvn->MakeConX(Klass::layout_helper_size_in_bytes(lhelper)),
+                                         igvn->makecon(TypeKlassPtr::make(vk)),
+                                         igvn->intcon(0),
+                                         NULL);
+  alloc->set_req(TypeFunc::FramePtr, frameptr);
+  igvn->C->add_safepoint_edges(alloc, 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));
+
+  ex_ctl = excp;
+  ex_mem = igvn->transform(all_mem);
+  ex_io = io;
+
+  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(igvn->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));
+
+  MergeMemNode* out_mem_merge = MergeMemNode::make(initial_mem);
+  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 = igvn->C->alias_type(field)->index();
+    minit_in->set_memory_at(fieldidx, initial_mem);
+    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));
+  mem = igvn->transform(out_mem_merge);
+
+  return javaoop;
+}
+
+ValueTypeNode* ValueTypeNode::make(PhaseGVN& gvn, ciValueKlass* klass) {
+  // Create a new ValueTypeNode with uninitialized values and NULL oop
+  const TypeValueType* type = TypeValueType::make(klass);
+  return new ValueTypeNode(type, gvn.zerocon(T_VALUETYPE));
+}
+
+Node* ValueTypeNode::make_default(PhaseGVN& gvn, ciValueKlass* vk) {
+  // TODO re-use constant oop of pre-allocated default value type here?
+  // Create a new ValueTypeNode with default values
+  ValueTypeNode* vt = ValueTypeNode::make(gvn, vk);
+  for (uint i = 0; i < vt->field_count(); ++i) {
+    ciType* field_type = vt->field_type(i);
+    Node* value = NULL;
+    if (field_type->is_valuetype()) {
+      value = ValueTypeNode::make_default(gvn, field_type->as_value_klass());
+    } else {
+      value = gvn.zerocon(field_type->basic_type());
+    }
+    vt->set_field_value(i, value);
+  }
+  return gvn.transform(vt);
+}
+
+Node* ValueTypeNode::make(PhaseGVN& gvn, Node* mem, Node* oop) {
+  // Create and initialize a ValueTypeNode by loading all field
+  // values from a heap-allocated version and also save the oop.
+  const TypeValueType* type = gvn.type(oop)->is_valuetypeptr()->value_type();
+  ValueTypeNode* vt = new ValueTypeNode(type, oop);
+  vt->load(gvn, mem, oop, oop, type->value_klass());
+  assert(vt->is_allocated(&gvn), "value type should be allocated");
+  assert(oop->is_Con() || oop->is_CheckCastPP() || oop->Opcode() == Op_ValueTypePtr || vt->is_loaded(&gvn, type) == oop, "value type should be loaded");
+  return gvn.transform(vt);
+}
+
+Node* ValueTypeNode::make(PhaseGVN& gvn, ciValueKlass* vk, Node* mem, Node* obj, Node* ptr, ciInstanceKlass* holder, int holder_offset) {
+  // Create and initialize a ValueTypeNode by loading all field values from
+  // a flattened value type field at 'holder_offset' or from a value type array.
+  ValueTypeNode* vt = make(gvn, vk);
+  // The value type is flattened into the object without an oop header. Subtract the
+  // offset of the first field to account for the missing header when loading the values.
+  holder_offset -= vk->first_field_offset();
+  vt->load(gvn, mem, obj, ptr, holder, holder_offset);
+  assert(vt->is_loaded(&gvn, vt->type()->isa_valuetype()) != obj, "holder oop should not be used as flattened value type oop");
+  return gvn.transform(vt)->as_ValueType();
+}
+
+Node* ValueTypeNode::make(PhaseGVN& gvn, Node* n, ciValueKlass* vk, int base_input, bool in) {
+  ValueTypeNode* vt = ValueTypeNode::make(gvn, vk);
+  ValueTypeBaseNode::make(&gvn, n, vt, vk, 0, base_input, in);
+  return gvn.transform(vt);
+}
+
 Node* ValueTypeNode::is_loaded(PhaseGVN* phase, const TypeValueType* t, Node* base, int holder_offset) {
   if (field_count() == 0) {
     assert(t->value_klass() == phase->C->env()->___Value_klass(), "unexpected value type klass");
     assert(is_allocated(phase), "must be allocated");
     return get_oop();

@@ -565,43 +755,31 @@
     phase->lazy_replace(projs.catchall_catchproj, phase->C->top());
     phase->lazy_replace(projs.resproj, phase->C->top());
   }
 }
 
-// When a call returns multiple values, it has several result
-// projections, one per field. Replacing the result of the call by a
-// value type node (after late inlining) requires that for each result
-// projection, we find the corresponding value type field.
-void ValueTypeNode::replace_call_results(Node* call, Compile* C) {
-  ciValueKlass* vk = value_klass();
-  for (DUIterator_Fast imax, i = call->fast_outs(imax); i < imax; i++) {
-    ProjNode *pn = call->fast_out(i)->as_Proj();
-    uint con = pn->_con;
-    if (con >= TypeFunc::Parms+1) {
-      uint field_nb = con - (TypeFunc::Parms+1);
-      int extra = 0;
-      for (uint j = 0; j < field_nb - extra; j++) {
-        ciField* f = vk->nonstatic_field_at(j);
-        BasicType bt = f->type()->basic_type();
-        if (bt == T_LONG || bt == T_DOUBLE) {
-          extra++;
-        }
-      }
-      ciField* f = vk->nonstatic_field_at(field_nb - extra);
-      Node* field = field_value_by_offset(f->offset(), true);
-
-      C->gvn_replace_by(pn, field);
-      C->initial_gvn()->hash_delete(pn);
-      pn->set_req(0, C->top());
-      --i; --imax;
-    }
-  }
-}
-
 
 #ifndef PRODUCT
 
 void ValueTypeNode::dump_spec(outputStream* st) const {
   TypeNode::dump_spec(st);
 }
 
 #endif
+
+ValueTypePtrNode* ValueTypePtrNode::make(PhaseGVN* gvn, CheckCastPPNode* cast) {
+  ciValueKlass* vk = cast->type()->is_valuetypeptr()->value_type()->value_klass();
+  ValueTypePtrNode* vt = new ValueTypePtrNode(vk, gvn->C);
+  assert(cast->in(1)->is_Proj(), "bad graph shape");
+  ValueTypeBaseNode::make(gvn, cast->in(1)->in(0), vt, vk, 0, TypeFunc::Parms+1, false);
+  return vt;
+}
+
+ValueTypePtrNode* ValueTypePtrNode::make(PhaseGVN& gvn, Node* mem, Node* oop) {
+  // Create and initialize a ValueTypePtrNode by loading all field
+  // values from a heap-allocated version and also save the oop.
+  ciValueKlass* vk = gvn.type(oop)->is_valuetypeptr()->value_type()->value_klass();
+  ValueTypePtrNode* vtptr = new ValueTypePtrNode(vk, gvn.C);
+  vtptr->set_oop(oop);
+  vtptr->load(gvn, mem, oop, oop, vk);
+  return vtptr;
+}
< prev index next >