--- old/src/share/vm/opto/valuetypenode.cpp 2016-11-16 09:06:13.974498630 +0100 +++ new/src/share/vm/opto/valuetypenode.cpp 2016-11-16 09:06:13.910498628 +0100 @@ -37,20 +37,68 @@ 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(); @@ -86,12 +134,7 @@ 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()); @@ -106,6 +149,7 @@ 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); @@ -113,14 +157,91 @@ 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) { @@ -133,14 +254,15 @@ 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))) { @@ -151,9 +273,11 @@ 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, @@ -162,20 +286,12 @@ #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); @@ -194,9 +310,6 @@ void ValueTypeNode::dump_spec(outputStream* st) const { TypeNode::dump_spec(st); - if (!get_oop()->is_top()) { - st->print(" #oop"); - } } #endif