* Removed all Id tags.
[cacao.git] / src / vm / jit / sparc64 / md.c
index 67a1691678e85295e4481822f15d96af93928c03..492390c0fd1d93de6df765a6cf13f23ab340d2df 100644 (file)
@@ -1,8 +1,35 @@
+/* src/vm/jit/sparc64/md.c - machine dependent SPARC functions
+
+   Copyright (C) 1996-2005, 2006 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
+
+   This file is part of CACAO.
+
+   This program is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+*/
 
-#include <assert.h>
 
 #include "config.h"
 
+#include <assert.h>
+
+
 #include "vm/types.h"
 
 #include "vm/jit/sparc64/md-abi.h"
 #include "vm/jit/asmpart.h"
 #include "vm/jit/stacktrace.h"
 
-#if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
-#include "vm/options.h" /* XXX debug */
-#include "vm/jit/disass.h" /* XXX debug */
-#endif
+/* assembler function prototypes **********************************************/
+void asm_store_fp_state_reg(u8 *mem);
+void asm_load_fp_state_reg(u8 *mem);
+
+
 
 /* shift away 13-bit immediate,  mask rd and rs1    */
 #define SHIFT_AND_MASK(instr) \
        ((instr >> 13) & 0x60fc1)
 
+/* NOP is defined as a SETHI instruction with rd and imm. set to zero */
+/* therefore we check if the 22-bit immediate is zero */
 #define IS_SETHI(instr) \
-       ((instr & 0xc1c00000)  == 0x00800000)
+       (((instr & 0xc1c00000)  == 0x01000000) \
+       && ((instr & 0x3fffff) != 0x0))
+       
+#define IS_LDX_IMM(instr) \
+       (((instr >> 13) & 0x60fc1) == 0x602c1)
+       
+#define IS_SUB(instr) \
+       (((instr >> 13) & 0x60fc0) == 0x40100)
 
 inline s2 decode_13bit_imm(u4 instr) {
        s2 imm;
@@ -49,66 +86,6 @@ void md_init(void)
 }
 
 
-/* md_codegen_patch_branch *****************************************************
-
-   Back-patches a branch instruction.
-
-*******************************************************************************/
-
-void md_codegen_patch_branch(codegendata *cd, s4 branchmpc, s4 targetmpc)
-{
-       s4 *mcodeptr;
-       s4  mcode;
-       s4  disp;                           /* branch displacement                */
-
-       /* calculate the patch position */
-
-       mcodeptr = (s4 *) (cd->mcodebase + branchmpc);
-
-       /* get the instruction before the exception point */
-
-       mcode = mcodeptr[-1];
-
-       /* check for BPcc or FBPfcc instruction */
-       if (((mcode >> 16) & 0xc1c0) == 0x0040) {
-                       
-       
-               /* Calculate the branch displacement.  For branches we need a
-                  displacement relative and shifted to the branch PC. */
-       
-               disp = (targetmpc - branchmpc) >> 2;
-       
-               /* check branch displacement (19-bit)*/
-       
-               if ((disp < (s4) 0xfffc0000) || (disp > (s4) 0x003ffff))
-                       vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x003ffff);
-       
-               /* patch the branch instruction before the mcodeptr */
-       
-               mcodeptr[-1] |= (disp & 0x003ffff);
-       }
-       /* check for BPr instruction */
-       else if (((mcode >> 16) & 0xd1c0) == 0x00c0) {
-
-               /* check branch displacement (16-bit)*/
-               
-               disp = (targetmpc - branchmpc) >> 2;
-       
-               if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x0007fff))
-                       vm_abort("branch displacement is out of range: %d > +/-%d", disp, 0x0007fff);
-                       
-               /* patch the upper 2-bit of the branch displacement */
-               mcodeptr[-1] |= ((disp & 0xc000) << 6);
-                       
-               /* patch the lower 14-bit of the branch displacement */
-               mcodeptr[-1] |= (disp & 0x003fff);
-               
-       }
-       else
-               assert(0);
-}
-
-
 /* md_stacktrace_get_returnaddress *********************************************
 
    Returns the return address of the current stackframe, specified by
@@ -127,12 +104,32 @@ u1 *md_stacktrace_get_returnaddress(u1 *sp, u4 framesize)
         */
        ra = *((u1 **) (sp + 120 + BIAS));
        
-       /* ra is the address of the call instr, advance to the real return address  */
-       ra += 8;
+       /* NOTE: on SPARC ra is the address of the call instruction */
 
        return ra;
 }
 
+u1 *md_get_framepointer(u1 *sp)
+{
+       u1 *fp;
+       /* flush register windows to the stack */
+       __asm__ ("flushw");
+
+       fp = *((u1 **) (sp + 112 + BIAS));
+
+       return fp;
+}
+
+u1 *md_get_pv_from_stackframe(u1 *sp)
+{
+       u1 *pv;
+       /* flush register windows to the stack */
+       __asm__ ("flushw");
+
+       pv = *((u1 **) (sp + 104 + BIAS));
+
+       return pv;
+}
 
 /* md_codegen_get_pv_from_pc ***************************************************
 
@@ -152,48 +149,39 @@ u1 *md_codegen_get_pv_from_pc(u1 *ra)
 {
        u1 *pv;
        u8  mcode;
-       u4  mcode_masked;
-       s2  offset;
+       s4  offset;
 
        pv = ra;
 
        /* get the instruction word after jump and nop */
        mcode = *((u4 *) (ra+8) );
 
-       /* check if we have 2 instructions (ldah, lda) */
-
-       mcode_masked = SHIFT_AND_MASK(mcode);
-
-       if (mcode_masked == 0x40001) {
-#if 0
-               /* get displacement of first instruction (ldah) */
-
-               offset = (s4) (mcode << 16);
-               pv += offset;
-
-               /* get displacement of second instruction (lda) */
-
-               mcode = *((u4 *) (ra + 1 * 4));
-
-               assert((mcode >> 16) == 0x237b);
-
-               offset = (s2) (mcode & 0x0000ffff);
-               pv += offset;
+       /* check if we have a sethi insruction */
+       if (IS_SETHI(mcode)) {
+               s4 xor_imm;
+                               
+               /* get 22-bit immediate of sethi instruction */
+               offset = (s4) (mcode & 0x3fffff);
+               offset = offset << 10;
+               
+               /* now the xor */
+               mcode = *((u4 *) (ra+12) );
+               xor_imm = decode_13bit_imm(mcode);
+               
+               offset ^= xor_imm;       
+       }
+       else {
+               u4 mcode_masked;
+               
+               mcode_masked = SHIFT_AND_MASK(mcode);
 
-       } else {
-               /* get displacement of first instruction (lda) */
+               assert(mcode_masked == 0x40001);
 
-               assert((mcode >> 16) == 0x237a);
-#endif
                /* mask and extend the negative sign for the 13 bit immediate */
                offset = decode_13bit_imm(mcode);
-
-               pv += offset;
-       }
-       else
-       {
-               assert(0);
        }
+       
+       pv += offset;
 
        return pv;
 }
@@ -206,89 +194,117 @@ u1 *md_codegen_get_pv_from_pc(u1 *ra)
 
    INVOKESTATIC/SPECIAL:
 
-   dfdeffb8    ldx      [i5 - 72],o5
-   03c0f809    jmp      o5
-   00000000    nop
+   ????????    ldx      [i5 - 72],o5
+   ????????    jmp      o5             <-- ra
+   ????????    nop
+
+   w/ sethi (mptr in dseg out of 13-bit simm range)
+
+   ????????    sethi    hi(0x2000),o5
+   ????????    sub      i5,o5,o5
+   ????????    ldx      [o5 - 72],o5
+   ????????    jmp      o5             <-- ra
+   ????????    nop
 
    INVOKEVIRTUAL:
 
-   dc990000    ld       t9,0(a0)
-   df3e0000    ld       [g2 + 0],o5
-   03c0f809    jmp      o5
-   00000000    nop
+   ????????    ldx      [o0 + 0},g2
+   ????????    ldx      [g2 + 0],o5
+   ????????    jmp      o5             <-- ra
+   ????????    nop
 
    INVOKEINTERFACE:
 
-   dc990000    ld       t9,0(a0)
-   df39ff90    ld       [g2 - 112],g2
-   df3e0018    ld       [g2 + 24],o5
-   03c0f809    jmp      o5
-   00000000    nop
+   ????????    ldx      [o0 + 0},g2
+   ????????    ldx      [g2 - 112],g2
+   ????????    ldx      [g2 + 24],o5
+   ????????    jmp      o5             <-- ra
+   ????????    nop
 
 *******************************************************************************/
 
 u1 *md_get_method_patch_address(u1 *ra, stackframeinfo *sfi, u1 *mptr)
 {
-       u4  mcode, mcode_masked;
+       u4  mcode, mcode_sethi, mcode_masked;
        s4  offset;
-       u1 *pa;
+       u1 *pa, *iptr;
 
-       /* go back to the actual load instruction (1 instruction before jump) */
-       /* ra is the address of the jump instruction on SPARC                 */
-       ra -= 1 * 4;
+       /* go back to the location of a possible sethi (3 instruction before jump) */
+       /* note: ra is the address of the jump instruction on SPARC                */
 
-       /* get first instruction word on current PC */
+       mcode_sethi = *((u4 *) (ra - 3 * 4));
 
-       mcode = *((u4 *) ra);
+       /* check for sethi instruction */
 
+       if (IS_SETHI(mcode_sethi)) {
+               u4 mcode_sub, mcode_ldx;
 
-       /* check if we have 2 instructions (lui) */
+               mcode_sub = *((u4 *) (ra - 2 * 4));
+               mcode_ldx = *((u4 *) (ra - 1 * 4));
 
-       if (IS_SETHI(mcode)) {
-               /* XXX write a regression for this */
-               assert(0);
+               /* make sure the sequence of instructions is a loadhi */
+               if ((IS_SUB(mcode_sub)) && (IS_LDX_IMM(mcode_ldx)))
+               {
 
-               /* get displacement of first instruction (lui) */
 
-               offset = (s4) (mcode << 16);
+               /* get 22-bit immediate of sethi instruction */
 
-               /* get displacement of second instruction (daddiu) */
+               offset = (s4) (mcode_sethi & 0x3fffff);
+               offset = offset << 10;
+               
+               /* goto next instruction */
+               
+               /* make sure it's a sub instruction (pv - big_disp) */
+               assert(IS_SUB(mcode_sub));
+               offset = -offset;
 
-               mcode = *((u4 *) (ra + 1 * 4));
+               /* get displacement of load instruction */
 
-               assert((mcode >> 16) != 0x6739);
+               assert(IS_LDX_IMM(mcode_ldx));
 
-               offset += (s2) (mcode & 0x0000ffff);
+               offset += decode_13bit_imm(mcode_ldx);
+               
+               pa = sfi->pv + offset;
 
-       } else {
+               return pa;
+               }
+       }
 
-               /* shift and maks rd */
+       /* we didn't find a sethi, or it didn't belong to a loadhi */
+       /* check for simple (one-instruction) load */
+       iptr = ra - 1 * 4;
+       mcode = *((u4 *) iptr);
 
-               mcode_masked = (mcode >> 13) & 0x060fff;
-               
-               /* get the offset from the instruction */
+       /* shift and mask rd */
 
-               offset = decode_13bit_imm(mcode);
+       mcode_masked = (mcode >> 13) & 0x060fff;
+       
+       /* get the offset from the instruction */
 
-               /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
+       offset = decode_13bit_imm(mcode);
 
-               if (mcode_masked == 0x0602c5) {
-                       /* in this case we use the passed method pointer */
+       /* check for call with rs1 == REG_METHODPTR: ldx [g2+x],pv_caller */
 
-                       pa = mptr + offset;
+       if (mcode_masked == 0x0602c5) {
+               /* in this case we use the passed method pointer */
 
-               } else {
-                       /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
+               /* return NULL if no mptr was specified (used for replacement) */
 
-                       assert(mcode_masked  == 0x0602fb);
+               if (mptr == NULL)
+                       return NULL;
 
-                       printf("data segment: pv=0x%08x, offset=%d\n", sfi->pv, offset);
+               pa = mptr + offset;
 
-                       /* and get the final data segment address */
+       } else {
+               /* in the normal case we check for a `ldx [i5+x],pv_caller' instruction */
 
-                       pa = sfi->pv + offset;
-               }
+               assert(mcode_masked  == 0x0602fb);
+
+               /* and get the final data segment address */
+
+               pa = sfi->pv + offset;
        }
+       
 
        return pa;
 }
@@ -307,17 +323,6 @@ void md_cacheflush(u1 *addr, s4 nbytes)
 }
 
 
-/* md_icacheflush **************************************************************
-
-   Calls the system's function to flush the instruction cache.
-
-*******************************************************************************/
-
-void md_icacheflush(u1 *addr, s4 nbytes)
-{
-       /* XXX don't know yet */        
-}
-
 /* md_dcacheflush **************************************************************
 
    Calls the system's function to flush the data cache.
@@ -327,6 +332,8 @@ void md_icacheflush(u1 *addr, s4 nbytes)
 void md_dcacheflush(u1 *addr, s4 nbytes)
 {
        /* XXX don't know yet */        
+       /* printf("md_dcacheflush\n"); */
+       __asm__ __volatile__ ( "membar 0x7F" : : : "memory" );
 }
 
 
@@ -336,18 +343,26 @@ void md_dcacheflush(u1 *addr, s4 nbytes)
 
 *******************************************************************************/
 
-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;
+       u4 mcode;
 
-       /* save the current machine code */
-       mcode = *(u4*)rp->pc;
+       if (index < 0) {
+               /* restore the patched-over instruction */
+               *(u4*)(rp->pc) = *(u4*)(savedmcode);
+       }
+       else {
+               /* save the current machine code */
+               *(u4*)(savedmcode) = *(u4*)(rp->pc);
 
-       /* write the new machine code */
-    *(u4*)(rp->pc) = (u4) rp->mcode;
+               /* build the machine code for the patch */
+               assert(0); /* XXX build trap instruction below */
+               mcode = 0;
 
-       /* store saved mcode */
-       rp->mcode = mcode;
+               /* write the new machine code */
+               *(u4*)(rp->pc) = (u4) mcode;
+       }
        
 #if !defined(NDEBUG) && defined(ENABLE_DISASSEMBLER)
        {
@@ -360,6 +375,7 @@ void md_patch_replacement_point(rplpoint *rp)
        /* flush instruction cache */
     /* md_icacheflush(rp->pc,4); */
 }
+#endif /* defined(ENABLE_REPLACEMENT) */
 
 /*
  * These are local overrides for various environment variables in Emacs.