--- old/src/hotspot/cpu/x86/interp_masm_x86.cpp 2019-11-27 16:55:41.699935848 +0100 +++ new/src/hotspot/cpu/x86/interp_masm_x86.cpp 2019-11-27 16:55:41.515932624 +0100 @@ -1233,7 +1233,7 @@ push(obj); // save holder allocate_instance(field_klass, obj, alloc_temp, dst_temp, false, alloc_failed); - // Have a oop instance buffer, copy into it + // Have an oop instance buffer, copy into it data_for_oop(obj, dst_temp, field_klass); pop(alloc_temp); // restore holder lea(src, Address(alloc_temp, field_offset)); @@ -1258,6 +1258,52 @@ bind(done); } +void InterpreterMacroAssembler::read_flattened_element(Register array, Register index, + Register t1, Register t2, + Register obj) { + assert_different_registers(array, index, t1, t2); + Label alloc_failed, empty_value, done; + const Register array_klass = t2; + const Register elem_klass = t1; + const Register alloc_temp = LP64_ONLY(rscratch1) NOT_LP64(rsi); + const Register dst_temp = LP64_ONLY(rscratch2) NOT_LP64(rdi); + + // load in array->klass()->element_klass() + load_klass(array_klass, array); + movptr(elem_klass, Address(array_klass, ArrayKlass::element_klass_offset())); + + //check for empty value klass + test_klass_is_empty_value(elem_klass, dst_temp, empty_value); + + // calc source into "array_klass" and free up some regs + const Register src = array_klass; + push(index); // preserve index reg in case alloc_failed + data_for_value_array_index(array, array_klass, index, src); + + allocate_instance(elem_klass, obj, alloc_temp, dst_temp, false, alloc_failed); + // Have an oop instance buffer, copy into it + movptr(Address(rsp, 0), obj); // preserve obj (overwrite index, no longer needed) + data_for_oop(obj, dst_temp, elem_klass); + access_value_copy(IS_DEST_UNINITIALIZED, src, dst_temp, elem_klass); + pop(obj); + jmp(done); + + bind(empty_value); + get_empty_value_oop(elem_klass, dst_temp, obj); + jmp(done); + + bind(alloc_failed); + pop(index); + if (array == c_rarg2) { + mov(elem_klass, array); + array = elem_klass; + } + call_VM(obj, CAST_FROM_FN_PTR(address, InterpreterRuntime::value_array_load), array, index); + + bind(done); +} + + // Lock object // // Args: --- old/src/hotspot/cpu/x86/interp_masm_x86.hpp 2019-11-27 16:55:42.239945310 +0100 +++ new/src/hotspot/cpu/x86/interp_masm_x86.hpp 2019-11-27 16:55:42.095942786 +0100 @@ -227,7 +227,7 @@ void allocate_instance(Register klass, Register new_obj, Register t1, Register t2, bool clear_fields, Label& alloc_failed); - // Allocate value buffer in new_obj and read in flattened field + // Allocate value buffer in "obj" and read in flattened field // NOTES: // - input holder object via "obj", which must be rax, // will return new value buffer obj via the same reg @@ -237,6 +237,15 @@ Register field_index, Register field_offset, Register obj = rax); + // Allocate value buffer in "obj" and read in flattened element at the given index + // NOTES: + // - Return via "obj" must be rax + // - kills all given regs + // - 32 bits: kills rdi and rsi + void read_flattened_element(Register array, Register index, + Register t1, Register t2, + Register obj = rax); + // Object locking void lock_object (Register lock_reg); void unlock_object(Register lock_reg); --- old/src/hotspot/cpu/x86/macroAssembler_x86.cpp 2019-11-27 16:55:42.767954561 +0100 +++ new/src/hotspot/cpu/x86/macroAssembler_x86.cpp 2019-11-27 16:55:42.611951827 +0100 @@ -5610,6 +5610,24 @@ } } +void MacroAssembler::data_for_value_array_index(Register array, Register array_klass, + Register index, Register data) { + assert(index != rcx, "index needs to shift by rcx"); + assert_different_registers(array, array_klass, index); + assert_different_registers(rcx, array, index); + + // array->base() + (index << Klass::layout_helper_log2_element_size(lh)); + movl(rcx, Address(array_klass, Klass::layout_helper_offset())); + + // Klass::layout_helper_log2_element_size(lh) + // (lh >> _lh_log2_element_size_shift) & _lh_log2_element_size_mask; + shrl(rcx, Klass::_lh_log2_element_size_shift); + andl(rcx, Klass::_lh_log2_element_size_mask); + shlptr(index); // index << rcx + + lea(data, Address(array, index, Address::times_1, arrayOopDesc::base_offset_in_bytes(T_VALUETYPE))); +} + void MacroAssembler::resolve(DecoratorSet decorators, Register obj) { // Use stronger ACCESS_WRITE|ACCESS_READ by default. if ((decorators & (ACCESS_READ | ACCESS_WRITE)) == 0) { --- old/src/hotspot/cpu/x86/macroAssembler_x86.hpp 2019-11-27 16:55:43.383965354 +0100 +++ new/src/hotspot/cpu/x86/macroAssembler_x86.hpp 2019-11-27 16:55:43.227962621 +0100 @@ -359,6 +359,9 @@ // value type data payload offsets... void first_field_offset(Register value_klass, Register offset); void data_for_oop(Register oop, Register data, Register value_klass); + // get data payload ptr a flat value array at index, kills rcx and index + void data_for_value_array_index(Register array, Register array_klass, + Register index, Register data); // Resolves obj access. Result is placed in the same register. --- old/src/hotspot/cpu/x86/templateTable_x86.cpp 2019-11-27 16:55:44.235980283 +0100 +++ new/src/hotspot/cpu/x86/templateTable_x86.cpp 2019-11-27 16:55:44.043976918 +0100 @@ -822,14 +822,11 @@ void TemplateTable::aaload() { transition(itos, atos); - - Register array = rcx; + Register array = rdx; Register index = rax; index_check(array, index); // kills rbx - - __ profile_array(rbx, array, rdx); - + __ profile_array(rbx, array, rcx); if (ValueArrayFlatten) { Label is_flat_array, done; __ test_flattened_array_oop(array, rbx, is_flat_array); @@ -841,7 +838,7 @@ IS_ARRAY); __ jmp(done); __ bind(is_flat_array); - __ call_VM(rax, CAST_FROM_FN_PTR(address, InterpreterRuntime::value_array_load), array, index); + __ read_flattened_element(array, index, rbx, rcx, rax); __ bind(done); } else { do_oop_load(_masm, @@ -851,8 +848,7 @@ rax, IS_ARRAY); } - - __ profile_element(rbx, rax, rdx); + __ profile_element(rbx, rax, rcx); } void TemplateTable::baload() { @@ -1224,9 +1220,20 @@ __ jump(ExternalAddress(Interpreter::_throw_ArrayStoreException_entry)); __ bind(is_type_ok); - __ movptr(rax, at_tos()); // value - __ movl(rcx, at_tos_p1()); // index - __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::value_array_store), rax, rdx, rcx); + // rbx: value's klass + // rdx: array + // rdi: array klass + __ test_klass_is_empty_value(rbx, rax, done); + + // calc dst for copy + __ movl(rax, at_tos_p1()); // index + __ data_for_value_array_index(rdx, rdi, rax, rax); + + // ...and src for copy + __ movptr(rcx, at_tos()); // value + __ data_for_oop(rcx, rcx, rbx); + + __ access_value_copy(IN_HEAP, rcx, rax, rbx); } // Pop stack arguments __ bind(done);