* Removed all Id tags.
[cacao.git] / src / vm / jit / powerpc / emit.c
index ec9ad6ea1843f6656624006a3b5f8cbc69b31608..f616af44016f9aff61343a3aacf9a69b18ad8e27 100644 (file)
@@ -1,6 +1,6 @@
 /* src/vm/jit/powerpc/emit.c - PowerPC 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
-
-   Changes:
-
-   $Id: emitfuncs.c 4398 2006-01-31 23:43:08Z twisti $
-
 */
 
 
 #include "config.h"
 
 #include <assert.h>
+#include <stdint.h>
 
 #include "vm/types.h"
 
 #include "md-abi.h"
 
-#include "vm/jit/emit.h"
-#include "vm/jit/jit.h"
 #include "vm/jit/powerpc/codegen.h"
 
+#include "mm/memory.h"
+
+#include "threads/lock-common.h"
+
+#include "vm/builtin.h"
+#include "vm/exceptions.h"
 
-/* code generation functions **************************************************/
+#include "vm/jit/abi.h"
+#include "vm/jit/asmpart.h"
+#include "vm/jit/codegen-common.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"
 
-/* emit_load_s1 ****************************************************************
 
-   Emits a possible load of the first source operand.
+/* emit_load *******************************************************************
+
+   Emits a possible load of an operand.
 
 *******************************************************************************/
 
-s4 emit_load_s1(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+s4 emit_load(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
 {
-       codegendata  *cd;
-       s4            disp;
-       s4            reg;
+       codegendata *cd;
+       s4           disp;
+       s4           reg;
 
        /* get required compiler data */
 
        cd = jd->cd;
 
-       if (src->flags & INMEMORY) {
+       if (IS_INMEMORY(src->flags)) {
                COUNT_SPILLS;
 
-               disp = src->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:
+               case TYPE_DBL:
+                       M_DLD(tempreg, REG_SP, disp);
+                       break;
+               default:
+                       vm_abort("emit_load: unknown type %d", src->type);
                }
 
                reg = tempreg;
-       } else
-               reg = src->regoff;
+       }
+       else
+               reg = src->vv.regoff;
 
        return reg;
 }
 
 
-/* emit_load_s2 ****************************************************************
+/* emit_load_low ***************************************************************
 
-   Emits a possible load of the second source operand.
+   Emits a possible load of the low 32-bits of an operand.
 
 *******************************************************************************/
 
-s4 emit_load_s2(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+s4 emit_load_low(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
 {
        codegendata  *cd;
        s4            disp;
        s4            reg;
 
+       assert(src->type == TYPE_LNG);
+
        /* get required compiler data */
 
        cd = jd->cd;
 
-       if (src->flags & INMEMORY) {
+       if (IS_INMEMORY(src->flags)) {
                COUNT_SPILLS;
 
-               disp = src->regoff * 4;
+               disp = src->vv.regoff;
 
-               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);
-               }
+               M_ILD(tempreg, REG_SP, disp + 4);
 
                reg = tempreg;
-       } else
-               reg = src->regoff;
+       }
+       else
+               reg = GET_LOW_REG(src->vv.regoff);
 
        return reg;
 }
 
 
-/* emit_load_s3 ****************************************************************
+/* emit_load_high **************************************************************
 
-   Emits a possible load of the third source operand.
+   Emits a possible load of the high 32-bits of an operand.
 
 *******************************************************************************/
 
-s4 emit_load_s3(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+s4 emit_load_high(jitdata *jd, instruction *iptr, varinfo *src, s4 tempreg)
 {
        codegendata  *cd;
        s4            disp;
        s4            reg;
 
+       assert(src->type == TYPE_LNG);
+
        /* get required compiler data */
 
        cd = jd->cd;
 
-       if (src->flags & INMEMORY) {
+       if (IS_INMEMORY(src->flags)) {
                COUNT_SPILLS;
 
-               disp = src->regoff * 4;
+               disp = src->vv.regoff;
 
-               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);
-               }
+               M_ILD(tempreg, REG_SP, disp);
 
                reg = tempreg;
-       } else
-               reg = src->regoff;
+       }
+       else
+               reg = GET_HIGH_REG(src->vv.regoff);
 
        return reg;
 }
 
 
-/* emit_load_s1_low ************************************************************
+/* emit_store ******************************************************************
 
-   Emits a possible load of the low 32-bits of the first long source
-   operand.
+   Emit a possible store for the given variable.
 
 *******************************************************************************/
 
-s4 emit_load_s1_low(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+void emit_store(jitdata *jd, instruction *iptr, varinfo *dst, s4 d)
 {
-       codegendata  *cd;
-       s4            disp;
-       s4            reg;
-
-       assert(src->type == TYPE_LNG);
+       codegendata *cd;
+       s4           disp;
 
        /* get required compiler data */
 
        cd = jd->cd;
 
-       if (src->flags & INMEMORY) {
+       if (IS_INMEMORY(dst->flags)) {
                COUNT_SPILLS;
 
-               disp = src->regoff * 4;
-
-               M_ILD(tempreg, REG_SP, disp + 4);
-
-               reg = tempreg;
-       } else
-               reg = GET_LOW_REG(src->regoff);
-
-       return reg;
+               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:
+               case TYPE_DBL:
+                       M_DST(d, REG_SP, disp);
+                       break;
+               default:
+                       vm_abort("emit_store: unknown type %d", dst->type);
+               }
+       }
 }
 
 
-/* emit_load_s2_low ************************************************************
+/* emit_copy *******************************************************************
 
-   Emits a possible load of the low 32-bits of the second long source
-   operand.
+   Generates a register/memory to register/memory copy.
 
 *******************************************************************************/
 
-s4 emit_load_s2_low(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+void emit_copy(jitdata *jd, instruction *iptr)
 {
-       codegendata  *cd;
-       s4            disp;
-       s4            reg;
-
-       assert(src->type == TYPE_LNG);
+       codegendata *cd;
+       varinfo     *src;
+       varinfo     *dst;
+       s4           s1, d;
 
        /* get required compiler data */
 
        cd = jd->cd;
 
-       if (src->flags & INMEMORY) {
-               COUNT_SPILLS;
+       /* get source and destination variables */
 
-               disp = src->regoff * 4;
+       src = VAROP(iptr->s1);
+       dst = VAROP(iptr->dst);
 
-               M_ILD(tempreg, REG_SP, disp + 4);
+       if ((src->vv.regoff != dst->vv.regoff) ||
+               (IS_INMEMORY(src->flags ^ dst->flags))) {
 
-               reg = tempreg;
-       } else
-               reg = GET_LOW_REG(src->regoff);
+               if ((src->type == TYPE_RET) || (dst->type == TYPE_RET)) {
+                       /* emit nothing, as the value won't be used anyway */
+                       return;
+               }
 
-       return reg;
+               /* 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)) {
+                       if (IS_LNG_TYPE(src->type))
+                               d = codegen_reg_of_var(iptr->opc, dst, REG_ITMP12_PACKED);
+                       else
+                               d = codegen_reg_of_var(iptr->opc, dst, REG_IFTMP);
+
+                       s1 = emit_load(jd, iptr, src, d);
+               }
+               else {
+                       if (IS_LNG_TYPE(src->type))
+                               s1 = emit_load(jd, iptr, src, REG_ITMP12_PACKED);
+                       else
+                               s1 = emit_load(jd, iptr, src, REG_IFTMP);
+
+                       d = codegen_reg_of_var(iptr->opc, dst, s1);
+               }
+
+               if (s1 != d) {
+                       switch (src->type) {
+                       case TYPE_INT:
+                       case TYPE_ADR:
+                               M_MOV(s1, d);
+                               break;
+                       case TYPE_LNG:
+                               M_MOV(GET_LOW_REG(s1), GET_LOW_REG(d));
+                               M_MOV(GET_HIGH_REG(s1), GET_HIGH_REG(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);
+       }
 }
 
 
-/* emit_load_s3_low ************************************************************
+/* emit_iconst *****************************************************************
 
-   Emits a possible load of the low 32-bits of the third long source
-   operand.
+   XXX
 
 *******************************************************************************/
 
-s4 emit_load_s3_low(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+void emit_iconst(codegendata *cd, s4 d, s4 value)
 {
-       codegendata  *cd;
-       s4            disp;
-       s4            reg;
+       s4 disp;
 
-       assert(src->type == TYPE_LNG);
+       if ((value >= -32768) && (value <= 32767))
+               M_LDA_INTERN(d, REG_ZERO, value);
+       else {
+               disp = dseg_add_s4(cd, value);
+               M_ILD(d, REG_PV, disp);
+       }
+}
 
-       /* get required compiler data */
 
-       cd = jd->cd;
+/* emit_branch *****************************************************************
 
-       if (src->flags & INMEMORY) {
-               COUNT_SPILLS;
+   Emits the code for conditional and unconditional branchs.
 
-               disp = src->regoff * 4;
+*******************************************************************************/
 
-               M_ILD(tempreg, REG_SP, disp + 4);
+void emit_branch(codegendata *cd, s4 disp, s4 condition, s4 reg, u4 opt)
+{
+       s4 checkdisp;
+       s4 branchdisp;
 
-               reg = tempreg;
-       } else
-               reg = GET_LOW_REG(src->regoff);
+       /* calculate the different displacements */
 
-       return reg;
-}
+       checkdisp  =  disp + 4;
+       branchdisp = (disp - 4) >> 2;
 
+       /* check which branch to generate */
 
-/* emit_load_s1_high ***********************************************************
+       if (condition == BRANCH_UNCONDITIONAL) {
+               /* check displacement for overflow */
 
-   Emits a possible load of the high 32-bits of the first long source
-   operand.
+               if ((checkdisp < (s4) 0xfe000000) || (checkdisp > (s4) 0x01fffffc)) {
+                       /* 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);
+                       }
 
-s4 emit_load_s1_high(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
-{
-       codegendata  *cd;
-       s4            disp;
-       s4            reg;
+                       vm_abort("emit_branch: emit unconditional long-branch code");
+               }
+               else {
+                       M_BR(branchdisp);
+               }
+       }
+       else {
+               /* and displacement for overflow */
 
-       assert(src->type == TYPE_LNG);
+               if ((checkdisp < (s4) 0xffff8000) || (checkdisp > (s4) 0x00007fff)) {
+                       /* if the long-branches flag isn't set yet, do it */
 
-       /* get required compiler data */
+                       if (!CODEGENDATA_HAS_FLAG_LONGBRANCHES(cd)) {
+                               cd->flags |= (CODEGENDATA_FLAG_ERROR |
+                                                         CODEGENDATA_FLAG_LONGBRANCHES);
+                       }
 
-       cd = jd->cd;
+                       switch (condition) {
+                       case BRANCH_EQ:
+                               M_BNE(1);
+                               M_BR(branchdisp);
+                               break;
+                       case BRANCH_NE:
+                               M_BEQ(1);
+                               M_BR(branchdisp);
+                               break;
+                       case BRANCH_LT:
+                               M_BGE(1);
+                               M_BR(branchdisp);
+                               break;
+                       case BRANCH_GE:
+                               M_BLT(1);
+                               M_BR(branchdisp);
+                               break;
+                       case BRANCH_GT:
+                               M_BLE(1);
+                               M_BR(branchdisp);
+                               break;
+                       case BRANCH_LE:
+                               M_BGT(1);
+                               M_BR(branchdisp);
+                               break;
+                       case BRANCH_NAN:
+                               vm_abort("emit_branch: long BRANCH_NAN");
+                               break;
+                       default:
+                               vm_abort("emit_branch: unknown condition %d", condition);
+                       }
+               }
+               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_NAN:
+                               M_BNAN(branchdisp);
+                               break;
+                       default:
+                               vm_abort("emit_branch: unknown condition %d", condition);
+                       }
+               }
+       }
+}
 
-       if (src->flags & INMEMORY) {
-               COUNT_SPILLS;
 
-               disp = src->regoff * 4;
+/* emit_arithmetic_check *******************************************************
 
-               M_ILD(tempreg, REG_SP, disp);
+   Emit an ArithmeticException check.
 
-               reg = tempreg;
-       } else
-               reg = GET_HIGH_REG(src->regoff);
+*******************************************************************************/
 
-       return reg;
+void emit_arithmetic_check(codegendata *cd, instruction *iptr, s4 reg)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TST(reg);
+               M_BNE(1);
+               M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_ARITHMETIC);
+       }
 }
 
 
-/* emit_load_s2_high ***********************************************************
+/* emit_arrayindexoutofbounds_check ********************************************
 
-   Emits a possible load of the high 32-bits of the second long source
-   operand.
+   Emit a ArrayIndexOutOfBoundsException check.
 
 *******************************************************************************/
 
-s4 emit_load_s2_high(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+void emit_arrayindexoutofbounds_check(codegendata *cd, instruction *iptr, s4 s1, s4 s2)
 {
-       codegendata  *cd;
-       s4            disp;
-       s4            reg;
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_ILD(REG_ITMP3, s1, OFFSET(java_array_t, size));
+               M_TRAPGEU(s2, REG_ITMP3);
+       }
+}
 
-       assert(src->type == TYPE_LNG);
 
-       /* get required compiler data */
+/* emit_classcast_check ********************************************************
 
-       cd = jd->cd;
+   Emit a ClassCastException check.
 
-       if (src->flags & INMEMORY) {
-               COUNT_SPILLS;
+*******************************************************************************/
 
-               disp = src->regoff * 4;
+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(1);
+                       break;
+               case BRANCH_EQ:
+                       M_BNE(1);
+                       break;
+               case BRANCH_GT:
+                       M_BLE(1);
+                       break;
+               default:
+                       vm_abort("emit_classcast_check: unknown condition %d", condition);
+               }
+               M_ALD_INTERN(s1, REG_ZERO, EXCEPTION_HARDWARE_CLASSCAST);
+       }
+}
 
-               M_ILD(tempreg, REG_SP, disp);
 
-               reg = tempreg;
-       } else
-               reg = GET_HIGH_REG(src->regoff);
+/* emit_nullpointer_check ******************************************************
 
-       return reg;
+   Emit a NullPointerException check.
+
+*******************************************************************************/
+
+void emit_nullpointer_check(codegendata *cd, instruction *iptr, s4 reg)
+{
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TST(reg);
+               M_BNE(1);
+               M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_NULLPOINTER);
+       }
 }
 
 
-/* emit_load_s3_high ***********************************************************
+/* emit_exception_check ********************************************************
 
-   Emits a possible load of the high 32-bits of the third long source
-   operand.
+   Emit an Exception check.
 
 *******************************************************************************/
 
-s4 emit_load_s3_high(jitdata *jd, instruction *iptr, stackptr src, s4 tempreg)
+void emit_exception_check(codegendata *cd, instruction *iptr)
 {
-       codegendata  *cd;
-       s4            disp;
-       s4            reg;
+       if (INSTRUCTION_MUST_CHECK(iptr)) {
+               M_TST(REG_RESULT);
+               M_BNE(1);
+               M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_EXCEPTION);
+       }
+}
 
-       assert(src->type == TYPE_LNG);
 
-       /* get required compiler data */
+/* emit_trap *******************************************************************
 
-       cd = jd->cd;
+   Emit a trap instruction and return the original machine code.
 
-       if (src->flags & INMEMORY) {
-               COUNT_SPILLS;
+*******************************************************************************/
 
-               disp = src->regoff * 4;
+uint32_t emit_trap(codegendata *cd)
+{
+       uint32_t mcode;
 
-               M_ILD(tempreg, REG_SP, disp);
+       /* Get machine code which is patched back in later. The
+          trap is 1 instruction word long. */
 
-               reg = tempreg;
-       } else
-               reg = GET_HIGH_REG(src->regoff);
+       mcode = *((u4 *) cd->mcodeptr);
 
-       return reg;
+       M_ALD_INTERN(REG_ZERO, REG_ZERO, EXCEPTION_HARDWARE_PATCHER);
+
+       return mcode;
 }
 
 
-/* emit_store ******************************************************************
+/* emit_verbosecall_enter ******************************************************
 
-   XXX
+   Generates the code for the call trace.
 
 *******************************************************************************/
 
-void emit_store(jitdata *jd, instruction *iptr, stackptr dst, s4 d)
+void emit_verbosecall_enter(jitdata *jd)
 {
+#if !defined(NDEBUG)
+       methodinfo   *m;
        codegendata  *cd;
+       registerdata *rd;
+       methoddesc   *md;
+       int32_t       disp;
+       int32_t       i;
+       int32_t       s, d;
+       int32_t       x;
+
+       if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
+               return;
 
        /* get required compiler data */
 
+       m  = jd->m;
        cd = jd->cd;
+       rd = jd->rd;
 
-       if (dst->flags & INMEMORY) {
-               COUNT_SPILLS;
+       md = m->parseddesc;
+
+       /* mark trace code */
+
+       M_NOP;
+
+       M_MFLR(REG_ZERO);
+       M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
+       M_STWU(REG_SP, REG_SP, -(LA_SIZE + (1 + ARG_CNT + TMP_CNT) * 8));
+
+       M_CLR(REG_ITMP1);                            /* prepare a "zero" register */
+
+       /* save argument registers */
+
+       for (i = 0; i < md->paramcount; i++) {
+               if (!md->params[i].inmemory) {
+                       s = md->params[i].regoff;
+                       d = LA_SIZE + (1 + i) * 8;
+
+                       switch (md->paramtypes[i].type) {
+                       case TYPE_INT:
+                       case TYPE_ADR:
+                               M_IST(REG_ITMP1, REG_SP, d);            /* high-bits are zero */
+                               M_IST(s, REG_SP, d + 4);
+                               break;
+                       case TYPE_LNG:
+                               M_LST(s, REG_SP, d);
+                               break;
+                       case TYPE_FLT:
+                               M_IST(REG_ITMP1, REG_SP, d);            /* high-bits are zero */
+                               M_FST(s, REG_SP, d + 4);
+                               break;
+                       case TYPE_DBL:
+                               M_DST(s, REG_SP, d);
+                               break;
+                       }
+               }
+       }
 
-               if (IS_FLT_DBL_TYPE(dst->type)) {
-                       if (IS_2_WORD_TYPE(dst->type))
-                               M_DST(d, REG_SP, dst->regoff * 4);
-                       else
-                               M_FST(d, REG_SP, dst->regoff * 4);
+       /* load arguments as longs */
 
-               } else {
-                       if (IS_2_WORD_TYPE(dst->type))
-                               M_LST(d, REG_SP, dst->regoff * 4);
-                       else
-                               M_IST(d, REG_SP, dst->regoff * 4);
+       d = 0;
+
+       for (i = 0; i < md->paramcount && i < TRACE_ARGS_NUM; i++) {
+               s = LA_SIZE + (1 + i) * 8;
+               x = PACK_REGS(abi_registers_integer_argument[d + 1],
+                                         abi_registers_integer_argument[d]);
+
+               M_LLD(x, REG_SP, s);
+
+               d += 2;
+       }
+
+       /* put methodinfo pointer as last argument on the stack */
+
+       disp = dseg_add_address(cd, m);
+       M_ALD(REG_ITMP1, REG_PV, disp);
+#if defined(__DARWIN__)
+       M_AST(REG_ITMP1, REG_SP, LA_SIZE + TRACE_ARGS_NUM * 8); 
+#else
+       M_AST(REG_ITMP1, REG_SP, LA_SIZE);
+#endif
+       disp = dseg_add_functionptr(cd, builtin_verbosecall_enter);
+       M_ALD(REG_ITMP2, REG_PV, disp);
+       M_MTCTR(REG_ITMP2);
+       M_JSR;
+
+       /* restore argument registers */
+
+       for (i = 0; i < md->paramcount; i++) {
+               if (!md->params[i].inmemory) {
+                       s = LA_SIZE + (1 + i) * 8;
+                       d = md->params[i].regoff;
+
+                       switch (md->paramtypes[i].type) {
+                       case TYPE_INT:
+                       case TYPE_ADR:
+                               M_ILD(d, REG_SP, s + 4);                      /* get low-bits */
+                               break;
+                       case TYPE_LNG:
+                               M_LLD(d, REG_SP, s);
+                               break;
+                       case TYPE_FLT:
+                               M_FLD(d, REG_SP, s + 4);                      /* get low-bits */
+                               break;
+                       case TYPE_DBL:
+                               M_DLD(d, REG_SP, s);
+                               break;
+                       }
                }
        }
+
+       M_ALD(REG_ZERO, REG_SP, LA_SIZE + (1 + ARG_CNT + TMP_CNT) * 8 + LA_LR_OFFSET);
+       M_MTLR(REG_ZERO);
+       M_LDA(REG_SP, REG_SP, LA_SIZE + (1 + ARG_CNT + TMP_CNT) * 8);
+
+       /* mark trace code */
+
+       M_NOP;
+#endif /* !defined(NDEBUG) */
 }
 
 
-/* emit_copy *******************************************************************
+/* emit_verbosecall_exit *******************************************************
 
-   XXX
+   Generates the code for the call trace.
+
+   void builtin_verbosecall_exit(s8 l, double d, float f, methodinfo *m);
 
 *******************************************************************************/
 
-void emit_copy(jitdata *jd, instruction *iptr, stackptr src, stackptr dst)
+void emit_verbosecall_exit(jitdata *jd)
 {
+#if !defined(NDEBUG)
+       methodinfo   *m;
        codegendata  *cd;
        registerdata *rd;
-       s4            s1, d;
+       methoddesc   *md;
+       s4            disp;
+
+       if (!JITDATA_HAS_FLAG_VERBOSECALL(jd))
+               return;
 
        /* get required compiler data */
 
+       m  = jd->m;
        cd = jd->cd;
        rd = jd->rd;
 
-       if (src->type == TYPE_LNG)
-               d = codegen_reg_of_var(rd, iptr->opc, dst, PACK_REGS(REG_ITMP2, REG_ITMP1));
-       else
-               d = codegen_reg_of_var(rd, iptr->opc, dst, REG_IFTMP);
+       md = m->parseddesc;
+       
+       /* mark trace code */
 
-       if ((src->regoff != dst->regoff) ||
-               ((src->flags ^ dst->flags) & INMEMORY)) {
-               s1 = emit_load_s1(jd, iptr, src, d);
+       M_NOP;
 
-               if (s1 != d) {
-                       if (IS_FLT_DBL_TYPE(src->type))
-                               M_FMOV(s1, d);
-                       else {
-                               if (IS_2_WORD_TYPE(src->type)) {
-                                       M_MOV(GET_LOW_REG(s1), GET_LOW_REG(d));
-                                       M_MOV(GET_HIGH_REG(s1), GET_HIGH_REG(d));
-                } else
-                    M_MOV(s1, d);
-                       }
-               }
+       M_MFLR(REG_ZERO);
+       M_AST(REG_ZERO, REG_SP, LA_LR_OFFSET);
+       M_STWU(REG_SP, REG_SP, -(LA_SIZE + (1 + 2 + 2 + 1 + 4) * 4));
 
-               emit_store(jd, iptr, dst, d);
+       /* save return registers */
+
+       M_LST(REG_RESULT_PACKED, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 0) * 4);
+       M_DST(REG_FRESULT, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 2) * 4);
+
+       /* keep this order */
+       switch (md->returntype.type) {
+       case TYPE_INT:
+       case TYPE_ADR:
+               M_INTMOVE(REG_RESULT, REG_A1);
+               M_CLR(REG_A0);
+               break;
+
+       case TYPE_LNG:
+               M_LNGMOVE(REG_RESULT_PACKED, REG_A0_A1_PACKED);
+               break;
        }
-}
 
+       M_FLTMOVE(REG_FRESULT, REG_FA0);
+       M_FLTMOVE(REG_FRESULT, REG_FA1);
 
-/* emit_iconst *****************************************************************
+       disp = dseg_add_address(cd, m);
+       M_ALD(REG_A2, REG_PV, disp);
 
-   XXX
+       disp = dseg_add_functionptr(cd, builtin_verbosecall_exit);
+       M_ALD(REG_ITMP2, REG_PV, disp);
+       M_MTCTR(REG_ITMP2);
+       M_JSR;
 
-*******************************************************************************/
+       /* restore return registers */
 
-void emit_iconst(codegendata *cd, s4 d, s4 value)
-{
-       s4 disp;
+       M_LLD(REG_RESULT_PACKED, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 0) * 4);
+       M_DLD(REG_FRESULT, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 2) * 4);
 
-       if ((value >= -32768) && (value <= 32767))
-               M_LDA_INTERN(d, REG_ZERO, value);
-       else {
-               disp = dseg_adds4(cd, value);
-               M_ILD(d, REG_PV, disp);
-       }
+       M_ALD(REG_ZERO, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 4) * 4 + LA_LR_OFFSET);
+       M_MTLR(REG_ZERO);
+       M_LDA(REG_SP, REG_SP, LA_SIZE + (1 + 2 + 2 + 1 + 4) * 4);
+
+       /* mark trace code */
+
+       M_NOP;
+#endif /* !defined(NDEBUG) */
 }