--- old/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp 2018-11-27 21:41:03.542976445 -0800 +++ new/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp 2018-11-27 21:41:03.418971696 -0800 @@ -206,11 +206,13 @@ // Implementation of NewObjectArrayStub -NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info) { +NewObjectArrayStub::NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, + CodeEmitInfo* info, bool is_value_type) { _klass_reg = klass_reg; _result = result; _length = length; _info = new CodeEmitInfo(info); + _is_value_type = is_value_type; } @@ -219,7 +221,11 @@ __ bind(_entry); assert(_length->as_register() == rbx, "length must in rbx,"); assert(_klass_reg->as_register() == rdx, "klass_reg must in rdx"); - __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id))); + if (_is_value_type) { + __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_value_array_id))); + } else { + __ call(RuntimeAddress(Runtime1::entry_for(Runtime1::new_object_array_id))); + } ce->add_call_info_here(_info); ce->verify_oop_map(_info); assert(_result->as_register() == rax, "result must in rax,"); --- old/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp 2018-11-27 21:41:04.042995597 -0800 +++ new/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp 2018-11-27 21:41:03.922991001 -0800 @@ -1261,13 +1261,18 @@ length.load_item_force(FrameMap::rbx_opr); LIR_Opr len = length.result(); - CodeStub* slow_path = new NewObjectArrayStub(klass_reg, len, reg, info); - ciKlass* obj = (ciKlass*) ciObjArrayKlass::make(x->klass()); + ciKlass* obj = (ciKlass*) x->exact_type(); + CodeStub* slow_path = new NewObjectArrayStub(klass_reg, len, reg, info, obj->is_value_array_klass()); if (obj == ciEnv::unloaded_ciobjarrayklass()) { BAILOUT("encountered unloaded_ciobjarrayklass due to out of memory error"); } klass2reg_with_patching(klass_reg, obj, patching_info); - __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, T_OBJECT, klass_reg, slow_path); + if (obj->is_value_array_klass()) { + // This check is valid even if the class is not yet loaded, because the class has a "Q" signature. + __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, T_VALUETYPE, klass_reg, slow_path); + } else { + __ allocate_array(reg, len, tmp1, tmp2, tmp3, tmp4, T_OBJECT, klass_reg, slow_path); + } LIR_Opr result = rlock_result(x); __ move(reg, result); --- old/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp 2018-11-27 21:41:04.555015210 -0800 +++ new/src/hotspot/cpu/x86/c1_Runtime1_x86.cpp 2018-11-27 21:41:04.435010613 -0800 @@ -1103,6 +1103,7 @@ case new_type_array_id: case new_object_array_id: + case new_value_array_id: { Register length = rbx; // Incoming Register klass = rdx; // Incoming @@ -1110,8 +1111,10 @@ if (id == new_type_array_id) { __ set_info("new_type_array", dont_gc_arguments); - } else { + } else if (id == new_object_array_id) { __ set_info("new_object_array", dont_gc_arguments); + } else { + __ set_info("new_value_array", dont_gc_arguments); } #ifdef ASSERT @@ -1121,10 +1124,11 @@ Register t0 = obj; __ movl(t0, Address(klass, Klass::layout_helper_offset())); __ sarl(t0, Klass::_lh_array_tag_shift); - int tag = ((id == new_type_array_id) - ? Klass::_lh_array_tag_type_value - : Klass::_lh_array_tag_obj_value); - __ cmpl(t0, tag); + switch (id) { + case new_type_array_id: __ cmpl(t0, Klass::_lh_array_tag_type_value); break; + case new_object_array_id: __ cmpl(t0, Klass::_lh_array_tag_obj_value); break; + case new_value_array_id: __ cmpl(t0, Klass::_lh_array_tag_vt_value); break; + } __ jcc(Assembler::equal, ok); __ stop("assert(is an array klass)"); __ should_not_reach_here(); @@ -1179,6 +1183,7 @@ if (id == new_type_array_id) { call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_type_array), klass, length); } else { + // Runtime1::new_object_array handles both object and value arrays call_offset = __ call_RT(obj, noreg, CAST_FROM_FN_PTR(address, new_object_array), klass, length); } --- old/src/hotspot/share/c1/c1_CodeStubs.hpp 2018-11-27 21:41:05.063034668 -0800 +++ new/src/hotspot/share/c1/c1_CodeStubs.hpp 2018-11-27 21:41:04.943030072 -0800 @@ -284,9 +284,9 @@ LIR_Opr _length; LIR_Opr _result; CodeEmitInfo* _info; - + bool _is_value_type; public: - NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info); + NewObjectArrayStub(LIR_Opr klass_reg, LIR_Opr length, LIR_Opr result, CodeEmitInfo* info, bool is_value_type); virtual void emit_code(LIR_Assembler* e); virtual CodeEmitInfo* info() const { return _info; } virtual void visit(LIR_OpVisitState* visitor) { --- old/src/hotspot/share/c1/c1_Instruction.cpp 2018-11-27 21:41:05.563053820 -0800 +++ new/src/hotspot/share/c1/c1_Instruction.cpp 2018-11-27 21:41:05.443049224 -0800 @@ -222,7 +222,12 @@ } ciType* NewObjectArray::exact_type() const { - return ciObjArrayKlass::make(klass()); + ciKlass* element_klass = klass(); + if (element_klass->is_valuetype()) { + return ciValueArrayKlass::make(element_klass); + } else { + return ciObjArrayKlass::make(element_klass); + } } ciType* NewArray::declared_type() const { --- old/src/hotspot/share/c1/c1_LIRGenerator.cpp 2018-11-27 21:41:06.071073279 -0800 +++ new/src/hotspot/share/c1/c1_LIRGenerator.cpp 2018-11-27 21:41:05.947068530 -0800 @@ -1583,6 +1583,7 @@ for (int i = 0; i < elem_klass->nof_nonstatic_fields(); i++) { ciField* inner_field = elem_klass->nonstatic_field_at(i); + assert(!inner_field->is_flattened(), "flattened fields must have been expanded"); int obj_offset = inner_field->offset(); int elm_offset = obj_offset - elem_klass->first_field_offset(); // object header is not stored in array. --- old/src/hotspot/share/c1/c1_Runtime1.cpp 2018-11-27 21:41:06.627094577 -0800 +++ new/src/hotspot/share/c1/c1_Runtime1.cpp 2018-11-27 21:41:06.471088602 -0800 @@ -384,9 +384,14 @@ // (This may have to change if this code changes!) assert(array_klass->is_klass(), "not a class"); Handle holder(THREAD, array_klass->klass_holder()); // keep the klass alive - Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass(); - objArrayOop obj = oopFactory::new_objArray(elem_klass, length, CHECK); - thread->set_vm_result(obj); + Klass* elem_klass = ArrayKlass::cast(array_klass)->element_klass(); + if (elem_klass->is_value()) { + arrayOop obj = oopFactory::new_valueArray(elem_klass, length, CHECK); + thread->set_vm_result(obj); + } else { + objArrayOop obj = oopFactory::new_objArray(elem_klass, length, CHECK); + thread->set_vm_result(obj); + } // This is pretty rare but this runtime patch is stressful to deoptimization // if we deoptimize here so force a deopt to stress the path. if (DeoptimizeALot) { --- old/src/hotspot/share/c1/c1_Runtime1.hpp 2018-11-27 21:41:07.139114188 -0800 +++ new/src/hotspot/share/c1/c1_Runtime1.hpp 2018-11-27 21:41:07.015109439 -0800 @@ -51,6 +51,7 @@ stub(fast_new_instance_init_check) \ stub(new_type_array) \ stub(new_object_array) \ + stub(new_value_array) \ stub(new_multi_array) \ stub(handle_exception_nofpu) /* optimized version that does not preserve fpu registers */ \ stub(handle_exception) \ --- old/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBasicFunctionality.java 2018-11-27 21:41:07.571130736 -0800 +++ new/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestBasicFunctionality.java 2018-11-27 21:41:07.451126140 -0800 @@ -757,4 +757,31 @@ staticVal3.verify(vt); va[0].verify(vt); } + + // Test the handling of anewarray of a VT + @Test() + public MyValue2[] test36() { + MyValue2[] va = new MyValue2[3]; + return va; + } + + @DontCompile + public void test36_verifier(boolean warmup) { + MyValue2[] va = new MyValue2[10]; + MyValue2[] result = test36(); + Asserts.assertEQ(result[2].hash(), va[0].hash()); + } + + // Test the handling of aaload from a VT array + @Test() + public MyValue2 test37(MyValue2[] array, int i) { + return array[i]; + } + + @DontCompile + public void test37_verifier(boolean warmup) { + MyValue2[] va = new MyValue2[10]; + MyValue2 result = test37(va, 9); + Asserts.assertEQ(result.hash(), va[0].hash()); + } }