< 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 >