Merged PR72 fix.
[cacao.git] / src / vm / jit / x86_64 / emit.c
index f22aa41032e3259c70a6b22481067208bd3852bd..b63551e54a85747db5d5bcc581154732169dbcf6 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/x86_64/emit.c - x86_64 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 6171 2006-12-11 11:47:42Z twisti $
-
 */
 
 #include "config.h"
-#include "vm/types.h"
 
 #include <assert.h>
 
+#include "vm/types.h"
+
 #include "md-abi.h"
 
 #include "vm/jit/x86_64/codegen.h"
 #include "vm/jit/x86_64/emit.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/jit/abi.h"
 #include "vm/jit/abi-asm.h"
 #include "vm/jit/asmpart.h"
 #include "vm/jit/codegen-common.h"
 #include "vm/jit/emit-common.h"
 #include "vm/jit/jit.h"
+#include "vm/jit/patcher-common.h"
 #include "vm/jit/replace.h"
+#include "vm/jit/trace.h"
+#include "vm/jit/trap.h"
+
+#include "vmcore/options.h"
 
 
 /* emit_load *******************************************************************
@@ -73,19 +72,24 @@ s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
        if (IS_INMEMORY(src->flags)) {
                COUNT_SPILLS;
 
-               disp = src->vv.regoff * 8;
-
-               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_INT_TYPE(src->type))
-                               M_ILD(tempreg, REG_SP, disp);
-                       else
-                               M_LLD(tempreg, REG_SP, disp);
+               disp = src->vv.regoff;
+
+               switch (src->type) {
+               case TYPE_INT:
+                       M_ILD(tempreg, REG_SP, disp);
+                       break;
+               case TYPE_LNG:
+               case TYPE_ADR:
+                       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;
@@ -110,51 +114,31 @@ inline void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
 {
        codegendata  *cd;
        s4            disp;
-#if 0
-       s4            s;
-       u2            opcode;
-#endif
 
        /* get required compiler data */
 
        cd = jd->cd;
 
-#if 0
-       /* do we have to generate a conditional move? */
-
-       if ((iptr != NULL) && (iptr->opc & ICMD_CONDITION_MASK)) {
-               /* the passed register d is actually the source register */
-
-               s = d;
-
-               /* Only pass the opcode to codegen_reg_of_var to get the real
-                  destination register. */
-
-               opcode = iptr->opc & ICMD_OPCODE_MASK;
-
-               /* get the real destination register */
-
-               d = codegen_reg_of_var(rd, opcode, dst, REG_ITMP1);
-
-               /* and emit the conditional move */
-
-               emit_cmovxx(cd, iptr, s, d);
-       }
-#endif
-
        if (IS_INMEMORY(dst->flags)) {
                COUNT_SPILLS;
 
-               disp = dst->vv.regoff * 8;
+               disp = dst->vv.regoff;
 
-               if (IS_FLT_DBL_TYPE(dst->type)) {
-                       if (IS_2_WORD_TYPE(dst->type))
-                               M_DST(d, REG_SP, disp);
-                       else
-                               M_FST(d, REG_SP, disp);
-               }
-               else
+               switch (dst->type) {
+               case TYPE_INT:
+               case TYPE_LNG:
+               case TYPE_ADR:
                        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);
+               }
        }
 }
 
@@ -165,36 +149,57 @@ inline void emit_store(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. */
 
                if (IS_INMEMORY(src->flags)) {
-                       d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
+                       d  = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
                        s1 = emit_load(jd, iptr, src, d);
                }
                else {
                        s1 = emit_load(jd, iptr, src, REG_IFTMP);
-                       d = codegen_reg_of_var(iptr->opc, dst, s1);
+                       d  = codegen_reg_of_var(iptr->opc, dst, s1);
                }
 
                if (s1 != d) {
-                       if (IS_FLT_DBL_TYPE(src->type))
-                               M_FMOV(s1, d);
-                       else
+                       switch (src->type) {
+                       case TYPE_INT:
+                       case TYPE_LNG:
+                       case TYPE_ADR:
                                M_MOV(s1, d);
+                               break;
+                       case TYPE_FLT:
+                       case TYPE_DBL:
+                               M_FMOV(s1, d);
+                               break;
+                       default:
+                               vm_abort("emit_copy: unknown type %d", src->type);
+                       }
                }
 
                emit_store(jd, iptr, dst, d);
@@ -229,6 +234,71 @@ void emit_cmovxx(codegendata *cd, instruction *iptr, s4 s, s4 d)
 }
 
 
+/* 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;
+
+       /* NOTE: 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_BULT(branchdisp);
+                       break;
+               case BRANCH_ULE:
+                       M_BULE(branchdisp);
+                       break;
+               case BRANCH_UGE:
+                       M_BUGE(branchdisp);
+                       break;
+               case BRANCH_UGT:
+                       M_BUGT(branchdisp);
+                       break;
+               default:
+                       vm_abort("emit_branch: unknown condition %d", condition);
+               }
+       }
+}
+
+
 /* emit_arithmetic_check *******************************************************
 
    Emit an ArithmeticException check.
@@ -239,8 +309,8 @@ void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
 {
        if (INSTRUCTION_MUST_CHECK(iptr)) {
                M_TEST(reg);
-               M_BEQ(0);
-               codegen_add_arithmeticexception_ref(cd);
+               M_BNE(8);
+               M_ALD_MEM(reg, TRAP_ArithmeticException);
        }
 }
 
@@ -254,10 +324,26 @@ void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
 void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
 {
        if (INSTRUCTION_MUST_CHECK(iptr)) {
-        M_ILD(REG_ITMP3, s1, OFFSET(java_arrayheader, size));
+        M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, size));
         M_ICMP(REG_ITMP3, s2);
-        M_BAE(0);
-        codegen_add_arrayindexoutofboundsexception_ref(cd, s2);
+               M_BULT(8);
+               M_ALD_MEM(s2, TRAP_ArrayIndexOutOfBoundsException);
+       }
+}
+
+
+/* emit_arraystore_check *******************************************************
+
+   Emit an ArrayStoreException check.
+
+*******************************************************************************/
+
+void emit_arraystore_check(codegendata *cd, instruction *iptr)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TEST(REG_RESULT);
+               M_BNE(8);
+               M_ALD_MEM(REG_RESULT, TRAP_ArrayStoreException);
        }
 }
 
@@ -270,7 +356,28 @@ void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1,
 
 void emit_classcast_check(codegendata *cd, instruction *iptr, s4 condition, s4 reg, s4 s1)
 {
-       vm_abort("IMPLEMENT ME!");
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               switch (condition) {
+               case BRANCH_LE:
+                       M_BGT(8);
+                       break;
+               case BRANCH_GE:
+                       M_BLT(8);
+                       break;
+               case BRANCH_EQ:
+                       M_BNE(8);
+                       break;
+               case BRANCH_NE:
+                       M_BEQ(8);
+                       break;
+               case BRANCH_UGT:
+                       M_BULE(8);
+                       break;
+               default:
+                       vm_abort("emit_classcast_check: unknown condition %d", condition);
+               }
+               M_ALD_MEM(s1, TRAP_ClassCastException);
+       }
 }
 
 
@@ -284,233 +391,61 @@ void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
 {
        if (INSTRUCTION_MUST_CHECK(iptr)) {
                M_TEST(reg);
-               M_BEQ(0);
-               codegen_add_nullpointerexception_ref(cd);
+               M_BNE(8);
+               M_ALD_MEM(reg, TRAP_NullPointerException);
        }
 }
 
 
-/* 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 a4. */
-
-               if (er->reg != -1)
-                       M_MOV(er->reg, rd->argintregs[4]);
-
-               /* calcuate exception address */
-
-               M_MOV_IMM(0, rd->argintregs[3]);
-               dseg_adddata(cd);
-               M_AADD_IMM32(er->branchpos - 6, rd->argintregs[3]);
-
-               /* move function to call into REG_ITMP3 */
-
-               M_MOV_IMM(er->function, REG_ITMP3);
-
-               if (targetdisp == 0) {
-                       targetdisp = cd->mcodeptr - cd->mcodebase;
-
-                       emit_lea_membase_reg(cd, RIP, -((cd->mcodeptr + 7) - cd->mcodebase), rd->argintregs[0]);
-                       M_MOV(REG_SP, rd->argintregs[1]);
-                       M_ALD(rd->argintregs[2], REG_SP, cd->stackframesize * 8);
-
-                       M_ASUB_IMM(2 * 8, REG_SP);
-                       M_AST(rd->argintregs[3], REG_SP, 0 * 8);             /* store XPC */
-
-                       M_CALL(REG_ITMP3);
-
-                       M_ALD(REG_ITMP2_XPC, REG_SP, 0 * 8);
-                       M_AADD_IMM(2 * 8, 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(8);
+               M_ALD_MEM(REG_RESULT, TRAP_CHECK_EXCEPTION);
        }
 }
 
 
-/* emit_patcher_stubs **********************************************************
+/* emit_trap_compiler **********************************************************
 
-   Generates the code for the patcher stubs.
+   Emit a trap instruction which calls the JIT compiler.
 
 *******************************************************************************/
 
-void emit_patcher_stubs(jitdata *jd)
+void emit_trap_compiler(codegendata *cd)
 {
-       codegendata *cd;
-       patchref    *pref;
-       u8           mcode;
-       u1          *savedmcodeptr;
-       u1          *tmpmcodeptr;
-       s4           targetdisp;
-       s4           disp;
-
-       /* get required compiler data */
-
-       cd = jd->cd;
-
-       /* generate code patching stub call code */
-
-       targetdisp = 0;
-
-       for (pref = cd->patchrefs; pref != NULL; pref = pref->next) {
-               /* check size of code segment */
-
-               MCODECHECK(512);
-
-               /* Get machine code which is patched back in later. A
-                  `call rel32' is 5 bytes long (but read 8 bytes). */
-
-               savedmcodeptr = cd->mcodebase + pref->branchpos;
-               mcode = *((u8 *) savedmcodeptr);
-
-               /* patch in `call rel32' to call the following code */
-
-               tmpmcodeptr  = cd->mcodeptr;    /* save current mcodeptr              */
-               cd->mcodeptr = savedmcodeptr;   /* set mcodeptr to patch position     */
-
-               M_CALL_IMM(tmpmcodeptr - (savedmcodeptr + PATCHER_CALL_SIZE));
-
-               cd->mcodeptr = tmpmcodeptr;     /* restore the current mcodeptr       */
-
-               /* move pointer to java_objectheader onto stack */
-
-#if defined(ENABLE_THREADS)
-               /* create a virtual java_objectheader */
-
-               (void) dseg_add_unique_address(cd, NULL);                  /* flcword */
-               (void) dseg_add_unique_address(cd, lock_get_initial_lock_word());
-               disp = dseg_add_unique_address(cd, NULL);                  /* vftbl   */
-
-               emit_lea_membase_reg(cd, RIP, -((cd->mcodeptr + 7) - cd->mcodebase) + disp, REG_ITMP3);
-               M_PUSH(REG_ITMP3);
-#else
-               M_PUSH_IMM(0);
-#endif
-
-               /* move machine code bytes and classinfo pointer into registers */
-
-               M_MOV_IMM(mcode, REG_ITMP3);
-               M_PUSH(REG_ITMP3);
-
-               M_MOV_IMM(pref->ref, REG_ITMP3);
-               M_PUSH(REG_ITMP3);
-
-               M_MOV_IMM(pref->disp, REG_ITMP3);
-               M_PUSH(REG_ITMP3);
-
-               M_MOV_IMM(pref->patcher, REG_ITMP3);
-               M_PUSH(REG_ITMP3);
-
-               if (targetdisp == 0) {
-                       targetdisp = cd->mcodeptr - cd->mcodebase;
-
-                       M_MOV_IMM(asm_patcher_wrapper, REG_ITMP3);
-                       M_JMP(REG_ITMP3);
-               }
-               else {
-                       M_JMP_IMM((cd->mcodebase + targetdisp) -
-                                         (cd->mcodeptr + PATCHER_CALL_SIZE));
-               }
-       }
+       M_ALD_MEM(REG_METHODPTR, TRAP_COMPILER);
 }
 
 
-/* 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 */
-
-       cd   = jd->cd;
-       code = jd->code;
-
-       rplp = code->rplpoints;
-
-       /* store beginning of replacement stubs */
+       uint16_t mcode;
 
-       code->replacementstubs = (u1*) (cd->mcodeptr - cd->mcodebase);
+       /* Get machine code which is patched back in later. The trap is 2
+          bytes long. */
 
-       for (i = 0; i < code->rplpointcount; ++i, ++rplp) {
-               /* do not generate stubs for non-trappable points */
+       mcode = *((uint16_t *) cd->mcodeptr);
 
-               if (rplp->flags & RPLPOINT_FLAG_NOTRAP)
-                       continue;
+       /* XXX This needs to be change to INT3 when the debugging problems
+          with gdb are resolved. */
 
-               /* check code segment size */
+       M_UD2;
 
-               MCODECHECK(512);
-
-               /* note start of stub code */
-
-#if !defined(NDEBUG)
-               savedmcodeptr = cd->mcodeptr;
-#endif
-
-               /* push address of `rplpoint` struct */
-                       
-               M_MOV_IMM(rplp, REG_ITMP3);
-               M_PUSH(REG_ITMP3);
-
-               /* jump to replacement function */
-
-               M_MOV_IMM(asm_replacement_out, REG_ITMP3);
-               M_PUSH(REG_ITMP3);
-               M_RET;
-
-               assert((cd->mcodeptr - savedmcodeptr) == REPLACEMENT_STUB_SIZE);
-       }
+       return mcode;
 }
 
 
@@ -524,16 +459,19 @@ void emit_replacement_stubs(jitdata *jd)
 void emit_verbosecall_enter(jitdata *jd)
 {
        methodinfo   *m;
+       codeinfo     *code;
        codegendata  *cd;
        registerdata *rd;
        methoddesc   *md;
-       s4            i, j, k;
+       s4            stackframesize;
+       s4            i, s;
 
        /* get required compiler data */
 
-       m  = jd->m;
-       cd = jd->cd;
-       rd = jd->rd;
+       m    = jd->m;
+       code = jd->code;
+       cd   = jd->cd;
+       rd   = jd->rd;
 
        md = m->parseddesc;
 
@@ -541,67 +479,94 @@ void emit_verbosecall_enter(jitdata *jd)
 
        M_NOP;
 
-       /* additional +1 is for 16-byte stack alignment */
+       /* keep 16-byte stack alignment */
+
+       stackframesize = md->paramcount + ARG_CNT + TMP_CNT;
+       ALIGN_2(stackframesize);
 
-       M_LSUB_IMM((ARG_CNT + TMP_CNT + 1 + 1) * 8, REG_SP);
+       M_LSUB_IMM(stackframesize * 8, REG_SP);
 
        /* save argument registers */
 
-       for (i = 0; i < INT_ARG_CNT; i++)
-               M_LST(rd->argintregs[i], REG_SP, (1 + i) * 8);
+       for (i = 0; i < md->paramcount; i++) {
+               if (!md->params[i].inmemory) {
+                       s = md->params[i].regoff;
+
+                       switch (md->paramtypes[i].type) {
+                       case TYPE_ADR:
+                       case TYPE_INT:
+                       case TYPE_LNG:
+                               M_LST(s, REG_SP, i * 8);
+                               break;
+                       case TYPE_FLT:
+                       case TYPE_DBL:
+                               M_DST(s, REG_SP, i * 8);
+                               break;
+                       }
+               }
+       }
+
+       /* save all argument and temporary registers for leaf methods */
 
-       for (i = 0; i < FLT_ARG_CNT; i++)
-               M_DST(rd->argfltregs[i], REG_SP, (1 + INT_ARG_CNT + i) * 8);
+       if (code_is_leafmethod(code)) {
+               for (i = 0; i < INT_ARG_CNT; i++)
+                       M_LST(abi_registers_integer_argument[i], REG_SP, (md->paramcount + i) * 8);
 
-       /* save temporary registers for leaf methods */
+               for (i = 0; i < FLT_ARG_CNT; i++)
+                       M_DST(abi_registers_float_argument[i], REG_SP, (md->paramcount + INT_ARG_CNT + i) * 8);
 
-       if (jd->isleafmethod) {
                for (i = 0; i < INT_TMP_CNT; i++)
-                       M_LST(rd->tmpintregs[i], REG_SP, (1 + ARG_CNT + i) * 8);
+                       M_LST(rd->tmpintregs[i], REG_SP, (md->paramcount + ARG_CNT + i) * 8);
 
                for (i = 0; i < FLT_TMP_CNT; i++)
-                       M_DST(rd->tmpfltregs[i], REG_SP, (1 + ARG_CNT + INT_TMP_CNT + i) * 8);
+                       M_DST(rd->tmpfltregs[i], REG_SP, (md->paramcount + ARG_CNT + INT_TMP_CNT + i) * 8);
        }
 
-       /* show integer hex code for float arguments */
+       M_MOV_IMM(m, REG_A0);
+       M_MOV(REG_SP, REG_A1);
+       M_MOV(REG_SP, REG_A2);
+       M_AADD_IMM((stackframesize + cd->stackframesize + 1) * 8, REG_A2);
+       M_MOV_IMM(trace_java_call_enter, REG_ITMP1);
+       M_CALL(REG_ITMP1);
 
-       for (i = 0, j = 0; i < md->paramcount && i < INT_ARG_CNT; i++) {
-               /* If the paramtype is a float, we have to right shift all
-                  following integer registers. */
-       
-               if (IS_FLT_DBL_TYPE(md->paramtypes[i].type)) {
-                       for (k = INT_ARG_CNT - 2; k >= i; k--)
-                               M_MOV(rd->argintregs[k], rd->argintregs[k + 1]);
+       /* restore argument registers */
 
-                       emit_movd_freg_reg(cd, rd->argfltregs[j], rd->argintregs[i]);
-                       j++;
+       for (i = 0; i < md->paramcount; i++) {
+               if (!md->params[i].inmemory) {
+                       s = md->params[i].regoff;
+
+                       switch (md->paramtypes[i].type) {
+                       case TYPE_ADR:
+                       case TYPE_INT:
+                       case TYPE_LNG:
+                               M_LLD(s, REG_SP, i * 8);
+                               break;
+                       case TYPE_FLT:
+                       case TYPE_DBL:
+                               M_DLD(s, REG_SP, i * 8);
+                               break;
+                       }
                }
        }
 
-       M_MOV_IMM(m, REG_ITMP2);
-       M_AST(REG_ITMP2, REG_SP, 0 * 8);
-       M_MOV_IMM(builtin_trace_args, REG_ITMP1);
-       M_CALL(REG_ITMP1);
-
-       /* restore argument registers */
 
-       for (i = 0; i < INT_ARG_CNT; i++)
-               M_LLD(rd->argintregs[i], REG_SP, (1 + i) * 8);
+       /* restore all argument and temporary registers for leaf methods */
 
-       for (i = 0; i < FLT_ARG_CNT; i++)
-               M_DLD(rd->argfltregs[i], REG_SP, (1 + INT_ARG_CNT + i) * 8);
+       if (code_is_leafmethod(code)) {
+               for (i = 0; i < INT_ARG_CNT; i++)
+                       M_LLD(abi_registers_integer_argument[i], REG_SP, (md->paramcount + i) * 8);
 
-       /* restore temporary registers for leaf methods */
+               for (i = 0; i < FLT_ARG_CNT; i++)
+                       M_DLD(abi_registers_float_argument[i], REG_SP, (md->paramcount + INT_ARG_CNT + i) * 8);
 
-       if (jd->isleafmethod) {
                for (i = 0; i < INT_TMP_CNT; i++)
-                       M_LLD(rd->tmpintregs[i], REG_SP, (1 + ARG_CNT + i) * 8);
+                       M_LLD(rd->tmpintregs[i], REG_SP, (md->paramcount + ARG_CNT + i) * 8);
 
                for (i = 0; i < FLT_TMP_CNT; i++)
-                       M_DLD(rd->tmpfltregs[i], REG_SP, (1 + ARG_CNT + INT_TMP_CNT + i) * 8);
+                       M_DLD(rd->tmpfltregs[i], REG_SP, (md->paramcount + ARG_CNT + INT_TMP_CNT + i) * 8);
        }
 
-       M_LADD_IMM((ARG_CNT + TMP_CNT + 1 + 1) * 8, REG_SP);
+       M_LADD_IMM(stackframesize * 8, REG_SP);
 
        /* mark trace code */
 
@@ -622,6 +587,7 @@ void emit_verbosecall_exit(jitdata *jd)
        methodinfo   *m;
        codegendata  *cd;
        registerdata *rd;
+       methoddesc   *md;
 
        /* get required compiler data */
 
@@ -629,25 +595,49 @@ void emit_verbosecall_exit(jitdata *jd)
        cd = jd->cd;
        rd = jd->rd;
 
+       md = m->parseddesc;
+
        /* mark trace code */
 
        M_NOP;
 
+       /* keep 16-byte stack alignment */
+
        M_ASUB_IMM(2 * 8, REG_SP);
 
-       M_LST(REG_RESULT, REG_SP, 0 * 8);
-       M_DST(REG_FRESULT, REG_SP, 1 * 8);
+       /* save return value */
+
+       switch (md->returntype.type) {
+       case TYPE_ADR:
+       case TYPE_INT:
+       case TYPE_LNG:
+               M_LST(REG_RESULT, REG_SP, 0 * 8);
+               break;
+       case TYPE_FLT:
+       case TYPE_DBL:
+               M_DST(REG_FRESULT, REG_SP, 0 * 8);
+               break;
+       }
 
-       M_MOV_IMM(m, rd->argintregs[0]);
-       M_MOV(REG_RESULT, rd->argintregs[1]);
-       M_FLTMOVE(REG_FRESULT, rd->argfltregs[0]);
-       M_FLTMOVE(REG_FRESULT, rd->argfltregs[1]);
+       M_MOV_IMM(m, REG_A0);
+       M_MOV(REG_SP, REG_A1);
 
-       M_MOV_IMM(builtin_displaymethodstop, REG_ITMP1);
+       M_MOV_IMM(trace_java_call_exit, REG_ITMP1);
        M_CALL(REG_ITMP1);
 
-       M_LLD(REG_RESULT, REG_SP, 0 * 8);
-       M_DLD(REG_FRESULT, REG_SP, 1 * 8);
+       /* restore return value */
+
+       switch (md->returntype.type) {
+       case TYPE_ADR:
+       case TYPE_INT:
+       case TYPE_LNG:
+               M_LLD(REG_RESULT, REG_SP, 0 * 8);
+               break;
+       case TYPE_FLT:
+       case TYPE_DBL:
+               M_DLD(REG_FRESULT, REG_SP, 0 * 8);
+               break;
+       }
 
        M_AADD_IMM(2 * 8, REG_SP);
 
@@ -759,53 +749,53 @@ void emit_ishift(jitdata *jd, s4 shift_op, instruction *iptr)
        if (IS_INMEMORY(v_dst->flags)) {
                if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
                        if (s1 == d) {
-                               M_ILD(RCX, REG_SP, s2 * 8);
-                               emit_shiftl_membase(cd, shift_op, REG_SP, d * 8);
+                               M_ILD(RCX, REG_SP, s2);
+                               emit_shiftl_membase(cd, shift_op, REG_SP, d);
 
                        } else {
-                               M_ILD(RCX, REG_SP, s2 * 8);
-                               M_ILD(REG_ITMP2, REG_SP, s1 * 8);
+                               M_ILD(RCX, REG_SP, s2);
+                               M_ILD(REG_ITMP2, REG_SP, s1);
                                emit_shiftl_reg(cd, shift_op, REG_ITMP2);
-                               M_IST(REG_ITMP2, REG_SP, d * 8);
+                               M_IST(REG_ITMP2, REG_SP, d);
                        }
 
                } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) {
                        /* s1 may be equal to RCX */
                        if (s1 == RCX) {
                                if (s2 == d) {
-                                       M_ILD(REG_ITMP1, REG_SP, s2 * 8);
-                                       M_IST(s1, REG_SP, d * 8);
+                                       M_ILD(REG_ITMP1, REG_SP, s2);
+                                       M_IST(s1, REG_SP, d);
                                        M_INTMOVE(REG_ITMP1, RCX);
 
                                } else {
-                                       M_IST(s1, REG_SP, d * 8);
-                                       M_ILD(RCX, REG_SP, s2 * 8);
+                                       M_IST(s1, REG_SP, d);
+                                       M_ILD(RCX, REG_SP, s2);
                                }
 
                        } else {
-                               M_ILD(RCX, REG_SP, s2 * 8);
-                               M_IST(s1, REG_SP, d * 8);
+                               M_ILD(RCX, REG_SP, s2);
+                               M_IST(s1, REG_SP, d);
                        }
 
-                       emit_shiftl_membase(cd, shift_op, REG_SP, d * 8);
+                       emit_shiftl_membase(cd, shift_op, REG_SP, d);
 
                } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
                        if (s1 == d) {
                                M_INTMOVE(s2, RCX);
-                               emit_shiftl_membase(cd, shift_op, REG_SP, d * 8);
+                               emit_shiftl_membase(cd, shift_op, REG_SP, d);
 
                        } else {
                                M_INTMOVE(s2, RCX);
-                               M_ILD(REG_ITMP2, REG_SP, s1 * 8);
+                               M_ILD(REG_ITMP2, REG_SP, s1);
                                emit_shiftl_reg(cd, shift_op, REG_ITMP2);
-                               M_IST(REG_ITMP2, REG_SP, d * 8);
+                               M_IST(REG_ITMP2, REG_SP, d);
                        }
 
                } else {
                        /* s1 may be equal to RCX */
-                       M_IST(s1, REG_SP, d * 8);
+                       M_IST(s1, REG_SP, d);
                        M_INTMOVE(s2, RCX);
-                       emit_shiftl_membase(cd, shift_op, REG_SP, d * 8);
+                       emit_shiftl_membase(cd, shift_op, REG_SP, d);
                }
 
                M_INTMOVE(REG_ITMP1, RCX);                             /* restore RCX */
@@ -817,19 +807,19 @@ void emit_ishift(jitdata *jd, s4 shift_op, instruction *iptr)
                }
                                        
                if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
-                       M_ILD(RCX, REG_SP, s2 * 8);
-                       M_ILD(d, REG_SP, s1 * 8);
+                       M_ILD(RCX, REG_SP, s2);
+                       M_ILD(d, REG_SP, s1);
                        emit_shiftl_reg(cd, shift_op, d);
 
                } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) {
                        /* s1 may be equal to RCX */
                        M_INTMOVE(s1, d);
-                       M_ILD(RCX, REG_SP, s2 * 8);
+                       M_ILD(RCX, REG_SP, s2);
                        emit_shiftl_reg(cd, shift_op, d);
 
                } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
                        M_INTMOVE(s2, RCX);
-                       M_ILD(d, REG_SP, s1 * 8);
+                       M_ILD(d, REG_SP, s1);
                        emit_shiftl_reg(cd, shift_op, d);
 
                } else {
@@ -886,53 +876,53 @@ void emit_lshift(jitdata *jd, s4 shift_op, instruction *iptr)
        if (IS_INMEMORY(v_dst->flags)) {
                if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
                        if (s1 == d) {
-                               M_ILD(RCX, REG_SP, s2 * 8);
-                               emit_shift_membase(cd, shift_op, REG_SP, d * 8);
+                               M_ILD(RCX, REG_SP, s2);
+                               emit_shift_membase(cd, shift_op, REG_SP, d);
 
                        } else {
-                               M_ILD(RCX, REG_SP, s2 * 8);
-                               M_LLD(REG_ITMP2, REG_SP, s1 * 8);
+                               M_ILD(RCX, REG_SP, s2);
+                               M_LLD(REG_ITMP2, REG_SP, s1);
                                emit_shift_reg(cd, shift_op, REG_ITMP2);
-                               M_LST(REG_ITMP2, REG_SP, d * 8);
+                               M_LST(REG_ITMP2, REG_SP, d);
                        }
 
                } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) {
                        /* s1 may be equal to RCX */
                        if (s1 == RCX) {
                                if (s2 == d) {
-                                       M_ILD(REG_ITMP1, REG_SP, s2 * 8);
-                                       M_LST(s1, REG_SP, d * 8);
+                                       M_ILD(REG_ITMP1, REG_SP, s2);
+                                       M_LST(s1, REG_SP, d);
                                        M_INTMOVE(REG_ITMP1, RCX);
 
                                } else {
-                                       M_LST(s1, REG_SP, d * 8);
-                                       M_ILD(RCX, REG_SP, s2 * 8);
+                                       M_LST(s1, REG_SP, d);
+                                       M_ILD(RCX, REG_SP, s2);
                                }
 
                        } else {
-                               M_ILD(RCX, REG_SP, s2 * 8);
-                               M_LST(s1, REG_SP, d * 8);
+                               M_ILD(RCX, REG_SP, s2);
+                               M_LST(s1, REG_SP, d);
                        }
 
-                       emit_shift_membase(cd, shift_op, REG_SP, d * 8);
+                       emit_shift_membase(cd, shift_op, REG_SP, d);
 
                } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
                        if (s1 == d) {
                                M_INTMOVE(s2, RCX);
-                               emit_shift_membase(cd, shift_op, REG_SP, d * 8);
+                               emit_shift_membase(cd, shift_op, REG_SP, d);
 
                        } else {
                                M_INTMOVE(s2, RCX);
-                               M_LLD(REG_ITMP2, REG_SP, s1 * 8);
+                               M_LLD(REG_ITMP2, REG_SP, s1);
                                emit_shift_reg(cd, shift_op, REG_ITMP2);
-                               M_LST(REG_ITMP2, REG_SP, d * 8);
+                               M_LST(REG_ITMP2, REG_SP, d);
                        }
 
                } else {
                        /* s1 may be equal to RCX */
-                       M_LST(s1, REG_SP, d * 8);
+                       M_LST(s1, REG_SP, d);
                        M_INTMOVE(s2, RCX);
-                       emit_shift_membase(cd, shift_op, REG_SP, d * 8);
+                       emit_shift_membase(cd, shift_op, REG_SP, d);
                }
 
                M_INTMOVE(REG_ITMP1, RCX);                             /* restore RCX */
@@ -944,19 +934,19 @@ void emit_lshift(jitdata *jd, s4 shift_op, instruction *iptr)
                }
 
                if (IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
-                       M_ILD(RCX, REG_SP, s2 * 8);
-                       M_LLD(d, REG_SP, s1 * 8);
+                       M_ILD(RCX, REG_SP, s2);
+                       M_LLD(d, REG_SP, s1);
                        emit_shift_reg(cd, shift_op, d);
 
                } else if (IS_INMEMORY(v_s2->flags) && !IS_INMEMORY(v_s1->flags)) {
                        /* s1 may be equal to RCX */
                        M_INTMOVE(s1, d);
-                       M_ILD(RCX, REG_SP, s2 * 8);
+                       M_ILD(RCX, REG_SP, s2);
                        emit_shift_reg(cd, shift_op, d);
 
                } else if (!IS_INMEMORY(v_s2->flags) && IS_INMEMORY(v_s1->flags)) {
                        M_INTMOVE(s2, RCX);
-                       M_LLD(d, REG_SP, s1 * 8);
+                       M_LLD(d, REG_SP, s1);
                        emit_shift_reg(cd, shift_op, d);
 
                } else {
@@ -1195,6 +1185,16 @@ void emit_movslq_reg_reg(codegendata *cd, s8 reg, s8 dreg)
 }
 
 
+void emit_movzbq_reg_reg(codegendata *cd, s8 reg, s8 dreg)
+{
+       emit_rex(1,(dreg),0,(reg));
+       *(cd->mcodeptr++) = 0x0f;
+       *(cd->mcodeptr++) = 0xb6;
+       /* XXX: why do reg and dreg have to be exchanged */
+       emit_reg((dreg),(reg));
+}
+
+
 void emit_movzwq_reg_reg(codegendata *cd, s8 reg, s8 dreg)
 {
        emit_rex(1,(dreg),0,(reg));
@@ -1266,6 +1266,15 @@ void emit_movb_imm_memindex(codegendata *cd, s4 imm, s4 disp, s4 basereg, s4 ind
 }
 
 
+void emit_mov_mem_reg(codegendata *cd, s4 disp, s4 dreg)
+{
+       emit_rex(1, dreg, 0, 0);
+       *(cd->mcodeptr++) = 0x8b;
+       emit_address_byte(0, dreg, 4);
+       emit_mem(4, disp);
+}
+
+
 /*
  * alu operations
  */
@@ -1332,7 +1341,8 @@ void emit_alu_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) {
 }
 
 
-void emit_alu_imm32_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) {
+void emit_alu_imm32_reg(codegendata *cd, s4 opc, s4 imm, s4 dreg)
+{
        emit_rex(1,0,0,(dreg));
        *(cd->mcodeptr++) = 0x81;
        emit_reg((opc),(dreg));
@@ -1340,6 +1350,15 @@ void emit_alu_imm32_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) {
 }
 
 
+void emit_alul_imm32_reg(codegendata *cd, s4 opc, s4 imm, s4 dreg)
+{
+       emit_rex(0,0,0,(dreg));
+       *(cd->mcodeptr++) = 0x81;
+       emit_reg((opc),(dreg));
+       emit_imm32((imm));
+}
+
+
 void emit_alul_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) {
        if (IS_IMM8(imm)) {
                emit_rex(0,0,0,(dreg));
@@ -1357,12 +1376,12 @@ void emit_alul_imm_reg(codegendata *cd, s8 opc, s8 imm, s8 dreg) {
 
 void emit_alu_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) {
        if (IS_IMM8(imm)) {
-               emit_rex(1,(basereg),0,0);
+               emit_rex(1,0,0,(basereg));
                *(cd->mcodeptr++) = 0x83;
                emit_membase(cd, (basereg),(disp),(opc));
                emit_imm8((imm));
        } else {
-               emit_rex(1,(basereg),0,0);
+               emit_rex(1,0,0,(basereg));
                *(cd->mcodeptr++) = 0x81;
                emit_membase(cd, (basereg),(disp),(opc));
                emit_imm32((imm));
@@ -1372,12 +1391,12 @@ void emit_alu_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp)
 
 void emit_alul_imm_membase(codegendata *cd, s8 opc, s8 imm, s8 basereg, s8 disp) {
        if (IS_IMM8(imm)) {
-               emit_rex(0,(basereg),0,0);
+               emit_rex(0,0,0,(basereg));
                *(cd->mcodeptr++) = 0x83;
                emit_membase(cd, (basereg),(disp),(opc));
                emit_imm8((imm));
        } else {
-               emit_rex(0,(basereg),0,0);
+               emit_rex(0,0,0,(basereg));
                *(cd->mcodeptr++) = 0x81;
                emit_membase(cd, (basereg),(disp),(opc));
                emit_imm32((imm));
@@ -1435,6 +1454,18 @@ void emit_leal_membase_reg(codegendata *cd, s8 basereg, s8 disp, s8 reg) {
 }
 
 
+void emit_incl_reg(codegendata *cd, s8 reg)
+{
+       *(cd->mcodeptr++) = 0xff;
+       emit_reg(0,(reg));
+}
+
+void emit_incq_reg(codegendata *cd, s8 reg)
+{
+       emit_rex(1,0,0,(reg));
+       *(cd->mcodeptr++) = 0xff;
+       emit_reg(0,(reg));
+}
 
 void emit_incl_membase(codegendata *cd, s8 basereg, s8 disp)
 {
@@ -1443,6 +1474,13 @@ void emit_incl_membase(codegendata *cd, s8 basereg, s8 disp)
        emit_membase(cd, (basereg),(disp),0);
 }
 
+void emit_incq_membase(codegendata *cd, s8 basereg, s8 disp)
+{
+       emit_rex(1,0,0,(basereg));
+       *(cd->mcodeptr++) = 0xff;
+       emit_membase(cd, (basereg),(disp),0);
+}
+
 
 
 void emit_cltd(codegendata *cd) {
@@ -1579,12 +1617,6 @@ void emit_idivl_reg(codegendata *cd, s8 reg) {
 
 
 
-void emit_ret(codegendata *cd) {
-    *(cd->mcodeptr++) = 0xc3;
-}
-
-
-
 /*
  * shift ops
  */
@@ -1681,6 +1713,18 @@ void emit_jmp_imm(codegendata *cd, s8 imm) {
        emit_imm32((imm));
 }
 
+/* like emit_jmp_imm but allows 8 bit optimization */
+void emit_jmp_imm2(codegendata *cd, s8 imm) {
+       if (IS_IMM8(imm)) {
+               *(cd->mcodeptr++) = 0xeb;
+               emit_imm8((imm));
+       }
+       else {
+               *(cd->mcodeptr++) = 0xe9;
+               emit_imm32((imm));
+       }
+}
+
 
 void emit_jmp_reg(codegendata *cd, s8 reg) {
        emit_rex(0,0,0,(reg));
@@ -1702,7 +1746,8 @@ void emit_jcc(codegendata *cd, s8 opc, s8 imm) {
  */
 
 /* we need the rex byte to get all low bytes */
-void emit_setcc_reg(codegendata *cd, s8 opc, s8 reg) {
+void emit_setcc_reg(codegendata *cd, s4 opc, s4 reg)
+{
        *(cd->mcodeptr++) = (0x40 | (((reg) >> 3) & 0x01));
        *(cd->mcodeptr++) = 0x0f;
        *(cd->mcodeptr++) = (0x90 + (opc));
@@ -1711,7 +1756,8 @@ void emit_setcc_reg(codegendata *cd, s8 opc, s8 reg) {
 
 
 /* we need the rex byte to get all low bytes */
-void emit_setcc_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp) {
+void emit_setcc_membase(codegendata *cd, s4 opc, s4 basereg, s4 disp)
+{
        *(cd->mcodeptr++) = (0x40 | (((basereg) >> 3) & 0x01));
        *(cd->mcodeptr++) = 0x0f;
        *(cd->mcodeptr++) = (0x90 + (opc));
@@ -1719,7 +1765,7 @@ void emit_setcc_membase(codegendata *cd, s8 opc, s8 basereg, s8 disp) {
 }
 
 
-void emit_cmovcc_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg)
+void emit_cmovcc_reg_reg(codegendata *cd, s4 opc, s4 reg, s4 dreg)
 {
        emit_rex(1,(dreg),0,(reg));
        *(cd->mcodeptr++) = 0x0f;
@@ -1728,7 +1774,7 @@ void emit_cmovcc_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg)
 }
 
 
-void emit_cmovccl_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg)
+void emit_cmovccl_reg_reg(codegendata *cd, s4 opc, s4 reg, s4 dreg)
 {
        emit_rex(0,(dreg),0,(reg));
        *(cd->mcodeptr++) = 0x0f;
@@ -1737,7 +1783,6 @@ void emit_cmovccl_reg_reg(codegendata *cd, s8 opc, s8 reg, s8 dreg)
 }
 
 
-
 void emit_neg_reg(codegendata *cd, s8 reg)
 {
        emit_rex(1,0,0,(reg));
@@ -1779,23 +1824,20 @@ void emit_xchg_reg_reg(codegendata *cd, s8 reg, s8 dreg) {
 }
 
 
-void emit_nop(codegendata *cd) {
-    *(cd->mcodeptr++) = 0x90;
-}
-
-
 
 /*
  * call instructions
  */
-void emit_call_reg(codegendata *cd, s8 reg) {
-       emit_rex(1,0,0,(reg));
+void emit_call_reg(codegendata *cd, s8 reg)
+{
+       emit_rex(0,0,0,(reg));
        *(cd->mcodeptr++) = 0xff;
        emit_reg(2,(reg));
 }
 
 
-void emit_call_imm(codegendata *cd, s8 imm) {
+void emit_call_imm(codegendata *cd, s8 imm)
+{
        *(cd->mcodeptr++) = 0xe8;
        emit_imm32((imm));
 }