< prev index next >
src/share/vm/opto/valuetypenode.cpp
Print this page
*** 35,58 ****
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.
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));
! }
return gvn.transform(vt);
}
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);
--- 35,106 ----
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 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);
! 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,99 ****
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);
! }
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());
--- 132,142 ----
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
! 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,128 ****
kit->record_for_igvn(region);
kit->record_for_igvn(oop);
kit->record_for_igvn(io);
kit->record_for_igvn(mem);
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;
}
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);
}
void ValueTypeNode::set_field_value(uint index, Node* value) {
assert(index < field_count(), "index out of bounds");
set_req(Values + index, value);
--- 147,249 ----
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);
}
! // 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,183 ****
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 {
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();
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) {
int nb = sfpt->replace_edges_in_range(this, in_oop, start, end);
--i; imax -= nb;
} else {
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));
}
jvms->set_endoff(sfpt->req());
int nb = sfpt->replace_edges_in_range(this, sobj, start, end);
--i; imax -= nb;
}
--- 252,299 ----
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);
}
! 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);
! 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());
! // 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,202 ****
#ifndef PRODUCT
void ValueTypeNode::dump_spec(outputStream* st) const {
TypeNode::dump_spec(st);
- if (!get_oop()->is_top()) {
- st->print(" #oop");
- }
}
#endif
--- 308,315 ----
< prev index next >