< prev index next >
src/cpu/x86/vm/sharedRuntime_x86_64.cpp
Print this page
*** 26,35 ****
--- 26,36 ----
#ifndef _WINDOWS
#include "alloca.h"
#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"
#include "interpreter/interpreter.hpp"
#include "logging/log.hpp"
*** 602,612 ****
BasicType bt,
BasicType prev_bt,
size_t size_in_bytes,
const VMRegPair& reg_pair,
const Address& to,
! int extraspace) {
assert(bt != T_VALUETYPE || !ValueTypePassFieldsAsArgs, "no value type here");
if (bt == T_VOID) {
assert(prev_bt == T_LONG || prev_bt == T_DOUBLE, "missing half");
return;
}
--- 603,614 ----
BasicType bt,
BasicType prev_bt,
size_t size_in_bytes,
const VMRegPair& reg_pair,
const Address& to,
! 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");
return;
}
*** 630,645 ****
assert(r_2->is_valid() == wide, "invalid size");
if (!r_1->is_valid()) {
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);
} else {
if (wide) {
__ movdbl(to, r_1->as_XMMRegister());
} else {
__ movflt(to, r_1->as_XMMRegister());
--- 632,656 ----
assert(r_2->is_valid() == wide, "invalid size");
if (!r_1->is_valid()) {
assert(!r_2->is_valid(), "must be invalid");
return;
}
!
! 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());
} else {
__ movflt(to, r_1->as_XMMRegister());
*** 662,677 ****
// compiled target. If there is one, we need to patch the caller's call.
patch_callers_callsite(masm);
__ bind(skip_fixup);
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()) {
// 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.
oop_maps = new OopMapSet();
OopMap* map = NULL;
--- 673,689 ----
// compiled target. If there is one, we need to patch the caller's call.
patch_callers_callsite(masm);
__ bind(skip_fixup);
+ bool has_value_argument = false;
if (ValueTypePassFieldsAsArgs) {
! // 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.
oop_maps = new OopMapSet();
OopMap* map = NULL;
*** 701,719 ****
__ jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
__ 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);
}
}
-
// 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
// we store it first rather than hold it in rax across all the shuffling
int total_args_passed = compute_total_args_passed_int(sig_extended);
--- 713,728 ----
__ jump(RuntimeAddress(StubRoutines::forward_exception_entry()));
__ bind(no_exception);
// We get an array of objects from the runtime call
! __ get_vm_result(r13, r15_thread); // Use r13 as temporary because r10 is trashed by movptr()
__ get_vm_result_2(rbx, r15_thread); // TODO: required to keep the callee Method live?
__ mov(r10, r13);
}
}
// 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
// we store it first rather than hold it in rax across all the shuffling
int total_args_passed = compute_total_args_passed_int(sig_extended);
*** 743,752 ****
--- 752,762 ----
// T_VALUETYPE/T_VOID. next_vt_arg is the next value type argument:
// used to get the buffer for that argument from the pool of buffers
// 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");
assert(next_arg_int < total_args_passed, "more arguments for the interpreter than expected?");
BasicType bt = sig_extended.at(next_arg_comp)._bt;
*** 755,765 ****
int next_off = st_off - Interpreter::stackElementSize;
const int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : st_off;
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);
next_arg_int++;
#ifdef ASSERT
if (bt == T_LONG || bt == T_DOUBLE) {
// Overwrite the unused slot with known junk
__ mov64(rax, CONST64(0xdeadffffdeadaaaa));
--- 765,775 ----
int next_off = st_off - Interpreter::stackElementSize;
const int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : st_off;
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, false);
next_arg_int++;
#ifdef ASSERT
if (bt == T_LONG || bt == T_DOUBLE) {
// Overwrite the unused slot with known junk
__ mov64(rax, CONST64(0xdeadffffdeadaaaa));
*** 767,777 ****
}
#endif /* ASSERT */
} else {
ignored++;
// get the buffer from the just allocated pool of buffers
! __ load_heap_oop(r11, Address(r10, next_vt_arg * type2aelembytes(T_VALUETYPE)));
next_vt_arg++; next_arg_int++;
int vt = 1;
// write fields we get from compiled code in registers/stack
// slots to the buffer: we know we are done with that value type
// argument when we hit the T_VOID that acts as an end of value
--- 777,788 ----
}
#endif /* ASSERT */
} else {
ignored++;
// get the buffer from the just allocated pool of buffers
! 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
// slots to the buffer: we know we are done with that value type
// argument when we hit the T_VOID that acts as an end of value
*** 792,810 ****
ignored++;
} else {
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_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);
}
} while (vt != 0);
// pass the buffer to the interpreter
__ movptr(Address(rsp, st_off), r11);
}
}
// Schedule the branch target address early.
__ movptr(rcx, Address(rbx, in_bytes(Method::interpreter_entry_offset())));
__ jmp(rcx);
}
--- 803,840 ----
ignored++;
} else {
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, is_oop);
}
} while (vt != 0);
// pass the buffer to the interpreter
__ movptr(Address(rsp, st_off), r11);
}
}
+ // If a value type was allocated and initialized, apply post barrier to all oop fields
+ if (has_value_argument && has_oop_field) {
+ __ push(r13); // save senderSP
+ __ push(rbx); // save callee
+ // 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);
+ // De-allocate argument register save area
+ if (frame::arg_reg_save_area_bytes != 0) {
+ __ addptr(rsp, frame::arg_reg_save_area_bytes);
+ }
+ __ pop(rbx); // restore callee
+ __ pop(r13); // restore sender SP
+ }
+
// Schedule the branch target address early.
__ movptr(rcx, Address(rbx, in_bytes(Method::interpreter_entry_offset())));
__ jmp(rcx);
}
*** 824,834 ****
static void gen_i2c_adapter_helper(MacroAssembler* masm,
BasicType bt,
BasicType prev_bt,
size_t size_in_bytes,
const VMRegPair& reg_pair,
! const Address& from) {
assert(bt != T_VALUETYPE || !ValueTypePassFieldsAsArgs, "no value type here");
if (bt == T_VOID) {
// Longs and doubles are passed in native word order, but misaligned
// in the 32-bit build.
assert(prev_bt == T_LONG || prev_bt == T_DOUBLE, "missing half");
--- 854,865 ----
static void gen_i2c_adapter_helper(MacroAssembler* masm,
BasicType bt,
BasicType prev_bt,
size_t size_in_bytes,
const VMRegPair& reg_pair,
! 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
// in the 32-bit build.
assert(prev_bt == T_LONG || prev_bt == T_DOUBLE, "missing half");
*** 845,866 ****
assert(!r_2->is_valid(), "must be invalid");
return;
}
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;
// 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);
} else {
if (wide) {
__ movdbl(r_1->as_XMMRegister(), from);
} else {
__ movflt(r_1->as_XMMRegister(), from);
--- 876,900 ----
assert(!r_2->is_valid(), "must be invalid");
return;
}
bool is_signed = (bt != T_CHAR) && (bt != T_BOOLEAN);
! 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.
! 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);
} else {
__ movflt(r_1->as_XMMRegister(), from);
*** 998,1008 ****
int next_off = ld_off - Interpreter::stackElementSize;
int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : ld_off;
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));
next_arg_int++;
} else {
next_arg_int++;
ignored++;
// get the buffer for that value type
--- 1032,1042 ----
int next_off = ld_off - Interpreter::stackElementSize;
int offset = (bt == T_LONG || bt == T_DOUBLE) ? next_off : ld_off;
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), false);
next_arg_int++;
} else {
next_arg_int++;
ignored++;
// get the buffer for that value type
*** 1028,1038 ****
ignored++;
} else {
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));
}
} while (vt != 0);
}
}
--- 1062,1073 ----
ignored++;
} else {
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);
! gen_i2c_adapter_helper(masm, bt, prev_bt, size_in_bytes, regs[next_arg_comp - ignored], Address(r10, off), is_oop);
}
} while (vt != 0);
}
}
*** 1106,1116 ****
int frame_size_in_words = 0;
gen_c2i_adapter(masm, sig_extended, regs, skip_fixup, i2c_entry, oop_maps, frame_complete, frame_size_in_words);
__ 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);
}
int SharedRuntime::c_calling_convention(const BasicType *sig_bt,
VMRegPair *regs,
VMRegPair *regs2,
--- 1141,1185 ----
int frame_size_in_words = 0;
gen_c2i_adapter(masm, sig_extended, regs, skip_fixup, i2c_entry, oop_maps, frame_complete, frame_size_in_words);
__ flush();
new_adapter = AdapterBlob::create(masm->code(), frame_complete, frame_size_in_words, oop_maps);
!
! // 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();
! char* sig_str = NEW_RESOURCE_ARRAY(char, 2*length + 3);
! 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,
VMRegPair *regs,
VMRegPair *regs2,
< prev index next >