Patch to build 64 bit VM
Greg Lewis
glewis at eyesbeyond.com
Mon Dec 22 06:09:53 PST 2008
G'day Xiaobin,
On Wed, Dec 17, 2008 at 09:14:16PM -0800, Xiaobin Lu wrote:
> I am attaching the patch for building 64 bit VM. They are BSD specific
> files. Would someone review it and help me check it in?
Sure. Can you comment a little on the changes to
src/os_cpu/bsd_x86/vm/bytes_bsd_x86.inline.hpp? It seems like the diff is
bigger than the changes if that makes sense (i.e. there are some whitespace
changes due to control flow changes which are hiding those).
> diff -r de4c58dbee8f src/cpu/x86/vm/stubGenerator_x86_32.cpp
> --- a/src/cpu/x86/vm/stubGenerator_x86_64.cpp Wed Nov 26 05:05:13 2008 -0800
> +++ b/src/cpu/x86/vm/stubGenerator_x86_64.cpp Wed Dec 17 21:06:49 2008 -0800
> @@ -954,9 +954,9 @@ class StubGenerator: public StubCodeGene
> __ jcc(Assembler::zero, exit); // if obj is NULL it is OK
> // Check if the oop is in the right area of memory
> __ movptr(c_rarg2, rax);
> - __ movptr(c_rarg3, (int64_t) Universe::verify_oop_mask());
> + __ movptr(c_rarg3, (intptr_t) Universe::verify_oop_mask());
> __ andptr(c_rarg2, c_rarg3);
> - __ movptr(c_rarg3, (int64_t) Universe::verify_oop_bits());
> + __ movptr(c_rarg3, (intptr_t) Universe::verify_oop_bits());
> __ cmpptr(c_rarg2, c_rarg3);
> __ jcc(Assembler::notZero, error);
>
> @@ -969,9 +969,9 @@ class StubGenerator: public StubCodeGene
> __ jcc(Assembler::zero, error); // if klass is NULL it is broken
> // Check if the klass is in the right area of memory
> __ mov(c_rarg2, rax);
> - __ movptr(c_rarg3, (int64_t) Universe::verify_klass_mask());
> + __ movptr(c_rarg3, (intptr_t) Universe::verify_klass_mask());
> __ andptr(c_rarg2, c_rarg3);
> - __ movptr(c_rarg3, (int64_t) Universe::verify_klass_bits());
> + __ movptr(c_rarg3, (intptr_t) Universe::verify_klass_bits());
> __ cmpptr(c_rarg2, c_rarg3);
> __ jcc(Assembler::notZero, error);
>
> @@ -980,9 +980,9 @@ class StubGenerator: public StubCodeGene
> __ testptr(rax, rax);
> __ jcc(Assembler::zero, error); // if klass' klass is NULL it is broken
> // Check if the klass' klass is in the right area of memory
> - __ movptr(c_rarg3, (int64_t) Universe::verify_klass_mask());
> + __ movptr(c_rarg3, (intptr_t) Universe::verify_klass_mask());
> __ andptr(rax, c_rarg3);
> - __ movptr(c_rarg3, (int64_t) Universe::verify_klass_bits());
> + __ movptr(c_rarg3, (intptr_t) Universe::verify_klass_bits());
> __ cmpptr(rax, c_rarg3);
> __ jcc(Assembler::notZero, error);
>
> diff -r de4c58dbee8f src/os_cpu/bsd_x86/vm/bytes_bsd_x86.inline.hpp
> --- a/src/os_cpu/bsd_x86/vm/bytes_bsd_x86.inline.hpp Wed Nov 26 05:05:13 2008 -0800
> +++ b/src/os_cpu/bsd_x86/vm/bytes_bsd_x86.inline.hpp Wed Dec 17 21:06:49 2008 -0800
> @@ -32,9 +32,9 @@
>
> #if defined(AMD64)
> # if defined(__APPLE__)
> -# define bswap16(x) OSSwapInt16(x)
> -# define bswap32(x) OSSwapInt32(x)
> -# define bswap64(x) OSSwapInt64(x)
> +# define bswap_16(x) OSSwapInt16(x)
> +# define bswap_32(x) OSSwapInt32(x)
> +# define bswap_64(x) OSSwapInt64(x)
> # elif defined(__OpenBSD__)
> # define bswap_16(x) swap16(x)
> # define bswap_32(x) swap32(x)
> diff -r de4c58dbee8f src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp
> --- a/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Wed Nov 26 05:05:13 2008 -0800
> +++ b/src/os_cpu/bsd_x86/vm/os_bsd_x86.cpp Wed Dec 17 21:06:49 2008 -0800
> @@ -456,197 +456,191 @@ JVM_handle_bsd_signal(int sig,
> if (nm != NULL && nm->has_unsafe_access()) {
> stub = StubRoutines::handler_for_unsafe_access();
> }
> + } else {
> +#if defined(AMD64) && !defined(__APPLE__)
> + if (sig == SIGFPE &&
> + (info->si_code == FPE_INTDIV || info->si_code == FPE_FLTDIV)) {
> + stub =
> + SharedRuntime::
> + continuation_for_implicit_exception(thread,
> + pc,
> + SharedRuntime::
> + IMPLICIT_DIVIDE_BY_ZERO);
> +#else
> + if (sig == SIGFPE /* && info->si_code == FPE_INTDIV */) {
> + // HACK: si_code does not work on bsd 2.2.12-20!!!
> + int op = pc[0];
> +# ifdef AMD64
> + // Skip REX
> + if ((pc[0] & 0xf0) == 0x40) {
> + op = pc[1];
> +# endif
> + if (op == 0xDB) {
> + // FIST
> + // TODO: The encoding of D2I in i486.ad can cause an exception
> + // prior to the fist instruction if there was an invalid operation
> + // pending. We want to dismiss that exception. From the win_32
> + // side it also seems that if it really was the fist causing
> + // the exception that we do the d2i by hand with different
> + // rounding. Seems kind of weird.
> + // NOTE: that we take the exception at the NEXT floating point instruction.
> + assert(pc[0] == 0xDB, "not a FIST opcode");
> + assert(pc[1] == 0x14, "not a FIST opcode");
> + assert(pc[2] == 0x24, "not a FIST opcode");
> + return true;
> + } else if (op == 0xF7) {
> + // IDIV
> + stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO);
> + } else {
> + // TODO: handle more cases if we are using other x86 instructions
> + // that can generate SIGFPE signal on bsd.
> + tty->print_cr("unknown opcode 0x%X with SIGFPE.", op);
> + fatal("please update this code.");
> + }
> +#endif // AMD64
> + } else if ((sig == SIGSEGV || sig == SIGBUS) &&
> + !MacroAssembler::needs_explicit_null_check((intptr_t)info->si_addr)) {
> + // Determination of interpreter/vtable stub/compiled code null exception
> + stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
> + }
> + } else if (thread->thread_state() == _thread_in_vm &&
> + sig == SIGBUS && /* info->si_code == BUS_OBJERR && */
> + thread->doing_unsafe_access()) {
> + stub = StubRoutines::handler_for_unsafe_access();
> + }
> +
> + // jni_fast_Get<Primitive>Field can trap at certain pc's if a GC kicks in
> + // and the heap gets shrunk before the field access.
> + if ((sig == SIGSEGV) || (sig == SIGBUS)) {
> + address addr = JNI_FastGetField::find_slowcase_pc(pc);
> + if (addr != (address)-1) {
> + stub = addr;
> + }
> + }
> +
> + // Check to see if we caught the safepoint code in the
> + // process of write protecting the memory serialization page.
> + // It write enables the page immediately after protecting it
> + // so we can just return to retry the write.
> + if ((sig == SIGSEGV || sig == SIGBUS) &&
> + os::is_memory_serialize_page(thread, (address) info->si_addr)) {
> + // Block current thread until the memory serialize page permission restored.
> + os::block_on_serialize_page_trap();
> + return true;
> + }
> }
> - else
> +#ifndef AMD64
> + // Execution protection violation
> + //
> + // This should be kept as the last step in the triage. We don't
> + // have a dedicated trap number for a no-execute fault, so be
> + // conservative and allow other handlers the first shot.
> + //
> + // Note: We don't test that info->si_code == SEGV_ACCERR here.
> + // this si_code is so generic that it is almost meaningless; and
> + // the si_code for this condition may change in the future.
> + // Furthermore, a false-positive should be harmless.
> + if (UnguardOnExecutionViolation > 0 &&
> + (sig == SIGSEGV || sig == SIGBUS) &&
> + uc->context_trapno == trap_page_fault) {
> + int page_size = os::vm_page_size();
> + address addr = (address) info->si_addr;
> + address pc = os::Bsd::ucontext_get_pc(uc);
> + // Make sure the pc and the faulting address are sane.
> + //
> + // If an instruction spans a page boundary, and the page containing
> + // the beginning of the instruction is executable but the following
> + // page is not, the pc and the faulting address might be slightly
> + // different - we still want to unguard the 2nd page in this case.
> + //
> + // 15 bytes seems to be a (very) safe value for max instruction size.
> + bool pc_is_near_addr =
> + (pointer_delta((void*) addr, (void*) pc, sizeof(char)) < 15);
> + bool instr_spans_page_boundary =
> + (align_size_down((intptr_t) pc ^ (intptr_t) addr,
> + (intptr_t) page_size) > 0);
>
> -#if defined(AMD64) && !defined(__APPLE__)
> - if (sig == SIGFPE &&
> - (info->si_code == FPE_INTDIV || info->si_code == FPE_FLTDIV)) {
> - stub =
> - SharedRuntime::
> - continuation_for_implicit_exception(thread,
> - pc,
> - SharedRuntime::
> - IMPLICIT_DIVIDE_BY_ZERO);
> + if (pc == addr || (pc_is_near_addr && instr_spans_page_boundary)) {
> + static volatile address last_addr =
> + (address) os::non_memory_address_word();
>
> -#else
> - if (sig == SIGFPE /* && info->si_code == FPE_INTDIV */) {
> - // HACK: si_code does not work on bsd 2.2.12-20!!!
> - int op = pc[0];
> + // In conservative mode, don't unguard unless the address is in the VM
> + if (addr != last_addr &&
> + (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) {
> +
> + // Unguard and retry
> + address page_start =
> + (address) align_size_down((intptr_t) addr, (intptr_t) page_size);
> + bool res = os::unguard_memory((char*) page_start, page_size);
> +
> + if (PrintMiscellaneous && Verbose) {
> + char buf[256];
> + jio_snprintf(buf, sizeof(buf), "Execution protection violation "
> + "at " INTPTR_FORMAT
> + ", unguarding " INTPTR_FORMAT ": %s, errno=%d", addr,
> + page_start, (res ? "success" : "failed"), errno);
> + tty->print_raw_cr(buf);
> + }
> + stub = pc;
> +
> + // Set last_addr so if we fault again at the same address, we don't end
> + // up in an endless loop.
> + //
> + // There are two potential complications here. Two threads trapping at
> + // the same address at the same time could cause one of the threads to
> + // think it already unguarded, and abort the VM. Likely very rare.
> + //
> + // The other race involves two threads alternately trapping at
> + // different addresses and failing to unguard the page, resulting in
> + // an endless loop. This condition is probably even more unlikely than
> + // the first.
> + //
> + // Although both cases could be avoided by using locks or thread local
> + // last_addr, these solutions are unnecessary complication: this
> + // handler is a best-effort safety net, not a complete solution. It is
> + // disabled by default and should only be used as a workaround in case
> + // we missed any no-execute-unsafe VM code.
> +
> + last_addr = addr;
> + }
> + }
> + }
> +#endif // !AMD64
> + if (stub != NULL) {
> + // save all thread context in case we need to restore it
> + if (thread != NULL) thread->set_saved_exception_pc(pc);
>
> -# ifdef AMD64
> - // Skip REX
> - if ((pc[0] & 0xf0) == 0x40) {
> - op = pc[1];
> -# endif
> -
> - if (op == 0xDB) {
> - // FIST
> - // TODO: The encoding of D2I in i486.ad can cause an exception
> - // prior to the fist instruction if there was an invalid operation
> - // pending. We want to dismiss that exception. From the win_32
> - // side it also seems that if it really was the fist causing
> - // the exception that we do the d2i by hand with different
> - // rounding. Seems kind of weird.
> - // NOTE: that we take the exception at the NEXT floating point instruction.
> - assert(pc[0] == 0xDB, "not a FIST opcode");
> - assert(pc[1] == 0x14, "not a FIST opcode");
> - assert(pc[2] == 0x24, "not a FIST opcode");
> - return true;
> - } else if (op == 0xF7) {
> - // IDIV
> - stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO);
> - } else {
> - // TODO: handle more cases if we are using other x86 instructions
> - // that can generate SIGFPE signal on bsd.
> - tty->print_cr("unknown opcode 0x%X with SIGFPE.", op);
> - fatal("please update this code.");
> - }
> -#endif // AMD64
> - } else if ((sig == SIGSEGV || sig == SIGBUS) &&
> - !MacroAssembler::needs_explicit_null_check((intptr_t)info->si_addr)) {
> - // Determination of interpreter/vtable stub/compiled code null exception
> - stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
> + uc->context_pc = (intptr_t)stub;
> + return true;
> }
> - } else if (thread->thread_state() == _thread_in_vm &&
> - sig == SIGBUS && /* info->si_code == BUS_OBJERR && */
> - thread->doing_unsafe_access()) {
> - stub = StubRoutines::handler_for_unsafe_access();
> - }
>
> - // jni_fast_Get<Primitive>Field can trap at certain pc's if a GC kicks in
> - // and the heap gets shrunk before the field access.
> - if ((sig == SIGSEGV) || (sig == SIGBUS)) {
> - address addr = JNI_FastGetField::find_slowcase_pc(pc);
> - if (addr != (address)-1) {
> - stub = addr;
> + // signal-chaining
> + if (os::Bsd::chained_handler(sig, info, ucVoid)) {
> + return true;
> }
> - }
>
> - // Check to see if we caught the safepoint code in the
> - // process of write protecting the memory serialization page.
> - // It write enables the page immediately after protecting it
> - // so we can just return to retry the write.
> - if ((sig == SIGSEGV || sig == SIGBUS) &&
> - os::is_memory_serialize_page(thread, (address) info->si_addr)) {
> - // Block current thread until the memory serialize page permission restored.
> - os::block_on_serialize_page_trap();
> - return true;
> + if (!abort_if_unrecognized) {
> + // caller wants another chance, so give it to him
> + return false;
> + }
> +
> + if (pc == NULL && uc != NULL) {
> + pc = os::Bsd::ucontext_get_pc(uc);
> + }
> +
> + // unmask current signal
> + sigset_t newset;
> + sigemptyset(&newset);
> + sigaddset(&newset, sig);
> + sigprocmask(SIG_UNBLOCK, &newset, NULL);
> +
> + VMError err(t, sig, pc, info, ucVoid);
> + err.report_and_die();
> +
> + ShouldNotReachHere();
> }
> }
> -
> -#ifndef AMD64
> - // Execution protection violation
> - //
> - // This should be kept as the last step in the triage. We don't
> - // have a dedicated trap number for a no-execute fault, so be
> - // conservative and allow other handlers the first shot.
> - //
> - // Note: We don't test that info->si_code == SEGV_ACCERR here.
> - // this si_code is so generic that it is almost meaningless; and
> - // the si_code for this condition may change in the future.
> - // Furthermore, a false-positive should be harmless.
> - if (UnguardOnExecutionViolation > 0 &&
> - (sig == SIGSEGV || sig == SIGBUS) &&
> - uc->context_trapno == trap_page_fault) {
> - int page_size = os::vm_page_size();
> - address addr = (address) info->si_addr;
> - address pc = os::Bsd::ucontext_get_pc(uc);
> - // Make sure the pc and the faulting address are sane.
> - //
> - // If an instruction spans a page boundary, and the page containing
> - // the beginning of the instruction is executable but the following
> - // page is not, the pc and the faulting address might be slightly
> - // different - we still want to unguard the 2nd page in this case.
> - //
> - // 15 bytes seems to be a (very) safe value for max instruction size.
> - bool pc_is_near_addr =
> - (pointer_delta((void*) addr, (void*) pc, sizeof(char)) < 15);
> - bool instr_spans_page_boundary =
> - (align_size_down((intptr_t) pc ^ (intptr_t) addr,
> - (intptr_t) page_size) > 0);
> -
> - if (pc == addr || (pc_is_near_addr && instr_spans_page_boundary)) {
> - static volatile address last_addr =
> - (address) os::non_memory_address_word();
> -
> - // In conservative mode, don't unguard unless the address is in the VM
> - if (addr != last_addr &&
> - (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) {
> -
> - // Unguard and retry
> - address page_start =
> - (address) align_size_down((intptr_t) addr, (intptr_t) page_size);
> - bool res = os::unguard_memory((char*) page_start, page_size);
> -
> - if (PrintMiscellaneous && Verbose) {
> - char buf[256];
> - jio_snprintf(buf, sizeof(buf), "Execution protection violation "
> - "at " INTPTR_FORMAT
> - ", unguarding " INTPTR_FORMAT ": %s, errno=%d", addr,
> - page_start, (res ? "success" : "failed"), errno);
> - tty->print_raw_cr(buf);
> - }
> - stub = pc;
> -
> - // Set last_addr so if we fault again at the same address, we don't end
> - // up in an endless loop.
> - //
> - // There are two potential complications here. Two threads trapping at
> - // the same address at the same time could cause one of the threads to
> - // think it already unguarded, and abort the VM. Likely very rare.
> - //
> - // The other race involves two threads alternately trapping at
> - // different addresses and failing to unguard the page, resulting in
> - // an endless loop. This condition is probably even more unlikely than
> - // the first.
> - //
> - // Although both cases could be avoided by using locks or thread local
> - // last_addr, these solutions are unnecessary complication: this
> - // handler is a best-effort safety net, not a complete solution. It is
> - // disabled by default and should only be used as a workaround in case
> - // we missed any no-execute-unsafe VM code.
> -
> - last_addr = addr;
> - }
> - }
> - }
> -#endif // !AMD64
> -
> - if (stub != NULL) {
> - // save all thread context in case we need to restore it
> - if (thread != NULL) thread->set_saved_exception_pc(pc);
> -
> - uc->context_pc = (intptr_t)stub;
> - return true;
> - }
> -
> - // signal-chaining
> - if (os::Bsd::chained_handler(sig, info, ucVoid)) {
> - return true;
> - }
> -
> - if (!abort_if_unrecognized) {
> - // caller wants another chance, so give it to him
> - return false;
> - }
> -
> - if (pc == NULL && uc != NULL) {
> - pc = os::Bsd::ucontext_get_pc(uc);
> - }
> -
> - // unmask current signal
> - sigset_t newset;
> - sigemptyset(&newset);
> - sigaddset(&newset, sig);
> - sigprocmask(SIG_UNBLOCK, &newset, NULL);
> -
> - VMError err(t, sig, pc, info, ucVoid);
> - err.report_and_die();
> -
> - ShouldNotReachHere();
> }
> -
> #ifdef _ALLBSD_SOURCE
> // From solaris_i486.s ported to bsd_i486.s
> extern "C" void fixcw();
>
--
Greg Lewis Email : glewis at eyesbeyond.com
Eyes Beyond Web : http://www.eyesbeyond.com
Information Technology FreeBSD : glewis at FreeBSD.org
More information about the bsd-port-dev
mailing list