--- old/src/share/vm/opto/macro.cpp 2017-02-13 17:39:02.023392543 +0100 +++ new/src/share/vm/opto/macro.cpp 2017-02-13 17:39:01.951392547 +0100 @@ -44,6 +44,7 @@ #include "opto/runtime.hpp" #include "opto/subnode.hpp" #include "opto/type.hpp" +#include "opto/valuetypenode.hpp" #include "runtime/sharedRuntime.hpp" @@ -391,7 +392,7 @@ return NULL; } mem = mem->in(MemNode::Memory); - } else if (mem->Opcode() == Op_StrInflatedCopy) { + } else if (mem->Opcode() == Op_StrInflatedCopy) { Node* adr = mem->in(3); // Destination array const TypePtr* atype = adr->bottom_type()->is_ptr(); int adr_idx = phase->C->get_alias_index(atype); @@ -562,6 +563,7 @@ // Search the last value stored into the object's field. Node *PhaseMacroExpand::value_from_mem(Node *sfpt_mem, Node *sfpt_ctl, BasicType ft, const Type *ftype, const TypeOopPtr *adr_t, AllocateNode *alloc) { assert(adr_t->is_known_instance_field(), "instance required"); + assert(ft != T_VALUETYPE, "should not be used for value type fields"); int instance_id = adr_t->instance_id(); assert((uint)instance_id == alloc->_idx, "wrong allocation"); @@ -573,7 +575,6 @@ Arena *a = Thread::current()->resource_area(); VectorSet visited(a); - bool done = sfpt_mem == alloc_mem; Node *mem = sfpt_mem; while (!done) { @@ -586,7 +587,7 @@ } else if (mem->is_Initialize()) { mem = mem->as_Initialize()->find_captured_store(offset, type2aelembytes(ft), &_igvn); if (mem == NULL) { - done = true; // Something go wrong. + done = true; // Something went wrong. } else if (mem->is_Store()) { const TypePtr* atype = mem->as_Store()->adr_type(); assert(C->get_alias_index(atype) == Compile::AliasIdxRaw, "store is correct memory slice"); @@ -654,10 +655,32 @@ return make_arraycopy_load(mem->as_ArrayCopy(), offset, ctl, ft, ftype, alloc); } } - // Something go wrong. + // Something went wrong. return NULL; } +// Search the last value stored into the value type's fields. +Node* PhaseMacroExpand::value_type_from_mem(Node* mem, Node* ctl, ciValueKlass* vk, const TypeAryPtr* adr_type, int offset, AllocateNode* alloc) { + // Subtract the offset of the first field to account for the missing oop header + offset -= vk->first_field_offset(); + // Create a new ValueTypeNode and retrieve the field values from memory + ValueTypeNode* vt = ValueTypeNode::make(_igvn, vk)->as_ValueType(); + for (int i = 0; i < vk->field_count(); ++i) { + ciType* field_type = vt->field_type(i); + int field_offset = offset + vt->field_offset(i); + // Each value type field has its own memory slice + adr_type = adr_type->with_field_offset(field_offset); + Node* value = NULL; + if (field_type->basic_type() == T_VALUETYPE) { + value = value_type_from_mem(mem, ctl, field_type->as_value_klass(), adr_type, field_offset, alloc); + } else { + value = value_from_mem(mem, ctl, field_type->basic_type(), Type::get_const_type(field_type), adr_type, alloc); + } + vt->set_field_value(i, value); + } + return vt; +} + // Check the possibility of scalar replacement. bool PhaseMacroExpand::can_eliminate_allocation(AllocateNode *alloc, GrowableArray & safepoints) { // Scan the uses of the allocation to check for anything that would @@ -712,7 +735,7 @@ if (n->is_Load() || n->is_LoadStore()) { NOT_PRODUCT(fail_eliminate = "Field load";) } else { - NOT_PRODUCT(fail_eliminate = "Not store field referrence";) + NOT_PRODUCT(fail_eliminate = "Not store field reference";) } can_eliminate = false; } @@ -750,7 +773,7 @@ } else { if (use->Opcode() == Op_Return) { NOT_PRODUCT(fail_eliminate = "Object is return value";) - }else { + } else { NOT_PRODUCT(fail_eliminate = "Object is referenced by node";) } DEBUG_ONLY(disq_node = use;) @@ -807,7 +830,9 @@ if (res != NULL) { klass = res_type->klass(); - if (res_type->isa_instptr() || res_type->isa_valuetypeptr()) { + // Value types are only allocated on demand + assert(!klass->is_valuetype(), "value type allocations should not be scalar replaceable"); + if (res_type->isa_instptr()) { // find the fields of the class which will be needed for safepoint debug information assert(klass->is_instance_klass(), "must be an instance klass."); iklass = klass->as_instance_klass(); @@ -851,6 +876,7 @@ offset = field->offset(); elem_type = field->type(); basic_elem_type = field->layout_type(); + // Value type fields should not have safepoint uses assert(basic_elem_type != T_VALUETYPE, "value type fields are flattened"); } else { offset = array_base + j * (intptr_t)element_size; @@ -879,9 +905,15 @@ field_type = Type::get_const_basic_type(basic_elem_type); } - const TypeOopPtr *field_addr_type = res_type->add_offset(offset)->isa_oopptr(); - - Node *field_val = value_from_mem(mem, ctl, basic_elem_type, field_type, field_addr_type, alloc); + Node* field_val = NULL; + const TypeOopPtr* field_addr_type = res_type->add_offset(offset)->isa_oopptr(); + if (klass->is_value_array_klass()) { + ciValueKlass* vk = elem_type->as_value_klass(); + assert(vk->flatten_array(), "must be flattened"); + field_val = value_type_from_mem(mem, ctl, vk, field_addr_type->isa_aryptr(), 0, alloc); + } else { + field_val = value_from_mem(mem, ctl, basic_elem_type, field_type, field_addr_type, alloc); + } if (field_val == NULL) { // We weren't able to find a value for this field, // give up on eliminating this allocation.