* Merged in twisti-branch.
[cacao.git] / src / vm / jit / arm / emit.c
index 67ae44c6f402ef65284ed182e53c25901bf7f8ea..7bcb3e7543d5b3e27a54b24c9d998bf80501a230 100644 (file)
@@ -44,6 +44,7 @@
 #endif
 
 #include "vm/builtin.h"
+#include "vm/exceptions.h"
 #include "vm/global.h"
 
 #include "vm/jit/asmpart.h"
@@ -338,6 +339,101 @@ void emit_iconst(codegendata *cd, s4 d, s4 value)
 }
 
 
+/* emit_branch *****************************************************************
+
+   Emits the code for conditional and unconditional branchs.
+
+*******************************************************************************/
+
+void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
+{
+       s4 checkdisp;
+       s4 branchdisp;
+
+       /* calculate the different displacements */
+
+       checkdisp  = (disp - 8);
+       branchdisp = (disp - 8) >> 2;
+
+       /* check which branch to generate */
+
+       if (condition == BRANCH_UNCONDITIONAL) {
+               /* check displacement for overflow */
+
+               if ((checkdisp < (s4) 0xff000000) || (checkdisp > (s4) 0x00ffffff)) {
+                       /* if the long-branches flag isn't set yet, do it */
+
+                       if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
+                               cd->flags |= (CODEGENDATA_FLAG_ERROR |
+                                                         CODEGENDATA_FLAG_LONGBRANCHES);
+                       }
+
+                       vm_abort("emit_branch: emit unconditional long-branch code");
+               }
+               else {
+                       M_B(branchdisp);
+               }
+       }
+       else {
+               /* and displacement for overflow */
+
+               if ((checkdisp < (s4) 0xff000000) || (checkdisp > (s4) 0x00ffffff)) {
+                       /* if the long-branches flag isn't set yet, do it */
+
+                       if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
+                               cd->flags |= (CODEGENDATA_FLAG_ERROR |
+                                                         CODEGENDATA_FLAG_LONGBRANCHES);
+                       }
+
+                       vm_abort("emit_branch: emit conditional long-branch code");
+               }
+               else {
+                       switch (condition) {
+                       case BRANCH_EQ:
+                               M_BEQ(branchdisp);
+                               break;
+                       case BRANCH_NE:
+                               M_BNE(branchdisp);
+                               break;
+                       case BRANCH_LT:
+                               M_BLT(branchdisp);
+                               break;
+                       case BRANCH_GE:
+                               M_BGE(branchdisp);
+                               break;
+                       case BRANCH_GT:
+                               M_BGT(branchdisp);
+                               break;
+                       case BRANCH_LE:
+                               M_BLE(branchdisp);
+                               break;
+                       case BRANCH_UGT:
+                               M_BHI(branchdisp);
+                               break;
+                       default:
+                               vm_abort("emit_branch: unknown condition %d", condition);
+                       }
+               }
+       }
+}
+
+
+/* emit_arithmetic_check *******************************************************
+
+   Emit an ArithmeticException check.
+
+*******************************************************************************/
+
+void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               CHECK_INT_REG(reg);
+               M_TEQ_IMM(reg, 0);
+               M_TRAPEQ(0, EXCEPTION_HARDWARE_ARITHMETIC);
+       }
+}
+
+
 /* emit_nullpointer_check ******************************************************
 
    Emit a NullPointerException check.
@@ -348,11 +444,16 @@ void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
 {
        if (INSTRUCTION_MUST_CHECK(iptr)) {
                M_TST(reg, reg);
-               M_BEQ(0);
-               codegen_add_nullpointerexception_ref(cd);
+               M_TRAPEQ(0, EXCEPTION_HARDWARE_NULLPOINTER);
        }
 }
 
+void emit_nullpointer_check_force(codegendata *cd, instruction *iptr, s4 reg)
+{
+       M_TST(reg, reg);
+       M_TRAPEQ(0, EXCEPTION_HARDWARE_NULLPOINTER);
+}
+
 
 /* emit_arrayindexoutofbounds_check ********************************************
 
@@ -365,8 +466,50 @@ void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1,
        if (INSTRUCTION_MUST_CHECK(iptr)) {
                M_ILD_INTERN(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
                M_CMP(s2, REG_ITMP3);
-               M_BHS(0);
-               codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
+               M_TRAPHS(s2, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
+       }
+}
+
+
+/* emit_classcast_check ********************************************************
+
+   Emit a ClassCastException check.
+
+*******************************************************************************/
+
+void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               switch (condition) {
+               case BRANCH_EQ:
+                       M_TRAPEQ(s1, EXCEPTION_HARDWARE_CLASSCAST);
+                       break;
+
+               case BRANCH_LE:
+                       M_TRAPLE(s1, EXCEPTION_HARDWARE_CLASSCAST);
+                       break;
+
+               case BRANCH_UGT:
+                       M_TRAPHI(s1, EXCEPTION_HARDWARE_CLASSCAST);
+                       break;
+
+               default:
+                       vm_abort("emit_classcast_check: unknown condition %d", condition);
+               }
+       }
+}
+
+/* emit_exception_check ********************************************************
+
+   Emit an Exception check.
+
+*******************************************************************************/
+
+void emit_exception_check(codegendata *cd, instruction *iptr)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TST(REG_RESULT, REG_RESULT);
+               M_TRAPEQ(0, EXCEPTION_HARDWARE_EXCEPTION);
        }
 }
 
@@ -377,6 +520,7 @@ void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1,
 
 *******************************************************************************/
 
+#if 0
 void emit_exception_stubs(jitdata *jd)
 {
        codegendata  *cd;
@@ -399,7 +543,7 @@ void emit_exception_stubs(jitdata *jd)
        for (er = cd->exceptionrefs; er != NULL; er = er->next) {
                /* back-patch the branch to this exception code */
 
-               branchmpc = er->branchpos;
+               branchmpc = er->branchmpc;
                targetmpc = cd->mcodeptr - cd->mcodebase;
 
                md_codegen_patch_branch(cd, branchmpc, targetmpc);
@@ -415,8 +559,8 @@ void emit_exception_stubs(jitdata *jd)
 
                /* calcuate exception address */
 
-               assert((er->branchpos - 4) % 4 == 0);
-               M_ADD_IMM_EXT_MUL4(REG_ITMP2_XPC, REG_IP, (er->branchpos - 4) / 4);
+               assert((er->branchmpc - 4) % 4 == 0);
+               M_ADD_IMM_EXT_MUL4(REG_ITMP2_XPC, REG_PV, (er->branchmpc - 4) / 4);
 
                /* move function to call into REG_ITMP3 */
 
@@ -426,7 +570,7 @@ void emit_exception_stubs(jitdata *jd)
                if (targetdisp == 0) {
                        targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
 
-                       M_MOV(rd->argintregs[0], REG_IP);
+                       M_MOV(rd->argintregs[0], REG_PV);
                        M_MOV(rd->argintregs[1], REG_SP);
 
                        if (jd->isleafmethod)
@@ -440,7 +584,7 @@ void emit_exception_stubs(jitdata *jd)
                        /* save registers */
                        /* TODO: we only need to save LR in leaf methods */
 
-                       M_STMFD(BITMASK_ARGS | 1<<REG_IP | 1<<REG_LR, REG_SP);
+                       M_STMFD(BITMASK_ARGS | 1<<REG_PV | 1<<REG_LR, REG_SP);
 
                        /* move a3 to stack */
 
@@ -459,7 +603,7 @@ void emit_exception_stubs(jitdata *jd)
 
                        /* restore registers */
 
-                       M_LDMFD(BITMASK_ARGS | 1<<REG_IP | 1<<REG_LR, REG_SP);
+                       M_LDMFD(BITMASK_ARGS | 1<<REG_PV | 1<<REG_LR, REG_SP);
 
                        disp = dseg_add_functionptr(cd, asm_handle_exception);
                        M_DSEG_LOAD(REG_ITMP3, disp);
@@ -473,6 +617,7 @@ void emit_exception_stubs(jitdata *jd)
                }
        }
 }
+#endif
 
 
 /* emit_patcher_stubs **********************************************************
@@ -548,7 +693,7 @@ void emit_patcher_stubs(jitdata *jd)
                (void) dseg_add_unique_address(cd, lock_get_initial_lock_word());
                disp = dseg_add_unique_address(cd, NULL);           /* vftbl      */
 
-               M_SUB_IMM_EXT_MUL4(REG_ITMP3, REG_IP, -disp / 4);
+               M_SUB_IMM_EXT_MUL4(REG_ITMP3, REG_PV, -disp / 4);
                M_STR_INTERN(REG_ITMP3, REG_SP, 3 * 4);
 #else
                M_EOR(REG_ITMP3, REG_ITMP3, REG_ITMP3);
@@ -580,13 +725,13 @@ void emit_patcher_stubs(jitdata *jd)
                M_STR_INTERN(REG_ITMP3, REG_SP, 0 * 4);
 
                /* finally call the patcher via asm_patcher_wrapper */
-               /* ATTENTION: don't use REG_IP here, because some patchers need it */
+               /* ATTENTION: don't use REG_PV here, because some patchers need it */
 
                if (targetdisp == 0) {
                        targetdisp = ((u4 *) cd->mcodeptr) - ((u4 *) cd->mcodebase);
 
                        disp = dseg_add_functionptr(cd, asm_patcher_wrapper);
-                       /*M_DSEG_BRANCH_NOLINK(REG_PC, REG_IP, a);*/
+                       /*M_DSEG_BRANCH_NOLINK(REG_PC, REG_PV, a);*/
                        /* TODO: this is only a hack */
                        M_DSEG_LOAD(REG_ITMP3, disp);
                        M_MOV(REG_PC, REG_ITMP3);
@@ -658,11 +803,13 @@ void emit_verbosecall_enter(jitdata *jd)
 
        M_NOP;
 
-       /* save argument registers to stack (including LR and IP) */
-       M_STMFD(BITMASK_ARGS | (1<<REG_LR) | (1<<REG_IP), REG_SP);
-       M_SUB_IMM(REG_SP, REG_SP, (2 + 2 + 1) * 4);     /* space for a3, a4 and m */
+       /* Save argument registers to stack (including LR and PV).  Keep
+          stack 8-byte aligned. */
+
+       M_STMFD(BITMASK_ARGS | (1<<REG_LR) | (1<<REG_PV), REG_SP);
+       M_SUB_IMM(REG_SP, REG_SP, (2 + 2 + 1 + 1) * 4); /* space for a3, a4 and m */
 
-       stackframesize += 6 + 2 + 2 + 1;
+       stackframesize += 6 + 2 + 2 + 1 + 1;
 
        /* prepare args for tracer */
 
@@ -689,12 +836,15 @@ void emit_verbosecall_enter(jitdata *jd)
                        }
                }
                else {
-                       s1 = md->params[i].regoff + stackframesize;
+                       s1 = REG_ITMP12_PACKED;
+                       s2 = md->params[i].regoff + stackframesize;
 
                        if (IS_2_WORD_TYPE(t))
-                               M_LLD(REG_ITMP12_PACKED, REG_SP, s1 * 4);
-                       else
-                               M_ILD(REG_ITMP1, REG_SP, s1 * 4);
+                               M_LLD(s1, REG_SP, s2 * 4);
+                       else {
+                               M_ILD(GET_LOW_REG(s1), REG_SP, s2 * 4);
+                               M_MOV_IMM(GET_HIGH_REG(s1), 0);
+                       }
                }
 
                /* place argument for tracer */
@@ -721,12 +871,13 @@ void emit_verbosecall_enter(jitdata *jd)
 
        /* call tracer here (we use a long branch) */
 
-       M_LONGBRANCH(builtin_trace_args);
+       M_LONGBRANCH(builtin_verbosecall_enter);
 
-       /* restore argument registers from stack */
+       /* Restore argument registers from stack.  Keep stack 8-byte
+          aligned. */
 
-       M_ADD_IMM(REG_SP, REG_SP, (2 + 2 + 1) * 4);        /* free argument stack */
-       M_LDMFD(BITMASK_ARGS | (1<<REG_LR) | (1<<REG_IP), REG_SP);
+       M_ADD_IMM(REG_SP, REG_SP, (2 + 2 + 1 + 1) * 4);    /* free argument stack */
+       M_LDMFD(BITMASK_ARGS | (1<<REG_LR) | (1<<REG_PV), REG_SP);
 
        /* mark trace code */
 
@@ -739,6 +890,8 @@ void emit_verbosecall_enter(jitdata *jd)
 
    Generates the code for the call trace.
 
+   void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
+
 *******************************************************************************/
 
 #if !defined(NDEBUG)
@@ -762,36 +915,40 @@ void emit_verbosecall_exit(jitdata *jd)
 
        M_NOP;
 
-       M_STMFD(BITMASK_RESULT | (1<<REG_LR) | (1<<REG_IP), REG_SP);
-       M_SUB_IMM(REG_SP, REG_SP, (1 + 1) * 4);    /* space for d[high reg] and f */
+       /* Keep stack 8-byte aligned. */
+
+       M_STMFD(BITMASK_RESULT | (1<<REG_LR) | (1<<REG_PV), REG_SP);
+       M_SUB_IMM(REG_SP, REG_SP, (1 + 1) * 4);              /* space for f and m */
 
        switch (md->returntype.type) {
        case TYPE_ADR:
        case TYPE_INT:
-               M_INTMOVE(REG_RESULT, GET_LOW_REG(REG_A1_A2_PACKED));
-               M_MOV_IMM(GET_HIGH_REG(REG_A1_A2_PACKED), 0);
+               M_INTMOVE(REG_RESULT, GET_LOW_REG(REG_A0_A1_PACKED));
+               M_MOV_IMM(GET_HIGH_REG(REG_A0_A1_PACKED), 0);
                break;
 
        case TYPE_LNG:
-               M_LNGMOVE(REG_RESULT_PACKED, REG_A1_A2_PACKED);
+               M_LNGMOVE(REG_RESULT_PACKED, REG_A0_A1_PACKED);
                break;
 
        case TYPE_FLT:
-               M_IST(REG_RESULT, REG_SP, 1 * 4);
+               M_IST(REG_RESULT, REG_SP, 0 * 4);
                break;
 
        case TYPE_DBL:
-               M_INTMOVE(REG_RESULT, REG_A3);
-               M_IST(REG_RESULT2, REG_SP, 0 * 4);
+               M_LNGMOVE(REG_RESULT_PACKED, REG_A2_A3_PACKED);
                break;
        }
 
        disp = dseg_add_address(cd, m);
-       M_DSEG_LOAD(REG_A0, disp);
-       M_LONGBRANCH(builtin_displaymethodstop);
+       M_DSEG_LOAD(REG_ITMP1, disp);
+       M_AST(REG_ITMP1, REG_SP, 1 * 4);
+       M_LONGBRANCH(builtin_verbosecall_exit);
+
+       /* Keep stack 8-byte aligned. */
 
        M_ADD_IMM(REG_SP, REG_SP, (1 + 1) * 4);            /* free argument stack */
-       M_LDMFD(BITMASK_RESULT | (1<<REG_LR) | (1<<REG_IP), REG_SP);
+       M_LDMFD(BITMASK_RESULT | (1<<REG_LR) | (1<<REG_PV), REG_SP);
 
        /* mark trace code */