* src/native/llni.h: Added macros for array handling.
[cacao.git] / src / vm / jit / i386 / emit.c
index a83cc4c8a907e1ac918d334de73f1f8894b76a88..b74a2959e0f4a98aa4552975a3623d9a42a552dc 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/i386/emit.c - i386 code emitter 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
-
-   $Id: emit.c 6137 2006-12-07 22:25:42Z edwin $
+   $Id: emit.c 8318 2007-08-16 10:05:34Z michi $
 
 */
 
 #include "vm/jit/i386/emit.h"
 #include "vm/jit/i386/md-abi.h"
 
-#if defined(ENABLE_THREADS)
-# include "threads/native/lock.h"
-#endif
+#include "mm/memory.h"
+
+#include "threads/lock-common.h"
 
 #include "vm/builtin.h"
-#include "vm/options.h"
-#include "vm/statistics.h"
+#include "vm/exceptions.h"
+
+#include "vm/jit/abi.h"
 #include "vm/jit/asmpart.h"
 #include "vm/jit/dseg.h"
 #include "vm/jit/emit-common.h"
 #include "vm/jit/jit.h"
 #include "vm/jit/replace.h"
 
+#include "vmcore/options.h"
+#include "vmcore/statistics.h"
+
 
 /* emit_load ******************************************************************
 
@@ -74,19 +74,24 @@ inline s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
        if (IS_INMEMORY(src->flags)) {
                COUNT_SPILLS;
 
-               disp = src->vv.regoff * 4;
-
-               if (IS_FLT_DBL_TYPE(src->type)) {
-                       if (IS_2_WORD_TYPE(src->type))
-                               M_DLD(tempreg, REG_SP, disp);
-                       else
-                               M_FLD(tempreg, REG_SP, disp);
-               }
-               else {
-                       if (IS_2_WORD_TYPE(src->type))
-                               M_LLD(tempreg, REG_SP, disp);
-                       else
-                               M_ILD(tempreg, REG_SP, disp);
+               disp = src->vv.regoff;
+
+               switch (src->type) {
+               case TYPE_INT:
+               case TYPE_ADR:
+                       M_ILD(tempreg, REG_SP, disp);
+                       break;
+               case TYPE_LNG:
+                       M_LLD(tempreg, REG_SP, disp);
+                       break;
+               case TYPE_FLT:
+                       M_FLD(tempreg, REG_SP, disp);
+                       break;
+               case TYPE_DBL:
+                       M_DLD(tempreg, REG_SP, disp);
+                       break;
+               default:
+                       vm_abort("emit_load: unknown type %d", src->type);
                }
 
                reg = tempreg;
@@ -120,7 +125,7 @@ inline s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src,s4 tempreg)
        if (IS_INMEMORY(src->flags)) {
                COUNT_SPILLS;
 
-               disp = src->vv.regoff * 4;
+               disp = src->vv.regoff;
 
                M_ILD(tempreg, REG_SP, disp);
 
@@ -154,7 +159,7 @@ inline s4 emit_load_high(jitdata *jd, instruction *iptr,varinfo *src,s4 tempreg)
        if (IS_INMEMORY(src->flags)) {
                COUNT_SPILLS;
 
-               disp = src->vv.regoff * 4;
+               disp = src->vv.regoff;
 
                M_ILD(tempreg, REG_SP, disp + 4);
 
@@ -176,6 +181,7 @@ inline s4 emit_load_high(jitdata *jd, instruction *iptr,varinfo *src,s4 tempreg)
 inline void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
 {
        codegendata  *cd;
+       s4            disp;
 
        /* get required compiler data */
 
@@ -184,17 +190,24 @@ inline void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
        if (IS_INMEMORY(dst->flags)) {
                COUNT_SPILLS;
 
-               if (IS_FLT_DBL_TYPE(dst->type)) {
-                       if (IS_2_WORD_TYPE(dst->type))
-                               M_DST(d, REG_SP, dst->vv.regoff * 4);
-                       else
-                               M_FST(d, REG_SP, dst->vv.regoff * 4);
-               }
-               else {
-                       if (IS_2_WORD_TYPE(dst->type))
-                               M_LST(d, REG_SP, dst->vv.regoff * 4);
-                       else
-                               M_IST(d, REG_SP, dst->vv.regoff * 4);
+               disp = dst->vv.regoff;
+
+               switch (dst->type) {
+               case TYPE_INT:
+               case TYPE_ADR:
+                       M_IST(d, REG_SP, disp);
+                       break;
+               case TYPE_LNG:
+                       M_LST(d, REG_SP, disp);
+                       break;
+               case TYPE_FLT:
+                       M_FST(d, REG_SP, disp);
+                       break;
+               case TYPE_DBL:
+                       M_DST(d, REG_SP, disp);
+                       break;
+               default:
+                       vm_abort("emit_store: unknown type %d", dst->type);
                }
        }
 }
@@ -219,7 +232,7 @@ inline void emit_store_low(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
 
        if (IS_INMEMORY(dst->flags)) {
                COUNT_SPILLS;
-               M_IST(GET_LOW_REG(d), REG_SP, dst->vv.regoff * 4);
+               M_IST(GET_LOW_REG(d), REG_SP, dst->vv.regoff);
        }
 }
 
@@ -243,7 +256,7 @@ inline void emit_store_high(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
 
        if (IS_INMEMORY(dst->flags)) {
                COUNT_SPILLS;
-               M_IST(GET_HIGH_REG(d), REG_SP, dst->vv.regoff * 4 + 4);
+               M_IST(GET_HIGH_REG(d), REG_SP, dst->vv.regoff + 4);
        }
 }
 
@@ -254,18 +267,30 @@ inline void emit_store_high(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
 
 *******************************************************************************/
 
-void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
+void emit_copy(jitdata *jd, instruction *iptr)
 {
-       codegendata  *cd;
-       s4            s1, d;
+       codegendata *cd;
+       varinfo     *src;
+       varinfo     *dst;
+       s4           s1, d;
 
        /* get required compiler data */
 
        cd = jd->cd;
 
+       /* get source and destination variables */
+
+       src = VAROP(iptr->s1);
+       dst = VAROP(iptr->dst);
+
        if ((src->vv.regoff != dst->vv.regoff) ||
                ((src->flags ^ dst->flags) & INMEMORY)) {
 
+               if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
+                       /* emit nothing, as the value won't be used anyway */
+                       return;
+               }
+
                /* If one of the variables resides in memory, we can eliminate
                   the register move from/to the temporary register with the
                   order of getting the destination register and the load. */
@@ -288,13 +313,20 @@ void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
                }
 
                if (s1 != d) {
-                       if (IS_FLT_DBL_TYPE(src->type)) {
+                       switch (src->type) {
+                       case TYPE_INT:
+                       case TYPE_ADR:
+                               M_MOV(s1, d);
+                               break;
+                       case TYPE_LNG:
+                               M_LNGMOVE(s1, d);
+                               break;
+                       case TYPE_FLT:
+                       case TYPE_DBL:
 /*                             M_FMOV(s1, d); */
-                       } else {
-                               if (IS_2_WORD_TYPE(src->type))
-                                       M_LNGMOVE(s1, d);
-                               else
-                    M_MOV(s1, d);
+                               break;
+                       default:
+                               vm_abort("emit_copy: unknown type %d", src->type);
                        }
                }
 
@@ -303,18 +335,83 @@ void emit_copy(jitdata *jd, instruction *iptr, varinfo *src, varinfo *dst)
 }
 
 
+/* emit_branch *****************************************************************
+
+   Emits the code for conditional and unconditional branchs.
+
+*******************************************************************************/
+
+void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 options)
+{
+       s4 branchdisp;
+
+       /* ATTENTION: a displacement overflow cannot happen */
+
+       /* check which branch to generate */
+
+       if (condition == BRANCH_UNCONDITIONAL) {
+
+               /* calculate the different displacements */
+
+               branchdisp = disp - BRANCH_UNCONDITIONAL_SIZE;
+
+               M_JMP_IMM(branchdisp);
+       }
+       else {
+               /* calculate the different displacements */
+
+               branchdisp = disp - BRANCH_CONDITIONAL_SIZE;
+
+               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_ULT:
+                       M_BB(branchdisp);
+                       break;
+               case BRANCH_ULE:
+                       M_BBE(branchdisp);
+                       break;
+               case BRANCH_UGE:
+                       M_BAE(branchdisp);
+                       break;
+               case BRANCH_UGT:
+                       M_BA(branchdisp);
+                       break;
+               default:
+                       vm_abort("emit_branch: unknown condition %d", condition);
+               }
+       }
+}
+
+
 /* emit_arithmetic_check *******************************************************
 
    Emit an ArithmeticException check.
 
 *******************************************************************************/
 
-void emit_arithmetic_check(codegendata *cd, s4 reg)
+void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
 {
-       if (checknull) {
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
                M_TEST(reg);
-               M_BEQ(0);
-               codegen_add_arithmeticexception_ref(cd);
+               M_BNE(6);
+               M_ALD_MEM(reg, EXCEPTION_HARDWARE_ARITHMETIC);
        }
 }
 
@@ -325,13 +422,13 @@ void emit_arithmetic_check(codegendata *cd, s4 reg)
 
 *******************************************************************************/
 
-void emit_arrayindexoutofbounds_check(codegendata *cd, s4 s1, s4 s2)
+void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
 {
-       if (checkbounds) {
-        M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+        M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, size));
         M_CMP(REG_ITMP3, s2);
-        M_BAE(0);
-        codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
+        M_BB(6);
+               M_ALD_MEM(s2, EXCEPTION_HARDWARE_ARRAYINDEXOUTOFBOUNDS);
        }
 }
 
@@ -342,9 +439,24 @@ void emit_arrayindexoutofbounds_check(codegendata *cd, s4 s1, s4 s2)
 
 *******************************************************************************/
 
-void emit_classcast_check(codegendata *cd, s4 condition, s4 reg, s4 s1)
-{
-       vm_abort("IMPLEMENT ME!");
+void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               switch (condition) {
+               case BRANCH_LE:
+                       M_BGT(6);
+                       break;
+               case BRANCH_EQ:
+                       M_BNE(6);
+                       break;
+               case BRANCH_ULE:
+                       M_BBE(6);
+                       break;
+               default:
+                       vm_abort("emit_classcast_check: unknown condition %d", condition);
+               }
+               M_ALD_MEM(s1, EXCEPTION_HARDWARE_CLASSCAST);
+       }
 }
 
 
@@ -354,97 +466,28 @@ void emit_classcast_check(codegendata *cd, s4 condition, s4 reg, s4 s1)
 
 *******************************************************************************/
 
-void emit_nullpointer_check(codegendata *cd, s4 reg)
+void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
 {
-       if (checknull) {
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
                M_TEST(reg);
-               M_BEQ(0);
-               codegen_add_nullpointerexception_ref(cd);
+               M_BNE(6);
+               M_ALD_MEM(reg, EXCEPTION_HARDWARE_NULLPOINTER);
        }
 }
 
 
-/* emit_exception_stubs ********************************************************
+/* emit_exception_check ********************************************************
 
-   Generates the code for the exception stubs.
+   Emit an Exception check.
 
 *******************************************************************************/
 
-void emit_exception_stubs(jitdata *jd)
+void emit_exception_check(codegendata *cd, instruction *iptr)
 {
-       codegendata  *cd;
-       registerdata *rd;
-       exceptionref *er;
-       s4            branchmpc;
-       s4            targetmpc;
-       s4            targetdisp;
-
-       /* get required compiler data */
-
-       cd = jd->cd;
-       rd = jd->rd;
-
-       /* generate exception stubs */
-
-       targetdisp = 0;
-
-       for (er = cd->exceptionrefs; er != NULL; er = er->next) {
-               /* back-patch the branch to this exception code */
-
-               branchmpc = er->branchpos;
-               targetmpc = cd->mcodeptr - cd->mcodebase;
-
-               md_codegen_patch_branch(cd, branchmpc, targetmpc);
-
-               MCODECHECK(512);
-
-               /* Check if the exception is an
-                  ArrayIndexOutOfBoundsException.  If so, move index register
-                  into REG_ITMP1. */
-
-               if (er->reg != -1)
-                       M_INTMOVE(er->reg, REG_ITMP1);
-
-               /* calcuate exception address */
-
-               M_MOV_IMM(0, REG_ITMP2_XPC);
-               dseg_adddata(cd);
-               M_AADD_IMM32(er->branchpos - 6, REG_ITMP2_XPC);
-
-               /* move function to call into REG_ITMP3 */
-
-               M_MOV_IMM(er->function, REG_ITMP3);
-
-               if (targetdisp == 0) {
-                       targetdisp = cd->mcodeptr - cd->mcodebase;
-
-                       M_ASUB_IMM(5 * 4, REG_SP);
-
-                       /* first store REG_ITMP1 so we can use it */
-
-                       M_AST(REG_ITMP1, REG_SP, 4 * 4);                    /* for AIOOBE */
-
-                       M_AST_IMM(0, REG_SP, 0 * 4);
-                       dseg_adddata(cd);
-                       M_MOV(REG_SP, REG_ITMP1);
-                       M_AADD_IMM(5 * 4, REG_ITMP1);
-                       M_AST(REG_ITMP1, REG_SP, 1 * 4);
-                       M_ALD(REG_ITMP1, REG_SP, (5 + cd->stackframesize) * 4);
-                       M_AST(REG_ITMP1, REG_SP, 2 * 4);
-                       M_AST(REG_ITMP2_XPC, REG_SP, 3 * 4);
-
-                       M_CALL(REG_ITMP3);
-
-                       M_ALD(REG_ITMP2_XPC, REG_SP, 3 * 4);
-                       M_AADD_IMM(5 * 4, REG_SP);
-
-                       M_MOV_IMM(asm_handle_exception, REG_ITMP3);
-                       M_JMP(REG_ITMP3);
-               }
-               else {
-                       M_JMP_IMM((cd->mcodebase + targetdisp) -
-                                         (cd->mcodeptr + PATCHER_CALL_SIZE));
-               }
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TEST(REG_RESULT);
+               M_BNE(6);
+               M_ALD_MEM(REG_RESULT, EXCEPTION_HARDWARE_EXCEPTION);
        }
 }
 
@@ -533,63 +576,26 @@ void emit_patcher_stubs(jitdata *jd)
 }
 
 
-/* emit_replacement_stubs ******************************************************
+/* emit_trap *******************************************************************
 
-   Generates the code for the replacement stubs.
+   Emit a trap instruction and return the original machine code.
 
 *******************************************************************************/
 
-void emit_replacement_stubs(jitdata *jd)
+uint32_t emit_trap(codegendata *cd)
 {
-       codegendata *cd;
-       codeinfo    *code;
-       rplpoint    *rplp;
-       s4           disp;
-       s4           i;
-#if !defined(NDEBUG)
-       u1          *savedmcodeptr;
-#endif
-
-       /* get required compiler data */
+       uint32_t mcode;
 
-       cd   = jd->cd;
-       code = jd->code;
+       /* Get machine code which is patched back in later. The
+          trap is 1 instruction word long. */
 
-       rplp = code->rplpoints;
+       mcode = *((uint32_t *) cd->mcodeptr);
 
-       /* store beginning of replacement stubs */
-
-       code->replacementstubs = (u1*) (cd->mcodeptr - cd->mcodebase);
-
-       for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
-               /* do not generate stubs for non-trappable points */
-
-               if (rplp->flags & RPLPOINT_FLAG_NOTRAP)
-                       continue;
-
-               /* check code segment size */
-
-               MCODECHECK(512);
-
-               /* note start of stub code */
-
-#if !defined(NDEBUG)
-               savedmcodeptr = cd->mcodeptr;
-#endif
-
-               /* push address of `rplpoint` struct */
-                       
-               M_PUSH_IMM(rplp);
-
-               /* jump to replacement function */
-
-               M_PUSH_IMM(asm_replacement_out);
-               M_RET;
+       M_NOP;
 
-               assert((cd->mcodeptr - savedmcodeptr) == REPLACEMENT_STUB_SIZE);
-       }
+       return mcode;
 }
-       
+
 
 /* emit_verbosecall_enter ******************************************************
 
@@ -604,8 +610,9 @@ void emit_verbosecall_enter(jitdata *jd)
        codegendata  *cd;
        registerdata *rd;
        methoddesc   *md;
-       s4            disp;
-       s4            i, t;
+       int32_t       disp;
+       int           i;
+       int           d;
 
        if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
                return;
@@ -624,61 +631,60 @@ void emit_verbosecall_enter(jitdata *jd)
 
        /* methodinfo* + arguments + return address */
 
-       disp = TRACE_ARGS_NUM * 8 + 4 + INT_TMP_CNT * 4 +
-               cd->stackframesize * 4 + 4;
+       disp = (TRACE_ARGS_NUM + 1 + TMP_CNT) * 8 + cd->stackframesize * 8 + 4;
 
-       M_ASUB_IMM(TRACE_ARGS_NUM * 8 + 4 + INT_TMP_CNT * 4, REG_SP);
+       M_ASUB_IMM((TRACE_ARGS_NUM + 1 + TMP_CNT) * 8, REG_SP);
 
        /* save temporary registers for leaf methods */
 
        for (i = 0; i < INT_TMP_CNT; i++)
-               M_IST(rd->tmpintregs[i], REG_SP, TRACE_ARGS_NUM * 8 + 4 + i * 4);
-
-       for (i = 0; i < md->paramcount && i < TRACE_ARGS_NUM; i++) {
-               t = md->paramtypes[i].type;
-
-               if (IS_INT_LNG_TYPE(t)) {
-                       if (IS_2_WORD_TYPE(t)) {
-                               M_LLD(REG_ITMP12_PACKED, REG_SP, disp);
-                               M_LST(REG_ITMP12_PACKED, REG_SP, i * 8);
-                       }
-                       else if (IS_ADR_TYPE(t)) {
-                               M_ALD(REG_ITMP1, REG_SP, disp);
-                               M_AST(REG_ITMP1, REG_SP, i * 8);
-                               M_IST_IMM(0, REG_SP, i * 8 + 4);
-                       }
-                       else {
-                               M_ILD(EAX, REG_SP, disp);
-                               emit_cltd(cd);
-                               M_LST(EAX_EDX_PACKED, REG_SP, i * 8);
-                       }
-               }
-               else {
-                       if (IS_2_WORD_TYPE(t)) {
-                               M_DLD(REG_NULL, REG_SP, disp);
-                               M_DST(REG_NULL, REG_SP, i * 8);
-                       }
-                       else {
-                               M_FLD(REG_NULL, REG_SP, disp);
-                               M_FST(REG_NULL, REG_SP, i * 8);
-                               M_IST_IMM(0, REG_SP, i * 8 + 4);
-                       }
+               M_IST(rd->tmpintregs[i], REG_SP, (TRACE_ARGS_NUM + 1 + i) * 8);
+
+       /* save argument registers */
+
+       for (i = 0; i < md->paramcount; i++) {
+               d = i * 8;
+
+               switch (md->paramtypes[i].type) {
+               case TYPE_INT:
+                       M_ILD(EAX, REG_SP, disp);
+                       emit_cltd(cd);
+                       M_LST(EAX_EDX_PACKED, REG_SP, d);
+                       break;
+               case TYPE_LNG:
+                       M_LLD(REG_ITMP12_PACKED, REG_SP, disp);
+                       M_LST(REG_ITMP12_PACKED, REG_SP, d);
+                       break;
+               case TYPE_ADR:
+                       M_ALD(REG_ITMP1, REG_SP, disp);
+                       M_AST(REG_ITMP1, REG_SP, d);
+                       M_IST_IMM(0, REG_SP, d + 4);                /* high-bits are zero */
+                       break;
+               case TYPE_FLT:
+                       M_FLD(REG_NULL, REG_SP, disp);
+                       M_FST(REG_NULL, REG_SP, d);
+                       M_IST_IMM(0, REG_SP, d + 4);                /* high-bits are zero */
+                       break;
+               case TYPE_DBL:
+                       M_DLD(REG_NULL, REG_SP, disp);
+                       M_DST(REG_NULL, REG_SP, d);
+                       break;
                }
 
-               disp += (IS_2_WORD_TYPE(t)) ? 8 : 4;
+               disp += 8;
        }
-       
+
        M_AST_IMM(m, REG_SP, TRACE_ARGS_NUM * 8);
 
-       M_MOV_IMM(builtin_trace_args, REG_ITMP1);
+       M_MOV_IMM(builtin_verbosecall_enter, REG_ITMP1);
        M_CALL(REG_ITMP1);
 
        /* restore temporary registers for leaf methods */
 
        for (i = 0; i < INT_TMP_CNT; i++)
-               M_ILD(rd->tmpintregs[i], REG_SP, TRACE_ARGS_NUM * 8 + 4 + i * 4);
+               M_ILD(rd->tmpintregs[i], REG_SP, (TRACE_ARGS_NUM + 1 + i) * 8);
 
-       M_AADD_IMM(TRACE_ARGS_NUM * 8 + 4 + INT_TMP_CNT * 4, REG_SP);
+       M_AADD_IMM((TRACE_ARGS_NUM + 1 + TMP_CNT) * 8, REG_SP);
 
        /* mark trace code */
 
@@ -691,6 +697,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)
@@ -713,21 +721,21 @@ void emit_verbosecall_exit(jitdata *jd)
 
        M_NOP;
 
-       M_ASUB_IMM(4 + 8 + 8 + 4 + 8, REG_SP);  /* +8: keep stack 16-byte aligned */
+       M_ASUB_IMM(8 + 8 + 4 + 4 + 8, REG_SP);  /* +8: keep stack 16-byte aligned */
 
-       M_AST_IMM(m, REG_SP, 0 * 4);
+       M_LST(REG_RESULT_PACKED, REG_SP, 0 * 8);
 
-       M_LST(REG_RESULT_PACKED, REG_SP, 1 * 4);
+       M_DSTNP(REG_NULL, REG_SP, 1 * 8);
+       M_FSTNP(REG_NULL, REG_SP, 2 * 8);
 
-       M_DSTNP(REG_NULL, REG_SP, 1 * 4 + 1 * 8);
-       M_FSTNP(REG_NULL, REG_SP, 1 * 4 + 2 * 8);
+       M_AST_IMM(m, REG_SP, 2 * 8 + 1 * 4);
 
-       M_MOV_IMM(builtin_displaymethodstop, REG_ITMP1);
+       M_MOV_IMM(builtin_verbosecall_exit, REG_ITMP1);
        M_CALL(REG_ITMP1);
 
-       M_LLD(REG_RESULT_PACKED, REG_SP, 1 * 4);
+       M_LLD(REG_RESULT_PACKED, REG_SP, 0 * 4);
 
-       M_AADD_IMM(4 + 8 + 8 + 4 + 8, REG_SP);
+       M_AADD_IMM(8 + 8 + 4 + 4 + 8, REG_SP);
 
        /* mark trace code */