* src/vm/jit/code.c (code_get_stack_frame_size): Implement stack alignment
[cacao.git] / src / vm / jit / mips / codegen.c
index 54f57a2994ae4d92142ed2e059218f573901885e..19fa69dd6998ce433d3767f39a78422f69279d8a 100644 (file)
@@ -35,7 +35,7 @@
    This module generates MIPS machine code for a sequence of
    intermediate code commands (ICMDs).
 
-   $Id: codegen.c 4530 2006-02-21 09:11:53Z twisti $
+   $Id: codegen.c 4654 2006-03-19 19:46:11Z edwin $
 
 */
 
@@ -66,6 +66,7 @@
 #include "vm/jit/jit.h"
 #include "vm/jit/patcher.h"
 #include "vm/jit/reg.h"
+#include "vm/jit/replace.h"
 
 #if defined(ENABLE_LSRA)
 # include "vm/jit/allocator/lsra.h"
@@ -93,6 +94,7 @@ bool codegen(methodinfo *m, codegendata *cd, registerdata *rd)
        methodinfo         *lm;             /* local methodinfo for ICMD_INVOKE*  */
        builtintable_entry *bte;
        methoddesc         *md;
+       rplpoint           *replacementpoint;
 
        {
        s4 i, p, t, l;
@@ -236,7 +238,7 @@ bool codegen(methodinfo *m, codegendata *cd, registerdata *rd)
 
                s1 = rd->memuse;
 
-               if (runverbose) {
+               if (opt_verbosecall) {
                        M_LDA(REG_SP, REG_SP, -(INT_ARG_CNT + FLT_ARG_CNT) * 8);
 
                        for (p = 0; p < INT_ARG_CNT; p++)
@@ -260,14 +262,14 @@ bool codegen(methodinfo *m, codegendata *cd, registerdata *rd)
 
                } else {
                        M_BEQZ(rd->argintregs[0], 0);
-                       codegen_addxnullrefs(cd, mcodeptr);
+                       codegen_add_nullpointerexception_ref(cd, mcodeptr);
                        p = dseg_addaddress(cd, BUILTIN_monitorenter);
                        M_ALD(REG_ITMP3, REG_PV, p);
                        M_JSR(REG_RA, REG_ITMP3);
                        M_AST(rd->argintregs[0], REG_SP, s1 * 8);         /* branch delay */
                }
 
-               if (runverbose) {
+               if (opt_verbosecall) {
                        for (p = 0; p < INT_ARG_CNT; p++)
                                M_LLD(rd->argintregs[p], REG_SP, p * 8);
 
@@ -282,7 +284,7 @@ bool codegen(methodinfo *m, codegendata *cd, registerdata *rd)
 
        /* copy argument registers to stack and call trace function */
 
-       if (runverbose) {
+       if (opt_verbosecall) {
                M_LDA(REG_SP, REG_SP, -(2 + INT_ARG_CNT + FLT_ARG_CNT + INT_TMP_CNT + FLT_TMP_CNT) * 8);
                M_AST(REG_RA, REG_SP, 1 * 8);
 
@@ -371,10 +373,30 @@ bool codegen(methodinfo *m, codegendata *cd, registerdata *rd)
 
        /* end of header generation */
 
+       replacementpoint = cd->code->rplpoints;
+
        /* walk through all basic blocks */
 
        for (bptr = m->basicblocks; bptr != NULL; bptr = bptr->next) {
 
+               /* handle replacement points */
+
+               if (bptr->bitflags & BBFLAG_REPLACEMENT && bptr->flags >= BBREACHED) {
+
+                       /* 8-byte align pc */
+                       if ((ptrint)mcodeptr & 4) {
+                               M_NOP;
+                       }
+                       
+                       replacementpoint->pc = (u1*)(ptrint)((u1*)mcodeptr - cd->mcodebase);
+                       replacementpoint++;
+
+                       assert(cd->lastmcodeptr <= (u1*)mcodeptr);
+                       cd->lastmcodeptr = (u1*)cd->mcodeptr + 2*4; /* br + delay slot */
+               }
+
+               /* store relative start of block */
+
                bptr->mpc = (s4) ((u1 *) mcodeptr - cd->mcodebase);
 
                if (bptr->flags >= BBREACHED) {
@@ -472,7 +494,7 @@ bool codegen(methodinfo *m, codegendata *cd, registerdata *rd)
 
                        var_to_reg_int(s1, src, REG_ITMP1);
                        M_BEQZ(s1, 0);
-                       codegen_addxnullrefs(cd, mcodeptr);
+                       codegen_add_nullpointerexception_ref(cd, mcodeptr);
                        M_NOP;
                        break;
 
@@ -1745,7 +1767,7 @@ bool codegen(methodinfo *m, codegendata *cd, registerdata *rd)
                        M_NOP;
 
                        M_BEQZ(REG_RESULT, 0);
-                       codegen_addxstorerefs(cd, mcodeptr);
+                       codegen_add_arraystoreexception_ref(cd, mcodeptr);
                        M_NOP;
 
                        var_to_reg_int(s1, src->prev->prev, REG_ITMP1);
@@ -2743,7 +2765,7 @@ nowperformreturn:
                        
                        /* call trace function */
 
-                       if (runverbose) {
+                       if (opt_verbosecall) {
                                M_LDA(REG_SP, REG_SP, -3 * 8);
                                M_LST(REG_RA, REG_SP, 0 * 8);
                                M_LST(REG_RESULT, REG_SP, 1 * 8);
@@ -3008,14 +3030,14 @@ gen_method:
 
                                if (iptr->op1 == true) {
                                        M_BEQZ(REG_RESULT, 0);
-                                       codegen_addxexceptionrefs(cd, mcodeptr);
+                                       codegen_add_fillinstacktrace_ref(cd, mcodeptr);
                                        M_NOP;
                                }
                                break;
 
                        case ICMD_INVOKESPECIAL:
                                M_BEQZ(rd->argintregs[0], 0);
-                               codegen_addxnullrefs(cd, mcodeptr);
+                               codegen_add_nullpointerexception_ref(cd, mcodeptr);
                                M_NOP;
                                /* fall through */
 
@@ -3227,13 +3249,13 @@ gen_method:
                                        M_ILD(REG_ITMP3, REG_ITMP2, OFFSET(vftbl_t, interfacetablelength));
                                        M_IADD_IMM(REG_ITMP3, -superindex, REG_ITMP3);
                                        M_BLEZ(REG_ITMP3, 0);
-                                       codegen_addxcastrefs(cd, mcodeptr);
+                                       codegen_add_classcastexception_ref(cd, mcodeptr);
                                        M_NOP;
                                        M_ALD(REG_ITMP3, REG_ITMP2,
                                                  OFFSET(vftbl_t, interfacetable[0]) -
                                                  superindex * sizeof(methodptr*));
                                        M_BEQZ(REG_ITMP3, 0);
-                                       codegen_addxcastrefs(cd, mcodeptr);
+                                       codegen_add_classcastexception_ref(cd, mcodeptr);
                                        M_NOP;
 
                                        if (!super) {
@@ -3286,7 +3308,7 @@ gen_method:
                                        /*                              } */
                                        M_CMPULT(REG_ITMP3, REG_ITMP2, REG_ITMP3);
                                        M_BNEZ(REG_ITMP3, 0);
-                                       codegen_addxcastrefs(cd, mcodeptr);
+                                       codegen_add_classcastexception_ref(cd, mcodeptr);
                                        M_NOP;
                                }
                                d = reg_of_var(rd, iptr->dst, s1);
@@ -3315,7 +3337,7 @@ gen_method:
                                M_NOP;
 
                                M_BEQZ(REG_RESULT, 0);
-                               codegen_addxcastrefs(cd, mcodeptr);
+                               codegen_add_classcastexception_ref(cd, mcodeptr);
                                M_NOP;
 
                                var_to_reg_int(s1, src, REG_ITMP1);
@@ -3532,7 +3554,7 @@ gen_method:
                        /* check for exception before result assignment */
 
                        M_BEQZ(REG_RESULT, 0);
-                       codegen_addxexceptionrefs(cd, mcodeptr);
+                       codegen_add_fillinstacktrace_ref(cd, mcodeptr);
                        M_NOP;
 
                        d = reg_of_var(rd, iptr->dst, REG_RESULT);
@@ -3597,6 +3619,7 @@ gen_method:
 
        dseg_createlinenumbertable(cd);
 
+#if 0
        {
        s4        *xcodeptr;
        branchref *bref;
@@ -3918,36 +3941,112 @@ gen_method:
                        M_NOP;
                }
        }
+#endif
 
-       /* generate patcher stub call code */
+
+       /* generate exception and patcher stubs */
 
        {
-               patchref *pref;
-               u8        mcode;
-               s4       *tmpmcodeptr;
+               exceptionref *eref;
+               patchref     *pref;
+               u8            mcode;
+               s4           *savedmcodeptr;
+               s4           *tmpmcodeptr;
+
+               savedmcodeptr = NULL;
+
+               /* generate exception stubs */
+
+               for (eref = cd->exceptionrefs; eref != NULL; eref = eref->next) {
+                       gen_resolvebranch((u1 *) cd->mcodebase + eref->branchpos, 
+                                                         eref->branchpos,
+                                                         (u1 *) mcodeptr - cd->mcodebase);
+
+                       MCODECHECK(100);
+
+                       /* Check if the exception is an
+                          ArrayIndexOutOfBoundsException.  If so, move index register
+                          into REG_ITMP1. */
+
+                       if (eref->reg != -1)
+                               M_MOV(eref->reg, REG_ITMP1);
+
+                       /* calcuate exception address */
+
+                       M_LDA(REG_ITMP2_XPC, REG_PV, eref->branchpos - 4);
+
+                       /* move function to call into REG_ITMP3 */
+
+                       disp = dseg_addaddress(cd, eref->function);
+                       M_ALD(REG_ITMP3, REG_PV, disp);
+
+                       if (savedmcodeptr != NULL) {
+                               M_BR(savedmcodeptr - mcodeptr);
+                               M_NOP;
+
+                       } else {
+                               savedmcodeptr = mcodeptr;
+
+                               M_MOV(REG_PV, rd->argintregs[0]);
+                               M_MOV(REG_SP, rd->argintregs[1]);
+
+                               if (m->isleafmethod)
+                                       M_MOV(REG_RA, rd->argintregs[2]);
+                               else
+                                       M_ALD(rd->argintregs[2],
+                                                 REG_SP, parentargs_base * 8 - SIZEOF_VOID_P);
+
+                               M_MOV(REG_ITMP2_XPC, rd->argintregs[3]);
+                               M_MOV(REG_ITMP1, rd->argintregs[4]);
+
+                               M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
+                               M_AST(REG_ITMP2_XPC, REG_SP, 0 * 8);
+
+                               if (m->isleafmethod)
+                                       M_AST(REG_RA, REG_SP, 1 * 8);
+
+                               M_JSR(REG_RA, REG_ITMP3);
+                               M_NOP;
+                               M_MOV(REG_RESULT, REG_ITMP1_XPTR);
+
+                               if (m->isleafmethod)
+                                       M_ALD(REG_RA, REG_SP, 1 * 8);
+
+                               M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8);
+                               M_AADD_IMM(REG_SP, 2 * 8, REG_SP);
+
+                               a = dseg_addaddress(cd, asm_handle_exception);
+                               M_ALD(REG_ITMP3, REG_PV, a);
+                               M_JMP(REG_ITMP3);
+                               M_NOP;
+                       }
+               }
+
+
+               /* generate code patching stub call code */
 
                for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
                        /* check code segment size */
 
                        MCODECHECK(100);
 
-                       /* Get machine code which is patched back in later. The call is   */
-                       /* 2 instruction words long.                                      */
+                       /* Get machine code which is patched back in later. The
+                          call is 2 instruction words long. */
 
-                       xcodeptr = (s4 *) (cd->mcodebase + pref->branchpos);
+                       tmpmcodeptr = (s4 *) (cd->mcodebase + pref->branchpos);
 
-                       /* We need to split this, because an unaligned 8 byte read causes */
-                       /* a SIGSEGV.                                                     */
+                       /* We need to split this, because an unaligned 8 byte read
+                          causes a SIGSEGV. */
 
-                       mcode = ((u8) xcodeptr[1] << 32) + (u4) xcodeptr[0];
+                       mcode = ((u8) tmpmcodeptr[1] << 32) + (u4) tmpmcodeptr[0];
 
-                       /* patch in the call to call the following code (done at compile  */
-                       /* time)                                                          */
+                       /* Patch in the call to call the following code (done at
+                          compile time). */
 
-                       tmpmcodeptr = mcodeptr;         /* save current mcodeptr          */
-                       mcodeptr = xcodeptr;            /* set mcodeptr to patch position */
+                       savedmcodeptr = mcodeptr;       /* save current mcodeptr          */
+                       mcodeptr      = tmpmcodeptr;    /* set mcodeptr to patch position */
 
-                       disp = (s4) (tmpmcodeptr - (xcodeptr + 1));
+                       disp = (s4) (savedmcodeptr - (tmpmcodeptr + 1));
 
                        if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) {
                                *exceptionptr =
@@ -3959,7 +4058,7 @@ gen_method:
                        M_BR(disp);
                        M_NOP;
 
-                       mcodeptr = tmpmcodeptr;         /* restore the current mcodeptr   */
+                       mcodeptr = savedmcodeptr;       /* restore the current mcodeptr   */
 
                        /* create stack frame */
 
@@ -4013,12 +4112,62 @@ gen_method:
                        M_JMP(REG_ITMP3);
                        M_NOP;
                }
-       }
+
+               /* generate replacement-out stubs */
+
+               {
+                       int i;
+
+                       replacementpoint = cd->code->rplpoints;
+                       for (i=0; i<cd->code->rplpointcount; ++i, ++replacementpoint) {
+                               /* check code segment size */
+
+                               MCODECHECK(100);
+
+                               /* note start of stub code */
+
+                               replacementpoint->outcode = (u1*) (ptrint)((u1*)mcodeptr - cd->mcodebase);
+
+                               /* make machine code for patching */
+
+                               tmpmcodeptr = mcodeptr;
+                               mcodeptr = (s4*) &(replacementpoint->mcode);
+
+                               disp = (ptrint)((s4*)replacementpoint->outcode - (s4*)replacementpoint->pc) - 1;
+                               if ((disp < (s4) 0xffff8000) || (disp > (s4) 0x00007fff)) {
+                                       *exceptionptr =
+                                               new_internalerror("Jump offset is out of range: %d > +/-%d",
+                                                               disp, 0x00007fff);
+                                       return false;
+                               }
+                               M_BR(disp);
+                               M_NOP; /* delay slot */
+
+                               mcodeptr = tmpmcodeptr;
+
+                               /* create stack frame - 16-byte aligned */
+
+                               M_ASUB_IMM(REG_SP, 2 * 8, REG_SP);
+
+                               /* push address of `rplpoint` struct */
+
+                               disp = dseg_addaddress(cd, replacementpoint);
+                               M_ALD(REG_ITMP3, REG_PV, disp);
+                               M_AST(REG_ITMP3, REG_SP, 0 * 8);
+
+                               /* jump to replacement function */
+
+                               disp = dseg_addaddress(cd, asm_replacement_out);
+                               M_ALD(REG_ITMP3, REG_PV, disp);
+                               M_JMP(REG_ITMP3);
+                               M_NOP; /* delay slot */
+                       }
+               }
        }
 
        codegen_finish(m, cd, (s4) ((u1 *) mcodeptr - cd->mcodebase));
 
-       docacheflush((void *) m->entrypoint, ((u1 *) mcodeptr - cd->mcodebase));
+       docacheflush((void *) cd->code->entrypoint, ((u1 *) mcodeptr - cd->mcodebase));
 
        /* everything's ok */
 
@@ -4139,7 +4288,7 @@ u1 *createnativestub(functionptr f, methodinfo *m, codegendata *cd,
 
        /* call trace function */
 
-       if (runverbose) {
+       if (opt_verbosecall) {
                M_LDA(REG_SP, REG_SP, -(1 + INT_ARG_CNT + FLT_ARG_CNT) * 8);
 
                /* save integer argument registers */
@@ -4335,7 +4484,7 @@ u1 *createnativestub(functionptr f, methodinfo *m, codegendata *cd,
 
        /* call finished trace function */
 
-       if (runverbose) {
+       if (opt_verbosecall) {
                if (IS_INT_LNG_TYPE(md->returntype.type))
                        M_LLD(REG_RESULT, REG_SP, 0 * 8);
                else
@@ -4398,31 +4547,31 @@ u1 *createnativestub(functionptr f, methodinfo *m, codegendata *cd,
 
        {
                patchref *pref;
-               s4       *xcodeptr;
-               s8        mcode;
+               u8        mcode;
+               s4       *savedmcodeptr;
                s4       *tmpmcodeptr;
 
                for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
-                       /* Get machine code which is patched back in later. The call is   */
-                       /* 2 instruction words long.                                      */
+                       /* Get machine code which is patched back in later. The
+                          call is 2 instruction words long. */
 
-                       xcodeptr = (s4 *) (cd->mcodebase + pref->branchpos);
+                       tmpmcodeptr = (s4 *) (cd->mcodebase + pref->branchpos);
 
-                       /* We need to split this, because an unaligned 8 byte read causes */
-                       /* a SIGSEGV.                                                     */
+                       /* We need to split this, because an unaligned 8 byte read
+                          causes a SIGSEGV. */
 
-                       mcode = ((u8) xcodeptr[1] << 32) + (u4) xcodeptr[0];
+                       mcode = ((u8) tmpmcodeptr[1] << 32) + (u4) tmpmcodeptr[0];
 
-                       /* patch in the call to call the following code (done at compile  */
-                       /* time)                                                          */
+                       /* Patch in the call to call the following code (done at
+                          compile time). */
 
-                       tmpmcodeptr = mcodeptr;         /* save current mcodeptr          */
-                       mcodeptr = xcodeptr;            /* set mcodeptr to patch position */
+                       savedmcodeptr = mcodeptr;       /* save current mcodeptr          */
+                       mcodeptr      = tmpmcodeptr;    /* set mcodeptr to patch position */
 
-                       M_BRS(tmpmcodeptr - (xcodeptr + 1));
+                       M_BRS(savedmcodeptr - (tmpmcodeptr + 1));
                        M_NOP;                          /* branch delay slot              */
 
-                       mcodeptr = tmpmcodeptr;         /* restore the current mcodeptr   */
+                       mcodeptr = savedmcodeptr;       /* restore the current mcodeptr   */
 
                        /* create stack frame                                             */
 
@@ -4479,9 +4628,9 @@ u1 *createnativestub(functionptr f, methodinfo *m, codegendata *cd,
 
        codegen_finish(m, cd, (s4) ((u1 *) mcodeptr - cd->mcodebase));
 
-       docacheflush((void *) m->entrypoint, ((u1 *) mcodeptr - cd->mcodebase));
+       docacheflush((void *) cd->code->entrypoint, ((u1 *) mcodeptr - cd->mcodebase));
 
-       return m->entrypoint;
+       return cd->code->entrypoint;
 }
 
 
@@ -4496,4 +4645,5 @@ u1 *createnativestub(functionptr f, methodinfo *m, codegendata *cd,
  * c-basic-offset: 4
  * tab-width: 4
  * End:
+ * vim:noexpandtab:sw=4:ts=4:
  */