src/cpu/x86/vm/stubGenerator_x86_64.cpp
Print this page
rev 4534 : 8010927: Kitchensink crashed with SIGSEGV, Problematic frame: v ~StubRoutines::checkcast_arraycopy
Summary: Changed gen_write_ref_array_post_barrier() code on x64 to pass start address and number of copied oop elements. In generate_checkcast_copy() skip post barrier code if no elements are copied.
Reviewed-by: roland
*** 1243,1273 ****
//
// Generate code for an array write post barrier
//
// Input:
// start - register containing starting address of destination array
! // end - register containing ending address of destination array
// scratch - scratch register
//
// The input registers are overwritten.
! // The ending address is inclusive.
! void gen_write_ref_array_post_barrier(Register start, Register end, Register scratch) {
! assert_different_registers(start, end, scratch);
BarrierSet* bs = Universe::heap()->barrier_set();
switch (bs->kind()) {
case BarrierSet::G1SATBCT:
case BarrierSet::G1SATBCTLogging:
-
{
__ pusha(); // push registers (overkill)
! // must compute element count unless barrier set interface is changed (other platforms supply count)
! assert_different_registers(start, end, scratch);
! __ lea(scratch, Address(end, BytesPerHeapOop));
! __ subptr(scratch, start); // subtract start to get #bytes
! __ shrptr(scratch, LogBytesPerHeapOop); // convert to element count
__ mov(c_rarg0, start);
! __ mov(c_rarg1, scratch);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), 2);
__ popa();
}
break;
case BarrierSet::CardTableModRef:
--- 1243,1274 ----
//
// Generate code for an array write post barrier
//
// Input:
// start - register containing starting address of destination array
! // count - elements count
// scratch - scratch register
//
// The input registers are overwritten.
! //
! void gen_write_ref_array_post_barrier(Register start, Register count, Register scratch) {
! assert_different_registers(start, count, scratch);
BarrierSet* bs = Universe::heap()->barrier_set();
switch (bs->kind()) {
case BarrierSet::G1SATBCT:
case BarrierSet::G1SATBCTLogging:
{
__ pusha(); // push registers (overkill)
! if (c_rarg0 == count) { // On win64 c_rarg0 == rcx
! assert_different_registers(c_rarg1, start);
! __ mov(c_rarg1, count);
__ mov(c_rarg0, start);
! } else {
! assert_different_registers(c_rarg0, count);
! __ mov(c_rarg0, start);
! __ mov(c_rarg1, count);
! }
__ call_VM_leaf(CAST_FROM_FN_PTR(address, BarrierSet::static_write_ref_array_post), 2);
__ popa();
}
break;
case BarrierSet::CardTableModRef:
*** 1275,1300 ****
{
CardTableModRefBS* ct = (CardTableModRefBS*)bs;
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
Label L_loop;
__ shrptr(start, CardTableModRefBS::card_shift);
- __ addptr(end, BytesPerHeapOop);
__ shrptr(end, CardTableModRefBS::card_shift);
! __ subptr(end, start); // number of bytes to copy
! intptr_t disp = (intptr_t) ct->byte_map_base;
! if (Assembler::is_simm32(disp)) {
! Address cardtable(noreg, noreg, Address::no_scale, disp);
! __ lea(scratch, cardtable);
! } else {
! ExternalAddress cardtable((address)disp);
! __ lea(scratch, cardtable);
! }
!
! const Register count = end; // 'end' register contains bytes count now
__ addptr(start, scratch);
__ BIND(L_loop);
__ movb(Address(start, count, Address::times_1), 0);
__ decrement(count);
__ jcc(Assembler::greaterEqual, L_loop);
--- 1276,1295 ----
{
CardTableModRefBS* ct = (CardTableModRefBS*)bs;
assert(sizeof(*ct->byte_map_base) == sizeof(jbyte), "adjust this code");
Label L_loop;
+ const Register end = count;
+ __ leaq(end, Address(start, count, TIMES_OOP, 0)); // end == start+count*oop_size
+ __ subptr(end, BytesPerHeapOop); // end - 1 to make inclusive
__ shrptr(start, CardTableModRefBS::card_shift);
__ shrptr(end, CardTableModRefBS::card_shift);
! __ subptr(end, start); // end --> cards count
! int64_t disp = (int64_t) ct->byte_map_base;
! __ mov64(scratch, disp);
__ addptr(start, scratch);
__ BIND(L_loop);
__ movb(Address(start, count, Address::times_1), 0);
__ decrement(count);
__ jcc(Assembler::greaterEqual, L_loop);
*** 1942,1953 ****
__ movl(rax, Address(end_from, 8));
__ movl(Address(end_to, 8), rax);
__ BIND(L_exit);
if (is_oop) {
! __ leaq(end_to, Address(saved_to, dword_count, Address::times_4, -4));
! gen_write_ref_array_post_barrier(saved_to, end_to, rax);
}
restore_arg_regs();
inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
--- 1937,1947 ----
__ movl(rax, Address(end_from, 8));
__ movl(Address(end_to, 8), rax);
__ BIND(L_exit);
if (is_oop) {
! gen_write_ref_array_post_barrier(saved_to, dword_count, rax);
}
restore_arg_regs();
inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
*** 2038,2052 ****
__ ret(0);
// Copy in multi-bytes chunks
copy_bytes_backward(from, to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
! __ bind(L_exit);
if (is_oop) {
! Register end_to = rdx;
! __ leaq(end_to, Address(to, dword_count, Address::times_4, -4));
! gen_write_ref_array_post_barrier(to, end_to, rax);
}
restore_arg_regs();
inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
--- 2032,2044 ----
__ ret(0);
// Copy in multi-bytes chunks
copy_bytes_backward(from, to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
! __ BIND(L_exit);
if (is_oop) {
! gen_write_ref_array_post_barrier(to, dword_count, rax);
}
restore_arg_regs();
inc_counter_np(SharedRuntime::_jint_array_copy_ctr); // Update counter after rscratch1 is free
__ xorptr(rax, rax); // return 0
__ leave(); // required for proper stackwalking of RuntimeStub frame
*** 2081,2090 ****
--- 2073,2083 ----
const Register to = rsi; // destination array address
const Register qword_count = rdx; // elements count
const Register end_from = from; // source array end address
const Register end_to = rcx; // destination array end address
const Register saved_to = to;
+ const Register saved_count = r11;
// End pointers are inclusive, and if count is not zero they point
// to the last unit copied: end_to[0] := end_from[0]
__ enter(); // required for proper stackwalking of RuntimeStub frame
// Save no-overlap entry point for generate_conjoint_long_oop_copy()
*** 2098,2107 ****
--- 2091,2102 ----
setup_arg_regs(); // from => rdi, to => rsi, count => rdx
// r9 and r10 may be used to save non-volatile registers
// 'from', 'to' and 'qword_count' are now valid
if (is_oop) {
+ // Save to and count for store barrier
+ __ movptr(saved_count, qword_count);
// no registers are destroyed by this call
gen_write_ref_array_pre_barrier(to, qword_count, dest_uninitialized);
}
// Copy from low to high addresses. Use 'to' as scratch.
*** 2130,2140 ****
// Copy in multi-bytes chunks
copy_bytes_forward(end_from, end_to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
if (is_oop) {
__ BIND(L_exit);
! gen_write_ref_array_post_barrier(saved_to, end_to, rax);
}
restore_arg_regs();
if (is_oop) {
inc_counter_np(SharedRuntime::_oop_array_copy_ctr); // Update counter after rscratch1 is free
} else {
--- 2125,2135 ----
// Copy in multi-bytes chunks
copy_bytes_forward(end_from, end_to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
if (is_oop) {
__ BIND(L_exit);
! gen_write_ref_array_post_barrier(saved_to, saved_count, rax);
}
restore_arg_regs();
if (is_oop) {
inc_counter_np(SharedRuntime::_oop_array_copy_ctr); // Update counter after rscratch1 is free
} else {
*** 2213,2224 ****
// Copy in multi-bytes chunks
copy_bytes_backward(from, to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
if (is_oop) {
__ BIND(L_exit);
! __ lea(rcx, Address(to, saved_count, Address::times_8, -8));
! gen_write_ref_array_post_barrier(to, rcx, rax);
}
restore_arg_regs();
if (is_oop) {
inc_counter_np(SharedRuntime::_oop_array_copy_ctr); // Update counter after rscratch1 is free
} else {
--- 2208,2218 ----
// Copy in multi-bytes chunks
copy_bytes_backward(from, to, qword_count, rax, L_copy_bytes, L_copy_8_bytes);
if (is_oop) {
__ BIND(L_exit);
! gen_write_ref_array_post_barrier(to, saved_count, rax);
}
restore_arg_regs();
if (is_oop) {
inc_counter_np(SharedRuntime::_oop_array_copy_ctr); // Update counter after rscratch1 is free
} else {
*** 2401,2425 ****
// It was a real error; we must depend on the caller to finish the job.
// Register rdx = -1 * number of *remaining* oops, r14 = *total* oops.
// Emit GC store barriers for the oops we have copied (r14 + rdx),
// and report their number to the caller.
! assert_different_registers(rax, r14_length, count, to, end_to, rcx);
! __ lea(end_to, to_element_addr);
! __ addptr(end_to, -heapOopSize); // make an inclusive end pointer
! gen_write_ref_array_post_barrier(to, end_to, rscratch1);
! __ movptr(rax, r14_length); // original oops
! __ addptr(rax, count); // K = (original - remaining) oops
! __ notptr(rax); // report (-1^K) to caller
! __ jmp(L_done);
// Come here on success only.
__ BIND(L_do_card_marks);
- __ addptr(end_to, -heapOopSize); // make an inclusive end pointer
- gen_write_ref_array_post_barrier(to, end_to, rscratch1);
__ xorptr(rax, rax); // return 0 on success
// Common exit point (success or failure).
__ BIND(L_done);
__ movptr(r13, Address(rsp, saved_r13_offset * wordSize));
__ movptr(r14, Address(rsp, saved_r14_offset * wordSize));
restore_arg_regs();
--- 2395,2419 ----
// It was a real error; we must depend on the caller to finish the job.
// Register rdx = -1 * number of *remaining* oops, r14 = *total* oops.
// Emit GC store barriers for the oops we have copied (r14 + rdx),
// and report their number to the caller.
! assert_different_registers(rax, r14_length, count, to, end_to, rcx, rscratch1);
! Label L_post_barrier;
! __ addptr(r14_length, count); // K = (original - remaining) oops
! __ movptr(rax, r14_length); // save the value
! __ notptr(rax); // report (-1^K) to caller (does not affect flags)
! __ jccb(Assembler::notZero, L_post_barrier);
! __ jmp(L_done); // K == 0, nothing was copied, skip post barrier
// Come here on success only.
__ BIND(L_do_card_marks);
__ xorptr(rax, rax); // return 0 on success
+ __ BIND(L_post_barrier);
+ gen_write_ref_array_post_barrier(to, r14_length, rscratch1);
+
// Common exit point (success or failure).
__ BIND(L_done);
__ movptr(r13, Address(rsp, saved_r13_offset * wordSize));
__ movptr(r14, Address(rsp, saved_r14_offset * wordSize));
restore_arg_regs();