--- old/src/cpu/x86/vm/sharedRuntime_x86_64.cpp 2017-05-05 11:33:35.962987892 +0200 +++ new/src/cpu/x86/vm/sharedRuntime_x86_64.cpp 2017-05-05 11:33:35.818987897 +0200 @@ -28,6 +28,7 @@ #endif #include "asm/macroAssembler.hpp" #include "asm/macroAssembler.inline.hpp" +#include "classfile/symbolTable.hpp" #include "code/debugInfoRec.hpp" #include "code/icBuffer.hpp" #include "code/vtableStubs.hpp" @@ -595,7 +596,8 @@ size_t size_in_bytes, const VMRegPair& reg_pair, const Address& to, - int extraspace) { + int extraspace, + bool is_oop) { assert(bt != T_VALUETYPE || !ValueTypePassFieldsAsArgs, "no value type here"); if (bt == T_VOID) { assert(prev_bt == T_LONG || prev_bt == T_DOUBLE, "missing half"); @@ -623,12 +625,21 @@ assert(!r_2->is_valid(), "must be invalid"); return; } - if (r_1->is_stack()) { - int ld_off = r_1->reg2stack() * VMRegImpl::stack_slot_size + extraspace; - __ load_sized_value(rax, Address(rsp, ld_off), size_in_bytes, /* is_signed */ false); - __ store_sized_value(to, rax, size_in_bytes); - } else if (r_1->is_Register()) { - __ store_sized_value(to, r_1->as_Register(), size_in_bytes); + + if (!r_1->is_XMMRegister()) { + Register val = rax; + assert_different_registers(to.base(), val); + if(r_1->is_stack()) { + int ld_off = r_1->reg2stack() * VMRegImpl::stack_slot_size + extraspace; + __ load_sized_value(val, Address(rsp, ld_off), size_in_bytes, /* is_signed */ false); + } else { + val = r_1->as_Register(); + } + if (is_oop) { + __ store_heap_oop(to, val); + } else { + __ store_sized_value(to, val, size_in_bytes); + } } else { if (wide) { __ movdbl(to, r_1->as_XMMRegister()); @@ -655,12 +666,13 @@ __ bind(skip_fixup); + bool has_value_argument = false; if (ValueTypePassFieldsAsArgs) { - // Is there a value type arguments? - int i = 0; - for (; i < sig_extended.length() && sig_extended.at(i)._bt != T_VALUETYPE; i++); - - if (i < sig_extended.length()) { + // Is there a value type argument? + for (int i = 0; i < sig_extended.length() && !has_value_argument; i++) { + has_value_argument = (sig_extended.at(i)._bt == T_VALUETYPE); + } + if (has_value_argument) { // There is at least a value type argument: we're coming from // compiled code so we have no buffers to back the value // types. Allocate the buffers here with a runtime call. @@ -694,15 +706,12 @@ __ bind(no_exception); // We get an array of objects from the runtime call - int offset_in_bytes = arrayOopDesc::base_offset_in_bytes(T_OBJECT); __ get_vm_result(r13, r15_thread); __ get_vm_result_2(rbx, r15_thread); // TODO: required to keep the callee Method live? - __ addptr(r13, offset_in_bytes); - __ mov(r10, r13); + __ mov(r10, r13); // Cannot use r10 above because it's trashed by movptr() } } - // Since all args are passed on the stack, total_args_passed * // Interpreter::stackElementSize is the space we need. Plus 1 because // we also account for the return address location since @@ -736,6 +745,7 @@ // we allocated above and want to pass to the // interpreter. next_arg_int is the next argument from the // interpreter point of view (value types are passed by reference). + bool has_oop_field = false; for (int next_arg_comp = 0, ignored = 0, next_vt_arg = 0, next_arg_int = 0; next_arg_comp < sig_extended.length(); next_arg_comp++) { assert(ignored <= next_arg_comp, "shouldn't skip over more slot than there are arguments"); @@ -748,7 +758,7 @@ const VMRegPair reg_pair = regs[next_arg_comp-ignored]; size_t size_in_bytes = reg_pair.second()->is_valid() ? 8 : 4; gen_c2i_adapter_helper(masm, bt, next_arg_comp > 0 ? sig_extended.at(next_arg_comp-1)._bt : T_ILLEGAL, - size_in_bytes, reg_pair, Address(rsp, offset), extraspace); + size_in_bytes, reg_pair, Address(rsp, offset), extraspace, false); next_arg_int++; #ifdef ASSERT if (bt == T_LONG || bt == T_DOUBLE) { @@ -760,7 +770,8 @@ } else { ignored++; // get the buffer from the just allocated pool of buffers - __ load_heap_oop(r11, Address(r10, next_vt_arg * type2aelembytes(T_VALUETYPE))); + int index = arrayOopDesc::base_offset_in_bytes(T_OBJECT) + next_vt_arg * type2aelembytes(T_VALUETYPE); + __ load_heap_oop(r11, Address(r10, index)); next_vt_arg++; next_arg_int++; int vt = 1; // write fields we get from compiled code in registers/stack @@ -785,8 +796,10 @@ int off = sig_extended.at(next_arg_comp)._offset; assert(off > 0, "offset in object should be positive"); size_t size_in_bytes = is_java_primitive(bt) ? type2aelembytes(bt) : wordSize; + bool is_oop = (bt == T_OBJECT || bt == T_ARRAY); + has_oop_field = has_oop_field || is_oop; gen_c2i_adapter_helper(masm, bt, next_arg_comp > 0 ? sig_extended.at(next_arg_comp-1)._bt : T_ILLEGAL, - size_in_bytes, regs[next_arg_comp-ignored], Address(r11, off), extraspace); + size_in_bytes, regs[next_arg_comp-ignored], Address(r11, off), extraspace, is_oop); } } while (vt != 0); // pass the buffer to the interpreter @@ -794,6 +807,24 @@ } } + // If a value type was allocated and initialized, apply post barrier to all oop fields + if (has_value_argument && has_oop_field) { + __ push_CPU_state(); + + // Allocate argument register save area + if (frame::arg_reg_save_area_bytes != 0) { + __ subptr(rsp, frame::arg_reg_save_area_bytes); + } + __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::apply_post_barriers), r15_thread, r10, rbx); + // De-allocate argument register save area + if (frame::arg_reg_save_area_bytes != 0) { + __ addptr(rsp, frame::arg_reg_save_area_bytes); + } + + __ pop_CPU_state(); + __ get_vm_result_2(rbx, r15_thread); // TODO: required to keep the callee Method live? + } + // Schedule the branch target address early. __ movptr(rcx, Address(rbx, in_bytes(Method::interpreter_entry_offset()))); __ jmp(rcx); @@ -817,7 +848,8 @@ BasicType prev_bt, size_t size_in_bytes, const VMRegPair& reg_pair, - const Address& from) { + const Address& from, + bool is_oop) { assert(bt != T_VALUETYPE || !ValueTypePassFieldsAsArgs, "no value type here"); if (bt == T_VOID) { // Longs and doubles are passed in native word order, but misaligned @@ -838,18 +870,21 @@ } bool is_signed = (bt != T_CHAR) && (bt != T_BOOLEAN); - if (r_1->is_stack()) { - // Convert stack slot to an SP offset (+ wordSize to account for return address) - int st_off = reg_pair.first()->reg2stack() * VMRegImpl::stack_slot_size + wordSize; + if (!r_1->is_XMMRegister()) { // We can use r13 as a temp here because compiled code doesn't need r13 as an input // and if we end up going thru a c2i because of a miss a reasonable value of r13 // will be generated. - __ load_sized_value(r13, from, size_in_bytes, is_signed); - __ movq(Address(rsp, st_off), r13); - } else if (r_1->is_Register()) { - Register r = r_1->as_Register(); - assert(r != rax, "must be different"); - __ load_sized_value(r, from, size_in_bytes, is_signed); + Register dst = r_1->is_stack() ? r13 : r_1->as_Register(); + if (is_oop) { + __ load_heap_oop(dst, from); + } else { + __ load_sized_value(dst, from, size_in_bytes, is_signed); + } + if (r_1->is_stack()) { + // Convert stack slot to an SP offset (+ wordSize to account for return address) + int st_off = reg_pair.first()->reg2stack() * VMRegImpl::stack_slot_size + wordSize; + __ movq(Address(rsp, st_off), dst); + } } else { if (wide) { __ movdbl(r_1->as_XMMRegister(), from); @@ -991,7 +1026,7 @@ const VMRegPair reg_pair = regs[next_arg_comp-ignored]; size_t size_in_bytes = reg_pair.second()->is_valid() ? 8 : 4; gen_i2c_adapter_helper(masm, bt, next_arg_comp > 0 ? sig_extended.at(next_arg_comp-1)._bt : T_ILLEGAL, - size_in_bytes, reg_pair, Address(saved_sp, offset)); + size_in_bytes, reg_pair, Address(saved_sp, offset), false); next_arg_int++; } else { next_arg_int++; @@ -1021,7 +1056,8 @@ int off = sig_extended.at(next_arg_comp)._offset; assert(off > 0, "offset in object should be positive"); size_t size_in_bytes = is_java_primitive(bt) ? type2aelembytes(bt) : wordSize; - gen_i2c_adapter_helper(masm, bt, prev_bt, size_in_bytes, regs[next_arg_comp - ignored], Address(r10, off)); + bool is_oop = (bt == T_OBJECT || bt == T_ARRAY); + gen_i2c_adapter_helper(masm, bt, prev_bt, size_in_bytes, regs[next_arg_comp - ignored], Address(r10, off), is_oop); } } while (vt != 0); } @@ -1099,7 +1135,42 @@ __ flush(); new_adapter = AdapterBlob::create(masm->code(), frame_complete, frame_size_in_words, oop_maps); - return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry); + + // If value types are passed as fields, save the extended signature as symbol in + // the AdapterHandlerEntry to be used by nmethod::preserve_callee_argument_oops(). + Symbol* extended_signature = NULL; + if (ValueTypePassFieldsAsArgs) { + bool has_value_argument = false; + Thread* THREAD = Thread::current(); + ResourceMark rm(THREAD); + int length = sig_extended.length(); + // TODO is 256 enough? Can we determine the required length? + char* sig_str = NEW_RESOURCE_ARRAY(char, 256); + int idx = 0; + sig_str[idx++] = '('; + for (int index = 0; index < length; index++ ) { + BasicType bt = sig_extended.at(index)._bt; + if (bt == T_VALUETYPE || bt == T_VOID) { + has_value_argument = true; + continue; // Ignore wrapper types + } + sig_str[idx++] = type2char(bt); + if (bt == T_OBJECT) { + sig_str[idx++] = ';'; + } else if (bt == T_ARRAY) { + // We don't know the array element type, put void as placeholder + sig_str[idx++] = 'V'; + } + } + sig_str[idx++] = ')'; + sig_str[idx++] = '\0'; + if (has_value_argument) { + // Extended signature is only required if a value type argument is passed + extended_signature = SymbolTable::new_permanent_symbol(sig_str, THREAD); + } + } + + return AdapterHandlerLibrary::new_entry(fingerprint, i2c_entry, c2i_entry, c2i_unverified_entry, extended_signature); } int SharedRuntime::c_calling_convention(const BasicType *sig_bt,