< prev index next >

src/share/vm/opto/valuetypenode.cpp

Print this page

        

@@ -35,24 +35,72 @@
   return new ValueTypeNode(type, gvn.zerocon(T_VALUETYPE));
 }
 
 Node* ValueTypeNode::make(PhaseGVN& gvn, Node* mem, Node* oop) {
   // Create and initialize a ValueTypeNode by loading all field
-  // values from memory and also save the oop to the heap-allocated version.
+  // values from a heap-allocated version and also save the oop.
   const TypeValueTypePtr* vtptr = gvn.type(oop)->is_valuetypeptr();
   ValueTypeNode* vt = new ValueTypeNode(vtptr->value_type(), oop);
-  for (uint index = 0; index < vt->field_count(); ++index) {
-    int offset = vt->get_field_offset(index);
-    const TypePtr* adr_type = vtptr->add_offset(offset);
-    const Type* field_type = Type::get_const_basic_type(vt->get_field_type(index));
-    Node* adr = gvn.transform(new AddPNode(oop, oop, gvn.longcon(offset)));
-    Node* ld = LoadNode::make(gvn, NULL, mem, adr, adr_type, field_type, field_type->basic_type(), MemNode::unordered);
-    vt->set_field_value(index, gvn.transform(ld));
-  }
+  vt->load_values(gvn, mem, vt->get_value_klass(), oop);
+  return gvn.transform(vt);
+}
+
+Node* ValueTypeNode::make(PhaseGVN& gvn, ciValueKlass* klass, Node* mem, ciInstanceKlass* holder, Node* obj, int field_offset) {
+  // Create and initialize a ValueTypeNode by loading all field
+  // values from a flattened value type field at 'field_offset' in 'obj'.
+  ValueTypeNode* vt = make(gvn, klass)->as_ValueType();
+  // 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.
+  int base_offset = field_offset - klass->get_first_field_offset();
+  vt->load_values(gvn, mem, holder, obj, base_offset);
   return gvn.transform(vt);
 }
 
+void ValueTypeNode::load_values(PhaseGVN& gvn, Node* mem, ciInstanceKlass* holder, Node* base, int base_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 = base_offset + get_field_offset(i);
+    Node* adr = gvn.transform(new AddPNode(base, base, gvn.longcon(offset)));
+    ciField* field = holder->get_field_by_offset(offset, false);
+    const TypePtr* adr_type = gvn.C->alias_type(field)->adr_type();
+    Node* value = NULL;
+    ciType* field_type = get_field_type(i);
+    if (field_type->is_valuetype()) {
+      // Recursively load the flattened value type field
+      value = ValueTypeNode::make(gvn, field_type->as_value_klass(), mem, holder, base, offset);
+    } else {
+      value = LoadNode::make(gvn, NULL, mem, adr, adr_type, Type::get_const_type(field_type), field_type->basic_type(), MemNode::unordered);
+    }
+    set_field_value(i, gvn.transform(value));
+  }
+}
+
+void ValueTypeNode::store_to_field(GraphKit* kit, ciInstanceKlass* holder, Node* obj, int field_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.
+  int base_offset = field_offset - get_value_klass()->get_first_field_offset();
+  store_values(kit, holder, obj, base_offset);
+}
+
+void ValueTypeNode::store_values(GraphKit* kit, ciInstanceKlass* holder, Node* base, int base_offset) const {
+  // Write field values to memory
+  for (uint i = 0; i < field_count(); ++i) {
+    int offset = base_offset + get_field_offset(i);
+    Node* adr = kit->basic_plus_adr(base, base, offset);
+    ciField* field = holder->get_field_by_offset(offset, false);
+    const TypePtr* adr_type = kit->C->alias_type(field)->adr_type();
+    Node* value = get_field_value(i);
+    if (value->is_ValueType()) {
+      // Recursively store the flattened value type field
+      value->isa_ValueType()->store_to_field(kit, holder, base, offset);
+    } else {
+      kit->store_to_memory(kit->control(), adr, value, get_field_type(i)->basic_type(), adr_type, MemNode::unordered);
+    }
+  }
+}
+
 Node* ValueTypeNode::store_to_memory(GraphKit* kit) {
   Node* in_oop = get_oop();
   Node* null_ctl = kit->top();
   // Check if value type is already allocated
   Node* not_null_oop = kit->null_check_oop(in_oop, &null_ctl);

@@ -84,16 +132,11 @@
   kit->set_control(null_ctl);
   kit->kill_dead_locals();
   Node* klass_node = kit->makecon(TypeKlassPtr::make(get_value_klass()));
   Node* alloc_oop  = kit->new_instance(klass_node);
   // Write field values to memory
-  for (uint index = 0; index < field_count(); ++index) {
-    int offset = get_field_offset(index);
-    const TypePtr* adr_type = vtptr_type->add_offset(offset);
-    Node* adr = kit->basic_plus_adr(alloc_oop, alloc_oop, offset);
-    kit->store_to_memory(kit->control(), adr, get_field_value(index), get_field_type(index), adr_type, MemNode::unordered);
-  }
+  store_values(kit, get_value_klass(), alloc_oop);
   region->init_req(2, kit->control());
   oop   ->init_req(2, alloc_oop);
   io    ->init_req(2, kit->i_o());
   mem   ->init_req(2, kit->merged_memory());
 

@@ -104,25 +147,103 @@
   kit->record_for_igvn(region);
   kit->record_for_igvn(oop);
   kit->record_for_igvn(io);
   kit->record_for_igvn(mem);
 
+  // Use cloned ValueTypeNode to propagate oop from now on
   Node* res_oop = kit->gvn().transform(oop);
   ValueTypeNode* vt = clone()->as_ValueType();
   vt->set_oop(res_oop);
   kit->replace_in_map(this, kit->gvn().transform(vt));
   return res_oop;
 }
 
+// Clones the values type to handle control flow merges involving multiple value types.
+// The input edges are replaced by PhiNodes to represent the merged values.
+ValueTypeNode* ValueTypeNode::clone_with_phis(PhaseGVN& gvn, Node* region) {
+  ValueTypeNode* vt = clone()->as_ValueType();
+
+  // Create a PhiNode for merging the oop values
+  const TypeValueTypePtr* vtptr = TypeValueTypePtr::make(vt->bottom_type()->isa_valuetype());
+  PhiNode* oop = PhiNode::make(region, vt->get_oop(), vtptr);
+  gvn.set_type(oop, vtptr);
+  vt->set_oop(oop);
+
+  // Create a PhiNode each for merging the field values
+  for (uint i = 0; i < vt->field_count(); ++i) {
+    ciType* type = vt->get_field_type(i);
+    Node*  value = vt->get_field_value(i);
+    if (type->is_valuetype()) {
+      // Handle flattened value type fields recursively
+      value = value->as_ValueType()->clone_with_phis(gvn, region);
+    } else {
+      const Type* phi_type = Type::get_const_type(type);
+      value = PhiNode::make(region, value, phi_type);
+      gvn.set_type(value, phi_type);
+    }
+    vt->set_field_value(i, value);
+  }
+  gvn.set_type(vt, vt->bottom_type());
+  return vt;
+}
+
+// Merges 'this' with 'other' by updating the input PhiNodes added by 'clone_with_phis'
+Node* ValueTypeNode::merge_with(GraphKit* kit, const ValueTypeNode* other, int pnum) {
+  // Merge oop inputs
+  PhiNode* phi = get_oop()->as_Phi();
+  phi->set_req(pnum, other->get_oop());
+  if (pnum == PhiNode::Input) {
+    // Last merge
+    set_oop(kit->gvn().transform_no_reclaim(phi));
+    kit->record_for_igvn(phi);
+  }
+  // Merge field values
+  for (uint i = 0; i < field_count(); ++i) {
+    Node* val1 =        get_field_value(i);
+    Node* val2 = other->get_field_value(i);
+    if (val1->isa_ValueType()) {
+      val1->as_ValueType()->merge_with(kit, val2->as_ValueType(), pnum);
+    } else {
+      assert(!val2->is_ValueType(), "inconsistent merge values");
+      val1->set_req(pnum, val2);
+    }
+    if (pnum == PhiNode::Input) {
+      // Last merge
+      set_field_value(i, kit->gvn().transform_no_reclaim(val1));
+      kit->record_for_igvn(val1);
+    }
+  }
+  if (pnum == PhiNode::Input) {
+    // Last merge for this value type.
+   kit->record_for_igvn(this);
+   return kit->gvn().transform_no_reclaim(this);
+  }
+  return this;
+}
+
 Node* ValueTypeNode::get_field_value(uint index) const {
   assert(index < field_count(), "index out of bounds");
   return in(Values + index);
 }
 
-Node* ValueTypeNode::get_field_value_by_offset(int field_offset) const {
-  int index = get_value_klass()->get_field_index_by_offset(field_offset);
-  return get_field_value(index);
+// Get the value of the field at the given offset.
+// If 'recursive' is true, flattened value type fields will be resolved recursively.
+Node* ValueTypeNode::get_field_value_by_offset(int offset, bool recursive) const {
+  // If the field at 'offset' belongs to a flattened value type field, 'index' refers to the
+  // corresponding ValueTypeNode input and 'sub_offset' is the offset in flattened value type.
+  int index = get_value_klass()->get_field_index_by_offset(offset);
+  int sub_offset = offset - get_field_offset(index);
+  Node* value = get_field_value(index);
+  if (recursive && value->is_ValueType()) {
+    // Flattened value type field
+    ValueTypeNode* vt = value->as_ValueType();
+    sub_offset += vt->get_value_klass()->get_first_field_offset(); // Add header size
+    return vt->get_field_value_by_offset(sub_offset);
+  }
+  assert(!(recursive && value->is_ValueType()), "should not be a value type");
+  assert(sub_offset == 0, "offset mismatch");
+  return value;
 }
 
 void ValueTypeNode::set_field_value(uint index, Node* value) {
   assert(index < field_count(), "index out of bounds");
   set_req(Values + index, value);

@@ -131,53 +252,48 @@
 int ValueTypeNode::get_field_offset(uint index) const {
   assert(index < field_count(), "index out of bounds");
   return get_value_klass()->get_field_offset_by_index(index);
 }
 
-BasicType ValueTypeNode::get_field_type(uint index) const {
+ciType* ValueTypeNode::get_field_type(uint index) const {
   assert(index < field_count(), "index out of bounds");
   return get_value_klass()->get_field_type_by_index(index);
 }
 
 void ValueTypeNode::make_scalar_in_safepoints(Compile* C) {
   const TypeValueTypePtr* res_type = TypeValueTypePtr::make(bottom_type()->isa_valuetype(), TypePtr::NotNull);
-  uint nfields = field_count();
+  ciValueKlass* vk = get_value_klass();
+  uint nfields = vk->get_field_count();
   for (DUIterator_Fast imax, i = fast_outs(imax); i < imax; i++) {
     Node* u = fast_out(i);
     if (u->is_SafePoint() && (!u->is_Call() || u->as_Call()->has_debug_use(this))) {
       Node* in_oop = get_oop();
       const Type* oop_type = in_oop->bottom_type();
       SafePointNode* sfpt = u->as_SafePoint();
       JVMState* jvms = sfpt->jvms();
       int start = jvms->debug_start();
       int end   = jvms->debug_end();
       if (oop_type->meet(TypePtr::NULL_PTR) != oop_type) {
+        // Replace safepoint edge by oop
         int nb = sfpt->replace_edges_in_range(this, in_oop, start, end);
         --i; imax -= nb;
       } else {
+        // Replace safepoint edge by SafePointScalarObjectNode and add field values
         assert(jvms != NULL, "missing JVMS");
         uint first_ind = (sfpt->req() - jvms->scloff());
         SafePointScalarObjectNode* sobj = new SafePointScalarObjectNode(res_type,
 #ifdef ASSERT
                                                                         NULL,
 #endif
                                                                         first_ind, nfields);
         sobj->init_req(0, C->root());
-        // fields must be added to the safepoint in order of increasing offset
-        int min = 0;
-        for (uint j = 0; j < nfields; j++) {
-          int off = INT_MAX;
-          uint next = 0;
-          for (uint k = 0; k < nfields; k++) {
-            int offset = get_field_offset(k);
-            if (offset > min && offset < off) {
-              off = offset;
-              next = k;
-            }
-          }
-          min = get_field_offset(next);
-          sfpt->add_req(in(Values + next));
+        // Iterate over the value type fields in order of increasing
+        // offset and add the field values to the safepoint.
+        for (uint j = 0; j < nfields; ++j) {
+          int offset = vk->nonstatic_field_at(j)->offset();
+          Node* value = get_field_value_by_offset(offset, true /* include flattened value type fields */);
+          sfpt->add_req(value);
         }
         jvms->set_endoff(sfpt->req());
         int nb = sfpt->replace_edges_in_range(this, sobj, start, end);
         --i; imax -= nb;
       }

@@ -192,11 +308,8 @@
 
 #ifndef PRODUCT
 
 void ValueTypeNode::dump_spec(outputStream* st) const {
   TypeNode::dump_spec(st);
-  if (!get_oop()->is_top()) {
-    st->print(" #oop");
-  }
 }
 
 #endif
< prev index next >