* Merged in twisti-branch.
[cacao.git] / src / vm / jit / x86_64 / md.c
index 555ea37c3a32adb46714287399f7ee8cf1429fee..3abd268f8987e9f7e4fe695d922f3eb9b2a454c0 100644 (file)
@@ -1,6 +1,6 @@
-/* src/vm/jit/x86_64/md.c - machine dependent x86_64 Linux functions
+/* src/vm/jit/x86_64/md.c - machine dependent x86_64 functions
 
-   Copyright (C) 1996-2005, 2006 R. Grafl, A. Krall, C. Kruegel,
+   Copyright (C) 1996-2005, 2006, 2007 R. Grafl, A. Krall, C. Kruegel,
    C. Oates, R. Obermaisser, M. Platter, M. Probst, S. Ring,
    E. Steiner, C. Thalinger, D. Thuernbeck, P. Tomsich, C. Ullrich,
    J. Wenninger, Institut f. Computersprachen - TU Wien
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
 
-   Contact: cacao@cacaojvm.org
-
-   Authors: Christian Thalinger
-
-   Changes: Edwin Steiner
-
-   $Id: md.c 4623 2006-03-16 00:05:18Z edwin $
+   $Id: md.c 7590 2007-03-28 18:54:02Z twisti $
 
 */
 
 
-#define _GNU_SOURCE
-
 #include "config.h"
 
+#include <assert.h>
 #include <stdlib.h>
-#include <ucontext.h>
 
 #include "vm/jit/x86_64/md-abi.h"
 
-#include "vm/exceptions.h"
-#include "vm/signallocal.h"
+#if defined(ENABLE_THREADS)
+# include "threads/native/threads.h"
+#endif
+
 #include "vm/jit/asmpart.h"
+#include "vm/jit/codegen-common.h"
 #include "vm/jit/stacktrace.h"
-#include "vm/options.h" /* XXX debug */
+
+#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
+#include "vmcore/options.h" /* XXX debug */
 #include "vm/jit/disass.h" /* XXX debug */
+#endif
 
 
 /* md_init *********************************************************************
@@ -62,120 +60,160 @@ void md_init(void)
 }
 
 
-/* md_signal_handler_sigsegv ***************************************************
+/* md_stacktrace_get_returnaddress *********************************************
 
-   NullPointerException signal handler for hardware null pointer
-   check.
+   Returns the return address of the current stackframe, specified by
+   the passed stack pointer and the stack frame size.
 
 *******************************************************************************/
 
-void md_signal_handler_sigsegv(int sig, siginfo_t *siginfo, void *_p)
+u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
 {
-       ucontext_t  *_uc;
-       mcontext_t  *_mc;
-       u1          *sp;
-       u1          *ra;
-       u1          *xpc;
+       u1 *ra;
 
-       _uc = (ucontext_t *) _p;
-       _mc = &_uc->uc_mcontext;
+       /* on x86_64 the return address is above the current stack frame */
 
-       /* ATTENTION: don't use CACAO internal REG_* defines as they are          */
-       /* different to the ones in <ucontext.h>                                  */
+       ra = *((u1 **) (sp + framesize));
 
-       sp  = (u1 *) _mc->gregs[REG_RSP];
-       xpc = (u1 *) _mc->gregs[REG_RIP];
-       ra  = xpc;                          /* return address is equal to xpc     */
+       return ra;
+}
 
-       _mc->gregs[REG_RAX] =
-               (ptrint) stacktrace_hardware_nullpointerexception(NULL, sp, ra, xpc);
 
-       _mc->gregs[REG_R10] = (ptrint) xpc;                      /* REG_ITMP2_XPC */
-       _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
-}
+/* md_get_method_patch_address *************************************************
 
+   Gets the patch address of the currently compiled method. The offset
+   is extracted from the load instruction(s) before the jump and added
+   to the right base address (PV or REG_METHODPTR).
 
-/* md_signal_handler_sigfpe ****************************************************
+   INVOKESTATIC/SPECIAL:
 
-   ArithmeticException signal handler for hardware divide by zero
-   check.
+   4d 8b 15 e2 fe ff ff             mov    -286(%rip),%r10
+   49 ff d2                         rex64Z callq  *%r10
+
+   INVOKEVIRTUAL:
+
+   4c 8b 17                         mov    (%rdi),%r10
+   49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
+   48 ff d3                         rex64 callq  *%rax
+
+   INVOKEINTERFACE:
+
+   4c 8b 17                         mov    (%rdi),%r10
+   4d 8b 92 00 00 00 00             mov    0x0(%r10),%r10
+   49 8b 82 00 00 00 00             mov    0x0(%r10),%rax
+   48 ff d3                         rex64 callq  *%r11
 
 *******************************************************************************/
 
-void md_signal_handler_sigfpe(int sig, siginfo_t *siginfo, void *_p)
+u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
 {
-       ucontext_t  *_uc;
-       mcontext_t  *_mc;
-       u1          *sp;
-       u1          *ra;
-       u1          *xpc;
+       u1  mcode;
+       s4  offset;
+       u1 *pa;                             /* patch address                      */
 
-       _uc = (ucontext_t *) _p;
-       _mc = &_uc->uc_mcontext;
+       /* go back to the actual call instruction (3-bytes) */
 
-       /* ATTENTION: don't use CACAO internal REG_* defines as they are          */
-       /* different to the ones in <ucontext.h>                                  */
+       ra = ra - 3;
 
-       sp  = (u1 *) _mc->gregs[REG_RSP];
-       xpc = (u1 *) _mc->gregs[REG_RIP];
-       ra  = xpc;                          /* return address is equal to xpc     */
+       /* get the last byte of the call */
 
-       _mc->gregs[REG_RAX] =
-               (ptrint) stacktrace_hardware_arithmeticexception(NULL, sp, ra, xpc);
+       mcode = ra[2];
 
-       _mc->gregs[REG_R10] = (ptrint) xpc;                      /* REG_ITMP2_XPC */
-       _mc->gregs[REG_RIP] = (ptrint) asm_handle_exception;
-}
+       /* check for the different calls */
 
+       if (mcode == 0xd2) {
+               /* INVOKESTATIC/SPECIAL */
 
-#if defined(USE_THREADS) && defined(NATIVE_THREADS)
-void thread_restartcriticalsection(ucontext_t *uc)
-{
-       void *critical;
+               /* Get the offset from the instruction (the offset address is
+                  4-bytes before the call instruction). */
+
+               offset = *((s4 *) (ra - 4));
 
-       critical = thread_checkcritical((void *) uc->uc_mcontext.gregs[REG_RIP]);
+               /* add the offset to the return address (IP-relative addressing) */
+
+               pa = ra + offset;
+       }
+       else if (mcode == 0xd3) {
+               /* INVOKEVIRTUAL/INTERFACE */
 
-       if (critical)
-               uc->uc_mcontext.gregs[REG_RIP] = (ptrint) critical;
+               /* return NULL if no mptr was specified (used for replacement) */
+
+               if (mptr == NULL)
+                       return NULL;
+
+               /* Get the offset from the instruction (the offset address is
+                  4-bytes before the call instruction). */
+
+               offset = *((s4 *) (ra - 4));
+
+               /* add the offset to the method pointer */
+
+               pa = mptr + offset;
+       }
+       else {
+               /* catch any problems */
+
+               assert(0);
+       }
+
+       return pa;
 }
-#endif
 
 
-/* md_stacktrace_get_returnaddress *********************************************
+/* md_codegen_get_pv_from_pc ***************************************************
 
-   Returns the return address of the current stackframe, specified by
-   the passed stack pointer and the stack frame size.
+   On this architecture just a wrapper function to
+   codegen_get_pv_from_pc.
 
 *******************************************************************************/
 
-u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
+u1 *md_codegen_get_pv_from_pc(u1 *ra)
 {
-       u1 *ra;
+       u1 *pv;
 
-       /* on x86_64 the return address is above the current stack frame */
+       /* Get the start address of the function which contains this
+       address from the method table. */
 
-       ra = *((u1 **) (sp + framesize));
+       pv = codegen_get_pv_from_pc(ra);
 
-       return ra;
+       return pv;
 }
 
 
-/* md_codegen_findmethod *******************************************************
+/* md_cacheflush ***************************************************************
 
-   On this architecture just a wrapper function to codegen_findmethod.
+   Calls the system's function to flush the instruction and data
+   cache.
 
 *******************************************************************************/
 
-u1 *md_codegen_findmethod(u1 *ra)
+void md_cacheflush(u1 *addr, s4 nbytes)
 {
-       u1 *pv;
+       /* do nothing */
+}
 
-       /* the the start address of the function which contains this
-       address from the method table */
 
-       pv = codegen_findmethod(ra);
+/* md_icacheflush **************************************************************
 
-       return pv;
+   Calls the system's function to flush the instruction cache.
+
+*******************************************************************************/
+
+void md_icacheflush(u1 *addr, s4 nbytes)
+{
+       /* do nothing */
+}
+
+
+/* md_dcacheflush **************************************************************
+
+   Calls the system's function to flush the data cache.
+
+*******************************************************************************/
+
+void md_dcacheflush(u1 *addr, s4 nbytes)
+{
+       /* do nothing */
 }
 
 
@@ -185,35 +223,57 @@ u1 *md_codegen_findmethod(u1 *ra)
 
 *******************************************************************************/
 
-void md_patch_replacement_point(rplpoint *rp)
+#if defined(ENABLE_REPLACEMENT)
+void md_patch_replacement_point(codeinfo *code, s4 index, rplpoint *rp, u1 *savedmcode)
 {
-    u8 mcode;
+       s4 disp;
+       u8 mcode;
 
        /* XXX this is probably unsafe! */
 
-       /* save the current machine code */
-       mcode = *(u8*)rp->pc;
+       if (index < 0) {
+               /* write spinning instruction */
+               *(u2*)(rp->pc) = 0xebfe;
+
+               /* write 5th byte */
+               rp->pc[4] = savedmcode[4];
+
+               /* write first word */
+               *(u4*)(rp->pc) = *(u4*)(savedmcode);
+       }
+       else {
+               /* save the current machine code */
+               *(u4*)(savedmcode) = *(u4*)(rp->pc);
+               savedmcode[4] = rp->pc[4];
+
+               /* build the machine code for the patch */
+               disp = (code->replacementstubs - rp->pc)
+                          + index * REPLACEMENT_STUB_SIZE
+                          - 5;
+
+               mcode = 0xe9 | ((u8) disp << 8);
 
-       /* write spinning instruction */
-       *(u2*)(rp->pc) = 0xebfe;
+               /* write spinning instruction */
+               *(u2*)(rp->pc) = 0xebfe;
 
-       /* write 5th byte */
-       rp->pc[4] = (rp->mcode >> 32);
+               /* write 5th byte */
+               rp->pc[4] = (mcode >> 32);
 
-       /* write first word */
-    *(u4*)(rp->pc) = (u4) rp->mcode;
+               /* write first word */
+               *(u4*)(rp->pc) = (u4) mcode;
+       }
 
-       /* store saved mcode */
-       rp->mcode = mcode;
-       
+#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER) && 0
        {
                u1* u1ptr = rp->pc;
                DISASSINSTR(u1ptr);
                fflush(stdout);
        }
+#endif
                        
     /* XXX if required asm_cacheflush(rp->pc,8); */
 }
+#endif /* defined(ENABLE_REPLACEMENT) */
 
 /*
  * These are local overrides for various environment variables in Emacs.